first commit
This commit is contained in:
87
docs/devtools/tooling/installer/src/host/prompts.md
Normal file
87
docs/devtools/tooling/installer/src/host/prompts.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# `prompts`
|
||||
|
||||
## Purpose
|
||||
|
||||
Runs the plugin's optional `prompts` stage and validates the answers
|
||||
against the schema the plugin returns. This is where `--answers <file>`
|
||||
flows in (via `answersFromFile`) and where `--no-interactive` is enforced.
|
||||
Validation failures surface as `INSTALLER.PROMPT_VALIDATION_FAILED` with
|
||||
the underlying Zod (or other compatible) error attached as `cause` and
|
||||
field-level issues attached as `context.issues`.
|
||||
|
||||
## Features
|
||||
|
||||
- Accepts both explicit `answers` (programmatic harness) and
|
||||
`answersFromFile` (loaded from a JSON file by the bin).
|
||||
- Fails fast under `noInteractive` when a plugin demands answers that
|
||||
weren't pre-supplied — prevents silent prompts in CI.
|
||||
- No-op when the plugin omits `prompts` — explicit answers pass through,
|
||||
otherwise an empty `{}` is supplied to plan. Plugins that need answers
|
||||
must declare a schema.
|
||||
- Wrapped in OTel span `installer.prompts` so prompt validation timing is
|
||||
observable.
|
||||
|
||||
## Basic Example
|
||||
|
||||
```ts
|
||||
import { runPrompts } from "@suaveplan/installer";
|
||||
import z from "zod";
|
||||
|
||||
const schema = z.object({ name: z.string().min(1) });
|
||||
const plugin = {
|
||||
id: "demo",
|
||||
version: "0.1.0",
|
||||
prompts: () => schema,
|
||||
plan: async () => [],
|
||||
apply: async () => undefined,
|
||||
};
|
||||
const answers = await runPrompts({
|
||||
plugin,
|
||||
ctx,
|
||||
explicitAnswers: { name: "alice" },
|
||||
});
|
||||
```
|
||||
|
||||
## Advanced Example
|
||||
|
||||
```ts
|
||||
import { runPrompts, InstallerError } from "@suaveplan/installer";
|
||||
|
||||
try {
|
||||
const answers = await runPrompts({
|
||||
plugin,
|
||||
ctx,
|
||||
answersFromFile: JSON.parse(await fileContent),
|
||||
});
|
||||
// ... pass to plan
|
||||
} catch (err) {
|
||||
if (
|
||||
err instanceof InstallerError &&
|
||||
err.code === "INSTALLER.PROMPT_VALIDATION_FAILED"
|
||||
) {
|
||||
const issues = err.context?.["issues"];
|
||||
console.error("Invalid answers:", issues);
|
||||
process.exit(2);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `runPrompts<TAnswers>(options): Promise<TAnswers>`
|
||||
- `interface RunPromptsOptions<TAnswers>` —
|
||||
`{ plugin, ctx, explicitAnswers?, answersFromFile? }`.
|
||||
- Errors: `INSTALLER.PROMPT_VALIDATION_FAILED` for missing answers,
|
||||
validation failures, or non-interactive without answers.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`explicitAnswers` is preferred over `answersFromFile` when both are
|
||||
supplied — the testing harness uses `explicitAnswers` and we want it to
|
||||
take precedence when callers also pass a file. `safeParse` is used
|
||||
instead of `parse` so the host can attach the Zod issues as structured
|
||||
context rather than letting them bubble as raw `ZodError`. The schema
|
||||
returned by `plugin.prompts` is treated structurally (`PromptSchema<T>`),
|
||||
not nominally — any object with `parse` and `safeParse` is acceptable,
|
||||
which lets plugins swap validators without breaking the host contract.
|
||||
Reference in New Issue
Block a user