grimoire-wizard 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -17,1538 +17,265 @@
17
17
 
18
18
  ---
19
19
 
20
- Grimoire is a config-driven CLI wizard framework for Node.js. You write a YAML or JSON file describing your prompts, branching logic, and output format, then grimoire handles the rest: rendering interactive prompts, tracking navigation history, evaluating conditions, and writing structured output. No code required for simple wizards. Full TypeScript support when you need to go deeper. It works equally well as a standalone CLI tool, a library embedded in your own tooling, or a non-interactive automation step in CI/CD pipelines.
21
-
22
- ## Features
23
-
24
- - **10 input types** — text, select, multiselect, confirm, password, number, search, editor, path, toggle
25
- - **Conditional branching** — show or skip steps based on previous answers using `when` conditions
26
- - **Route-based navigation** — select steps can branch to different step sequences
27
- - **Back-navigation** — built-in history stack lets users go back through steps
28
- - **Step groups** — organize steps into named sections with visual headers
29
- - **Visual progress bar** — step counter shown at each prompt
30
- - **Theming** — 7 semantic color tokens and 4 icon overrides for full visual control
31
- - **Structured output** — export answers as JSON, YAML, or `.env` format
32
- - **Config inheritance** — `extends` keyword merges a base config into your wizard
33
- - **Pre-flight checks** — run shell commands before the wizard starts; abort on failure
34
- - **Plugin system** — register custom step types with their own render and validate logic
35
- - **`$ENV_VAR` resolution** — use environment variables as default values in any step
36
- - **Async validation** — hook into step completion to run async checks (API calls, file system, etc.)
37
- - **`--dry-run` preview** — print the full step plan without running any prompts
38
- - **`--mock` non-interactive mode** — supply preset answers as JSON for CI/CD pipelines
39
- - **`--json` structured output** — emit a machine-readable JSON result envelope for AI agents and scripts
40
- - **JSON Schema** — `grimoire.schema.json` for IDE autocomplete in VS Code and any JSON Schema-aware editor
41
- - **Shell completions** — bash, zsh, and fish completion scripts via `grimoire completion`
42
- - **`grimoire create` scaffolder** — interactively generate a new wizard config file
43
- - **`grimoire demo` showcase** — run a built-in demo that exercises all 10 step types
44
- - **Answer caching** — previous answers become defaults on the next run; password steps are never cached
45
- - **Templates** — save and load named answer presets per wizard
46
- - **MRU ordering** — frequently selected options float to the top of select/multiselect/search lists
47
- - **`optionsFrom`** — load select/multiselect/search options from an external JSON or YAML file
48
- - **Lifecycle hooks** — `onBeforeStep` and `onAfterStep` callbacks in the programmatic API
49
- - **Ink renderer** — alternative renderer with box-drawing characters and progress percentages
50
- - **Clack-style renderer** — connected `│` guide lines, `◇` collapsed steps, `┌`/`└` session framing, bordered note boxes
51
- - **6 theme presets** — catppuccin, dracula, nord, tokyonight, monokai; set `preset` in your theme config
52
- - **Note step type** — display bordered info boxes inline in the wizard flow
53
- - **Progress persistence** — auto-resume from where you left off after Ctrl+C; `--no-resume` to disable
54
- - **Step review screen** — review all answers before final submission; set `review: true` in meta
55
- - **Wizard pipelines** — chain multiple wizard configs, forwarding answers between them
56
- - **ASCII art banner** — figlet + gradient banner shown at startup; suppressed with `--plain`
57
- - **`--plain` / `--no-color` flags** — disable colors and banner for plain-text environments
58
-
59
- ## Quick Start
20
+ ## Install
60
21
 
61
22
  ```bash
62
23
  npm install -g grimoire-wizard
63
24
  ```
64
25
 
26
+ ---
27
+
28
+ ## Quick Start
29
+
65
30
  Create `setup.yaml`:
66
31
 
67
32
  ```yaml
68
33
  meta:
69
34
  name: Project Setup
35
+ review: true
70
36
 
71
37
  steps:
72
38
  - id: project-name
73
39
  type: text
74
- message: What is your project name?
40
+ message: Project name?
75
41
  validate:
76
42
  - rule: required
77
- - rule: minLength
78
- value: 2
43
+ - rule: pattern
44
+ value: "^[a-z0-9-]+$"
79
45
 
80
- - id: language
46
+ - id: project-type
81
47
  type: select
82
- message: Pick a language
48
+ message: What kind of project?
83
49
  options:
84
- - { value: typescript, label: TypeScript }
85
- - { value: javascript, label: JavaScript }
50
+ - { value: web, label: "Web App" }
51
+ - { value: api, label: "REST API" }
52
+ - { value: cli, label: "CLI Tool" }
53
+ routes:
54
+ web: framework
55
+ api: framework
56
+ cli: features
86
57
 
87
- output:
88
- format: json
89
- ```
58
+ - id: framework
59
+ type: search
60
+ message: Pick a framework
61
+ options:
62
+ - { value: nextjs, label: "Next.js" }
63
+ - { value: remix, label: Remix }
64
+ - { value: fastify, label: Fastify }
65
+ - { value: express, label: Express }
66
+
67
+ - id: features
68
+ type: multiselect
69
+ message: Features to include
70
+ min: 1
71
+ options:
72
+ - { value: eslint, label: ESLint }
73
+ - { value: prettier, label: Prettier }
74
+ - { value: vitest, label: Vitest }
75
+ - { value: husky, label: Husky }
76
+
77
+ - id: port
78
+ type: number
79
+ message: Dev server port
80
+ default: 3000
81
+ min: 1024
82
+ max: 65535
83
+
84
+ - id: output-dir
85
+ type: path
86
+ message: Output directory
87
+ default: ./my-project
88
+
89
+ - id: theme
90
+ type: toggle
91
+ message: Color scheme
92
+ active: Dark
93
+ inactive: Light
94
+ default: true
95
+
96
+ - id: ts-strict
97
+ type: confirm
98
+ message: Enable strict TypeScript?
99
+ default: true
100
+ when:
101
+ field: project-type
102
+ notEquals: cli
90
103
 
91
- Run it:
104
+ - id: notes
105
+ type: editor
106
+ message: Any notes for the README?
92
107
 
93
- ```bash
94
- grimoire run setup.yaml
95
- ```
108
+ - id: api-key
109
+ type: password
110
+ message: API key (optional)
96
111
 
97
- Or scaffold a new config interactively:
112
+ - id: info
113
+ type: note
114
+ message: "Almost done"
115
+ description: "Review your answers on the next screen."
98
116
 
99
- ```bash
100
- grimoire create my-wizard.yaml
101
- ```
117
+ - id: confirm
118
+ type: confirm
119
+ message: Create project?
120
+ default: true
102
121
 
103
- ## Installation
122
+ output:
123
+ format: json
124
+ path: answers.json
104
125
 
105
- ```bash
106
- npm install grimoire-wizard
126
+ theme:
127
+ preset: catppuccin
107
128
  ```
108
129
 
109
- Node.js >= 18 required. ESM only — your project must use `"type": "module"` or import from `.mjs` files.
110
-
111
- ## CLI Commands
112
-
113
- ### `grimoire run <config>`
114
-
115
- Run a wizard from a config file. Accepts `.yaml`, `.json`, `.js`, or `.ts` files.
130
+ Run it:
116
131
 
