Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,72 @@
# `plan`
## Purpose
Invokes `plugin.plan(answers, ctx)` and validates the returned `FileOp[]`
against `FileOpsSchema` before letting them flow into apply. This is the
quality gate that prevents a buggy plugin from feeding malformed ops into
the host's transactional apply path. Both plugin-thrown errors and
schema-validation failures surface as `INSTALLER.PLAN_FAILED` so callers
have a single code to switch on.
## Features
- Schema validation via `FileOpsSchema` — every op kind, path, contents
type, and conflict policy is checked at the boundary.
- Wrapped in OTel span `installer.plan` carrying `plugin.id`,
`plugin.version`, and `dry_run`.
- Distinguishes `plan` failures (plugin threw) from invalid-shape failures
(plan returned bad ops) only via `messageKey` — both surface as the
same code, which keeps consumer error handlers simple.
- Original error chained via `cause` so the underlying Zod error or
plugin exception is recoverable for logging.
## Basic Example
```ts
import { runPlan } from "@suaveplan/installer";
const ops = await runPlan(myPlugin, answers, ctx);
console.log(`plan returned ${ops.length} ops`);
```
## Advanced Example
```ts
import { InstallerError, runPlan } from "@suaveplan/installer";
try {
const ops = await runPlan(myPlugin, answers, ctx);
return ops;
} catch (err) {
if (
err instanceof InstallerError &&
err.code === "INSTALLER.PLAN_FAILED"
) {
const issues = err.context?.["issues"];
if (issues) {
console.error("Plugin returned invalid ops:", issues);
} else {
console.error("Plugin plan threw:", err.cause);
}
}
throw err;
}
```
## API Reference
- `runPlan<TAnswers, THandle>(plugin, answers, ctx): Promise<ReadonlyArray<FileOp>>`
- Errors: `INSTALLER.PLAN_FAILED` with either:
- `installer.plan.invalid_ops` and `context.issues` for schema failures
- `installer.plan.threw` and `cause` set to the plugin's exception
## Implementation Notes
Validation runs *after* the plugin returns, so a plugin can build ops
incrementally without seeing intermediate validation errors. The schema
also fixes the common mistake of returning a single op instead of an
array — `FileOpsSchema` requires `Array<FileOp>` so that gets caught at
the boundary instead of crashing later in apply. If the plugin already
threw an `InstallerError`, we re-throw it directly rather than wrapping
twice — this preserves `cause` chains all the way to the top.