@entelligentsia/forgecli 1.0.21 → 1.0.36

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 (218) hide show
  1. package/CHANGELOG.md +346 -0
  2. package/README.md +2 -0
  3. package/dist/CHANGELOG-forge-plugin.md +281 -0
  4. package/dist/bin/argv.d.ts +2 -2
  5. package/dist/bin/argv.js +25 -0
  6. package/dist/bin/argv.js.map +1 -1
  7. package/dist/bin/forge.js +12 -0
  8. package/dist/bin/forge.js.map +1 -1
  9. package/dist/bin/init.d.ts +23 -0
  10. package/dist/bin/init.js +123 -0
  11. package/dist/bin/init.js.map +1 -0
  12. package/dist/bin/uninstall.d.ts +20 -0
  13. package/dist/bin/uninstall.js +141 -0
  14. package/dist/bin/uninstall.js.map +1 -0
  15. package/dist/extensions/forgecli/claude-bootstrap/bootstrap.d.ts +40 -0
  16. package/dist/extensions/forgecli/claude-bootstrap/bootstrap.js +593 -0
  17. package/dist/extensions/forgecli/claude-bootstrap/bootstrap.js.map +1 -0
  18. package/dist/extensions/forgecli/claude-bootstrap/settings-merge.d.ts +46 -0
  19. package/dist/extensions/forgecli/claude-bootstrap/settings-merge.js +245 -0
  20. package/dist/extensions/forgecli/claude-bootstrap/settings-merge.js.map +1 -0
  21. package/dist/extensions/forgecli/claude-bootstrap/uninstall.d.ts +23 -0
  22. package/dist/extensions/forgecli/claude-bootstrap/uninstall.js +215 -0
  23. package/dist/extensions/forgecli/claude-bootstrap/uninstall.js.map +1 -0
  24. package/dist/extensions/forgecli/dashboard/component.js +10 -7
  25. package/dist/extensions/forgecli/dashboard/component.js.map +1 -1
  26. package/dist/extensions/forgecli/forge-tools.d.ts +1 -0
  27. package/dist/extensions/forgecli/forge-tools.js +73 -0
  28. package/dist/extensions/forgecli/forge-tools.js.map +1 -1
  29. package/dist/extensions/forgecli/lib/forge-root.d.ts +5 -0
  30. package/dist/extensions/forgecli/lib/forge-root.js +14 -1
  31. package/dist/extensions/forgecli/lib/forge-root.js.map +1 -1
  32. package/dist/extensions/forgecli/orchestrators/bug/bug-body.d.ts +1 -0
  33. package/dist/extensions/forgecli/orchestrators/bug/bug-body.js +65 -0
  34. package/dist/extensions/forgecli/orchestrators/bug/bug-body.js.map +1 -0
  35. package/dist/extensions/forgecli/orchestrators/bug/bug-id.d.ts +23 -0
  36. package/dist/extensions/forgecli/orchestrators/bug/bug-id.js +140 -0
  37. package/dist/extensions/forgecli/orchestrators/bug/bug-id.js.map +1 -0
  38. package/dist/extensions/forgecli/orchestrators/bug/bug-phase-dispatch.d.ts +54 -0
  39. package/dist/extensions/forgecli/orchestrators/bug/bug-phase-dispatch.js +349 -0
  40. package/dist/extensions/forgecli/orchestrators/bug/bug-phase-dispatch.js.map +1 -0
  41. package/dist/extensions/forgecli/orchestrators/bug/bug-phases.d.ts +8 -0
  42. package/dist/extensions/forgecli/orchestrators/bug/bug-phases.js +60 -0
  43. package/dist/extensions/forgecli/orchestrators/bug/bug-phases.js.map +1 -0
  44. package/dist/extensions/forgecli/orchestrators/bug/bug-state.d.ts +14 -0
  45. package/dist/extensions/forgecli/orchestrators/bug/bug-state.js +100 -0
  46. package/dist/extensions/forgecli/orchestrators/bug/bug-state.js.map +1 -0
  47. package/dist/extensions/forgecli/orchestrators/bug/bug-triage-routing.d.ts +72 -0
  48. package/dist/extensions/forgecli/orchestrators/bug/bug-triage-routing.js +204 -0
  49. package/dist/extensions/forgecli/orchestrators/bug/bug-triage-routing.js.map +1 -0
  50. package/dist/extensions/forgecli/orchestrators/bug/bug-verdict-loop.d.ts +38 -0
  51. package/dist/extensions/forgecli/orchestrators/bug/bug-verdict-loop.js +166 -0
  52. package/dist/extensions/forgecli/orchestrators/bug/bug-verdict-loop.js.map +1 -0
  53. package/dist/extensions/forgecli/orchestrators/bug/bug-verdict.d.ts +3 -0
  54. package/dist/extensions/forgecli/orchestrators/bug/bug-verdict.js +55 -0
  55. package/dist/extensions/forgecli/orchestrators/bug/bug-verdict.js.map +1 -0
  56. package/dist/extensions/forgecli/orchestrators/bug/run-bug-command.d.ts +7 -0
  57. package/dist/extensions/forgecli/orchestrators/bug/run-bug-command.js +293 -0
  58. package/dist/extensions/forgecli/orchestrators/bug/run-bug-command.js.map +1 -0
  59. package/dist/extensions/forgecli/orchestrators/bug/run-bug-pipeline.d.ts +2 -0
  60. package/dist/extensions/forgecli/orchestrators/bug/run-bug-pipeline.js +501 -0
  61. package/dist/extensions/forgecli/orchestrators/bug/run-bug-pipeline.js.map +1 -0
  62. package/dist/extensions/forgecli/orchestrators/bug/run-bug-types.d.ts +41 -0
  63. package/dist/extensions/forgecli/orchestrators/bug/run-bug-types.js +5 -0
  64. package/dist/extensions/forgecli/orchestrators/bug/run-bug-types.js.map +1 -0
  65. package/dist/extensions/forgecli/orchestrators/common/orchestrator-entry.d.ts +43 -0
  66. package/dist/extensions/forgecli/orchestrators/common/orchestrator-entry.js +85 -0
  67. package/dist/extensions/forgecli/orchestrators/common/orchestrator-entry.js.map +1 -0
  68. package/dist/extensions/forgecli/orchestrators/common/orchestrator-misc.d.ts +8 -0
  69. package/dist/extensions/forgecli/orchestrators/common/orchestrator-misc.js +37 -0
  70. package/dist/extensions/forgecli/orchestrators/common/orchestrator-misc.js.map +1 -0
  71. package/dist/extensions/forgecli/orchestrators/common/orchestrator-notify.d.ts +28 -0
  72. package/dist/extensions/forgecli/orchestrators/common/orchestrator-notify.js +45 -0
  73. package/dist/extensions/forgecli/orchestrators/common/orchestrator-notify.js.map +1 -0
  74. package/dist/extensions/forgecli/orchestrators/common/orchestrator-transcript-session.d.ts +26 -0
  75. package/dist/extensions/forgecli/orchestrators/common/orchestrator-transcript-session.js +75 -0
  76. package/dist/extensions/forgecli/orchestrators/common/orchestrator-transcript-session.js.map +1 -0
  77. package/dist/extensions/forgecli/orchestrators/common/summary-recovery.d.ts +24 -0
  78. package/dist/extensions/forgecli/orchestrators/common/summary-recovery.js +37 -0
  79. package/dist/extensions/forgecli/orchestrators/common/summary-recovery.js.map +1 -0
  80. package/dist/extensions/forgecli/orchestrators/fix-bug.d.ts +9 -92
  81. package/dist/extensions/forgecli/orchestrators/fix-bug.js +23 -1695
  82. package/dist/extensions/forgecli/orchestrators/fix-bug.js.map +1 -1
  83. package/dist/extensions/forgecli/orchestrators/run-sprint.d.ts +3 -12
  84. package/dist/extensions/forgecli/orchestrators/run-sprint.js +97 -270
  85. package/dist/extensions/forgecli/orchestrators/run-sprint.js.map +1 -1
  86. package/dist/extensions/forgecli/orchestrators/run-task.d.ts +10 -214
  87. package/dist/extensions/forgecli/orchestrators/run-task.js +31 -1481
  88. package/dist/extensions/forgecli/orchestrators/run-task.js.map +1 -1
  89. package/dist/extensions/forgecli/orchestrators/sprint/sprint-ceremony.d.ts +33 -0
  90. package/dist/extensions/forgecli/orchestrators/sprint/sprint-ceremony.js +135 -0
  91. package/dist/extensions/forgecli/orchestrators/sprint/sprint-ceremony.js.map +1 -0
  92. package/dist/extensions/forgecli/orchestrators/sprint/sprint-state.d.ts +18 -0
  93. package/dist/extensions/forgecli/orchestrators/sprint/sprint-state.js +55 -0
  94. package/dist/extensions/forgecli/orchestrators/sprint/sprint-state.js.map +1 -0
  95. package/dist/extensions/forgecli/orchestrators/task/run-task-command.d.ts +9 -0
  96. package/dist/extensions/forgecli/orchestrators/task/run-task-command.js +174 -0
  97. package/dist/extensions/forgecli/orchestrators/task/run-task-command.js.map +1 -0
  98. package/dist/extensions/forgecli/orchestrators/task/run-task-pipeline.d.ts +2 -0
  99. package/dist/extensions/forgecli/orchestrators/task/run-task-pipeline.js +494 -0
  100. package/dist/extensions/forgecli/orchestrators/task/run-task-pipeline.js.map +1 -0
  101. package/dist/extensions/forgecli/orchestrators/task/run-task-types.d.ts +62 -0
  102. package/dist/extensions/forgecli/orchestrators/task/run-task-types.js +5 -0
  103. package/dist/extensions/forgecli/orchestrators/task/run-task-types.js.map +1 -0
  104. package/dist/extensions/forgecli/orchestrators/task/task-body.d.ts +4 -0
  105. package/dist/extensions/forgecli/orchestrators/task/task-body.js +48 -0
  106. package/dist/extensions/forgecli/orchestrators/task/task-body.js.map +1 -0
  107. package/dist/extensions/forgecli/orchestrators/task/task-events.d.ts +63 -0
  108. package/dist/extensions/forgecli/orchestrators/task/task-events.js +185 -0
  109. package/dist/extensions/forgecli/orchestrators/task/task-events.js.map +1 -0
  110. package/dist/extensions/forgecli/orchestrators/task/task-gates.d.ts +34 -0
  111. package/dist/extensions/forgecli/orchestrators/task/task-gates.js +78 -0
  112. package/dist/extensions/forgecli/orchestrators/task/task-gates.js.map +1 -0
  113. package/dist/extensions/forgecli/orchestrators/task/task-phase-dispatch.d.ts +42 -0
  114. package/dist/extensions/forgecli/orchestrators/task/task-phase-dispatch.js +370 -0
  115. package/dist/extensions/forgecli/orchestrators/task/task-phase-dispatch.js.map +1 -0
  116. package/dist/extensions/forgecli/orchestrators/task/task-phases.d.ts +14 -0
  117. package/dist/extensions/forgecli/orchestrators/task/task-phases.js +26 -0
  118. package/dist/extensions/forgecli/orchestrators/task/task-phases.js.map +1 -0
  119. package/dist/extensions/forgecli/orchestrators/task/task-record.d.ts +9 -0
  120. package/dist/extensions/forgecli/orchestrators/task/task-record.js +58 -0
  121. package/dist/extensions/forgecli/orchestrators/task/task-record.js.map +1 -0
  122. package/dist/extensions/forgecli/orchestrators/task/task-state.d.ts +14 -0
  123. package/dist/extensions/forgecli/orchestrators/task/task-state.js +35 -0
  124. package/dist/extensions/forgecli/orchestrators/task/task-state.js.map +1 -0
  125. package/dist/extensions/forgecli/orchestrators/task/task-verdict-loop.d.ts +36 -0
  126. package/dist/extensions/forgecli/orchestrators/task/task-verdict-loop.js +152 -0
  127. package/dist/extensions/forgecli/orchestrators/task/task-verdict-loop.js.map +1 -0
  128. package/dist/extensions/forgecli/update/forge-update-command.js +10 -7
  129. package/dist/extensions/forgecli/update/forge-update-command.js.map +1 -1
  130. package/dist/forge-payload/.base-pack/commands/approve.md +2 -2
  131. package/dist/forge-payload/.base-pack/commands/check-agent.md +2 -2
  132. package/dist/forge-payload/.base-pack/commands/collate.md +2 -2
  133. package/dist/forge-payload/.base-pack/commands/commit.md +2 -2
  134. package/dist/forge-payload/.base-pack/commands/enhance.md +2 -2
  135. package/dist/forge-payload/.base-pack/commands/fix-bug.md +2 -2
  136. package/dist/forge-payload/.base-pack/commands/implement.md +2 -2
  137. package/dist/forge-payload/.base-pack/commands/init.md +278 -0
  138. package/dist/forge-payload/.base-pack/commands/new-sprint.md +2 -2
  139. package/dist/forge-payload/.base-pack/commands/plan-sprint.md +2 -2
  140. package/dist/forge-payload/.base-pack/commands/plan.md +2 -2
  141. package/dist/forge-payload/.base-pack/commands/retro.md +2 -2
  142. package/dist/forge-payload/.base-pack/commands/review-code.md +2 -2
  143. package/dist/forge-payload/.base-pack/commands/review-plan.md +2 -2
  144. package/dist/forge-payload/.base-pack/commands/run-sprint.md +2 -2
  145. package/dist/forge-payload/.base-pack/commands/run-task.md +2 -2
  146. package/dist/forge-payload/.base-pack/commands/validate.md +2 -2
  147. package/dist/forge-payload/.base-pack/workflows/_fragments/event-emission-schema.md +4 -0
  148. package/dist/forge-payload/.base-pack/workflows/_fragments/event-vocabulary.md +88 -0
  149. package/dist/forge-payload/.base-pack/workflows/collator_agent.md +5 -6
  150. package/dist/forge-payload/.base-pack/workflows/commit_task.md +41 -38
  151. package/dist/forge-payload/.base-pack/workflows/implement_plan.md +3 -3
  152. package/dist/forge-payload/.base-pack/workflows/migrate_structural.md +1 -1
  153. package/dist/forge-payload/.base-pack/workflows-js/wfl-fix-bug.js +42 -6
  154. package/dist/forge-payload/.base-pack/workflows-js/wfl-init.js +449 -0
  155. package/dist/forge-payload/.base-pack/workflows-js/wfl-run-task.js +32 -1
  156. package/dist/forge-payload/.claude-plugin/plugin.json +1 -1
  157. package/dist/forge-payload/.schemas/enum-catalog.json +2 -2
  158. package/dist/forge-payload/.schemas/event.schema.json +8 -3
  159. package/dist/forge-payload/.schemas/migrations.json +141 -0
  160. package/dist/forge-payload/commands/add-pipeline.md +1 -1
  161. package/dist/forge-payload/commands/add-task.md +3 -3
  162. package/dist/forge-payload/commands/ask.md +1 -1
  163. package/dist/forge-payload/commands/check-agent.md +1 -1
  164. package/dist/forge-payload/commands/config.md +1 -1
  165. package/dist/forge-payload/commands/health.md +1 -1
  166. package/dist/forge-payload/commands/init.md +62 -7
  167. package/dist/forge-payload/commands/rebuild.md +3 -3
  168. package/dist/forge-payload/commands/remove.md +1 -1
  169. package/dist/forge-payload/commands/repair.md +1 -1
  170. package/dist/forge-payload/commands/report-bug.md +1 -1
  171. package/dist/forge-payload/commands/status.md +1 -1
  172. package/dist/forge-payload/commands/update.md +3 -3
  173. package/dist/forge-payload/hooks/lib/common.cjs +228 -0
  174. package/dist/forge-payload/hooks/lib/plugin-detection.cjs +106 -0
  175. package/dist/forge-payload/hooks/lib/update-msg.cjs +23 -0
  176. package/dist/forge-payload/hooks/lib/update-url.cjs +46 -0
  177. package/dist/forge-payload/hooks/lib/write-registry.js +53 -0
  178. package/dist/forge-payload/init/discovery/discover-database.md +32 -0
  179. package/dist/forge-payload/init/discovery/discover-processes.md +31 -0
  180. package/dist/forge-payload/init/discovery/discover-routing.md +31 -0
  181. package/dist/forge-payload/init/discovery/discover-stack.md +33 -0
  182. package/dist/forge-payload/init/discovery/discover-testing.md +34 -0
  183. package/dist/forge-payload/init/generation/generate-commands.md +171 -0
  184. package/dist/forge-payload/init/generation/generate-kb-doc.md +60 -0
  185. package/dist/forge-payload/init/generation/generate-knowledge-base.md +56 -0
  186. package/dist/forge-payload/init/generation/generate-persona.md +73 -0
  187. package/dist/forge-payload/init/generation/generate-personas.md +54 -0
  188. package/dist/forge-payload/init/generation/generate-skill.md +66 -0
  189. package/dist/forge-payload/init/generation/generate-skills.md +36 -0
  190. package/dist/forge-payload/init/generation/generate-template.md +60 -0
  191. package/dist/forge-payload/init/generation/generate-templates.md +39 -0
  192. package/dist/forge-payload/init/generation/generate-tools.md +133 -0
  193. package/dist/forge-payload/init/generation/generate-workflows.md +78 -0
  194. package/dist/forge-payload/init/phases/phase-1-collect.md +10 -2
  195. package/dist/forge-payload/init/phases/phase-3-materialize.md +1 -1
  196. package/dist/forge-payload/init/phases/phase-4-register.md +8 -0
  197. package/dist/forge-payload/init/workflow-gen-plan.json +17 -0
  198. package/dist/forge-payload/integrity.json +16 -16
  199. package/dist/forge-payload/meta/store-schema/event.schema.md +7 -0
  200. package/dist/forge-payload/meta/workflows/_fragments/event-emission-schema.md +4 -0
  201. package/dist/forge-payload/meta/workflows/_fragments/event-vocabulary.md +88 -0
  202. package/dist/forge-payload/meta/workflows/meta-collate.md +5 -6
  203. package/dist/forge-payload/meta/workflows/meta-commit.md +46 -43
  204. package/dist/forge-payload/meta/workflows/meta-fix-bug.md +7 -2
  205. package/dist/forge-payload/meta/workflows/meta-implement.md +3 -3
  206. package/dist/forge-payload/meta/workflows/meta-migrate.md +1 -1
  207. package/dist/forge-payload/meta/workflows/meta-orchestrate.md +4 -1
  208. package/dist/forge-payload/schemas/enum-catalog.json +2 -2
  209. package/dist/forge-payload/schemas/event.schema.json +8 -3
  210. package/dist/forge-payload/schemas/structure-manifest.json +5 -12
  211. package/dist/forge-payload/tools/commit-task.cjs +218 -0
  212. package/dist/forge-payload/tools/forge-preflight.cjs +268 -0
  213. package/dist/forge-payload/tools/lib/paths.cjs +12 -11
  214. package/dist/forge-payload/tools/lib/pricing.cjs +31 -11
  215. package/dist/forge-payload/tools/query-logger.cjs +34 -0
  216. package/dist/forge-payload/tools/store-cli.cjs +6 -1
  217. package/dist/forge-payload/tools/substitute-placeholders.cjs +5 -6
  218. package/package.json +2 -2
