@entelligentsia/forgecli 0.1.0 → 0.3.0

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.
Files changed (144) hide show
  1. package/CHANGELOG.md +138 -0
  2. package/README.md +177 -38
  3. package/dist/bin/argv.js +5 -0
  4. package/dist/bin/argv.js.map +1 -1
  5. package/dist/bin/forge.js +1 -0
  6. package/dist/bin/forge.js.map +1 -1
  7. package/dist/extensions/forgecli/ask-user-tool.d.ts +17 -0
  8. package/dist/extensions/forgecli/ask-user-tool.js +139 -0
  9. package/dist/extensions/forgecli/ask-user-tool.js.map +1 -0
  10. package/dist/extensions/forgecli/forge-commands.d.ts +21 -0
  11. package/dist/extensions/forgecli/forge-commands.js +141 -0
  12. package/dist/extensions/forgecli/forge-commands.js.map +1 -1
  13. package/dist/extensions/forgecli/forge-init.d.ts +26 -0
  14. package/dist/extensions/forgecli/forge-init.js +948 -0
  15. package/dist/extensions/forgecli/forge-init.js.map +1 -0
  16. package/dist/extensions/forgecli/health-check.d.ts +18 -0
  17. package/dist/extensions/forgecli/health-check.js +154 -0
  18. package/dist/extensions/forgecli/health-check.js.map +1 -0
  19. package/dist/extensions/forgecli/hook-dispatcher.d.ts +34 -1
  20. package/dist/extensions/forgecli/hook-dispatcher.js +237 -3
  21. package/dist/extensions/forgecli/hook-dispatcher.js.map +1 -1
  22. package/dist/extensions/forgecli/index.js +28 -11
  23. package/dist/extensions/forgecli/index.js.map +1 -1
  24. package/dist/extensions/forgecli/init-context.d.ts +99 -0
  25. package/dist/extensions/forgecli/init-context.js +163 -0
  26. package/dist/extensions/forgecli/init-context.js.map +1 -0
  27. package/dist/extensions/forgecli/init-progress.d.ts +39 -0
  28. package/dist/extensions/forgecli/init-progress.js +117 -0
  29. package/dist/extensions/forgecli/init-progress.js.map +1 -0
  30. package/dist/extensions/forgecli/refresh-kb-links.d.ts +18 -0
  31. package/dist/extensions/forgecli/refresh-kb-links.js +228 -0
  32. package/dist/extensions/forgecli/refresh-kb-links.js.map +1 -0
  33. package/dist/extensions/forgecli/store-validator.d.ts +13 -0
  34. package/dist/extensions/forgecli/store-validator.js +35 -0
  35. package/dist/extensions/forgecli/store-validator.js.map +1 -0
  36. package/dist/extensions/forgecli/transition-guard.d.ts +20 -0
  37. package/dist/extensions/forgecli/transition-guard.js +125 -0
  38. package/dist/extensions/forgecli/transition-guard.js.map +1 -0
  39. package/dist/forge-payload/.base-pack/commands/approve.md +22 -0
  40. package/dist/forge-payload/.base-pack/commands/collate.md +22 -0
  41. package/dist/forge-payload/.base-pack/commands/commit.md +22 -0
  42. package/dist/forge-payload/.base-pack/commands/enhance.md +37 -0
  43. package/dist/forge-payload/.base-pack/commands/fix-bug.md +22 -0
  44. package/dist/forge-payload/.base-pack/commands/implement.md +22 -0
  45. package/dist/forge-payload/.base-pack/commands/plan.md +22 -0
  46. package/dist/forge-payload/.base-pack/commands/quiz-agent.md +22 -0
  47. package/dist/forge-payload/.base-pack/commands/retrospective.md +22 -0
  48. package/dist/forge-payload/.base-pack/commands/review-code.md +22 -0
  49. package/dist/forge-payload/.base-pack/commands/review-plan.md +22 -0
  50. package/dist/forge-payload/.base-pack/commands/run-sprint.md +22 -0
  51. package/dist/forge-payload/.base-pack/commands/run-task.md +22 -0
  52. package/dist/forge-payload/.base-pack/commands/sprint-intake.md +22 -0
  53. package/dist/forge-payload/.base-pack/commands/sprint-plan.md +22 -0
  54. package/dist/forge-payload/.base-pack/commands/validate.md +22 -0
  55. package/dist/forge-payload/.claude-plugin/plugin.json +15 -0
  56. package/dist/forge-payload/.init/discovery/discover-database.md +32 -0
  57. package/dist/forge-payload/.init/discovery/discover-processes.md +31 -0
  58. package/dist/forge-payload/.init/discovery/discover-routing.md +31 -0
  59. package/dist/forge-payload/.init/discovery/discover-stack.md +33 -0
  60. package/dist/forge-payload/.init/discovery/discover-testing.md +34 -0
  61. package/dist/forge-payload/.init/generation/generate-kb-doc.md +60 -0
  62. package/dist/forge-payload/.schemas/bug.schema.json +53 -0
  63. package/dist/forge-payload/.schemas/collation-state.schema.json +16 -0
  64. package/dist/forge-payload/.schemas/event-sidecar.schema.json +22 -0
  65. package/dist/forge-payload/.schemas/event.schema.json +32 -0
  66. package/dist/forge-payload/.schemas/feature.schema.json +22 -0
  67. package/dist/forge-payload/.schemas/progress-entry.schema.json +16 -0
  68. package/dist/forge-payload/.schemas/project-context.schema.json +167 -0
  69. package/dist/forge-payload/.schemas/project-overlay.schema.json +25 -0
  70. package/dist/forge-payload/.schemas/sprint.schema.json +27 -0
  71. package/dist/forge-payload/.schemas/structure-versions.schema.json +57 -0
  72. package/dist/forge-payload/.schemas/task.schema.json +58 -0
  73. package/dist/forge-payload/.tools/banners.cjs +435 -0
  74. package/dist/forge-payload/.tools/build-context-pack.cjs +290 -0
  75. package/dist/forge-payload/.tools/build-init-context.cjs +322 -0
  76. package/dist/forge-payload/.tools/build-overlay.cjs +326 -0
  77. package/dist/forge-payload/.tools/build-persona-pack.cjs +226 -0
  78. package/dist/forge-payload/.tools/collate.cjs +1041 -0
  79. package/dist/forge-payload/.tools/generation-manifest.cjs +311 -0
  80. package/dist/forge-payload/.tools/lib/forge-root.cjs +59 -0
  81. package/dist/forge-payload/.tools/lib/paths.cjs +29 -0
  82. package/dist/forge-payload/.tools/lib/pricing.cjs +165 -0
  83. package/dist/forge-payload/.tools/lib/project-root.cjs +32 -0
  84. package/dist/forge-payload/.tools/lib/result.js +40 -0
  85. package/dist/forge-payload/.tools/lib/validate.js +131 -0
  86. package/dist/forge-payload/.tools/manage-config.cjs +340 -0
  87. package/dist/forge-payload/.tools/manage-versions.cjs +365 -0
  88. package/dist/forge-payload/.tools/seed-store.cjs +237 -0
  89. package/dist/forge-payload/.tools/store-cli.cjs +1123 -0
  90. package/dist/forge-payload/.tools/store.cjs +315 -0
  91. package/dist/forge-payload/.tools/substitute-placeholders.cjs +625 -0
  92. package/dist/forge-payload/.tools/validate-store.cjs +522 -0
  93. package/package.json +1 -1
  94. /package/dist/forge-payload/{personas → .base-pack/personas}/architect.md +0 -0
  95. /package/dist/forge-payload/{personas → .base-pack/personas}/bug-fixer.md +0 -0
  96. /package/dist/forge-payload/{personas → .base-pack/personas}/collator.md +0 -0
  97. /package/dist/forge-payload/{personas → .base-pack/personas}/engineer.md +0 -0
  98. /package/dist/forge-payload/{personas → .base-pack/personas}/librarian.md +0 -0
  99. /package/dist/forge-payload/{personas → .base-pack/personas}/orchestrator.md +0 -0
  100. /package/dist/forge-payload/{personas → .base-pack/personas}/product-manager.md +0 -0
  101. /package/dist/forge-payload/{personas → .base-pack/personas}/qa-engineer.md +0 -0
  102. /package/dist/forge-payload/{personas → .base-pack/personas}/supervisor.md +0 -0
  103. /package/dist/forge-payload/{skills → .base-pack/skills}/architect-skills.md +0 -0
  104. /package/dist/forge-payload/{skills → .base-pack/skills}/bug-fixer-skills.md +0 -0
  105. /package/dist/forge-payload/{skills → .base-pack/skills}/collator-skills.md +0 -0
  106. /package/dist/forge-payload/{skills → .base-pack/skills}/engineer-skills.md +0 -0
  107. /package/dist/forge-payload/{skills → .base-pack/skills}/generic-skills.md +0 -0
  108. /package/dist/forge-payload/{skills → .base-pack/skills}/librarian-skills.md +0 -0
  109. /package/dist/forge-payload/{skills → .base-pack/skills}/qa-engineer-skills.md +0 -0
  110. /package/dist/forge-payload/{skills → .base-pack/skills}/store-custodian-skills.md +0 -0
  111. /package/dist/forge-payload/{skills → .base-pack/skills}/supervisor-skills.md +0 -0
  112. /package/dist/forge-payload/{templates → .base-pack/templates}/CODE_REVIEW_TEMPLATE.md +0 -0
  113. /package/dist/forge-payload/{templates → .base-pack/templates}/COST_REPORT_TEMPLATE.md +0 -0
  114. /package/dist/forge-payload/{templates → .base-pack/templates}/PLAN_REVIEW_TEMPLATE.md +0 -0
  115. /package/dist/forge-payload/{templates → .base-pack/templates}/PLAN_SUMMARY_TEMPLATE.json +0 -0
  116. /package/dist/forge-payload/{templates → .base-pack/templates}/PLAN_TEMPLATE.md +0 -0
  117. /package/dist/forge-payload/{templates → .base-pack/templates}/PROGRESS_TEMPLATE.md +0 -0
  118. /package/dist/forge-payload/{templates → .base-pack/templates}/RETROSPECTIVE_TEMPLATE.md +0 -0
  119. /package/dist/forge-payload/{templates → .base-pack/templates}/SPRINT_MANIFEST_TEMPLATE.md +0 -0
  120. /package/dist/forge-payload/{templates → .base-pack/templates}/SPRINT_REQUIREMENTS_TEMPLATE.md +0 -0
  121. /package/dist/forge-payload/{templates → .base-pack/templates}/TASK_PROMPT_TEMPLATE.md +0 -0
  122. /package/dist/forge-payload/{workflows → .base-pack/workflows}/_fragments/context-injection.md +0 -0
  123. /package/dist/forge-payload/{workflows → .base-pack/workflows}/_fragments/event-emission-schema.md +0 -0
  124. /package/dist/forge-payload/{workflows → .base-pack/workflows}/_fragments/finalize.md +0 -0
  125. /package/dist/forge-payload/{workflows → .base-pack/workflows}/_fragments/progress-reporting.md +0 -0
  126. /package/dist/forge-payload/{workflows → .base-pack/workflows}/architect_approve.md +0 -0
  127. /package/dist/forge-payload/{workflows → .base-pack/workflows}/architect_review_sprint_completion.md +0 -0
  128. /package/dist/forge-payload/{workflows → .base-pack/workflows}/architect_sprint_intake.md +0 -0
  129. /package/dist/forge-payload/{workflows → .base-pack/workflows}/architect_sprint_plan.md +0 -0
  130. /package/dist/forge-payload/{workflows → .base-pack/workflows}/collator_agent.md +0 -0
  131. /package/dist/forge-payload/{workflows → .base-pack/workflows}/commit_task.md +0 -0
  132. /package/dist/forge-payload/{workflows → .base-pack/workflows}/fix_bug.md +0 -0
  133. /package/dist/forge-payload/{workflows → .base-pack/workflows}/implement_plan.md +0 -0
  134. /package/dist/forge-payload/{workflows → .base-pack/workflows}/migrate_structural.md +0 -0
  135. /package/dist/forge-payload/{workflows → .base-pack/workflows}/orchestrate_task.md +0 -0
  136. /package/dist/forge-payload/{workflows → .base-pack/workflows}/plan_task.md +0 -0
  137. /package/dist/forge-payload/{workflows → .base-pack/workflows}/quiz_agent.md +0 -0
  138. /package/dist/forge-payload/{workflows → .base-pack/workflows}/review_code.md +0 -0
  139. /package/dist/forge-payload/{workflows → .base-pack/workflows}/review_plan.md +0 -0
  140. /package/dist/forge-payload/{workflows → .base-pack/workflows}/run_sprint.md +0 -0
  141. /package/dist/forge-payload/{workflows → .base-pack/workflows}/sprint_retrospective.md +0 -0
  142. /package/dist/forge-payload/{workflows → .base-pack/workflows}/update_implementation.md +0 -0
  143. /package/dist/forge-payload/{workflows → .base-pack/workflows}/update_plan.md +0 -0
  144. /package/dist/forge-payload/{workflows → .base-pack/workflows}/validate_task.md +0 -0