117
132
  ```bash
118
133
  grimoire run setup.yaml
119
- grimoire run setup.yaml -o answers.json
120
- grimoire run setup.yaml --dry-run
121
- grimoire run setup.yaml --mock '{"project-name":"my-app","language":"typescript"}'
122
- grimoire run setup.yaml --json
123
- ```
124
-
125
- | Flag | Description |
126
- |------|-------------|
127
- | `-o, --output <path>` | Write answers to a file |
128
- | `-f, --format <format>` | Output format: `json`, `yaml`, or `env` (default: `json`) |
129
- | `-q, --quiet` | Suppress header and summary output |
130
- | `--dry-run` | Print the step plan without running any prompts |
131
- | `--mock <json>` | Run non-interactively with preset answers (JSON object string) |
132
- | `--json` | Emit a structured JSON result envelope to stdout |
133
- | `--no-cache` | Disable answer caching for this run |
134
- | `--no-resume` | Disable progress resume for this run |
135
- | `--template <name>` | Load a saved template as default answers |
136
- | `--renderer <type>` | Renderer to use: `inquirer` (default), `ink`, or `clack` |
137
- | `--plain` | Plain output mode (no colors, no banner) |
138
- | `--no-color` | Disable colored output |
139
-
140
- #### `--dry-run`
141
-
142
- Prints every step with its type, ID, prompt message, visibility status, and any conditions or routes. Useful for reviewing a config before running it.
143
-
144
- ```
145
- Dry Run: "Project Setup"
146
-
147
- Step 1 text project-name "What is your project name?"
148
- Step 2 select language "Pick a language"
149
- ```
150
-
151
- #### `--mock`
152
-
153
- Runs the wizard without any interactive prompts. Pass a JSON object where keys are step IDs and values are the answers. Steps with defaults will use their defaults if not provided in the mock object.
154
-
155
- ```bash
156
- grimoire run setup.yaml --mock '{"project-name":"my-app","language":"typescript"}'
157
- ```
158
-
159
- #### `--json`
160
-
161
- Suppresses all interactive output and emits a single JSON object to stdout:
162
-
163
- ```json
164
- {
165
- "ok": true,
166
- "wizard": "Project Setup",
167
- "answers": {
168
- "project-name": "my-app",
169
- "language": "typescript"
170
- },
171
- "stepsCompleted": 2,
172
- "format": "json"
173
- }
174
- ```
175
-
176
- On error, emits `{ "ok": false, "error": "..." }` and exits with code 1.
177
-
178
- ---
179
-
180
- ### `grimoire validate <config>`
181
-
182
- Parse and validate a config file without running any prompts. Exits with a non-zero code if the config is invalid.
183
-
184
- ```bash
185
- grimoire validate setup.yaml
186
- # Valid wizard config: "Project Setup"
187
- # 2 steps defined
188
- ```
189
-
190
- ---
191
-
192
- ### `grimoire create [output]`
193
-
194
- Interactively scaffold a new wizard config file. Asks for a wizard name, description, number of steps, step types, output format, and optional theme. Writes a ready-to-run YAML file.
195
-
196
- ```bash
197
- grimoire create # writes to wizard.yaml
198
- grimoire create my-wizard.yaml # writes to my-wizard.yaml
199
- ```
200
-
201
- ---
202
-
203
- ### `grimoire demo`
204
-
205
- Run the built-in demo wizard that exercises all 10 step types, step groups, and theming.
206
-
207
- ```bash
208
- grimoire demo
209
- ```
210
-
211
- ---
212
-
213
- ### `grimoire completion <shell>`
214
-
215
- Print a shell completion script to stdout. Pipe it into your shell's completion directory.
216
-
217
- ```bash
218
- grimoire completion bash
219
- grimoire completion zsh
220
- grimoire completion fish
221
134
  ```
222
135
 