@@ -0,0 +1,449 @@
1
+ export const meta = {
2
+ name: 'wfl:init',
3
+ description: 'Code-orchestrated /forge:init LLM half — parallel discovery fan-out → config-writer (Phase 1 Collect), parallel KB-doc fan-out → index → context (Phase 2 Discover), deterministic materialize (Phase 3), content-register (Phase 4). JS holds the phase index, verify gates, retry caps, and fan-out; subagents execute the phase rulebooks. Args: { forgeRoot, kbFolder, startPhase, createClaudeMd, isoTimestamp, rawArguments }.',
4
+ whenToUse: "Run the LLM-orchestrated half of /forge:init after `4ge init claude .` has bootstrapped the project structure. Dispatch by name: workflow('wfl:init', { forgeRoot, kbFolder, startPhase, createClaudeMd, isoTimestamp, rawArguments }).",
5
+ phases: [
6
+ { title: 'Collect', detail: 'parallel() 5 discovery agents scan codebase domains; config-writer agent merges findings and writes config + init-progress.json; verify-phase gate with one retry cap' },
7
+ { title: 'Discover', detail: 'gate+scaffold agent verifies phase 1; parallel() 7 KB-doc agents generate architecture docs with JS-held retry-once; sequential index + context agents close the phase' },
8
+ { title: 'Materialize', detail: 'single haiku agent runs deterministic substitute-placeholders + generation-manifest + build-overlay; Phase 3 verify failure is a hard halt (no retry — rebuild/restart)' },
9
+ { title: 'Register', detail: 'single haiku agent runs content-register steps; CLAUDE.md creation gated on args.createClaudeMd === true; returns pendingActions for Tomoshibi' },
10
+ { title: 'Report', detail: 'return structured result { ok, lastPhase, stack, skillMatches, counts, confidence, pendingActions, failure? } for the command wrapper to render' },
11
+ ],
12
+ };
13
+
14
+ // wfl:init — code-orchestrated LLM half of /forge:init
15
+ //
16
+ // Why a script: init is a deterministic 4-phase FSM with mechanical verify
17
+ // gates (verify-phase.cjs --phase N), bounded retries (max 1), fan-out steps
18
+ // (5 discovery scans, 7 KB docs), and escalate-don't-continue semantics.
19
+ // JS holds the phase index, the verify-gate routing, the retry counters, and
20
+ // the fan-out; subagents only execute one phase rulebook each.
21
+ //
22
+ // WORKFLOW-API CONTRACT (forge#112 — field failure; enforced by
23
+ // wfl-drivers-parse.test.cjs):
24
+ // - Exactly ONE export: the meta literal. The body runs at top level in the
25
+ // harness's async context (top-level await/return valid; args is a global).
26
+ // - phase(title) takes ONLY a title — a callback second arg is silently
27
+ // discarded. Phase bodies run inline after the phase() call.
28
+ // - parallel() takes thunks: parallel([() => agent(...), ...]).
29
+ // - agent(prompt, opts) — model goes in opts.model; structured results
30
+ // REQUIRE opts.schema (otherwise agent() returns plain text and .ok
31
+ // reads are undefined).
32
+ //
33
+ // CLI-FIRST BOOTSTRAP ADR (doc/decisions/cli-first-bootstrap.md):
34
+ // `4ge init claude .` runs first (deterministic, zero tokens): scaffolds
35
+ // .forge/ as a complete vendored Forge root (tools, schemas, hooks, init/,
36
+ // .base-pack/, meta/) and installs THIS FILE into .claude/workflows/.
37
+ // All rulebook reads use vendored .forge/init/... paths; discovery prompts
38
+ // fall back to direct project analysis if a prompt file is absent.
39
+ //
40
+ // SIDE-EFFECT OWNERSHIP: this script has NO filesystem/shell access. Each
41
+ // per-phase subagent owns rulebook execution (artifact writes, checkpoint
42
+ // writes, verify runs). The JS driver holds ONLY control flow.
43
+ //
44
+ // Timestamps: the Workflow sandbox blocks timestamp minting (Date.now,
45
+ // Math.random, and the zero-arg Date constructor are all unavailable).
46
+ // The command wrapper supplies args.isoTimestamp.
47
+ //
48
+ // MODEL TIERING: generation/discovery → sonnet; deterministic gates and
49
+ // registration → haiku. No opus (init has no review/approve gates).
50
+
51
+ // ─────────────────────────────────────────────────────────────────────────────
52
+ // Schemas
53
+ // ─────────────────────────────────────────────────────────────────────────────
54
+
55
+ const DISCOVERY_SCHEMA = {
56
+ type: 'object',
57
+ properties: {
58
+ domain: { type: 'string', description: 'discovery domain name (stack|routing|processes|database|testing)' },
59
+ findings: { type: 'object', description: 'domain-specific structured findings' },
60
+ confidence: { type: 'number', description: '0–1 confidence in completeness of scan' },
61
+ warnings: { type: 'array', items: { type: 'string' }, description: 'ambiguities or partial coverage notes' },
62
+ },
63
+ required: ['domain', 'findings', 'confidence'],
64
+ };
65
+
66
+ const KB_DOC_SCHEMA = {
67
+ type: 'object',
68
+ properties: {
69
+ id: { type: 'string', description: 'KB doc id matching the phase-2 table row' },
70
+ ok: { type: 'boolean', description: 'true if doc written successfully' },
71
+ confidence: { type: 'number', description: '0–1 confidence in doc completeness' },
72
+ error: { type: 'string', description: 'error message if ok=false' },
73
+ },
74
+ required: ['id', 'ok', 'confidence'],
75
+ };
76
+
77
+ const PHASE_RESULT_SCHEMA = {
78
+ type: 'object',
79
+ properties: {
80
+ verifyExit: { type: 'number', description: 'exit code from verify-phase.cjs (0=pass, non-zero=fail)' },
81
+ verifyError: { type: 'string', description: 'stderr/stdout from failed verify run' },
82
+ stack: { type: 'string', description: 'technology stack summary (Phase 1 output)' },
83
+ skillMatches: {
84
+ type: 'array',
85
+ items: { type: 'string' },
86
+ description: 'skill IDs matching project tech stack (from skill-recommendations.md)',
87
+ },
88
+ confidence: { type: 'number', description: '0–1 confidence' },
89
+ ok: { type: 'boolean', description: 'true if phase completed and verify passed' },
90
+ },
91
+ required: ['verifyExit', 'ok'],
92
+ };
93
+
94
+ const OK_SCHEMA = {
95
+ type: 'object',
96
+ properties: {
97
+ ok: { type: 'boolean', description: 'true if all steps completed' },
98
+ error: { type: 'string', description: 'error message if ok=false' },
99
+ },
100
+ required: ['ok'],
101
+ };
102
+
103
+ const REGISTER_SCHEMA = {
104
+ type: 'object',
105
+ properties: {
106
+ ok: { type: 'boolean', description: 'true if all register steps completed' },
107
+ error: { type: 'string', description: 'error message if ok=false' },
108
+ pendingActions: { type: 'array', items: { type: 'string' }, description: 'orchestrator-owned follow-ups, e.g. ["refresh-kb-links"]' },
109
+ },
110
+ required: ['ok'],
111
+ };
112
+
113
+ // ─────────────────────────────────────────────────────────────────────────────
114
+ // Model tiering
115
+ // ─────────────────────────────────────────────────────────────────────────────
116
+
117
+ const ROLE_TIER = {
118
+ 'discovery': 'sonnet',
119
+ 'config': 'sonnet',
120
+ 'kb-doc': 'sonnet',
121
+ 'index': 'sonnet',
122
+ 'context': 'sonnet',
123
+ 'gate': 'haiku',
124
+ 'materialize': 'haiku',
125
+ 'register': 'haiku',
126
+ };
127
+
128
+ // ─────────────────────────────────────────────────────────────────────────────
129
+ // Helpers
130
+ // ─────────────────────────────────────────────────────────────────────────────
131
+
132
+ function halt(lastPhase, reason, extra) {
133
+ return { ok: false, lastPhase, failure: reason, ...extra };
134
+ }
135
+
136
+ const VENDORED = 'Use only .forge/tools/ paths for all tool invocations (vendored-tools world).';
137
+
138
+ // ─────────────────────────────────────────────────────────────────────────────
139
+ // Main workflow body (top-level async context; top-level return is valid)
140
+ // ─────────────────────────────────────────────────────────────────────────────
141
+
142
+ const {
143
+ forgeRoot,
144
+ kbFolder = 'engineering',
145
+ startPhase = 1,
146
+ createClaudeMd = null,
147
+ isoTimestamp,
148
+ rawArguments = '',
149
+ } = args || {};
150
+
151
+ // ─────────────────────────────────────────────────────────────────────────────
152
+ // Phase 1 — Collect (startPhase <= 1)
153
+ // ─────────────────────────────────────────────────────────────────────────────
154
+ let phase1Result;
155
+ if (startPhase <= 1) {
156
+ phase('Collect');
157
+
158
+ // Fan-out: 5 parallel discovery agents
159
+ const DOMAINS = ['stack', 'routing', 'processes', 'database', 'testing'];
160
+ const discoveryResults = await parallel(
161
+ DOMAINS.map((domain) => () =>
162
+ agent(`
163
+ You are a codebase discovery agent for the "${domain}" domain.
164
+ 1. Read \`.forge/init/discovery/discover-${domain}.md\` if it exists and follow
165
+ its instructions against the current project.
166
+ 2. If that file does NOT exist, read \`.forge/init/phases/phase-1-collect.md\`
167
+ Step 2 for context, then perform a best-effort "${domain}" discovery of the
168
+ project directly (read manifests, source files, configs) and add a warning
169
+ noting the missing discovery prompt file.
170
+ Set domain="${domain}" in your structured output. ${VENDORED}
171
+ `, { model: ROLE_TIER['discovery'], label: `discover:${domain}`, phase: 'Collect', schema: DISCOVERY_SCHEMA })
172
+ )
173
+ );
174
+
175
+ // Config-writer agent: merge findings, write config, verify Phase 1
176
+ const configResult = await agent(`
177
+ You are the Forge init config-writer agent. You have received the following
178
+ discovery findings from 5 parallel discovery agents:
179
+
180
+ ${JSON.stringify(discoveryResults.filter(Boolean), null, 2)}
181
+
182
+ Execute the Phase 1 Collect rulebook steps:
183
+ 1. Read \`.forge/init/phases/phase-1-collect.md\` for the full step list.
184
+ 2. Call \`node .forge/tools/manage-config.cjs\` to write the config. If kbFolder
185
+ is non-default, set paths.engineering="${kbFolder}". Set mode=full.
186
+ 3. Compute skill-recommendation matches from .forge/meta/skill-recommendations.md
187
+ and the output of \`node .forge/tools/list-skills.js\`. Do NOT install —
188
+ report matches in skillMatches only.
189
+ 4. Write .forge/init-progress.json: { "lastPhase": 1, "timestamp": "${isoTimestamp}" }.
190
+ 5. Run: node .forge/tools/verify-phase.cjs --phase 1
191
+ 6. In your structured output set verifyExit=<exit code>,
192
+ verifyError=<stderr if non-zero>, stack=<one-line stack summary>,
193
+ skillMatches=[<matched skill ids>], confidence=<0-1>, ok=(verifyExit===0).
194
+ ${VENDORED}
195
+ kbFolder="${kbFolder}", isoTimestamp="${isoTimestamp}".
196
+ `, { model: ROLE_TIER['config'], label: 'config-writer', phase: 'Collect', schema: PHASE_RESULT_SCHEMA });
197
+
198
+ // Verify routing: one retry on failure
199
+ if (configResult && configResult.verifyExit !== 0) {
200
+ const retryResult = await agent(`
201
+ Phase 1 of Forge init verify failed. Error:
202
+ ${configResult.verifyError || '(no error text)'}
203
+
204
+ Read the error carefully. Fix the config by re-running
205
+ \`node .forge/tools/manage-config.cjs\` with the correct values, then
206
+ re-run \`node .forge/tools/verify-phase.cjs --phase 1\`.
207
+ In your structured output set verifyExit=<exit code>, ok=(verifyExit===0).
208
+ ${VENDORED}
209
+ `, { model: ROLE_TIER['config'], label: 'config-writer:retry', phase: 'Collect', schema: PHASE_RESULT_SCHEMA });
210
+ if (!retryResult || retryResult.verifyExit !== 0) {
211
+ return halt(1, 'Phase 1 verify failed after retry', {
212
+ verifyError: retryResult ? retryResult.verifyError : 'retry agent returned null',
213
+ });
214
+ }
215
+ phase1Result = { ...configResult, ...retryResult };
216
+ } else if (configResult) {
217
+ phase1Result = configResult;
218
+ } else {
219
+ return halt(1, 'config-writer agent returned null');
220
+ }
221
+
222
+ if (!phase1Result.ok) {
223
+ return halt(1, 'Phase 1 failed', {
224
+ verifyError: phase1Result.verifyError,
225
+ stack: phase1Result.stack,
226
+ });
227
+ }
228
+ } else {
229
+ phase1Result = { ok: true, lastPhase: 1, skipped: true };
230
+ }
231
+
232
+ // ─────────────────────────────────────────────────────────────────────────────
233
+ // Phase 2 — Discover (startPhase <= 2)
234
+ // ─────────────────────────────────────────────────────────────────────────────
235
+ let phase2Result;
236
+ const KB_DOC_IDS = [
237
+ 'architecture/stack',
238
+ 'architecture/processes',
239
+ 'architecture/routing',
240
+ 'architecture/database',
241
+ 'architecture/testing',
242
+ 'business-domain/domain-model',
243
+ 'business-domain/domain-concepts',
244
+ ];
245
+
246
+ if (startPhase <= 2) {
247
+ phase('Discover');
248
+
249
+ // Gate+scaffold agent: verify Phase 1 passed, mkdir scaffold
250
+ const gateResult = await agent(`
251
+ You are the Forge init Phase 2 gate agent. Execute these steps in order:
252
+ 1. Run: node .forge/tools/verify-phase.cjs --phase 1
253
+ If exit non-zero, set ok=false and error=<stderr> in your output and stop.
254
+ 2. Read \`.forge/init/phases/phase-2-discover.md\` Step 2 (scaffold mkdir
255
+ commands) and execute them. Create the KB directory structure under ${kbFolder}/.
256
+ 3. Set ok=true.
257
+ ${VENDORED}
258
+ `, { model: ROLE_TIER['gate'], label: 'phase2-gate', phase: 'Discover', schema: OK_SCHEMA });
259
+
260
+ if (!gateResult || !gateResult.ok) {
261
+ return halt(2, 'Phase 2 gate failed — Phase 1 verify did not pass', {
262
+ verifyError: gateResult ? gateResult.error : 'gate agent returned null',
263
+ });
264
+ }
265
+
266
+ // Fan-out: 7 parallel KB-doc agents
267
+ const kbDocPrompt = (docId) => `
268
+ You are a Forge KB-doc generation agent. Your doc id is: "${docId}".
269
+ 1. Read \`.forge/init/phases/phase-2-discover.md\` for the full doc spec for "${docId}".
270
+ 2. If \`.forge/init/generation/generate-kb-doc.md\` exists, read it for the
271
+ generation rulebook; otherwise follow the doc spec from step 1 directly.
272
+ 3. Generate the doc using all available project context (including
273
+ .forge/config.json written in Phase 1).
274
+ 4. Write the doc to the correct path under ${kbFolder}/.
275
+ 5. Set id="${docId}", ok=<true if written>, confidence=<0-1>, error=<if not ok>.
276
+ ${VENDORED}
277
+ `;
278
+
279
+ const kbDocResults = await parallel(
280
+ KB_DOC_IDS.map((docId) => () =>
281
+ agent(kbDocPrompt(docId), { model: ROLE_TIER['kb-doc'], label: `kb-doc:${docId}`, phase: 'Discover', schema: KB_DOC_SCHEMA })
282
+ )
283
+ );
284
+
285
+ // JS-held retry-once for any failed KB-doc
286
+ const failedDocs = KB_DOC_IDS.filter((docId, i) => !kbDocResults[i] || !kbDocResults[i].ok);
287
+ if (failedDocs.length > 0) {
288
+ const retryResults = await parallel(
289
+ failedDocs.map((docId) => () =>
290
+ agent(`
291
+ KB-doc "${docId}" failed on first attempt. Retry it:
292
+ ${kbDocPrompt(docId)}
293
+ `, { model: ROLE_TIER['kb-doc'], label: `kb-doc-retry:${docId}`, phase: 'Discover', schema: KB_DOC_SCHEMA })
294
+ )
295
+ );
296
+ const stillFailed = failedDocs.filter((docId, i) => !retryResults[i] || !retryResults[i].ok);
297
+ if (stillFailed.length > 0) {
298
+ return halt(2, `KB-doc generation failed after retry for: ${stillFailed.join(', ')}`, {
299
+ failedDocs: stillFailed.join(', '),
300
+ });
301
+ }
302
+ }
303
+
304
+ // Sequential index agent (after all leaf docs — real data dependency)
305
+ const indexResult = await agent(`
306
+ You are the Forge init index agent. All 7 KB architecture docs have been generated.
307
+ Read \`.forge/init/phases/phase-2-discover.md\` Step 4 (index files).
308
+ Generate the 3 INDEX files:
309
+ - ${kbFolder}/architecture/INDEX.md
310
+ - ${kbFolder}/business-domain/INDEX.md
311
+ - ${kbFolder}/INDEX.md
312
+ Set ok=true when done, or ok=false with error=<message>.
313
+ ${VENDORED}
314
+ `, { model: ROLE_TIER['index'], label: 'index', phase: 'Discover', schema: OK_SCHEMA });
315
+
316
+ if (!indexResult || !indexResult.ok) {
317
+ return halt(2, 'Index agent failed', { error: indexResult ? indexResult.error : 'null result' });
318
+ }
319
+
320
+ // Context agent: project-context.json + calibration + init-progress.json + verify
321
+ const contextResult = await agent(`
322
+ You are the Forge init context agent. KB docs and index files are complete.
323
+ Execute \`.forge/init/phases/phase-2-discover.md\` Steps 5–6:
324
+ 5. Write project-context.json (combined structured context from all discovery
325
+ findings). Write calibration baseline.
326
+ 6. Write .forge/init-progress.json: { "lastPhase": 2, "timestamp": "${isoTimestamp}" }.
327
+ Run: node .forge/tools/verify-phase.cjs --phase 2 --kb-path "${kbFolder}"
328
+ Set verifyExit=<exit code>, verifyError=<stderr if non-zero>, ok=(verifyExit===0).
329
+ ${VENDORED}
330
+ `, { model: ROLE_TIER['context'], label: 'context', phase: 'Discover', schema: PHASE_RESULT_SCHEMA });
331
+
332
+ // Verify routing: one retry on failure
333
+ if (contextResult && contextResult.verifyExit !== 0) {
334
+ const verifyRetry = await agent(`
335
+ Phase 2 of Forge init verify failed. Error:
336
+ ${contextResult.verifyError || '(no error text)'}
337
+ Read the error, fix the missing or malformed outputs, re-run
338
+ \`node .forge/tools/verify-phase.cjs --phase 2 --kb-path "${kbFolder}"\`.
339
+ Set verifyExit=<exit code>, ok=(verifyExit===0).
340
+ ${VENDORED}
341
+ `, { model: ROLE_TIER['context'], label: 'context:retry', phase: 'Discover', schema: PHASE_RESULT_SCHEMA });
342
+ if (!verifyRetry || verifyRetry.verifyExit !== 0) {
343
+ return halt(2, 'Phase 2 verify failed after retry', {
344
+ verifyError: verifyRetry ? verifyRetry.verifyError : 'retry returned null',
345
+ });
346
+ }
347
+ phase2Result = verifyRetry;
348
+ } else if (contextResult) {
349
+ phase2Result = contextResult;
350
+ } else {
351
+ return halt(2, 'context agent returned null');
352
+ }
353
+
354
+ if (!phase2Result.ok) {
355
+ return halt(2, 'Phase 2 failed', { verifyError: phase2Result.verifyError });
356
+ }
357
+ } else {
358
+ phase2Result = { ok: true, lastPhase: 2, skipped: true };
359
+ }
360
+
361
+ // ─────────────────────────────────────────────────────────────────────────────
362
+ // Phase 3 — Materialize (startPhase <= 3)
363
+ // ─────────────────────────────────────────────────────────────────────────────
364
+ let phase3Result;
365
+ if (startPhase <= 3) {
366
+ phase('Materialize');
367
+
368
+ // Single haiku agent — deterministic shell steps
369
+ const materializeResult = await agent(`
370
+ You are the Forge init materialize agent. Read
371
+ \`.forge/init/phases/phase-3-materialize.md\` for the rulebook, then execute
372
+ these deterministic steps:
373
+ 1. Run: node .forge/tools/build-init-context.cjs
374
+ 2. Run: node .forge/tools/substitute-placeholders.cjs
375
+ 3. Record generation-manifest entries for all materialized assets.
376
+ 4. Run a build-overlay smoke check: node .forge/tools/build-overlay.cjs --check
377
+ 5. Write .forge/init-progress.json: { "lastPhase": 3, "timestamp": "${isoTimestamp}" }
378
+ 6. Run: node .forge/tools/verify-phase.cjs --phase 3
379
+ Set verifyExit=<exit code>, verifyError=<stderr if non-zero>, ok=(verifyExit===0).
380
+ ${VENDORED}
381
+ IMPORTANT: If verify-phase exits non-zero, report it faithfully — do NOT retry.
382
+ Phase 3 verify failure is a hard halt. The rulebook says: rebuild or restart init.
383
+ `, { model: ROLE_TIER['materialize'], label: 'materialize', phase: 'Materialize', schema: PHASE_RESULT_SCHEMA });
384
+
385
+ // Phase 3: hard halt on verify failure (no retry)
386
+ if (!materializeResult || materializeResult.verifyExit !== 0) {
387
+ const verifyError = materializeResult ? materializeResult.verifyError : 'materialize agent returned null';
388
+ return halt(3, [
389
+ 'Phase 3 (Materialize) verify failed. This is a hard halt — no retry.',
390
+ 'Per the phase-3-materialize.md rulebook: you must rebuild or restart /forge:init.',
391
+ 'Run: /forge:init (or `4ge init claude .` to re-scaffold, then /forge:init).',
392
+ `Verify error: ${verifyError}`,
393
+ ].join(' '), { verifyError, rebuild: true, restart: true });
394
+ }
395
+
396
+ phase3Result = materializeResult;
397
+ } else {
398
+ phase3Result = { ok: true, lastPhase: 3, skipped: true };
399
+ }
400
+
401
+ // ─────────────────────────────────────────────────────────────────────────────
402
+ // Phase 4 — Register (startPhase <= 4)
403
+ // ─────────────────────────────────────────────────────────────────────────────
404
+ let phase4Result;
405
+ if (startPhase <= 4) {
406
+ phase('Register');
407
+
408
+ const registerResult = await agent(`
409
+ You are the Forge init register agent. Execute the content-register steps:
410
+ 1. Read \`.forge/init/phases/phase-4-register.md\` for the full step list.
411
+ 2. Execute steps 1–10 and step 12 verbatim.
412
+ 3. Step 13 (CLAUDE.md file creation): ${createClaudeMd === true
413
+ ? 'createClaudeMd=true — execute this step (create the CLAUDE.md file).'
414
+ : 'createClaudeMd is not true — SKIP step 13 (the prompt was hoisted to the wrapper).'}
415
+ 4. Step 11 (Tomoshibi forge:refresh-kb-links): DO NOT execute. This is
416
+ orchestrator-owned. Set pendingActions=["refresh-kb-links"] and the
417
+ wrapper (init.md) will run it post-workflow.
418
+ 5. Delete .forge/init-progress.json (phase 4 complete — no resume needed).
419
+ 6. Set ok=true, pendingActions=["refresh-kb-links"].
420
+ ${VENDORED}
421
+ createClaudeMd=${JSON.stringify(createClaudeMd)}, isoTimestamp="${isoTimestamp}".
422
+ `, { model: ROLE_TIER['register'], label: 'register', phase: 'Register', schema: REGISTER_SCHEMA });
423
+
424
+ if (!registerResult || !registerResult.ok) {
425
+ return halt(4, registerResult ? (registerResult.error || 'Phase 4 failed') : 'register agent returned null');
426
+ }
427
+ phase4Result = registerResult;
428
+ } else {
429
+ phase4Result = { ok: true, lastPhase: 4, skipped: true };
430
+ }
431
+
432
+ // ─────────────────────────────────────────────────────────────────────────────
433
+ // Report
434
+ // ─────────────────────────────────────────────────────────────────────────────
435
+ phase('Report');
436
+
437
+ return {
438
+ ok: true,
439
+ lastPhase: 4,
440
+ stack: phase1Result && phase1Result.stack,
441
+ skillMatches: phase1Result && phase1Result.skillMatches,
442
+ counts: {
443
+ kbDocs: KB_DOC_IDS.length,
444
+ workflows: 4, // wfl-run-task, wfl-run-sprint, wfl-fix-bug, wfl-init (installed by the CLI half)
445
+ commands: 3, // run-task, run-sprint, fix-bug (init.md is the wrapper, not a base-pack command)
446
+ },
447
+ confidence: phase1Result && phase1Result.confidence,
448
+ pendingActions: (phase4Result && phase4Result.pendingActions) || ['refresh-kb-links'],
449
+ };
@@ -133,6 +133,22 @@ const SKIP_STATUS = ['blocked', 'escalated', 'committed', 'abandoned']
133
133
  // NOTE: `approve` is NOT here — orchestrate_task advances it on completion like a
