# @suaveplan/installer - Plugin host + lifecycle for project boilerplating and asset installation: detect → prompts → plan → apply → postInstall, transactional apply with rollback, conflict policies, manifest discovery. ## Summary Plugin host for project boilerplating and asset installation. Pipelines plugins through `detect → prompts → plan → apply → postInstall` with transactional rollback, conflict resolution, and dry-run support. ## Documentation tree - [bin](./src/bin/suaveplan-install.md) — _(no submodules)_ - [suaveplan-install](./src/bin/suaveplan-install.md) — _(no submodules)_ - [errors](./src/errors/errors.md) — _(no submodules)_ - [errors](./src/errors/errors.md) — _(no submodules)_ - [disk-fs](./src/fs/disk-fs.md) — Disk-backed implementation of `MutableInstallerFs` used by the `suaveplan-install` bin and any host-side code that want… - [installer-fs](./src/fs/installer-fs.md) — Re-exports the read-only `InstallerFs` interface from the types module and declares its mutating extension `MutableInst… - [memory-fs](./src/fs/memory-fs.md) — In-memory implementation of `MutableInstallerFs`. Used by the testing harness (`runPlugin` constructs one if the caller… - [host](./src/host/host.md) — _(no submodules)_ - conflict — Resolves the per-op `conflict` policy on… - [apply](./src/host/apply/apply.md) — _(no submodules)_ - conflict — Resolves the per-op `conflict` policy on… - [apply](./src/host/apply/apply.md) — _(no submodules)_ - conflict — Resolves the per-op `conflict` policy on… - [conflict](./src/host/apply/conflict.md) — Resolves the per-op `conflict` policy on a target that already exists. Five policies are supported: `error` (raise `APP… - [json-merge](./src/host/apply/json-merge.md) — Implements the deep-merge semantics used by `patch-json` ops with `conflict: "merge"`. Match the conventions of `@suave… - [text-patch](./src/host/apply/text-patch.md) — Applies an ordered sequence of `TextEdit`s to a string. Used by `patch-text` ops to make targeted insertions/deletions/… - [detect](./src/host/detect.md) — Runs a plugin's optional `detect` stage inside an OpenTelemetry span. The plugin reports what is already present in the… - [host](./src/host/host.md) — _(no submodules)_ - conflict — Resolves the per-op `conflict` policy on… - [plan](./src/host/plan.md) — Invokes `plugin.plan(answers, ctx)` and validates the returned `FileOp[]` against `FileOpsSchema` before letting them f… - [post-install](./src/host/post-install.md) — Runs the plugin's optional `postInstall` stage with abort propagation. This is where plugins do follow-up work that doe… - [prompts](./src/host/prompts.md) — Runs the plugin's optional `prompts` stage and validates the answers against the schema the plugin returns. This is whe… - [manifest](./src/manifest/manifest.md) — _(no submodules)_ - [discover](./src/manifest/discover.md) — Walks the consumer's `node_modules` tree and returns every installer plugin matching the naming conventions: first-part… - [manifest](./src/manifest/manifest.md) — _(no submodules)_ - [installer-fs.test-helpers](./src/testing/installer-fs.test-helpers.md) — Convenience helpers for assertions against the in-memory installer fs in plugin tests. `createMemoryFs(seed)` is a thin… - [run-plugin](./src/testing/run-plugin.md) — End-to-end test harness for plugins. `runPlugin(plugin, options)` wires up an in-memory filesystem, a scripted CLI, a n… - [script-cli](./src/testing/script-cli.md) — Non-TTY `InstallerCli` driven by pre-recorded answers. `ScriptCli` is the default CLI used by `runPlugin` — tests scrip… - [error-codes](./src/error-codes.md) — Defines the canonical error-code registry for `@suaveplan/installer` and the `InstallerError` class that carries those… - [suaveplan-install](./src/bin/suaveplan-install.md) — _(no submodules)_- [errors](./src/errors/errors.md) — _(no submodules)_- [errors](./src/errors/errors.md) — _(no submodules)_- [disk-fs](./src/fs/disk-fs.md) — Disk-backed implementation of `MutableInstallerFs` used by the `suaveplan-install` bin and any host-side code that want… - [installer-fs](./src/fs/installer-fs.md) — Re-exports the read-only `InstallerFs` interface from the types module and declares its mutating extension `MutableInst… - [memory-fs](./src/fs/memory-fs.md) — In-memory implementation of `MutableInstallerFs`. Used by the testing harness (`runPlugin` constructs one if the caller… - [host](./src/host/host.md) — _(no submodules)_- conflict — Resolves the per-op `conflict` policy on… - [apply](./src/host/apply/apply.md) — _(no submodules)_- conflict — Resolves the per-op `conflict` policy on… - [apply](./src/host/apply/apply.md) — _(no submodules)_- conflict — Resolves the per-op `conflict` policy on… - [conflict](./src/host/apply/conflict.md) — Resolves the per-op `conflict` policy on a target that already exists. Five policies are supported: `error` (raise `APP… - [json-merge](./src/host/apply/json-merge.md) — Implements the deep-merge semantics used by `patch-json` ops with `conflict: "merge"`. Match the conventions of `@suave… - [text-patch](./src/host/apply/text-patch.md) — Applies an ordered sequence of `TextEdit`s to a string. Used by `patch-text` ops to make targeted insertions/deletions/… - [detect](./src/host/detect.md) — Runs a plugin's optional `detect` stage inside an OpenTelemetry span. The plugin reports what is already present in the… - [host](./src/host/host.md) — _(no submodules)_- conflict — Resolves the per-op `conflict` policy on… - [plan](./src/host/plan.md) — Invokes `plugin.plan(answers, ctx)` and validates the returned `FileOp[]` against `FileOpsSchema` before letting them f… - [post-install](./src/host/post-install.md) — Runs the plugin's optional `postInstall` stage with abort propagation. This is where plugins do follow-up work that doe… - [prompts](./src/host/prompts.md) — Runs the plugin's optional `prompts` stage and validates the answers against the schema the plugin returns. This is whe… - [manifest](./src/manifest/manifest.md) — _(no submodules)_- [discover](./src/manifest/discover.md) — Walks the consumer's `node_modules` tree and returns every installer plugin matching the naming conventions: first-part… - [manifest](./src/manifest/manifest.md) — _(no submodules)_- [installer-fs.test-helpers](./src/testing/installer-fs.test-helpers.md) — Convenience helpers for assertions against the in-memory installer fs in plugin tests. `createMemoryFs(seed)` is a thin… - [run-plugin](./src/testing/run-plugin.md) — End-to-end test harness for plugins. `runPlugin(plugin, options)` wires up an in-memory filesystem, a scripted CLI, a n… - [script-cli](./src/testing/script-cli.md) — Non-TTY `InstallerCli` driven by pre-recorded answers. `ScriptCli` is the default CLI used by `runPlugin` — tests scrip… - [error-codes](./src/error-codes.md) — Defines the canonical error-code registry for `@suaveplan/installer` and the `InstallerError` class that carries those… - [suaveplan-install](./src/bin/suaveplan-install.md) — _(no submodules)_- [errors](./src/errors/errors.md) — _(no submodules)_- [errors](./src/errors/errors.md) — _(no submodules)_- [disk-fs](./src/fs/disk-fs.md) — Disk-backed implementation of `MutableInstallerFs` used by the `suaveplan-install` bin and any host-side code that want… - [installer-fs](./src/fs/installer-fs.md) — Re-exports the read-only `InstallerFs` interface from the types module and declares its mutating extension `MutableInst… - [memory-fs](./src/fs/memory-fs.md) — In-memory implementation of `MutableInstallerFs`. Used by the testing harness (`runPlugin` constructs one if the caller… - [host](./src/host/host.md) — _(no submodules)_- conflict — Resolves the per-op `conflict` policy on… - [apply](./src/host/apply/apply.md) — _(no submodules)_- conflict — Resolves the per-op `conflict` policy on… - [apply](./src/host/apply/apply.md) — _(no submodules)_- conflict — Resolves the per-op `conflict` policy on… - [conflict](./src/host/apply/conflict.md) — Resolves the per-op `conflict` policy on a target that already exists. Five policies are supported: `error` (raise `APP… - [json-merge](./src/host/apply/json-merge.md) — Implements the deep-merge semantics used by `patch-json` ops with `conflict: "merge"`. Match the conventions of `@suave… - [text-patch](./src/host/apply/text-patch.md) — Applies an ordered sequence of `TextEdit`s to a string. Used by `patch-text` ops to make targeted insertions/deletions/… - [detect](./src/host/detect.md) — Runs a plugin's optional `detect` stage inside an OpenTelemetry span. The plugin reports what is already present in the… - [host](./src/host/host.md) — _(no submodules)_- conflict — Resolves the per-op `conflict` policy on… - [plan](./src/host/plan.md) — Invokes `plugin.plan(answers, ctx)` and validates the returned `FileOp[]` against `FileOpsSchema` before letting them f… - [post-install](./src/host/post-install.md) — Runs the plugin's optional `postInstall` stage with abort propagation. This is where plugins do follow-up work that doe… - [prompts](./src/host/prompts.md) — Runs the plugin's optional `prompts` stage and validates the answers against the schema the plugin returns. This is whe… - [manifest](./src/manifest/manifest.md) — _(no submodules)_- [discover](./src/manifest/discover.md) — Walks the consumer's `node_modules` tree and returns every installer plugin matching the naming conventions: first-part… - [manifest](./src/manifest/manifest.md) — _(no submodules)_- [installer-fs.test-helpers](./src/testing/installer-fs.test-helpers.md) — Convenience helpers for assertions against the in-memory installer fs in plugin tests. `createMemoryFs(seed)` is a thin… - [run-plugin](./src/testing/run-plugin.md) — End-to-end test harness for plugins. `runPlugin(plugin, options)` wires up an in-memory filesystem, a scripted CLI, a n… - [script-cli](./src/testing/script-cli.md) — Non-TTY `InstallerCli` driven by pre-recorded answers. `ScriptCli` is the default CLI used by `runPlugin` — tests scrip… - [error-codes](./src/error-codes.md) — Defines the canonical error-code registry for `@suaveplan/installer` and the `InstallerError` class that carries those… - [suaveplan-install](./src/bin/suaveplan-install.md) — _(no submodules)_- [errors](./src/errors/errors.md) — _(no submodules)_- [errors](./src/errors/errors.md) — _(no submodules)_- [disk-fs](./src/fs/disk-fs.md) — Disk-backed implementation of `MutableInstallerFs` used by the `suaveplan-install` bin and any host-side code that want… - [installer-fs](./src/fs/installer-fs.md) — Re-exports the read-only `InstallerFs` interface from the types module and declares its mutating extension `MutableInst… - [memory-fs](./src/fs/memory-fs.md) — In-memory implementation of `MutableInstallerFs`. Used by the testing harness (`runPlugin` constructs one if the caller… - [host](./src/host/host.md) — _(no submodules)_- apply — _(no submodules)_… - [apply](./src/host/apply/apply.md) — _(no submodules)_- conflict — Resolves the per-op `conflict` policy on… - [apply](./src/host/apply/apply.md) — _(no submodules)_- conflict — Resolves the per-op `conflict` policy on… - [conflict](./src/host/apply/conflict.md) — Resolves the per-op `conflict` policy on a target that already exists. Five policies are supported: `error` (raise `APP… - [json-merge](./src/host/apply/json-merge.md) — Implements the deep-merge semantics used by `patch-json` ops with `conflict: "merge"`. Match the conventions of `@suave… - [text-patch](./src/host/apply/text-patch.md) — Applies an ordered sequence of `TextEdit`s to a string. Used by `patch-text` ops to make targeted insertions/deletions/… - [detect](./src/host/detect.md) — Runs a plugin's optional `detect` stage inside an OpenTelemetry span. The plugin reports what is already present in the… - [host](./src/host/host.md) — _(no submodules)_- apply — _(no submodules)_… - [plan](./src/host/plan.md) — Invokes `plugin.plan(answers, ctx)` and validates the returned `FileOp[]` against `FileOpsSchema` before letting them f… - [post-install](./src/host/post-install.md) — Runs the plugin's optional `postInstall` stage with abort propagation. This is where plugins do follow-up work that doe… - [prompts](./src/host/prompts.md) — Runs the plugin's optional `prompts` stage and validates the answers against the schema the plugin returns. This is whe… - [manifest](./src/manifest/manifest.md) — _(no submodules)_- [discover](./src/manifest/discover.md) — Walks the consumer's `node_modules` tree and returns every installer plugin matching the naming conventions: first-part… - [manifest](./src/manifest/manifest.md) — _(no submodules)_- [installer-fs.test-helpers](./src/testing/installer-fs.test-helpers.md) — Convenience helpers for assertions against the in-memory installer fs in plugin tests. `createMemoryFs(seed)` is a thin… - [run-plugin](./src/testing/run-plugin.md) — End-to-end test harness for plugins. `runPlugin(plugin, options)` wires up an in-memory filesystem, a scripted CLI, a n… - [script-cli](./src/testing/script-cli.md) — Non-TTY `InstallerCli` driven by pre-recorded answers. `ScriptCli` is the default CLI used by `runPlugin` — tests scrip… - [error-codes](./src/error-codes.md) — Defines the canonical error-code registry for `@suaveplan/installer` and the `InstallerError` class that carries those… - [suaveplan-install](./src/bin/suaveplan-install.md) — _(no submodules)_- [errors](./src/errors/errors.md) — _(no submodules)_ - [errors](./src/errors/errors.md) — _(no submodules)_- [disk-fs](./src/fs/disk-fs.md) — Disk-backed implementation of `MutableInstallerFs` used by the `suaveplan-install` bin and any host-side code that want… - [installer-fs](./src/fs/installer-fs.md) — Re-exports the read-only `InstallerFs` interface from the types module and declares its mutating extension `MutableInst… - [memory-fs](./src/fs/memory-fs.md) — In-memory implementation of `MutableInstallerFs`. Used by the testing harness (`runPlugin` constructs one if the caller… - [host](./src/host/host.md) — _(no submodules)_ - [apply](./src/host/apply/apply.md) — _(no submodules)_ - [apply](./src/host/apply/apply.md) — _(no submodules)_ - [conflict](./src/host/apply/conflict.md) — Resolves the per-op `conflict` policy on a target that already exists. Five policies are supported: `error` (raise `APP… - [json-merge](./src/host/apply/json-merge.md) — Implements the deep-merge semantics used by `patch-json` ops with `conflict: "merge"`. Match the conventions of `@suave… - [text-patch](./src/host/apply/text-patch.md) — Applies an ordered sequence of `TextEdit`s to a string. Used by `patch-text` ops to make targeted insertions/deletions/… - [detect](./src/host/detect.md) — Runs a plugin's optional `detect` stage inside an OpenTelemetry span. The plugin reports what is already present in the… - [host](./src/host/host.md) — _(no submodules)_ - [plan](./src/host/plan.md) — Invokes `plugin.plan(answers, ctx)` and validates the returned `FileOp[]` against `FileOpsSchema` before letting them f… - [post-install](./src/host/post-install.md) — Runs the plugin's optional `postInstall` stage with abort propagation. This is where plugins do follow-up work that doe… - [prompts](./src/host/prompts.md) — Runs the plugin's optional `prompts` stage and validates the answers against the schema the plugin returns. This is whe… - [manifest](./src/manifest/manifest.md) — _(no submodules)_ - [discover](./src/manifest/discover.md) — Walks the consumer's `node_modules` tree and returns every installer plugin matching the naming conventions: first-part… - [manifest](./src/manifest/manifest.md) — _(no submodules)_- [installer-fs.test-helpers](./src/testing/installer-fs.test-helpers.md) — Convenience helpers for assertions against the in-memory installer fs in plugin tests. `createMemoryFs(seed)` is a thin… - [run-plugin](./src/testing/run-plugin.md) — End-to-end test harness for plugins. `runPlugin(plugin, options)` wires up an in-memory filesystem, a scripted CLI, a n… - [script-cli](./src/testing/script-cli.md) — Non-TTY `InstallerCli` driven by pre-recorded answers. `ScriptCli` is the default CLI used by `runPlugin` — tests scrip… - [error-codes](./src/error-codes.md) — Defines the canonical error-code registry for `@suaveplan/installer` and the `InstallerError` class that carries those… ## Quickstart ```bash # Add a plugin to your project as a dev dep, then run the installer bun add -D @suaveplan/install-agent-skills npx @suaveplan/installer add agent-skills ``` ## Programmatic use ```ts import { Host, DiskFs, type InstallerContext, } from "@suaveplan/installer"; const fs = new DiskFs({ cwd: process.cwd() }); const host = new Host(ctx, fs); const result = await host.run(myPlugin, { dryRun: false, force: false, noInteractive: true, }); console.log(result.summary); ``` ## Testing harness ```ts import { runPlugin, ScriptCli } from "@suaveplan/installer"; const result = await runPlugin(myPlugin, { answers: { name: "agent-skills" }, }); expect(result.summary.written).toBeGreaterThan(0); ``` ## Subpath exports - `@suaveplan/installer` — main barrel. - `@suaveplan/installer/types` — types-only. - `@suaveplan/installer/errors` — `INSTALLER_CODES`, `InstallerError`. - `@suaveplan/installer/host` — `Host`, stage runners, apply/conflict helpers. - `@suaveplan/installer/fs` — `DiskFs`, `MemoryFs`, `MutableInstallerFs`. - `@suaveplan/installer/manifest` — `discoverPlugins`, `findPlugin`, `loadManifest`, `validateManifest`. - `@suaveplan/installer/testing` — `runPlugin`, `ScriptCli`, `assertWrote`, `createMemoryFs`. ## Module documentation Every implementation file ships with a sibling `.md` covering Purpose, Features, Usage examples, API Reference, and Implementation Notes. See `src/host/host.md`, `src/host/apply/apply.md`, `src/manifest/discover.md` for the load-bearing modules. ## License MIT