148 lines
10 KiB
Markdown
148 lines
10 KiB
Markdown
# `host`
|
|
|
|
<!-- begin:auto-docs -->
|
|
_(no submodules)_
|
|
<!-- end:auto-docs --> - conflict — Resolves the per-op `conflict` policy on…
|
|
- [apply](./apply/apply.md) — <!-- begin:auto-docs --> _(no submodules)_- conflict — Resolves the per-op `conflict` policy on…
|
|
- [conflict](./apply/conflict.md) — Resolves the per-op `conflict` policy on a target that already exists. Five policies are supported: `error` (raise `APP…
|
|
- [json-merge](./apply/json-merge.md) — Implements the deep-merge semantics used by `patch-json` ops with `conflict: "merge"`. Match the conventions of `@suave…
|
|
- [text-patch](./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](./detect.md) — Runs a plugin's optional `detect` stage inside an OpenTelemetry span. The plugin reports what is already present in the…
|
|
- [host](./host.md) — <!-- begin:auto-docs --> _(no submodules)_- conflict — Resolves the per-op `conflict` policy on…
|
|
- [plan](./plan.md) — Invokes `plugin.plan(answers, ctx)` and validates the returned `FileOp[]` against `FileOpsSchema` before letting them f…
|
|
- [post-install](./post-install.md) — Runs the plugin's optional `postInstall` stage with abort propagation. This is where plugins do follow-up work that doe…
|
|
- [prompts](./prompts.md) — Runs the plugin's optional `prompts` stage and validates the answers against the schema the plugin returns. This is whe…
|
|
- conflict — Resolves the per-op `conflict` policy on…
|
|
|
|
- [apply](./apply/apply.md) — <!-- begin:auto-docs --> _(no submodules)_- conflict — Resolves the per-op `conflict` policy on…
|
|
- [conflict](./apply/conflict.md) — Resolves the per-op `conflict` policy on a target that already exists. Five policies are supported: `error` (raise `APP…
|
|
- [json-merge](./apply/json-merge.md) — Implements the deep-merge semantics used by `patch-json` ops with `conflict: "merge"`. Match the conventions of `@suave…
|
|
- [text-patch](./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](./detect.md) — Runs a plugin's optional `detect` stage inside an OpenTelemetry span. The plugin reports what is already present in the…
|
|
- [host](./host.md) — <!-- begin:auto-docs --> _(no submodules)_- conflict — Resolves the per-op `conflict` policy on…
|
|
- [plan](./plan.md) — Invokes `plugin.plan(answers, ctx)` and validates the returned `FileOp[]` against `FileOpsSchema` before letting them f…
|
|
- [post-install](./post-install.md) — Runs the plugin's optional `postInstall` stage with abort propagation. This is where plugins do follow-up work that doe…
|
|
- [prompts](./prompts.md) — Runs the plugin's optional `prompts` stage and validates the answers against the schema the plugin returns. This is whe…
|
|
|
|
- conflict — Resolves the per-op `conflict` policy on…
|
|
|
|
- [apply](./apply/apply.md) — <!-- begin:auto-docs --> _(no submodules)_- conflict — Resolves the per-op `conflict` policy on…
|
|
- [conflict](./apply/conflict.md) — Resolves the per-op `conflict` policy on a target that already exists. Five policies are supported: `error` (raise `APP…
|
|
- [json-merge](./apply/json-merge.md) — Implements the deep-merge semantics used by `patch-json` ops with `conflict: "merge"`. Match the conventions of `@suave…
|
|
- [text-patch](./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](./detect.md) — Runs a plugin's optional `detect` stage inside an OpenTelemetry span. The plugin reports what is already present in the…
|
|
- [host](./host.md) — <!-- begin:auto-docs --> _(no submodules)_- conflict — Resolves the per-op `conflict` policy on…
|
|
- [plan](./plan.md) — Invokes `plugin.plan(answers, ctx)` and validates the returned `FileOp[]` against `FileOpsSchema` before letting them f…
|
|
- [post-install](./post-install.md) — Runs the plugin's optional `postInstall` stage with abort propagation. This is where plugins do follow-up work that doe…
|
|
- [prompts](./prompts.md) — Runs the plugin's optional `prompts` stage and validates the answers against the schema the plugin returns. This is whe…
|
|
|
|
- conflict — Resolves the per-op `conflict` policy on…
|
|
|
|
- [apply](./apply/apply.md) — <!-- begin:auto-docs --> _(no submodules)_- conflict — Resolves the per-op `conflict` policy on…
|
|
- [conflict](./apply/conflict.md) — Resolves the per-op `conflict` policy on a target that already exists. Five policies are supported: `error` (raise `APP…
|
|
- [json-merge](./apply/json-merge.md) — Implements the deep-merge semantics used by `patch-json` ops with `conflict: "merge"`. Match the conventions of `@suave…
|
|
- [text-patch](./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](./detect.md) — Runs a plugin's optional `detect` stage inside an OpenTelemetry span. The plugin reports what is already present in the…
|
|
- [host](./host.md) — <!-- begin:auto-docs --> _(no submodules)_- apply — <!-- begin:auto-docs --> _(no submodules)_…
|
|
- [plan](./plan.md) — Invokes `plugin.plan(answers, ctx)` and validates the returned `FileOp[]` against `FileOpsSchema` before letting them f…
|
|
- [post-install](./post-install.md) — Runs the plugin's optional `postInstall` stage with abort propagation. This is where plugins do follow-up work that doe…
|
|
- [prompts](./prompts.md) — Runs the plugin's optional `prompts` stage and validates the answers against the schema the plugin returns. This is whe…
|
|
- [apply](./apply/apply.md) — <!-- begin:auto-docs --> _(no submodules)_- [conflict](./apply/conflict.md) — Resolves the per-op `conflict` policy on a target that already exists. Five policies are supported: `error` (raise `APP…
|
|
- [json-merge](./apply/json-merge.md) — Implements the deep-merge semantics used by `patch-json` ops with `conflict: "merge"`. Match the conventions of `@suave…
|
|
- [text-patch](./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](./detect.md) — Runs a plugin's optional `detect` stage inside an OpenTelemetry span. The plugin reports what is already present in the…
|
|
- [host](./host.md) — <!-- begin:auto-docs --> _(no submodules)_- [plan](./plan.md) — Invokes `plugin.plan(answers, ctx)` and validates the returned `FileOp[]` against `FileOpsSchema` before letting them f…
|
|
- [post-install](./post-install.md) — Runs the plugin's optional `postInstall` stage with abort propagation. This is where plugins do follow-up work that doe…
|
|
- [prompts](./prompts.md) — Runs the plugin's optional `prompts` stage and validates the answers against the schema the plugin returns. This is whe…
|
|
|
|
## Purpose
|
|
|
|
The plugin host. `Host.run(plugin, options)` executes the strict pipeline
|
|
`detect → prompts → plan → apply → postInstall`, with abort propagation,
|
|
`--dry-run` short-circuiting, and `only`/`exclude` filtering. Each stage is
|
|
wrapped in an OpenTelemetry span (`installer.<stage>`) carrying
|
|
`plugin.id`, `plugin.version`, and `dry_run` attributes — that
|
|
instrumentation is what lets operators correlate apply failures with the
|
|
specific plugin and version that produced them.
|
|
|
|
## Features
|
|
|
|
- Strict ordering — optional stages (`detect`, `prompts`, `postInstall`)
|
|
are skipped without affecting the order of mandatory stages (`plan`,
|
|
`apply`).
|
|
- Abort checks at every stage boundary — if the signal aborts mid-run, the
|
|
host raises `INSTALLER.ABORTED` and apply rolls back any partial work.
|
|
- `--dry-run` — when set, the host returns the plan ops without invoking
|
|
apply or postInstall.
|
|
- `only`/`exclude` — substring filters applied to the op target path
|
|
(`op.to` for renames, `op.path` otherwise) before apply runs.
|
|
- `answersFromFile` channel — used by the bin's `--answers <file>` flag to
|
|
feed pre-recorded answers into prompt validation without going
|
|
interactive.
|
|
|
|
## Basic Example
|
|
|
|
```ts
|
|
import { Host, MemoryFs } from "@suaveplan/installer";
|
|
|
|
const fs = new MemoryFs();
|
|
const host = new Host(
|
|
{
|
|
cwd: "/",
|
|
fs,
|
|
cli: { confirm: async () => false, prompt: async () => "", write: () => undefined },
|
|
signal: new AbortController().signal,
|
|
logger: {
|
|
debug: () => undefined,
|
|
info: () => undefined,
|
|
warn: () => undefined,
|
|
error: () => undefined,
|
|
},
|
|
templates: { render: (s) => s },
|
|
dryRun: false,
|
|
force: false,
|
|
noInteractive: true,
|
|
},
|
|
fs
|
|
);
|
|
const result = await host.run(myPlugin);
|
|
console.log(result.summary);
|
|
```
|
|
|
|
## Advanced Example
|
|
|
|
```ts
|
|
import { Host } from "@suaveplan/installer";
|
|
|
|
const ac = new AbortController();
|
|
const host = new Host({ ...ctx, signal: ac.signal, dryRun: true }, fs);
|
|
|
|
setTimeout(() => ac.abort(), 5_000);
|
|
|
|
const dryResult = await host.run(myPlugin, {
|
|
only: ["crypto", "events"],
|
|
exclude: ["legacy"],
|
|
});
|
|
console.log(`would apply ${dryResult.ops.length} ops`);
|
|
```
|
|
|
|
## API Reference
|
|
|
|
- `class Host` — constructed with `(ctx: InstallerContext, fs: MutableInstallerFs)`.
|
|
- `Host.run<TAnswers, THandle>(plugin, options): Promise<HostRunResult<THandle>>`
|
|
- `interface HostRunOptions<TAnswers> extends RunOptions<TAnswers>` —
|
|
adds `answersFromFile?: unknown` for the bin.
|
|
- `interface HostRunResult<THandle>` — `{ detect, ops, summary, handle, dryRun }`.
|
|
|
|
## Implementation Notes
|
|
|
|
`filterOps` runs _after_ plan but _before_ apply, so the conformance
|
|
guarantee that "every emitted op respects its conflict policy on re-run"
|
|
applies to the post-filter set. `--dry-run` returns a synthetic summary
|
|
(`skipped = ops.length`) so dashboards see a coherent counter even on
|
|
hypothetical runs. Abort checks are placed at every awaitable boundary
|
|
(after detect, after prompts, before apply) so a long-running prompt
|
|
schema can be cancelled cleanly. `applyOps` itself owns the rollback
|
|
journal — the host's only responsibility post-apply is to wire up
|
|
`postInstall` with the resulting handle.
|