134
134
  // non-review phase (the approve workflow self-escalates if it rejects).
135
135
  const REVIEW_ROLES = ['review-plan', 'review-code', 'validate']
136
+
137
+ // Task-phase `type` tokens — verbatim port of the canonical table in
138
+ // .forge/workflows/_fragments/event-vocabulary.md § Task pipeline
139
+ // (forge-engineering#39). The COMPLETE event carries the pass token (or the
140
+ // fail token when a review phase's verdict is "revision"); the START event is
141
+ // always untyped. Roles outside this map emit untyped events (valid).
142
+ const TASK_TYPE_TOKENS = {
143
+ 'plan': { pass: 'task-planned', fail: 'task-planned' },
144
+ 'review-plan': { pass: 'plan-approved', fail: 'review-failed' },
145
+ 'implement': { pass: 'task-implemented', fail: 'task-implemented' },
146
+ 'review-code': { pass: 'review-passed', fail: 'review-failed' },
147
+ 'validate': { pass: 'task-validated', fail: 'review-failed' },
148
+ 'approve': { pass: 'task-approved', fail: 'review-failed' },
149
+ 'commit': { pass: 'task-committed', fail: 'task-committed' },
150
+ }
151
+
136
152
  // Per-phase model tier — verbatim port of orchestrate_task.md § Role-to-Tier Mapping.