package/CHANGELOG.md CHANGED
@@ -5,6 +5,141 @@ All notable changes to `@entelligentsia/forgecli` are documented here.
5
5
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ---
11
+
12
+ ## [0.3.0] — 2026-05-09
13
+
14
+ Headline: Pi-runtime parity adapters — interactive UX + hook safety net.
15
+ `forge:ask_user` delivers real TUI prompts for all `/forge:init` gate sites;
16
+ the hook safety net enforces store-cli write validity and legal status
17
+ transitions at runtime. Fixes BUG-026 (non-blocking Y/N prompts) and BUG-027
18
+ (unguarded store-cli writes under pi runtime).
19
+
20
+ ### Added
21
+
22
+ - **`forge:ask_user` custom tool** (FORGE-S18-T04).
23
+ Registers `forge_ask_user` via `pi.registerTool`. Accepts `{question, type, options?, default?}`
24
+ where `type` is `confirm` (Y/N), `choice` (select from list), or `text` (free-form input).
25
+ Uses `ctx.ui.confirm / select / input` from the pi `ExtensionContext` — no raw pi-tui
26
+ component wiring needed. Blocks the model loop until the user responds. Non-interactive
27
+ bypass: `FORGE_YES=1`, `--non-interactive`, or headless mode returns the default
28
+ immediately. Cancellation surfaces as `isError: true`. 14 Vitest tests.
29
+
30
+ - **`registerHookDispatcher` wired to `tool_call` / `tool_result`** (FORGE-S18-T02).
31
+ Replaces the 7-line empty shim with a real implementation. Subscribes both pi events
32
+ (wired to tool_call/tool_result; enforcement layer added by T03).
33
+ Exports `parseStoreCLIInvocation()` + `StoreCLICall` interface for T03 to layer
34
+ validation on top. Hook inventory document produced at
35
+ `engineering/sprints/FORGE-S18/FORGE-S18-T02/HOOK_INVENTORY.md`.
36
+
37
+ - **Store-cli pushback correction loop + audit-log mode** (FORGE-S18-T03).
38
+ Extends the T02 hook-dispatcher scaffold from audit-only to enforcement.
39
+ `store-validator.ts` spawns `store-cli validate` synchronously on every write call;
40
+ `transition-guard.ts` enforces the legal status-transition table for task/sprint/bug
41
+ records. Returns `{ block: true, reason }` on violation. `FORGE_HOOK_AUDIT=1` logs
42
+ every decision (would-block/would-allow) with timestamp, entity, reason — returns
43
+ `undefined` (allow-through) regardless, enabling observation without disruption.
44
+ Closes FORGE-BUG-027.
45
+
46
+ ### Changed
47
+
48
+ - **Gate sites in `/forge:init` now use `forge:ask_user`** (FORGE-S18-T05). G2
49
+ (pre-flight phase selector) and G3 (KB folder prompt) replaced from
50
+ `sendToAgent+waitForIdle` to `ctx.ui.confirm / ctx.ui.input`. Operator receives a
51
+ real TUI prompt instead of model-generated text. Gate audit captured in
52
+ `GATE_AUDIT.md`.
53
+
54
+ ### Fixed
55
+
56
+ - **BUG-026** — Pi runtime: TUI Y/N prompts in command bodies don't wait for user
57
+ input. Fixed by `forge:ask_user` tool (T04) + gate-site retrofit (T05). `/forge:init`
58
+ gate sites G2 and G3 now use `ctx.ui.confirm/input` and block until the operator
59
+ responds.
60
+ - **BUG-027** — Pi runtime: validation hooks not wired — store-cli writes unguarded,
61
+ no pushback correction loop. Fixed by hook adapter (T02) + enforcement layer (T03).
62
+ `registerHookDispatcher` intercepts `store-cli write` and `store-cli update-status`
63
+ calls, validates against schema and transition table, returns `{ block: true, reason }`
64
+ on violation.
65
+
66
+ ---
67
+
68
+ ## [0.2.1] — 2026-05-09
69
+
70
+ Headline: Non-interactive mode for CI and scripted use. `FORGE_YES=1` and
71
+ `forge --non-interactive` both bypass every Y/N gate in `/forge:init`, resolving
72
+ each to its documented default. Unblocks scripted adoption immediately (BUG-026
73
+ short-circuit; T04/T05 deliver the real interactive TUI path).
74
+
75
+ ### Added
76
+
77
+ - **`--non-interactive` CLI flag** (FORGE-S18-T01). Parsed by `argv.ts`,
78
+ sets `FORGE_NON_INTERACTIVE=1`. Documented in `--help` output.
79
+ - **`FORGE_YES=1` environment variable** (FORGE-S18-T01). Ergonomic shorthand
80
+ for scripts (`FORGE_YES=1 forge`). Checked alongside `FORGE_NON_INTERACTIVE`.
81
+ - **`isNonInteractive()` helper** in `forge-init.ts`. Bypasses G1 (resume
82
+ confirm), G2 (pre-flight phase selector), G3 (KB folder name), G4 (CLAUDE.md
83
+ create confirm) when active.
84
+ - **README non-interactive mode section** — flag, env var, and default-resolution
85
+ table for all four gate sites.
86
+ - **Vitest gate coverage** — 12 new test cases covering each gate under
87
+ interactive, `FORGE_NON_INTERACTIVE=1`, and `FORGE_YES=1` arms.
88
+ - **E2E smoke gates E2E-04/05/06** — auth-free checks that flag and env vars
89
+ are accepted without errors.
90
+
91
+ ## [0.2.0] — 2026-05-09
92
+
93
+ Headline: `/forge:init` is now a real implementation. The 0.1.0 stub at
94
+ `src/extensions/forgecli/index.ts:77-82` is replaced with a full-parity port of
95
+ the Claude-Code plugin's `/forge:init` flow. Default payload trimmed by 35.8%
96
+ unpacked. Tarball size-budget gate enforced in smoke + CI.
97
+
98
+ ### Added
99
+
100
+ - **`/forge:init` real implementation** (FORGE-S17-T02). Full parity to the
101
+ plugin: 4-phase flow, `--fast` / `--full` flags, resume detection via
102
+ `.forge/init-progress.json`, hero banner with project-name discovery, idempotent
103
+ re-run. Consumes `dist/forge-payload/`, substitutes placeholders against user
104
+ project context, writes `.forge/{personas,skills,workflows,templates,config.json,project-context.json}`.
105
+ - **Tarball size-budget gate** (FORGE-S17-T05) at
106
+ `test/e2e/lib/tarball-size-gate.sh` (sourceable) plus
107
+ `test/e2e/size-budget.test.sh` (18 boundary assertions). Smoke gate runs after
108
+ `npm pack` with PASS / WARN (>35 MB) / FAIL (>50 MB) status. Thresholds
109
+ env-overridable via `FORGE_TARBALL_SIZE_*`.
110
+ - **`scripts/build-payload.cjs --include-full`** flag and `--help`
111
+ (FORGE-S17-T04). Opt-in to the legacy un-trimmed payload for forensic /
112
+ round-trip verification — round-trip verified byte-exact.
113
+ - **Mid-sprint runtime fixes** (FORGE-BUG-017..025) — `/forge:init` runtime
114
+ defects discovered during init-port adaptation review; pi-aware
115
+ `paths.forgeRoot`; skip Claude-Code-only command output during init.
116
+
117
+ ### Changed
118
+
119
+ - **Default payload trimmed by 35.8% unpacked** (FORGE-S17-T03 audit applied
120
+ by FORGE-S17-T04). Files 175 → 105, unpacked 704,388 → 452,445 bytes,
121
+ forge-payload tar.gz 194,067 → 123,505 bytes (−36.4%). Trim sites:
122
+ - top-level `personas/skills/workflows/templates/` removed (Pass 1 vestige,
123
+ never read at runtime),
124
+ - `.tools/lib/` allowlisted to runtime-loaded subset
125
+ (`forge-root, paths, pricing, project-root, result.js, validate.js`),
126
+ - `.init/generation/` reduced to `generate-kb-doc.md`,
127
+ - `.schemas/` reduced to `*.schema.json`.
128
+ - **Full `npm pack` output** (the published artifact, with bundled pi runtime
129
+ as bulk): 30.42 MB compressed, 19.58 MB headroom under the 50 MB hard gate.
130
+
131
+ ### Documentation
132
+
133
+ - README updated with size-budget tuning surface and trimmed-payload note.
134
+
135
+ ### Bundled / pinned (unchanged from 0.1.0)
136
+
137
+ - `@earendil-works/pi-coding-agent@0.74.0`,
138
+ `@earendil-works/pi-ai@0.74.0`,
139
+ `@earendil-works/pi-tui@0.74.0` via `bundledDependencies`.
140
+ - `forge.bundledVersion: 0.40.3` (`Entelligentsia/forge@v0.40.3`) — drift audit
141
+ clean, no upstream movement during sprint.
142
+
8
143
  ## [0.1.0] — 2026-05-08