223
- See [Shell Completions](#shell-completions) for installation instructions.
224
-
225
136
  ---
226
137
 
227
- ### `grimoire cache clear [name]`
138
+ ## Why grimoire?
228
139
 
229
- Delete cached answers for a specific wizard, or all wizards if no name is given.
230
-
231
- ```bash
232
- grimoire cache clear # clears all cached answers
233
- grimoire cache clear "Project Setup" # clears cache for one wizard
234
- ```
140
+ - **No code required** for simple wizards. Write YAML, get a polished interactive CLI.
141
+ - **CI-friendly** — `--mock '{"step-id":"value"}'` runs non-interactively; `--json` emits structured output.
142
+ - **TypeScript API** when you need lifecycle hooks, async validation, plugins, or pipelines.
143
+ - **Post-wizard actions** shell commands with `{{step-id}}` interpolation run after completion.
235
144
 
236
145
  ---
237
146
 
238
- ### `grimoire template list <wizard-name>`
239
-
240
- List all saved templates for a wizard.
147
+ ## Step Types
241
148
 
242
- ```bash
243
- grimoire template list "Project Setup"
244
- # Templates for "Project Setup":
245
- # - staging
246
- # - production
247
- ```
149
+ | type | returns | use case |
150
+ |------|---------|----------|
151
+ | `text` | `string` | Free-form input with validation |
152
+ | `select` | `string` | Single choice from a list; supports `routes` |
153
+ | `multiselect` | `string[]` | Multiple choices; `min`/`max` constraints |
154
+ | `confirm` | `boolean` | Yes/no prompt |
155
+ | `password` | `string` | Masked input, never cached |
156
+ | `number` | `number` | Numeric input with `min`/`max`/`step` |
157
+ | `search` | `string` | Fuzzy-searchable single choice |
158
+ | `editor` | `string` | Opens terminal editor, returns full text |
159
+ | `path` | `string` | Path input with tab-completion |
160
+ | `toggle` | `boolean` | Binary toggle with custom labels |
161
+ | `note` | — | Inline info box, no input collected |
248
162
 
249
163
  ---
250
164
 
251
- ### `grimoire template delete <wizard-name> <template-name>`
165
+ ## CLI
252
166
 
253
- Delete a saved template.
254
-
255
- ```bash
256
- grimoire template delete "Project Setup" staging
257
- ```
167
+ | command | description |
168
+ |---------|-------------|
169
+ | `grimoire run <config>` | Run a wizard. Flags: `--mock`, `--json`, `--dry-run`, `--template`, `--renderer` |
170
+ | `grimoire validate <config>` | Parse and validate without running |
171
+ | `grimoire create [output]` | Scaffold a new wizard config interactively |
172
+ | `grimoire demo` | Run the built-in demo (all 11 step types) |
173
+ | `grimoire completion <shell>` | Print bash/zsh/fish completion script |
174
+ | `grimoire cache clear [name]` | Clear cached answers |
175
+ | `grimoire template list/delete` | Manage named answer presets |
258
176
 
259
177
  ---
260
178
 
261
- ## Config Format
262
-
263
- A grimoire config has these top-level sections:
264
-
265
- | Section | Required | Description |
266
- |---------|----------|-------------|
267
- | `meta` | yes | Wizard name, version, description |
268
- | `steps` | yes | Array of step definitions |
269
- | `output` | no | Output format and file path |
270
- | `theme` | no | Color tokens and icon overrides |
271
- | `checks` | no | Pre-flight shell commands |
272
- | `extends` | no | Path to a base config to inherit from |
179
+ ## Config Shape
273
180
 
274
181
  ```yaml
182
+ # meta (required)
275
183
  meta:
276
- name: My Wizard
277
- version: 1.0.0
278
- description: A short description shown at startup.
184
+ name: string # wizard title
185
+ version: string # optional semver
186
+ description: string # shown at startup
187
+ review: boolean # show review screen before submit
279
188
 
189
+ # extends (optional) — inherit from a base config
280
190
  extends: ./base.yaml
281
191
 
282
- theme:
283
- tokens:
284
- primary: "#cba6f7"
285
- icons:
286
- pointer: ">"
287
-
192
+ # checks (optional) — pre-flight shell commands, abort on failure
288
193
  checks:
289
- - name: Git available
290
- run: git --version
291
- message: Git is required.
194
+ - name: string
195
+ run: string # shell command
196
+ message: string # error if non-zero exit
292
197
 
198
+ # steps (required) — array of step definitions
293
199
  steps:
294
- - id: project-name
295
- type: text
296
- message: What is your project name?
297
-
200
+ - id: string # unique key in answers output
201
+ type: string # see step types table
202
+ message: string # prompt text
203
+ group: string # section header (shown once per group)
204
+ when: Condition # show only if condition passes
205
+ next: string # override sequential flow; "__done__" to end
206
+ default: any # initial value; "$ENV_VAR" reads from env
207
+ validate: Rule[] # required, minLength, maxLength, pattern, min, max
208
+
209
+ # output (optional)
298
210
  output:
299
- format: json
300
- path: answers.json
301
- ```
302
-
303
- ### `meta`
304
-
305
- | Field | Required | Description |
306
- |-------|----------|-------------|
307
- | `name` | yes | Wizard name, shown in the header |
308
- | `version` | no | Config version string |
309
- | `description` | no | Short description shown below the name |
310
-
311
- ---
312
-
313
- ## Step Types Reference
314
-
315
- Every step requires `id`, `type`, and `message`. All other fields are optional unless noted.
316
-
317
- ### `text`
318
-
319
- Free-form text input with optional placeholder, default, and validation.
320
-
321
- ```yaml
322
- - id: project-name
323
- type: text
324
- message: What is your project name?
325
- placeholder: my-awesome-project
326
- default: my-app
327
- validate:
328
- - rule: required
329
- - rule: minLength
330
- value: 2
331
- - rule: maxLength
332
- value: 64
333
- - rule: pattern
334
- value: "^[a-z0-9-]+$"
335
- message: Only lowercase letters, numbers, and hyphens
336
- ```
337
-
338
- ### `select`
339
-
340
- Single-choice list. Returns the selected `value` string. Options can have a `hint` and can be `disabled`.
341
-
342
- ```yaml
343
- - id: language
344
- type: select
345
- message: Pick a language
346
- default: typescript
347
- options:
348
- - { value: typescript, label: TypeScript }
349
- - { value: javascript, label: JavaScript }
350
- - { value: python, label: Python }
351
- - { value: go, label: Go, hint: "Fast and simple" }
352
- - { value: rust, label: Rust, disabled: true }
353
- routes:
354
- typescript: ts-config
355
- python: python-version
356
- ```
357
-
358
- Instead of inline `options`, use `optionsFrom` to load options from an external file. See [Dynamic Options (`optionsFrom`)](#dynamic-options-optionsfrom).
359
-
360
- ### `multiselect`
361
-
362
- Multi-choice list. Returns an array of selected `value` strings. Use `min` and `max` to constrain selection count.
363
-
364
- ```yaml
365
- - id: features
366
- type: multiselect
367
- message: Select features to include
368
- min: 1
369
- max: 4
370
- options:
371
- - { value: eslint, label: ESLint, hint: Linting }
372
- - { value: prettier, label: Prettier, hint: Formatting }
373
- - { value: vitest, label: Vitest, hint: Testing }
374
- - { value: husky, label: Husky, hint: "Git hooks" }
375
- ```
376
-
377
- Supports `optionsFrom` as an alternative to inline `options`. See [Dynamic Options (`optionsFrom`)](#dynamic-options-optionsfrom).
211
+ format: json | yaml | env
212
+ path: string # write answers to file
378
213
 
379
- ### `confirm`
380
-
381
- Yes/no prompt. Returns a boolean.
382
-
383
- ```yaml
384
- - id: use-typescript
385
- type: confirm
386
- message: Use TypeScript?
387
- default: true
388
- ```
389
-
390
- ### `password`
391
-
392
- Masked text input. The value is included in output but never echoed to the terminal.
393
-
394
- ```yaml
395
- - id: api-key
396
- type: password
397
- message: Enter your API key
398
- validate:
399
- - rule: required
400
- - rule: minLength
401
- value: 32
402
- message: API keys must be at least 32 characters
403
- ```
404
-
405
- ### `number`
406
-
407
- Numeric input. Supports `min`, `max`, and `step` constraints.
408
-
409
- ```yaml
410
- - id: port
411
- type: number
412
- message: Dev server port
413
- default: 3000
414
- min: 1024
415
- max: 65535
416
- step: 1
417
- ```
418
-
419
- ### `search`
420
-
421
- Searchable single-choice list with fuzzy filtering. Useful for long option lists.
422
-
423
- ```yaml
424
- - id: framework
425
- type: search
426
- message: Search for a framework
427
- placeholder: Type to filter...
428
- options:
429
- - { value: nextjs, label: "Next.js" }
430
- - { value: remix, label: Remix }
431
- - { value: astro, label: Astro }
432
- - { value: sveltekit, label: SvelteKit }
433
- - { value: nuxt, label: Nuxt }
434
- - { value: gatsby, label: Gatsby }
435
- ```
436
-
437
- Supports `optionsFrom` as an alternative to inline `options`. See [Dynamic Options (`optionsFrom`)](#dynamic-options-optionsfrom).
438
-
439
- ### `editor`
440
-
441
- Opens a multi-line text editor in the terminal. Returns the full text content when the user saves and exits.
442
-
443
- ```yaml
444
- - id: readme-content
445
- type: editor
446
- message: Write your README content
447
- default: "# My Project\n\nA short description."
448
- required: false
449
- ```
450
-
451
- ### `path`
452
-
453
- File system path input with tab-completion for existing paths.
454
-
455
- ```yaml
456
- - id: project-dir
457
- type: path
458
- message: Where should we create the project?
459
- placeholder: ./my-project
460
- default: .
461
- validate:
462
- - rule: required
463
- ```
464
-
465
- ### `toggle`
466
-
467
- A binary toggle with custom labels for each state. Returns a boolean.
468
-
469
- ```yaml
470
- - id: dark-mode
471
- type: toggle
472
- message: Color scheme
473
- active: Dark
474
- inactive: Light
475
- default: true
476
- ```
477
-
478
- ### `note`
479
-
480
- Displays a bordered info box inline in the wizard flow. No input is collected. Useful for showing instructions, warnings, or section headers between prompts.
481
-
482
- ```yaml
483
- - id: info
484
- type: note
485
- message: Setup Complete
486
- description: "Run npm install to get started"
487
- ```
488
-
489
- The `message` becomes the box title and `description` is the body text. Note steps are skipped in `--mock` mode and excluded from the answers output.
490
-
491
- ---
492
-
493
- ## Dynamic Options (`optionsFrom`)
494
-
495
- `select`, `multiselect`, and `search` steps can load their options from an external JSON or YAML file instead of defining them inline. This is useful when the option list is large, shared across multiple wizards, or generated by another tool.
496
-
497
- ```yaml
498
- - id: framework
499
- type: select
500
- message: Pick a framework
501
- optionsFrom: ./frameworks.json
502
- ```
503
-
504
- `frameworks.json`:
505
-
506
- ```json
507
- [
508
- { "value": "nextjs", "label": "Next.js" },
509
- { "value": "remix", "label": "Remix" },
510
- { "value": "astro", "label": "Astro" }
511
- ]
512
- ```
513
-
514
- Or as YAML:
515
-
516
- ```yaml
517
- # frameworks.yaml
518
- - value: nextjs
519
- label: Next.js
520
- - value: remix
521
- label: Remix
522
- - value: astro
523
- label: Astro
524
- ```
525
-
526
- ```yaml
527
- - id: framework
528
- type: select
529
- message: Pick a framework
530
- optionsFrom: ./frameworks.yaml
214
+ # theme (optional)
215
+ theme:
216
+ preset: catppuccin | dracula | nord | tokyonight | monokai
217
+ tokens: # override individual color tokens
218
+ primary: "#hex"
219
+ icons:
220
+ pointer: ">"
531
221
  ```
532
222
 
533
- The path in `optionsFrom` is resolved relative to the config file. Absolute paths are also accepted. You cannot use both `options` and `optionsFrom` on the same step. `optionsFrom` is not supported in `parseWizardYAML`; use `loadWizardConfig` with a file path instead.
534
-
535
223
  ---
536
224
 
537
- ## Step Groups
538
-
539
- Add a `group` field to any step to display a section header when that group starts. The header is shown once, the first time a step in that group is reached.
540
-
541
- ```yaml
542
- steps:
543
- - id: name
544
- type: text
545
- group: "Project Info"
546
- message: Project name?
547
-
548
- - id: description
549
- type: text
550
- group: "Project Info"
551
- message: Short description?
552
-
553
- - id: framework
554
- type: select
555
- group: "Tech Stack"
556
- message: Pick a framework
557
- options:
558
- - { value: react, label: React }
559
- - { value: vue, label: Vue }
560
- ```
561
-
562
- ---
225
+ ## Programmatic API
563
226
 
564
- ## Conditions
227
+ ```typescript
228
+ import { defineWizard, runWizard, runPipeline } from 'grimoire-wizard'
565
229
 
566
- Use the `when` field on any step to show it only when a condition is met. Steps that don't pass their condition are skipped and excluded from the output.
230
+ const config = defineWizard({
231
+ meta: { name: 'Deploy' },
232
+ steps: [
233
+ { id: 'env', type: 'select', message: 'Target?',
234
+ options: [{ value: 'prod', label: 'Production' }, { value: 'staging', label: 'Staging' }] },
235
+ { id: 'confirm', type: 'confirm', message: 'Deploy now?', default: false },
236
+ ],
237
+ output: { format: 'json' },
238
+ })
567
239
 
568
- ```yaml
569
- - id: ts-config
570
- type: select
571
- message: Which tsconfig preset?
572
- when:
573
- field: language
574
- equals: typescript
575
- options:
576
- - { value: strict, label: Strict }
577
- - { value: base, label: Base }
240
+ const answers = await runWizard(config, {
241
+ mockAnswers: { env: 'staging', confirm: true }, // CI mode
242
+ onStepComplete: (stepId, value) => console.log(stepId, value),
243
+ onCancel: () => process.exit(1),
244
+ asyncValidate: async (stepId, value) => {
245
+ if (stepId === 'env' && value === 'prod') return 'Use staging first'
246
+ return null
247
+ },
248
+ plugins: [], // GrimoirePlugin[] for custom step types
249
+ cache: true, // persist answers as defaults on next run
250
+ })
578
251
  ```
579
252
 
580
- ### Condition operators
581
-
582
- | Operator | Shape | Description |
583
- |----------|-------|-------------|
584
- | `equals` | `{ field, equals }` | Field value equals the given value |
585
- | `notEquals` | `{ field, notEquals }` | Field value does not equal the given value |
586
- | `includes` | `{ field, includes }` | Array field includes the given value |
587
- | `notIncludes` | `{ field, notIncludes }` | Array field does not include the given value |
588
- | `greaterThan` | `{ field, greaterThan }` | Numeric field is greater than the given value |
589
- | `lessThan` | `{ field, lessThan }` | Numeric field is less than the given value |
590
- | `isEmpty` | `{ field, isEmpty: true }` | Field is empty, null, or an empty array |
591
- | `isNotEmpty` | `{ field, isNotEmpty: true }` | Field is not empty |
592
-
593
- ### Compound conditions
594
-
595
- Combine conditions with `all`, `any`, or `not`:
596
-
597
- ```yaml
598
- # All conditions must be true
599
- when:
600
- all:
601
- - field: language
602
- equals: typescript
603
- - field: features
604
- includes: eslint
605
-
606
- # Any condition must be true
607
- when:
608
- any:
609
- - field: project-type
610
- equals: web
611
- - field: project-type
612
- equals: api
613
-
614
- # Negate a condition
615
- when:
616
- not:
617
- field: skip-tests
618
- equals: true
619
- ```
253
+ Key `RunWizardOptions`: `mockAnswers`, `templateAnswers`, `onBeforeStep`, `onAfterStep`, `onStepComplete`, `onCancel`, `asyncValidate`, `plugins`, `cache`, `mru`, `renderer`, `quiet`, `plain`.
620
254
 
621
255
  ---
622
256
 
623
- ## Routes
624
-
625
- A `select` step can branch to different step sequences based on the chosen value. Set `routes` to a map of option values to step IDs. Grimoire jumps to the mapped step instead of the next step in the list.
626
-
627
- ```yaml
628
- - id: project-type
629
- type: select
630
- message: What kind of project?
631
- options:
632
- - { value: web, label: "Web App" }
633
- - { value: api, label: "REST API" }
634
- - { value: cli, label: "CLI Tool" }
635
- routes:
636
- web: web-framework
637
- api: api-framework
638
- cli: cli-features
639
-
640
- - id: web-framework
641
- type: select
642
- message: Which web framework?
643
- options:
644
- - { value: nextjs, label: "Next.js" }
645
- - { value: remix, label: Remix }
646
- next: deploy
647
-
648
- - id: api-framework
649
- type: select
650
- message: Which API framework?
651
- options:
652
- - { value: express, label: Express }
653
- - { value: fastify, label: Fastify }
654
- next: deploy
257
+ ## AI Agent Integration
655
258
 
656
- - id: cli-features
657
- type: multiselect
658
- message: CLI features to include
659
- options:
660
- - { value: args, label: "Argument parsing" }
661
- - { value: colors, label: "Colored output" }
662
- next: deploy
259
+ Paste this URL into Claude, ChatGPT, or any LLM to generate correct wizard configs instantly:
663
260
 
664
- - id: deploy
665
- type: select
666
- message: Deployment target?
667
- options:
668
- - { value: vercel, label: Vercel }
669
- - { value: docker, label: Docker }
670
261
  ```
671
-
672
- Steps not reached via routing are skipped and excluded from output. Use `next` on any step to override the default sequential flow and jump to a specific step ID. The special value `__done__` ends the wizard immediately.
673
-
674
- ---
675
-
676
- ## Validation
677
-
678
- Add a `validate` array to any step that supports it (`text`, `password`, `editor`, `path`). Rules are checked in order and the first failure stops validation.
679
-
680
- ```yaml
681
- validate:
682
- - rule: required
683
- - rule: minLength
684
- value: 2
685
- - rule: maxLength
686
- value: 128
687
- - rule: pattern
688
- value: "^[a-zA-Z0-9_-]+$"
689
- message: Only letters, numbers, underscores, and hyphens allowed
690
- - rule: min
691
- value: 0
692
- - rule: max
693
- value: 100
262
+ https://raw.githubusercontent.com/YosefHayim/grimoire/main/docs/GRIMOIRE_REFERENCE.md
694
263
  ```
695
264
 
696
- | Rule | Applies to | Description |
697
- |------|-----------|-------------|
698
- | `required` | all | Value must not be empty |
699
- | `minLength` | text, password, editor, path | Minimum character count |
700
- | `maxLength` | text, password, editor, path | Maximum character count |
701
- | `pattern` | text, password, editor, path | Must match the given regex string |
702
- | `min` | number | Minimum numeric value |
703
- | `max` | number | Maximum numeric value |
704
-
705
- All rules accept an optional `message` field to override the default error text.
265
+ The reference doc covers the full schema, all step types, conditions, routes, actions, and annotated examples.
706
266
 
707
267
  ---
708
268
 
709
- ## Theming
710
-
711
- Define a `theme` block in your config to customize colors and icons. Colors accept any 6-digit hex string. All tokens are optional and fall back to grimoire's defaults.
712
-
713
- ```yaml
714
- theme:
715
- tokens:
716
- primary: "#89b4fa"
717
- success: "#a6e3a1"
718
- error: "#f38ba8"
719
- warning: "#fab387"
720
- info: "#74c7ec"
721
- muted: "#6c7086"
722
- accent: "#cba6f7"
723
- icons:
724
- step: "●"
725
- stepDone: "✔"
726
- stepPending: "○"
727
- pointer: "❯"
728
- ```
729
-
730
- ### Color tokens
731
-
732
- | Token | Used for |
733
- |-------|---------|
734
- | `primary` | Step headers, active selections |
735
- | `success` | Completion messages, check marks |
736
- | `error` | Validation errors, failed checks |
737
- | `warning` | Cancellation messages |
738
- | `info` | Informational text |
739
- | `muted` | Descriptions, secondary text |
740
- | `accent` | Highlights, group headers |
741
-
742
- ### Icons
743
-
744
- | Icon | Used for |
745
- |------|---------|
746
- | `step` | Current step indicator |
747
- | `stepDone` | Completed step indicator |
748
- | `stepPending` | Upcoming step indicator |
749
- | `pointer` | Selection cursor in lists |
750
-
751
- ### Theme presets
752
-
753
- Instead of specifying individual tokens, pick a built-in preset with a single line:
754
-
755
- ```yaml
756
- theme:
757
- preset: catppuccin
758
- ```
759
-
760
- | Preset | Primary color | Style |
761
- |--------|--------------|-------|
762
- | `default` | `#7C3AED` | Purple |
763
- | `catppuccin` | `#cba6f7` | Soft lavender (Mocha) |
764
- | `dracula` | `#bd93f9` | Purple on dark |
765
- | `nord` | `#88c0d0` | Arctic blue |
766
- | `tokyonight` | `#7aa2f7` | Night blue |
767
- | `monokai` | `#a6e22e` | Vibrant green |
269
+ ## Contributing
768
270
 
769
- Any `tokens` or `icons` you set alongside `preset` override the preset's values.
271
+ Open to contributors. Check the [issues](https://github.com/YosefHayim/grimoire/issues) for good first tasks, or open one if you have an idea.
770
272
 
771
273
  ---
772
274
 
773
- ## Environment Variables
275
+ ## Requirements
774
276
 
775
- Any `default` field that starts with `$` is treated as an environment variable reference. Grimoire resolves it at runtime from `process.env`. If the variable is not set, the literal string (e.g., `$MY_VAR`) is used as the default.
776
-
777
- ```yaml
778
- - id: api-url
779
- type: text
780
- message: API base URL
781
- default: $API_BASE_URL
782
-
783
- - id: port
784
- type: number
785
- message: Port number
786
- default: $PORT
787
-
788
- - id: debug
789
- type: confirm
790
- message: Enable debug mode?
791
- default: $DEBUG_MODE
792
- ```
793
-
794
- Supported on: `text`, `select`, `search`, `editor`, `path`, `number`, `confirm`, `toggle`.
795
-
796
- ---
797
-
798
- ## Config Inheritance
799
-
800
- Use `extends` to inherit from a base config. The child config's `steps`, `theme`, `output`, and `checks` replace the base config's values entirely. The `meta` from the child takes precedence.
801
-
802
- ```yaml
803
- # base.yaml
804
- meta:
805
- name: Base Wizard
806
- theme:
807
- tokens:
808
- primary: "#7C3AED"
809
- steps:
810
- - id: name
811
- type: text
812
- message: Project name?
813
- validate:
814
- - rule: required
815
- output:
816
- format: json
817
- ```
818
-
819
- ```yaml
820
- # extended.yaml
821
- extends: ./base.yaml
822
-
823
- meta:
824
- name: Extended Wizard
825
- description: Extends base config with additional steps
826
-
827
- steps:
828
- - id: name
829
- type: text
830
- message: Project name?
831
- validate:
832
- - rule: required
833
-
834
- - id: language
835
- type: select
836
- message: Language?
837
- options:
838
- - { value: typescript, label: TypeScript }
839
- - { value: javascript, label: JavaScript }
840
-
841
- - id: confirm
842
- type: confirm
843
- message: Create project?
844
- next: __done__
845
-
846
- output:
847
- format: yaml
848
- path: project-config.yaml
849
- ```
850
-
851
- The `extends` path is resolved relative to the child config file.
852
-
853
- ---
854
-
855
- ## Pre-flight Checks
856
-
857
- The `checks` block runs shell commands before the wizard starts. If any command exits with a non-zero code, grimoire prints the associated `message` and aborts. Pre-flight checks are skipped in `--mock` mode.
858
-
859
- ```yaml
860
- checks:
861
- - name: Node.js installed
862
- run: node --version
863
- message: "Node.js is required. Install from https://nodejs.org"
864
-
865
- - name: Git available
866
- run: git --version
867
- message: "Git is required. Install from https://git-scm.com"
868
-
869
- - name: Docker running
870
- run: docker info
871
- message: "Docker must be running before deployment."
872
- ```
873
-
874
- | Field | Required | Description |
875
- |-------|----------|-------------|
876
- | `name` | yes | Display name shown in the pre-flight output |
877
- | `run` | yes | Shell command to execute |
878
- | `message` | yes | Error message shown if the command fails |
879
-
880
- ---
881
-
882
- ## Plugin System
883
-
884
- Plugins let you register custom step types with their own render and validate logic. A plugin is a plain object with a `name` and a `steps` map.
885
-
886
- ```typescript
887
- import { runWizard, defineWizard } from 'grimoire-wizard'
888
- import type { GrimoirePlugin } from 'grimoire-wizard'
889
-
890
- const myPlugin: GrimoirePlugin = {
891
- name: 'my-plugin',
892
- steps: {
893
- 'date-picker': {
894
- async render(config, state, theme) {
895
- // config is the raw step config object
896
- // state is the current WizardState
897
- // theme is the ResolvedTheme
898
- const answer = await myDatePickerPrompt(config.message as string)
899
- return answer
900
- },
901
- validate(value, config) {
902
- if (!value) return 'A date is required'
903
- return null // null means valid
904
- },
905
- },
906
- },
907
- }
908
-
909
- const config = defineWizard({
910
- meta: { name: 'My Wizard' },
911
- steps: [
912
- {
913
- id: 'launch-date',
914
- type: 'date-picker',
915
- message: 'Pick a launch date',
916
- } as any,
917
- ],
918
- output: { format: 'json' },
919
- })
920
-
921
- const answers = await runWizard(config, {
922
- plugins: [myPlugin],
923
- })
924
- ```
925
-
926
- Built-in step types (`text`, `select`, `multiselect`, `confirm`, `password`, `number`, `search`, `editor`, `path`, `toggle`) cannot be overridden by plugins.
927
-
928
- ### Plugin interfaces
929
-
930
- ```typescript
931
- interface GrimoirePlugin {
932
- name: string;
933
- steps: Record<string, StepPlugin>;
934
- }
935
-
936
- interface StepPlugin {
937
- render(
938
- config: Record<string, unknown>,
939
- state: WizardState,
940
- theme: ResolvedTheme
941
- ): Promise<unknown>;
942
- validate?(value: unknown, config: Record<string, unknown>): string | null;
943
- }
944
- ```
945
-
946
- ---
947
-
948
- ## Programmatic API
949
-
950
- ### Core functions
951
-
952
- ```typescript
953
- import { loadWizardConfig, runWizard, defineWizard } from 'grimoire-wizard'
954
-
955
- // Load from a file (YAML, JSON, JS, or TS)
956
- const config = await loadWizardConfig('./setup.yaml')
957
- const answers = await runWizard(config)
958
- console.log(answers)
959
- ```
960
-
961
- ### `defineWizard(config)`
962
-
963
- Identity function that returns the config unchanged. Its value is type inference: TypeScript will check your config object against `WizardConfig` at compile time.
964
-
965
- ```typescript
966
- import { defineWizard, runWizard } from 'grimoire-wizard'
967
-
968
- const config = defineWizard({
969
- meta: {
970
- name: 'Deploy Config',
971
- description: 'Configure your deployment target.',
972
- },
973
- steps: [
974
- {
975
- id: 'environment',
976
- type: 'select',
977
- message: 'Target environment?',
978
- options: [
979
- { label: 'Production', value: 'prod' },
980
- { label: 'Staging', value: 'staging' },
981
- ],
982
- },
983
- {
984
- id: 'confirm',
985
- type: 'confirm',
986
- message: 'Ready to deploy?',
987
- default: false,
988
- },
989
- ],
990
- output: { format: 'json' },
991
- })
992
-
993
- const answers = await runWizard(config, {
994
- onStepComplete: (stepId, value, state) => {
995
- console.log(`${stepId} answered: ${String(value)}`)
996
- },
997
- onCancel: (state) => {
998
- console.log('Wizard cancelled')
999
- process.exit(1)
1000
- },
1001
- })
1002
- ```
1003
-
1004
- ### `RunWizardOptions`
1005
-
1006
- | Option | Type | Description |
1007
- |--------|------|-------------|
1008
- | `renderer` | `WizardRenderer` | Custom renderer (defaults to `InquirerRenderer`) |
1009
- | `quiet` | `boolean` | Suppress title, description, and summary output |
1010
- | `plain` | `boolean` | Disable colors and banner (plain-text mode) |
1011
- | `mockAnswers` | `Record<string, unknown>` | Preset answers for non-interactive mode |
1012
- | `templateAnswers` | `Record<string, unknown>` | Pre-loaded template answers used as defaults |
1013
- | `onBeforeStep` | `(stepId, step, state) => void \| Promise<void>` | Called before each step is rendered |
1014
- | `onAfterStep` | `(stepId, value, state) => void \| Promise<void>` | Called after each step completes, before moving on |
1015
- | `onStepComplete` | `(stepId, value, state) => void` | Called after each step completes |
1016
- | `onCancel` | `(state) => void` | Called when the user cancels with Ctrl+C |
1017
- | `plugins` | `GrimoirePlugin[]` | Custom step type plugins |
1018
- | `asyncValidate` | `(stepId, value, answers) => Promise<string \| null>` | Async validation hook called after each step |
1019
- | `cache` | `boolean \| { dir?: string }` | Enable/disable answer caching, or set a custom cache directory (default: `true`) |
1020
- | `mru` | `boolean` | Enable/disable MRU ordering for select/multiselect/search steps (default: `true`) |
1021
-
1022
- ### Async validation
1023
-
1024
- The `asyncValidate` hook runs after each step's synchronous validation passes. Return a string to show as an error and re-prompt the step, or return `null` to accept the value.
1025
-
1026
- ```typescript
1027
- const answers = await runWizard(config, {
1028
- asyncValidate: async (stepId, value, answers) => {
1029
- if (stepId === 'username') {
1030
- const taken = await checkUsernameAvailability(value as string)
1031
- if (taken) return 'That username is already taken'
1032
- }
1033
- return null
1034
- },
1035
- })
1036
- ```
1037
-
1038
- ### Lifecycle hooks
1039
-
1040
- `onBeforeStep` fires just before a step is rendered. `onAfterStep` fires after the user answers but before the wizard advances. Both can be async.
1041
-
1042
- ```typescript
1043
- const answers = await runWizard(config, {
1044
- onBeforeStep: async (stepId, step, state) => {
1045
- console.log(`About to render: ${stepId}`)
1046
- },
1047
- onAfterStep: async (stepId, value, state) => {
1048
- await logAnswer(stepId, value)
1049
- },
1050
- })
1051
- ```
1052
-
1053
- ### Ink renderer
1054
-
1055
- The `InkRenderer` is an alternative to the default `InquirerRenderer`. It uses box-drawing characters, a filled progress bar with percentage, and formatted step headers.
1056
-
1057
- ```typescript
1058
- import { runWizard } from 'grimoire-wizard'
1059
- import { InkRenderer } from 'grimoire-wizard/renderers/ink'
1060
-
1061
- const answers = await runWizard(config, {
1062
- renderer: new InkRenderer(),
1063
- })
1064
- ```
1065
-
1066
- Or from the CLI:
1067
-
1068
- ```bash
1069
- grimoire run setup.yaml --renderer ink
1070
- ```
1071
-
1072
- ### Clack renderer
1073
-
1074
- The `ClackRenderer` gives your wizard a clack-style visual flow: a continuous `│` guide line connects all prompts, answered steps collapse to a single `◇ Question · answer` line, and the session opens with a `┌` header and closes with a `└` outro. Note steps render as bordered boxes. Spinners animate during async operations.
1075
-
1076
- ```bash
1077
- grimoire run setup.yaml --renderer clack
1078
- ```
1079
-
1080
- Or programmatically:
1081
-
1082
- ```typescript
1083
- import { runWizard } from 'grimoire-wizard'
1084
- import { ClackRenderer } from 'grimoire-wizard'
1085
-
1086
- const answers = await runWizard(config, {
1087
- renderer: new ClackRenderer(),
1088
- })
1089
- ```
1090
-
1091
- ### Exported types
1092
-
1093
- ```typescript
1094
- import type {
1095
- WizardConfig,
1096
- StepConfig,
1097
- TextStepConfig,
1098
- SelectStepConfig,
1099
- MultiSelectStepConfig,
1100
- ConfirmStepConfig,
1101
- PasswordStepConfig,
1102
- NumberStepConfig,
1103
- SearchStepConfig,
1104
- EditorStepConfig,
1105
- PathStepConfig,
1106
- ToggleStepConfig,
1107
- NoteStepConfig,
1108
- SelectOption,
1109
- ValidationRule,
1110
- Condition,
1111
- ThemeConfig,
1112
- ResolvedTheme,
1113
- WizardState,
1114
- WizardTransition,
1115
- WizardRenderer,
1116
- WizardEvent,
1117
- PreFlightCheck,
1118
- RunWizardOptions,
1119
- GrimoirePlugin,
1120
- StepPlugin,
1121
- } from 'grimoire-wizard'
1122
- ```
1123
-
1124
- ### Utility functions
1125
-
1126
- ```typescript
1127
- import {
1128
- parseWizardConfig, // Parse and validate a raw config object against the schema
1129
- parseWizardYAML, // Parse a YAML string into a WizardConfig
1130
- evaluateCondition, // Evaluate a Condition against an answers map
1131
- isStepVisible, // Check if a step should be shown given current answers
1132
- createWizardState, // Create an initial WizardState from a config
1133
- wizardReducer, // Pure reducer for wizard state transitions
1134
- getVisibleSteps, // Get all currently visible steps given current answers
1135
- resolveNextStep, // Resolve the next step ID (respects routes and next fields)
1136
- validateStepAnswer, // Run validation rules against a value
1137
- resolveTheme, // Merge a ThemeConfig with defaults into a ResolvedTheme
1138
- resolveEnvDefault, // Resolve a $ENV_VAR string from process.env
1139
- runPreFlightChecks, // Run a checks array and throw on first failure
1140
- registerPlugin, // Register a GrimoirePlugin into the global registry
1141
- getPluginStep, // Look up a registered StepPlugin by type name
1142
- clearPlugins, // Clear all registered plugins
1143
- // Cache
1144
- loadCachedAnswers, // Load cached answers for a wizard by name
1145
- saveCachedAnswers, // Save answers to the cache for a wizard
1146
- clearCache, // Delete cached answers (one wizard or all)
1147
- // MRU
1148
- recordSelection, // Record a user's selection for MRU tracking
1149
- getOrderedOptions, // Return options sorted by selection frequency
1150
- // Templates
1151
- saveTemplate, // Save a named answer preset for a wizard
1152
- loadTemplate, // Load a named answer preset
1153
- listTemplates, // List all saved template names for a wizard
1154
- deleteTemplate, // Delete a named template
1155
- // Banner
1156
- renderBanner, // Render the ASCII art banner for a wizard name
1157
- // Renderers
1158
- ClackRenderer, // Clack-style renderer with guide lines and collapsed steps
1159
- // Pipelines
1160
- runPipeline, // Chain multiple wizard configs in sequence
1161
- // Progress persistence
1162
- saveProgress, // Save wizard progress to disk
1163
- loadProgress, // Load saved wizard progress
1164
- clearProgress, // Delete saved wizard progress
1165
- } from 'grimoire-wizard'
1166
- ```
1167
-
1168
- ---
1169
-
1170
- ## Answer Caching
1171
-
1172
- Grimoire remembers your answers between runs. The next time you run the same wizard, cached answers become the default values for each step, so you only need to change what's different.
1173
-
1174
- Password steps are never cached.
1175
-
1176
- Cache files are stored in `~/.config/grimoire/cache/` as JSON, one file per wizard (named by slugifying the wizard's `meta.name`).
1177
-
1178
- Caching is enabled by default. Disable it for a single run with `--no-cache`:
1179
-
1180
- ```bash
1181
- grimoire run setup.yaml --no-cache
1182
- ```
1183
-
1184
- Clear the cache from the CLI:
1185
-
1186
- ```bash
1187
- grimoire cache clear # clears all wizards
1188
- grimoire cache clear "Project Setup" # clears one wizard
1189
- ```
1190
-
1191
- Control caching in the programmatic API via the `cache` option:
1192
-
1193
- ```typescript
1194
- // Disable caching entirely
1195
- const answers = await runWizard(config, { cache: false })
1196
-
1197
- // Use a custom cache directory
1198
- const answers = await runWizard(config, { cache: { dir: '/tmp/my-cache' } })
1199
- ```
1200
-
1201
- ---
1202
-
1203
- ## Progress Persistence
1204
-
1205
- If you press Ctrl+C mid-wizard, grimoire saves your progress automatically. The next time you run the same wizard, it resumes from where you left off, with all previous answers pre-filled.
1206
-
1207
- Progress files are stored in `~/.config/grimoire/progress/` as JSON, one file per wizard.
1208
-
1209
- Disable resume for a single run:
1210
-
1211
- ```bash
1212
- grimoire run setup.yaml --no-resume
1213
- ```
1214
-
1215
- Or programmatically:
1216
-
1217
- ```typescript
1218
- const answers = await runWizard(config, { resume: false })
1219
- ```
1220
-
1221
- Manage progress files directly:
1222
-
1223
- ```typescript
1224
- import { saveProgress, loadProgress, clearProgress } from 'grimoire-wizard'
1225
-
1226
- const saved = loadProgress('Project Setup')
1227
- clearProgress('Project Setup')
1228
- ```
1229
-
1230
- ---
1231
-
1232
- ## Review Screen
1233
-
1234
- Set `review: true` in your wizard's `meta` block to show a summary of all answers before the wizard completes. The user can confirm or go back to change any answer.
1235
-
1236
- ```yaml
1237
- meta:
1238
- name: Deploy Wizard
1239
- review: true
1240
- ```
1241
-
1242
- The review screen lists every answered step with its question and value. Selecting an answer jumps back to that step. Confirming submits the wizard.
1243
-
1244
- ---
1245
-
1246
- ## Wizard Pipelines
1247
-
1248
- Pipelines let you chain multiple wizard configs in sequence. Each wizard's answers are forwarded to the next, so later wizards can reference earlier answers in their `when` conditions and `default` values.
1249
-
1250
- ```typescript
1251
- import { runPipeline } from 'grimoire-wizard'
1252
-
1253
- const results = await runPipeline([
1254
- { config: setupConfig },
1255
- { config: deployConfig, when: { field: 'name', equals: 'my-app' } },
1256
- ])
1257
- ```
1258
-
1259
- Each entry in the array accepts:
1260
-
1261
- | Field | Type | Description |
1262
- |-------|------|-------------|
1263
- | `config` | `WizardConfig` | The wizard config to run |
1264
- | `mockAnswers` | `Record<string, unknown>` | Preset answers for this stage |
1265
- | `when` | `Condition` | Skip this stage if the condition is not met |
1266
-
1267
- `runPipeline` returns an array of answer objects, one per stage that ran. Stages that are skipped via `when` return `null`.
1268
-
1269
- ---
1270
-
1271
- ## Templates
1272
-
1273
- Templates are named answer presets. Save a set of answers under a name, then load them as defaults on future runs. Useful for environments like staging vs. production that share the same wizard but need different values.
1274
-
1275
- Templates are stored in `~/.config/grimoire/templates/<wizard-slug>/`.
1276
-
1277
- ### Saving a template
1278
-
1279
- Templates are saved programmatically after a run:
1280
-
1281
- ```typescript
1282
- import { runWizard, saveTemplate } from 'grimoire-wizard'
1283
-
1284
- const answers = await runWizard(config)
1285
- saveTemplate('Project Setup', 'production', answers)
1286
- ```
1287
-
1288
- ### Loading a template via CLI
1289
-
1290
- ```bash
1291
- grimoire run setup.yaml --template production
1292
- ```
1293
-
1294
- Template answers become the defaults for each step. The user can still change any value.
1295
-
1296
- ### Managing templates
1297
-
1298
- ```bash
1299
- grimoire template list "Project Setup"
1300
- grimoire template delete "Project Setup" production
1301
- ```
1302
-
1303
- ### Programmatic API
1304
-
1305
- ```typescript
1306
- import { saveTemplate, loadTemplate, listTemplates, deleteTemplate } from 'grimoire-wizard'
1307
-
1308
- saveTemplate('Project Setup', 'staging', answers)
1309
-
1310
- const staging = loadTemplate('Project Setup', 'staging')
1311
-
1312
- const names = listTemplates('Project Setup')
1313
- // ['production', 'staging']
1314
-
1315
- deleteTemplate('Project Setup', 'staging')
1316
- ```
1317
-
1318
- ---
1319
-
1320
- ## MRU (Most Recently Used) Ordering
1321
-
1322
- For `select`, `multiselect`, and `search` steps, grimoire tracks which options you pick and floats the most frequently chosen ones to the top of the list on subsequent runs. Options you've never picked stay in their original order below.
1323
-
1324
- MRU data is stored in `~/.config/grimoire/mru/` and is per-wizard, per-step.
1325
-
1326
- MRU ordering is enabled by default. Disable it programmatically:
1327
-
1328
- ```typescript
1329
- const answers = await runWizard(config, { mru: false })
1330
- ```
1331
-
1332
- There's no CLI flag for this. It's a programmatic-only option.
1333
-
1334
- ---
1335
-
1336
- ## Banner
1337
-
1338
- When grimoire starts a wizard in interactive mode, it renders the wizard name as ASCII art using figlet with a purple-to-blue-to-green gradient. If figlet rendering fails for any reason, it falls back to plain bold text.
1339
-
1340
- The banner is suppressed in `--quiet` mode and in `--plain` mode. Use `--plain` to get clean, color-free output suitable for terminals that don't support ANSI codes or for piping:
1341
-
1342
- ```bash
1343
- grimoire run setup.yaml --plain
1344
- ```
1345
-
1346
- The `NO_COLOR` environment variable also disables colors and the banner:
1347
-
1348
- ```bash
1349
- NO_COLOR=1 grimoire run setup.yaml
1350
- ```
1351
-
1352
- ---
1353
-
1354
- ## CI/CD Integration
1355
-
1356
- Combine `--mock` and `--json` to run wizards non-interactively in pipelines and capture structured output.
1357
-
1358
- ```bash
1359
- # Run with preset answers, capture JSON output
1360
- grimoire run deploy.yaml \
1361
- --mock '{"environment":"staging","version":"1.2.3","confirm":true}' \
1362
- --json > deploy-answers.json
1363
-
1364
- # Use the output in subsequent steps
1365
- cat deploy-answers.json | jq '.answers.environment'
1366
- ```
1367
-
1368
- The `--json` flag always emits to stdout. On success:
1369
-
1370
- ```json
1371
- {
1372
- "ok": true,
1373
- "wizard": "Deployment Wizard",
1374
- "answers": { "environment": "staging", "version": "1.2.3" },
1375
- "stepsCompleted": 3,
1376
- "format": "json"
1377
- }
1378
- ```
1379
-
1380
- On failure:
1381
-
1382
- ```json
1383
- {
1384
- "ok": false,
1385
- "error": "Mock mode: no answer provided for step \"confirm\" and no default available"
1386
- }
1387
- ```
1388
-
1389
- Exit code is `0` on success and `1` on failure, so pipelines can branch on the result.
1390
-
1391
- ---
1392
-
1393
- ## JSON Schema
1394
-
1395
- Grimoire ships a JSON Schema at `schema/grimoire.schema.json`. Add it to your editor for autocomplete and inline validation of config files.
1396
-
1397
- ### VS Code
1398
-
1399
- Add this to your workspace `.vscode/settings.json`:
1400
-
1401
- ```json
1402
- {
1403
- "yaml.schemas": {
1404
- "./node_modules/grimoire-wizard/schema/grimoire.schema.json": "*.wizard.yaml"
1405
- }
1406
- }
1407
- ```
1408
-
1409
- Or add a `$schema` comment at the top of any config file:
1410
-
1411
- ```yaml
1412
- # yaml-language-server: $schema=./node_modules/grimoire-wizard/schema/grimoire.schema.json
1413
- meta:
1414
- name: My Wizard
1415
- ```
1416
-
1417
- ### Other editors
1418
-
1419
- Point your editor's JSON Schema support at:
1420
-
1421
- ```
1422
- ./node_modules/grimoire-wizard/schema/grimoire.schema.json
1423
- ```
1424
-
1425
- ---
1426
-
1427
- ## Shell Completions
1428
-
1429
- ### Bash
1430
-
1431
- ```bash
1432
- grimoire completion bash > ~/.bash_completion.d/grimoire
1433
- source ~/.bash_completion.d/grimoire
1434
- ```
1435
-
1436
- Or add to your `.bashrc`:
1437
-
1438
- ```bash
1439
- eval "$(grimoire completion bash)"
1440
- ```
1441
-
1442
- ### Zsh
1443
-
1444
- ```bash
1445
- grimoire completion zsh > ~/.zsh/completions/_grimoire
1446
- ```
1447
-
1448
- Make sure `~/.zsh/completions` is in your `$fpath`. Then reload:
1449
-
1450
- ```bash
1451
- autoload -Uz compinit && compinit
1452
- ```
1453
-
1454
- ### Fish
1455
-
1456
- ```bash
1457
- grimoire completion fish > ~/.config/fish/completions/grimoire.fish
1458
- ```
1459
-
1460
- ---
1461
-
1462
- ## Examples
1463
-
1464
- The `examples/` directory contains ready-to-run configs in both YAML (`examples/yaml/`) and JSON (`examples/json/`) formats. Every YAML example (except `base.yaml` and `extended.yaml`, which use `extends:`) has a JSON equivalent.
1465
-
1466
- ### `examples/yaml/basic.yaml`
1467
-
1468
- A 6-step project setup wizard covering the core input types: project name (text with validation and pattern), description (optional text), language (select with default), features (multiselect with min), license (select), and confirm. Good starting point for your own configs.
1469
-
1470
- ```bash
1471
- grimoire run examples/yaml/basic.yaml
1472
- grimoire run examples/json/basic.json # JSON equivalent
1473
- ```
1474
-
1475
- ### `examples/yaml/conditional.yaml`
1476
-
1477
- An 11-step wizard that branches based on project type. A `select` step with `routes` sends users down one of four paths (web, api, cli, lib), each with its own framework or feature selection step. Additional steps use `when` conditions to show or hide options based on earlier answers.
1478
-
1479
- ```bash
1480
- grimoire run examples/yaml/conditional.yaml
1481
- ```
1482
-
1483
- ### `examples/yaml/themed.yaml`
1484
-
1485
- An 8-step account setup wizard styled with the Catppuccin Mocha color palette. Demonstrates all 7 color tokens and custom icon overrides. Steps cover username, email, role, experience, interests, newsletter, password, and confirm.
1486
-
1487
- ```bash
1488
- grimoire run examples/yaml/themed.yaml
1489
- ```
1490
-
1491
- ### `examples/yaml/demo.yaml`
1492
-
1493
- The built-in demo config used by `grimoire demo`. Exercises all 10 step types across 4 named groups: Text Inputs (text, editor, path, password), Selections (select, multiselect, search), Toggles and Numbers (toggle, number), and Confirmation (confirm).
1494
-
1495
- ```bash
1496
- grimoire run examples/yaml/demo.yaml
1497
- # or
1498
- grimoire demo
1499
- ```
1500
-
1501
- ### `examples/yaml/all-features.yaml`
1502
-
1503
- A focused showcase of the newer step types: search, path, toggle, editor, and number, organized into two groups (Project Setup and Configuration).
1504
-
1505
- ```bash
1506
- grimoire run examples/yaml/all-features.yaml
1507
- ```
1508
-
1509
- ### `examples/yaml/base.yaml`
1510
-
1511
- A minimal base config with a name step, optional description, and confirm. Intended to be inherited via `extends`.
1512
-
1513
- ```bash
1514
- grimoire run examples/yaml/base.yaml
1515
- ```
1516
-
1517
- ### `examples/yaml/extended.yaml`
1518
-
1519
- Extends `base.yaml` and adds a language select step. Demonstrates how `extends` merges configs and how the child's `output` and `meta` override the base.
1520
-
1521
- ```bash
1522
- grimoire run examples/yaml/extended.yaml
1523
- ```
1524
-
1525
- ### `examples/yaml/with-checks.yaml`
1526
-
1527
- A deployment wizard with two pre-flight checks (Node.js and Git). Shows how `checks` abort the wizard before any prompts if the environment isn't ready.
1528
-
1529
- ```bash
1530
- grimoire run examples/yaml/with-checks.yaml
1531
- ```
1532
-
1533
- ### `examples/yaml/themed-catppuccin.yaml`
1534
-
1535
- A 3-step project setup wizard using the `catppuccin` theme preset. Shows how a single `preset` line replaces manual token configuration.
1536
-
1537
- ```bash
1538
- grimoire run examples/yaml/themed-catppuccin.yaml
1539
- grimoire run examples/json/themed-catppuccin.json # JSON equivalent
1540
- ```
1541
-
1542
- ### `examples/yaml/pipeline.yaml`
1543
-
1544
- A multi-stage wizard demonstrating the pipeline concept using `note` steps as stage dividers. Shows how to structure a wizard that covers multiple logical phases in a single config.
1545
-
1546
- ```bash
1547
- grimoire run examples/yaml/pipeline.yaml
1548
- ```
1549
-
1550
- ---
277
+ Node.js >= 18. ESM only (`"type": "module"` or `.mjs`).
1551
278
 
1552
279
  ## License
1553
280
 
1554
- MIT. PRs welcome.
281
+ MIT