137
153
  // The resolve agent uses this as a reference; JS loop calls resolveModel() not tierFor().
138
154
  const ROLE_TIER = {
@@ -338,17 +354,30 @@ function runPhase(taskId, sprintId, phase, iteration, { firstPhase = false, simp
338
354
  const eventIdLine = eventId
339
355
  ? ' Use eventId="' + eventId + '" for the COMPLETE event (the driver will call merge-sidecar with this id).'
340
356
  : ' Use a fresh crypto.randomUUID() for both start and complete event ids.'
357
+ // forge-engineering#39: explicit type-token guidance per
358
+ // .forge/workflows/_fragments/event-vocabulary.md. Without it, subagents
359
+ // guessed and leaked the action value into `type` ("start"/"complete" —
360
+ // schema-rejected store residue).
361
+ const typeTokens = TASK_TYPE_TOKENS[phase.role]
362
+ const typeTokenLine = typeTokens
363
+ ? (REVIEW_ROLES.includes(phase.role)
364
+ ? 'set type="' + typeTokens.pass + '" when your verdict is Approved, type="' + typeTokens.fail + '" when it is Revision Required.'
365
+ : 'set type="' + typeTokens.pass + '".')
366
+ : 'omit the "type" field entirely (untyped events are valid; this role has no table entry).'
341
367
  lines.push(
342
368
  '',
343
369
  '3. EMIT YOUR PHASE EVENTS. You are the only actor that knows your runtime attribution.',
344
370
  ' 3a. BEFORE running the phase workflow: note the start timestamp (startTimestamp = new Date().toISOString()).',
345
371
  ' Emit a start event via `node .forge/tools/store-cli.cjs emit ' + sprintId + " '{event-json}'\`",
346
372
  ' with action="start", role="' + phase.role + '", iteration=' + iteration + ', startTimestamp and endTimestamp both equal to startTimestamp (0-duration placeholder).',
373
+ ' The start event MUST NOT include a "type" field.',
347
374
  ' 3b. AFTER the phase workflow completes: note the end timestamp (endTimestamp = new Date().toISOString()).',
348
375
  ' Compute durationMinutes = (new Date(endTimestamp) - new Date(startTimestamp)) / 60000.',
349
376
  ' Emit a complete event via `node .forge/tools/store-cli.cjs emit ' + sprintId + " '{event-json}'\`",
350
377
  ' conforming to `.forge/schemas/event.schema.json` (role, action="complete", phase, iteration=' + iteration + ',',
351
378
  ' startTimestamp, endTimestamp, durationMinutes, plus your own model/provider/token usage — do NOT invent placeholder model strings).',
379
+ ' COMPLETE-event type (per .forge/workflows/_fragments/event-vocabulary.md): ' + typeTokenLine,
380
+ ' NEVER copy the action value ("start"/"complete") into "type" — those tokens are schema-rejected and the event would be dropped.',
352
381
  ' ' + eventIdLine,
353
382
  ' If `/cost` data is available, also write the token sidecar via the `--sidecar` form with the COMPLETE eventId. Best-effort; skip silently if unavailable.',
354
383
  '',
@@ -404,7 +433,9 @@ function emitSkip(taskId, sprintId, taskStatus) {
404
433
  `Emit a task_skipped event for Forge task ${taskId} (sprint ${sprintId}).`,
405
434
  `node .forge/tools/store-cli.cjs emit ${sprintId}`,
406
435
  `'{"type":"task-dispatch","action":"skip","taskId":"${taskId}","sprintId":"${sprintId}",`,
407
- `"role":"orchestrator","phase":"pre-task","iteration":0,`,
436
+ // forge-engineering#39: iteration must be >= 1 (schema minimum) — the
437
+ // former zero value made every skip event silently schema-rejected.
438
+ `"role":"orchestrator","phase":"pre-task","iteration":1,`,
408
439
  `"notes":"pre-task SKIP_STATUS guard: task status is ${taskStatus}",`,
409
440
  `"startTimestamp":"<ISO-now>","endTimestamp":"<ISO-now>","durationMinutes":0,`,
410
441
  `"model":"<your-model-id>","provider":"anthropic"}'`,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forge",
3
- "version": "1.2.17",
3
+ "version": "1.4.5",
4
4
  "description": "Self-enhancing AI software development lifecycle — generates project-specific SDLC instances from meta-definitions",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "1.2.13",
3
- "generated": "2026-06-03",
2
+ "version": "1.4.3",
3
+ "generated": "2026-06-07",
4
4
  "note": "Authoritative enum catalog. Source: build-enum-catalog.cjs. Regenerate via node forge/tools/build-manifest.cjs.",
5
5
  "enums": {
6
6
  "task.status": [
@@ -59,11 +59,11 @@
59
59
  "sprint-complete",
60
60
  "sprint-halted",
61
61
  "task-dispatch",
62
- "bug-fixed",
63
62
 
64
63
  "bug-triaged", "fix-planned", "fix-review-passed", "fix-review-failed",
65
64
  "fix-implemented", "fix-code-review-passed", "fix-code-review-failed",
66
- "fix-approved", "bug-committed",
65
+ "fix-approved", "fix-revision-requested", "bug-committed",
66
+ "bug-commit-failed", "bug-skipped",
67
67
 
68
68
  "skill_usage"
69
69
  ]
@@ -129,7 +129,8 @@
129
129
  "enum": [
130
130
  "bug-triaged", "fix-planned", "fix-review-passed", "fix-review-failed",
131
131
  "fix-implemented", "fix-code-review-passed", "fix-code-review-failed",
132
- "fix-approved", "bug-committed", "bug-fixed"
132
+ "fix-approved", "fix-revision-requested", "bug-committed",
133
+ "bug-commit-failed"
133
134
  ]
134
135
  }
135
136
  },
@@ -137,6 +138,10 @@
137
138
  },
138
139
  "then": { "required": ["bugId", "phase", "iteration"] }
139
140
  },
141
+ {
142
+ "if": { "properties": { "type": { "const": "bug-skipped" } }, "required": ["type"] },
143
+ "then": { "required": ["bugId"] }
144
+ },
140
145
  {
141
146
  "if": { "properties": { "type": { "const": "sprint-start" } }, "required": ["type"] },
142
147
  "then": {