9
144
 
10
145
  First public stable release of `@entelligentsia/forgecli` — the Forge SDLC
@@ -57,4 +192,7 @@ ported onto `@earendil-works/pi-coding-agent`.
57
192
  - `claude-agent-sdk` plan-limit support (deferred to S17+).
58
193
  - Cost telemetry surfacing in `/forge:*` (waived for S16).
59
194
 
195
+ [0.3.0]: https://github.com/Entelligentsia/forge-cli/releases/tag/v0.3.0
196
+ [0.2.1]: https://github.com/Entelligentsia/forge-cli/releases/tag/v0.2.1
197
+ [0.2.0]: https://github.com/Entelligentsia/forge-cli/releases/tag/v0.2.0
60
198
  [0.1.0]: https://github.com/Entelligentsia/forge-cli/releases/tag/v0.1.0
package/README.md CHANGED
@@ -1,52 +1,191 @@
1
- # forgecli
1
+ ## @entelligentsia/forgecli
2
2
 
3
- **Status:** Stage 1 scaffold (FORGE-S15-T01). No runtime logic yet.
3
+ Forge SDLC on the [pi-coding-agent](https://www.npmjs.com/package/@earendil-works/pi-coding-agent) runtime. Three bin aliases: `forge`, `forgecli`, `4ge`.
4
4
 
5
- `forgecli` is the TypeScript port of the Forge SDLC plugin, packaged as a `pi-coding-agent` extension. It will eventually expose the same workflows, personas, and tools that live in the Claude Code Forge plugin (`forge/`), but on the pi runtime.
5
+ Bundled Forge plugin: **v0.40.3**.
6
+ Bundled pi runtime: pinned in `package.json`.
6
7
 
7
- ## Layout
8
+ ## Install
8
9
 
10
+ ```sh
11
+ npm install -g @entelligentsia/forgecli
9
12
  ```
10
- forge-cli/
11
- ├── package.json ← name "forgecli", ESM, peer dep on @earendil-works/pi-coding-agent ^0.73.0
12
- ├── tsconfig.json ← strict, NodeNext, ES2022, outDir dist/
13
- ├── biome.json ← mirrors pi-mono conventions
14
- ├── src/
15
- │ ├── extensions/forgecli/
16
- │ │ ├── index.ts ← extension entrypoint (no-op stub)
17
- │ │ ├── forge-tools.ts ← tool registration shim
18
- │ │ ├── forge-commands.ts command registration shim
19
- │ │ ├── hook-dispatcher.ts← hook routing shim
20
- │ │ ├── forge-root.ts ← .forge/config.json resolver stub
21
- │ │ └── subagent/ ← T02 vendors pi-mono subagent module here
22
- │ └── bin/forgecli.ts ← CLI entry stub (real impl in T03)
23
- ├── agents/ ← reserved for generated agents
24
- ├── prompts/ ← reserved for generated prompts
25
- ├── skills/ ← reserved for skill defs
26
- └── test/poc/ ← spike tests for T04–T09
13
+
14
+ Requires Node 20+.
15
+
16
+ ## Quick start
17
+
18
+ ```sh
19
+ cd your-project
20
+ forge # launch interactive session (forge | forgecli | 4ge)
21
+ > /forge:init # bootstrap Forge SDLC — 4 phases, ~45s
22
+ ```
23
+
24
+ `/forge:init` is idempotent and resumable via `.forge/init-progress.json`. Re-running picks up where the previous run stopped.
25
+
26
+ ## What `/forge:init` does
27
+
28
+ 1. **Collect** 5 parallel discovery scans → `.forge/config.json`
29
+ 2. **Discover** KB doc generation + `.forge/project-context.json`
30
+ 3. **Materialize** — substitute placeholders → fully functional workflows
31
+ 4. **Register** — versioning, manifest, cache, store entries
32
+
33
+ Outputs land in `.forge/{personas,skills,workflows,templates,config.json,project-context.json}` and the configured KB folder (default `engineering/`).
34
+
35
+ ## CLI flags
36
+
37
+ ```
38
+ forge --version Print version triplet (forgecli, forge, pi)
39
+ forge --help Show forge + pi help
40
+ forge --no-update-check Skip update check
41
+ forge --non-interactive Bypass all Y/N gates with defaults (CI/scripted use)
42
+ forge --registry <path> Override model registry
43
+ ```
44
+
45
+ Pi flags (`-p`, `--cwd`, `--session`, `--model`, `--tools`, `--thinking`, …) are forwarded verbatim. Run `forge --help` for the full list.
46
+
47
+ ## Non-interactive mode
48
+
49
+ For CI, scripts, or any context where the model cannot answer Y/N prompts:
50
+
51
+ ```sh
52
+ # Using the flag
53
+ forge --non-interactive
54
+
55
+ # Using the environment variable
56
+ FORGE_YES=1 forge
57
+ ```
58
+
59
+ Both activate the same bypass. When active, every Y/N gate in `/forge:init` resolves to its documented default:
60
+
61
+ | Gate | Default resolution |
62
+ |------|--------------------|
63
+ | Resume previous init? | No — delete checkpoint, start fresh |
64
+ | Pre-flight phase selector (Phase 1–4 prompt) | Skip prompt — proceed from Phase 1 |
65
+ | Knowledge base folder name | Use default `engineering/` |
66
+ | Create CLAUDE.md? | Yes — create with KB links |
67
+
68
+ ## Hook safety net
69
+
70
+ forge-cli intercepts `store-cli write` and `store-cli update-status` bash calls and validates them before they reach the store. This prevents malformed payloads and illegal status transitions from corrupting the project's engineering knowledge base.
71
+
72
+ ### Default-on enforcement
73
+
74
+ When enforcement is active (default), the hook dispatcher:
75
+
76
+ 1. **Schema validation** — every `store-cli write <entity> '<json>'` invocation is validated against the entity schema. If the payload is invalid, the model receives a structured error via `{ block: true, reason: <error> }` and is expected to self-correct on the next attempt.
77
+
78
+ 2. **Transition guard** — every `store-cli update-status <entity> <id> status <value>` invocation is checked against the legal transition table for the entity. Illegal transitions (e.g. `draft → committed`, skipping required intermediate states) are blocked with an explanatory message naming both `from` and `to` states and the legal next states.
79
+
80
+ Both checks are enforced by default. The hooks fire synchronously before the tool executes, so the model sees the error as the tool result and retries with a corrected payload.
81
+
82
+ ### `--force` scope
83
+
84
+ When `--force` is present in the `store-cli` argv:
85
+
86
+ - **Transition guard** is bypassed — `--force` is an explicit operator override for status transitions.
87
+ - **Schema validation still runs** — a malformed payload is always invalid regardless of intent.
88
+
89
+ ### `FORGE_HOOK_AUDIT=1` — audit-only mode
90
+
91
+ Set `FORGE_HOOK_AUDIT=1` to observe hook decisions without taking action. In audit mode:
92
+
93
+ - Every decision (would-block, would-allow, lookup-failed) is logged to `.forge/logs/hooks.log`.
94
+ - Nothing is blocked — all calls proceed regardless of validation outcome.
95
+ - Useful for calibrating the false-positive rate before enabling enforcement in a new project.
96
+
97
+ Log format (one entry per line):
98
+
27
99
  ```
100
+ [store-cli-intercept] subcmd=write entity=task payload={"taskId":"..."}
101
+ [store-cli-intercept] decision=would-block reason=missing required field: taskId
102
+ [store-cli-intercept] decision=would-allow
103
+ [store-cli-intercept] decision=lookup-failed entity=task entityId=FORGE-S18-T03
104
+ ```
105
+
106
+ ### Interpreting block messages
107
+
108
+ When the model emits a malformed `store-cli` call and the hook blocks it, the tool result will contain:
109
+
110
+ ```
111
+ block: true
112
+ reason: <error text>
113
+ ```
114
+
115
+ The model should read the `reason` field and self-correct the payload or transition before retrying. Common block reasons:
28
116
 
29
- ## Reference
117
+ | Reason pattern | Cause | Fix |
118
+ |---|---|---|
119
+ | `missing required field: <field>` | Schema validation — required field absent | Add the missing field to the payload |
120
+ | `<from> → <to> is not a legal transition...` | Transition guard — illegal status jump | Use the listed legal next states |
121
+ | `store-cli validate exited with code 1` | Schema validation — malformed JSON or unknown entity | Fix the JSON payload |
30
122
 
31
- - `architectural-review.md` (sibling of this README) — design decisions and constraints.
32
- - `forge-cli-feasibility.txt` — feasibility study and PoC notes.
33
- - `.claude/skills/forge-cli-engineer/SKILL.md` — implementer skill (boundary rules, git protocol).
123
+ ## Custom tools
34
124
 
35
- ## Next steps
125
+ ### `forge:ask_user` — interactive prompt
36
126
 
37
- | Task | What lands |
38
- |---|---|
39
- | FORGE-S15-T02 | Vendor subagent module from pi-mono |
40
- | FORGE-S15-T03 | No-op extension entrypoint + `pi -e` smoke load |
41
- | FORGE-S15-T04–T09 | Spike R1–R6 PoCs |
42
- | FORGE-S15-T10 | Stage 2 gate |
127
+ The `forge_ask_user` custom tool allows Forge workflows to request user input
128
+ during model execution. It presents the appropriate TUI prompt and blocks the
129
+ model loop until the user responds.
43
130
 
44
- ## Build / verify (Stage 1)
131
+ **Schema:**
45
132
 
46
- ```bash
47
- cd forge-cli
48
- npm install
49
- npx tsc --noEmit
133
+ ```typescript
134
+ {
135
+ question: string; // The prompt shown to the user
136
+ type: "confirm" // Y/N boolean confirmation
137
+ | "choice" // Select from a list
138
+ | "text"; // Free-form single-line input
139
+ options?: string[]; // Required when type === "choice"
140
+ default?: string; // Returned in non-interactive mode
141
+ }
50
142
  ```
51
143
 
52
- No runtime entrypoint is wired up yet — `npm run lint` and `npx tsc --noEmit` are the only meaningful verifications at this stage.
144
+ **Returns:** A string — `"Y"` or `"N"` for `confirm`, the selected option for
145
+ `choice`, or the entered text for `text`. On cancellation (user dismisses the
146
+ dialog), the tool returns `isError: true` with a structured message.
147
+
148
+ **Examples:**
149
+
150
+ ```
151
+ // Confirm
152
+ forge_ask_user({ question: "Overwrite existing files?", type: "confirm" })
153
+ // → "Y" or "N"
154
+
155
+ // Choice
156
+ forge_ask_user({
157
+ question: "Select environment:",
158
+ type: "choice",
159
+ options: ["development", "staging", "production"]
160
+ })
161
+ // → "development" | "staging" | "production"
162
+
163
+ // Text
164
+ forge_ask_user({ question: "Enter project name:", type: "text", default: "myproject" })
165
+ // → user-entered string (or "myproject" in non-interactive mode)
166
+ ```
167
+
168
+ **Non-interactive behaviour:** When `FORGE_YES=1`, `--non-interactive` is set,
169
+ or pi is running in headless/RPC mode, the tool returns the `default` immediately
170
+ without rendering any TUI. Fallback defaults when no explicit `default` is
171
+ provided: `confirm` → `"Y"`, `choice` → `options[0]`, `text` → `""`.
172
+
173
+ ## Roadmap
174
+
175
+ | Command | Status |
176
+ |---------------------------|---------------------|
177
+ | `/forge:init` | Shipped (0.3.0) |
178
+ | Other `/forge:*` commands | Roadmap |
179
+
180
+ Track via [issues](https://github.com/Entelligentsia/forge-cli/issues).
181
+
182
+ ## Links
183
+
184
+ - Source: <https://github.com/Entelligentsia/forge-cli>
185
+ - Issues: <https://github.com/Entelligentsia/forge-cli/issues>
186
+ - Forge plugin (Claude Code): <https://github.com/Entelligentsia/forge>
187
+ - Changelog: [CHANGELOG.md](./CHANGELOG.md)
188
+
189
+ ## License
190
+
191
+ MIT — see [LICENSE](./LICENSE).
package/dist/bin/argv.js CHANGED
@@ -71,6 +71,11 @@ export function parseForgeArgv(argv) {
71
71
  i++;
72
72
  continue;
73
73
  }
74
+ if (token === "--non-interactive") {
75
+ env.FORGE_NON_INTERACTIVE = "1";
76
+ i++;
77
+ continue;
78
+ }
74
79
  if (token === "--registry") {
75
80
  if (i + 1 >= argv.length) {
76
81
  return { error: "forge: --registry requires a path argument. Run `forge --help` for usage." };
@@ -1 +1 @@
1
- {"version":3,"file":"argv.js","sourceRoot":"","sources":["../../src/bin/argv.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"argv.js","sourceRoot":"","sources":["../../src/bin/argv.ts"],"names":[],"mappings":"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"}
package/dist/bin/forge.js CHANGED
@@ -56,6 +56,7 @@ Forge-owned options:
56
56
  --version Print version triplet and exit
57
57
  --help, -h Print this help message
58
58
  --no-update-check Skip forge update check (sets FORGE_NO_UPDATE_CHECK=1)
59
+ --non-interactive Bypass all Y/N gates with defaults, e.g. for CI (sets FORGE_NON_INTERACTIVE=1)
59
60
  --registry <path> Override model registry path (sets FORGE_MODEL_REGISTRY=path)
60
61
 
61
62
  Pi options (forwarded verbatim):
@@ -1 +1 @@
1
- {"version":3,"file":"forge.js","sourceRoot":"","sources":["../../src/bin/forge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"forge.js","sourceRoot":"","sources":["../../src/bin/forge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ import { Type } from "typebox";
3
+ export declare const AskUserParams: Type.TObject<{
4
+ question: Type.TString;
5
+ type: Type.TUnion<[Type.TLiteral<"confirm">, Type.TLiteral<"choice">, Type.TLiteral<"text">]>;
6
+ options: Type.TOptional<Type.TArray<Type.TString>>;
7
+ default: Type.TOptional<Type.TString>;
8
+ }>;
9
+ /**
10
+ * Register the forge_ask_user tool with the pi ExtensionAPI.
11
+ *
12
+ * The tool is named `forge_ask_user` (snake_case per pi convention); the
13
+ * human/LLM-facing name `forge:ask_user` appears in description and promptSnippet.
14
+ *
15
+ * @param pi The pi ExtensionAPI instance.
16
+ */
17
+ export declare function registerAskUserTool(pi: ExtensionAPI): void;
@@ -0,0 +1,139 @@
1
+ // forge:ask_user custom tool — FORGE-S18-T04
2
+ //
3
+ // Registers forge_ask_user via pi.registerTool. The tool accepts a question and
4
+ // an input type (confirm | choice | text), presents the appropriate TUI prompt
5
+ // via ctx.ui.confirm / ctx.ui.select / ctx.ui.input, and returns the user's
6
+ // answer as a string.
7
+ //
8
+ // Non-interactive bypass:
9
+ // When FORGE_YES=1 or FORGE_NON_INTERACTIVE=1 (set by `forge --non-interactive`),
10
+ // or when ctx.hasUI is false (headless / RPC mode), the tool returns the supplied
11
+ // default without rendering any TUI. Fallback defaults when no explicit default:
12
+ // confirm → "Y"
13
+ // choice → options[0] (or "" if empty)
14
+ // text → ""
15
+ //
16
+ // Cancellation:
17
+ // ctx.ui.* returns undefined when the user cancels. The tool surfaces this as
18
+ // isError: true with a structured message — never silently defaults.
19
+ //
20
+ // Iron Law 6 compliance: no shell-string interpolation. No subprocess spawning.
21
+ import { Type } from "typebox";
22
+ // ── Schema ────────────────────────────────────────────────────────────────────
23
+ export const AskUserParams = Type.Object({
24
+ question: Type.String({
25
+ description: "The question or prompt to display to the user.",
26
+ }),
27
+ type: Type.Union([Type.Literal("confirm"), Type.Literal("choice"), Type.Literal("text")], {
28
+ description: "Input modality: confirm (Y/N boolean), choice (select from list), or text (free-form single-line input).",
29
+ }),
30
+ options: Type.Optional(Type.Array(Type.String(), {
31
+ description: "Required when type === 'choice'. The list of options to present to the user.",
32
+ })),
33
+ default: Type.Optional(Type.String({
34
+ description: "Default value returned in non-interactive mode or when no default is needed. " +
35
+ "If absent, the fallback is: confirm → 'Y', choice → options[0], text → ''.",
36
+ })),
37
+ });
38
+ // ── Non-interactive helper ────────────────────────────────────────────────────
39
+ /**
40
+ * Returns true when running in non-interactive / CI mode.
41
+ *
42
+ * Inlined here (not imported from forge-init.ts) to keep the module boundary
43
+ * clean and avoid any risk of circular imports.
44
+ *
45
+ * Activated by:
46
+ * - `FORGE_YES=1` — ergonomic shell shorthand (FORGE-S18-T01)
47
+ * - `FORGE_NON_INTERACTIVE=1` — set by `forge --non-interactive` flag
48
+ */
49
+ function isNonInteractive() {
50
+ return process.env.FORGE_YES === "1" || process.env.FORGE_NON_INTERACTIVE === "1";
51
+ }
52
+ // ── Result helpers ────────────────────────────────────────────────────────────
53
+ function okResult(text) {
54
+ return {
55
+ content: [{ type: "text", text: text || "" }],
56
+ details: {},
57
+ };
58
+ }
59
+ function errResult(text) {
60
+ return {
61
+ content: [{ type: "text", text }],
62
+ details: {},
63
+ isError: true,
64
+ };
65
+ }
66
+ // ── Fallback computation ──────────────────────────────────────────────────────
67
+ /**
68
+ * Compute the non-interactive fallback value.
69
+ *
70
+ * Priority: explicit `default` field → type-specific hardcoded fallback.
71
+ */
72
+ function computeFallback(params) {
73
+ if (params.default !== undefined)
74
+ return params.default;
75
+ if (params.type === "confirm")
76
+ return "Y";
77
+ if (params.type === "choice")
78
+ return params.options?.[0] ?? "";
79
+ return ""; // text
80
+ }
81
+ // ── Public registration ───────────────────────────────────────────────────────
82
+ /**
83
+ * Register the forge_ask_user tool with the pi ExtensionAPI.
84
+ *
85
+ * The tool is named `forge_ask_user` (snake_case per pi convention); the
86
+ * human/LLM-facing name `forge:ask_user` appears in description and promptSnippet.
87
+ *
88
+ * @param pi The pi ExtensionAPI instance.
89
+ */
90
+ export function registerAskUserTool(pi) {
91
+ pi.registerTool({
92
+ name: "forge_ask_user",
93
+ label: "Forge Ask User",
94
+ description: "forge:ask_user — Present an interactive prompt to the user and return their answer. " +
95
+ "Accepts three input types: 'confirm' (Y/N), 'choice' (select from a list), or 'text' " +
96
+ "(free-form single-line input). Blocks the model loop until the user responds. " +
97
+ "In non-interactive mode (FORGE_YES=1 or --non-interactive), returns the default immediately.",
98
+ promptSnippet: "Use forge_ask_user when a Forge workflow needs synchronous user input — confirm (Y/N), choice from a list, or free-form text.",
99
+ parameters: AskUserParams,
100
+ async execute(_toolCallId, params, signal, _onUpdate, ctx) {
101
+ // Non-interactive bypass: applies when env flag is set OR when running
102
+ // headless (ctx.hasUI=false, e.g. RPC mode / print mode).
103
+ if (isNonInteractive() || !ctx.hasUI) {
104
+ const fallback = computeFallback(params);
105
+ // Emit a one-line audit entry to stderr (not a file) so CI logs capture it.
106
+ process.stderr.write(`[forge:ask_user] non-interactive fallback — type=${params.type} question="${params.question}" default="${fallback}"\n`);
107
+ return okResult(fallback);
108
+ }
109
+ const opts = signal !== undefined ? { signal } : {};
110
+ if (params.type === "confirm") {
111
+ // ctx.ui.confirm returns true/false or undefined (cancel).
112
+ const answer = await ctx.ui.confirm("forge:ask_user", params.question, opts);
113
+ if (answer === undefined) {
114
+ return errResult(`forge:ask_user cancelled — user dismissed the prompt. question: "${params.question}"`);
115
+ }
116
+ return okResult(answer ? "Y" : "N");
117
+ }
118
+ if (params.type === "choice") {
119
+ if (!params.options || params.options.length === 0) {
120
+ return errResult("forge:ask_user error — type 'choice' requires a non-empty 'options' array.");
121
+ }
122
+ // ctx.ui.select returns the selected string or undefined (cancel).
123
+ const answer = await ctx.ui.select("forge:ask_user", params.options, opts);
124
+ if (answer === undefined) {
125
+ return errResult(`forge:ask_user cancelled — user dismissed the prompt. question: "${params.question}"`);
126
+ }
127
+ return okResult(answer);
128
+ }
129
+ // type === "text"
130
+ // ctx.ui.input returns the entered string or undefined (cancel/ESC).
131
+ const answer = await ctx.ui.input("forge:ask_user", params.question, opts);
132
+ if (answer === undefined) {
133
+ return errResult(`forge:ask_user cancelled — user dismissed the prompt. question: "${params.question}"`);
134
+ }
135
+ return okResult(answer);
136
+ },
137
+ });
138
+ }
139
+ //# sourceMappingURL=ask-user-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ask-user-tool.js","sourceRoot":"","sources":["../../../src/extensions/forgecli/ask-user-tool.ts"],"names":[],"mappings":"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"}
@@ -7,8 +7,29 @@ interface RegisterOptions {
7
7
  }
8
8
  declare function resetTomoshibiState(): void;
9
9
  export declare function registerForgeCommands(pi: ExtensionAPI, options: RegisterOptions): void;
10
+ /** Parse YAML frontmatter from a markdown file. Returns name and description or null. */
11
+ declare function parseFrontmatter(content: string): {
12
+ name: string;
13
+ description: string;
14
+ } | null;
15
+ export interface RegisterAllOptions {
16
+ /** Absolute path to dist/forge-payload/ (containing .base-pack/commands/). */
17
+ bundlePayloadRoot: string;
18
+ /** Current working directory (for health check). */
19
+ cwd?: string;
20
+ /** Absolute path to dist/forge-payload/ for health check bundle root. */
21
+ bundleRoot?: string;
22
+ }
23
+ /**
24
+ * Register all forge commands from the bundled .base-pack/commands/ directory.
25
+ * Commands already registered (real handlers) are skipped.
26
+ * Returns the number of commands registered.
27
+ */
28
+ export declare function registerAllForgeCommands(pi: ExtensionAPI, options: RegisterAllOptions): number;
10
29
  export declare const __test__: {
11
30
  resetTomoshibiState: typeof resetTomoshibiState;
12
31
  getTomoshibiPending: () => boolean;
32
+ parseFrontmatter: typeof parseFrontmatter;
33
+ REAL_HANDLERS: Set<string>;
13
34
  };
14
35
  export {};