@entelligentsia/forgecli 1.0.3 → 1.0.14

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 (497) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/README.md +2 -1
  3. package/dist/CHANGELOG-forge-plugin.md +250 -0
  4. package/dist/CHANGELOG-pi.md +94 -0
  5. package/dist/bin/forge.js +0 -0
  6. package/dist/extensions/forgecli/config-layer.d.ts +16 -0
  7. package/dist/extensions/forgecli/config-layer.js +5 -0
  8. package/dist/extensions/forgecli/config-layer.js.map +1 -1
  9. package/dist/extensions/forgecli/dashboard/component.d.ts +102 -0
  10. package/dist/extensions/forgecli/dashboard/component.js +882 -0
  11. package/dist/extensions/forgecli/dashboard/component.js.map +1 -0
  12. package/dist/extensions/forgecli/dashboard/register.d.ts +2 -0
  13. package/dist/extensions/forgecli/dashboard/register.js +45 -0
  14. package/dist/extensions/forgecli/dashboard/register.js.map +1 -0
  15. package/dist/extensions/forgecli/dashboard/view-model.d.ts +35 -0
  16. package/dist/extensions/forgecli/dashboard/view-model.js +54 -0
  17. package/dist/extensions/forgecli/dashboard/view-model.js.map +1 -0
  18. package/dist/extensions/forgecli/fix-bug.js +72 -7
  19. package/dist/extensions/forgecli/fix-bug.js.map +1 -1
  20. package/dist/extensions/forgecli/forge-artifact-tool.js +27 -4
  21. package/dist/extensions/forgecli/forge-artifact-tool.js.map +1 -1
  22. package/dist/extensions/forgecli/forge-cli-schema.json +4 -0
  23. package/dist/extensions/forgecli/forge-commands.js +1 -0
  24. package/dist/extensions/forgecli/forge-commands.js.map +1 -1
  25. package/dist/extensions/forgecli/forge-init/phase4-register.js +53 -0
  26. package/dist/extensions/forgecli/forge-init/phase4-register.js.map +1 -1
  27. package/dist/extensions/forgecli/forge-subagent.js +6 -4
  28. package/dist/extensions/forgecli/forge-subagent.js.map +1 -1
  29. package/dist/extensions/forgecli/forge-tools.js +2 -2
  30. package/dist/extensions/forgecli/forge-tools.js.map +1 -1
  31. package/dist/extensions/forgecli/index.js +5 -0
  32. package/dist/extensions/forgecli/index.js.map +1 -1
  33. package/dist/extensions/forgecli/lib/halt-advisor.d.ts +54 -0
  34. package/dist/extensions/forgecli/lib/halt-advisor.js +90 -0
  35. package/dist/extensions/forgecli/lib/halt-advisor.js.map +1 -0
  36. package/dist/extensions/forgecli/migration-engine.js +25 -12
  37. package/dist/extensions/forgecli/migration-engine.js.map +1 -1
  38. package/dist/extensions/forgecli/orchestrator-status-bar.d.ts +25 -0
  39. package/dist/extensions/forgecli/orchestrator-status-bar.js +183 -0
  40. package/dist/extensions/forgecli/orchestrator-status-bar.js.map +1 -0
  41. package/dist/extensions/forgecli/orchestrator-tree.d.ts +96 -0
  42. package/dist/extensions/forgecli/orchestrator-tree.js +390 -0
  43. package/dist/extensions/forgecli/orchestrator-tree.js.map +1 -0
  44. package/dist/extensions/forgecli/project-orientation.js +12 -8
  45. package/dist/extensions/forgecli/project-orientation.js.map +1 -1
  46. package/dist/extensions/forgecli/regenerate.d.ts +16 -0
  47. package/dist/extensions/forgecli/regenerate.js +110 -0
  48. package/dist/extensions/forgecli/regenerate.js.map +1 -1
  49. package/dist/extensions/forgecli/run-sprint.js +33 -3
  50. package/dist/extensions/forgecli/run-sprint.js.map +1 -1
  51. package/dist/extensions/forgecli/run-task.d.ts +32 -0
  52. package/dist/extensions/forgecli/run-task.js +185 -12
  53. package/dist/extensions/forgecli/run-task.js.map +1 -1
  54. package/dist/extensions/forgecli/subagent/phase-guard.js +15 -5
  55. package/dist/extensions/forgecli/subagent/phase-guard.js.map +1 -1
  56. package/dist/extensions/forgecli/subagent/phase-summary-map.d.ts +1 -0
  57. package/dist/extensions/forgecli/subagent/phase-summary-map.js +17 -0
  58. package/dist/extensions/forgecli/subagent/phase-summary-map.js.map +1 -1
  59. package/dist/extensions/forgecli/thread-switcher.js +105 -764
  60. package/dist/extensions/forgecli/thread-switcher.js.map +1 -1
  61. package/dist/extensions/forgecli/viewport-events.js +32 -0
  62. package/dist/extensions/forgecli/viewport-events.js.map +1 -1
  63. package/dist/forge-payload/.base-pack/commands/fix-bug.md +1 -1
  64. package/dist/forge-payload/.base-pack/commands/run-sprint.md +1 -1
  65. package/dist/forge-payload/.base-pack/commands/run-task.md +1 -1
  66. package/dist/forge-payload/.base-pack/personas/architect.md +1 -1
  67. package/dist/forge-payload/.base-pack/personas/bug-fixer.md +1 -1
  68. package/dist/forge-payload/.base-pack/personas/collator.md +3 -3
  69. package/dist/forge-payload/.base-pack/personas/engineer.md +1 -1
  70. package/dist/forge-payload/.base-pack/personas/librarian.md +1 -1
  71. package/dist/forge-payload/.base-pack/personas/orchestrator.md +1 -1
  72. package/dist/forge-payload/.base-pack/personas/product-manager.md +1 -1
  73. package/dist/forge-payload/.base-pack/personas/qa-engineer.md +1 -1
  74. package/dist/forge-payload/.base-pack/personas/supervisor.md +1 -1
  75. package/dist/forge-payload/.base-pack/workflows/_fragments/event-emission-schema.md +1 -1
  76. package/dist/forge-payload/.base-pack/workflows/_fragments/friction-emit.md +1 -1
  77. package/dist/forge-payload/.base-pack/workflows/_fragments/iron-laws.md +1 -1
  78. package/dist/forge-payload/.base-pack/workflows/_fragments/progress-reporting.md +2 -2
  79. package/dist/forge-payload/.base-pack/workflows/_fragments/store-cli-verbs.md +29 -5
  80. package/dist/forge-payload/.base-pack/workflows/architect_approve.md +8 -10
  81. package/dist/forge-payload/.base-pack/workflows/architect_review_sprint_completion.md +2 -2
  82. package/dist/forge-payload/.base-pack/workflows/architect_sprint_intake.md +2 -2
  83. package/dist/forge-payload/.base-pack/workflows/architect_sprint_plan.md +5 -5
  84. package/dist/forge-payload/.base-pack/workflows/collator_agent.md +5 -7
  85. package/dist/forge-payload/.base-pack/workflows/commit_task.md +7 -9
  86. package/dist/forge-payload/.base-pack/workflows/enhance.md +5 -5
  87. package/dist/forge-payload/.base-pack/workflows/implement_plan.md +9 -9
  88. package/dist/forge-payload/.base-pack/workflows/migrate_structural.md +12 -13
  89. package/dist/forge-payload/.base-pack/workflows/plan_task.md +5 -6
  90. package/dist/forge-payload/.base-pack/workflows/review_code.md +8 -8
  91. package/dist/forge-payload/.base-pack/workflows/review_plan.md +8 -8
  92. package/dist/forge-payload/.base-pack/workflows/sprint_retrospective.md +3 -3
  93. package/dist/forge-payload/.base-pack/workflows/triage.md +13 -10
  94. package/dist/forge-payload/.base-pack/workflows/update_implementation.md +2 -2
  95. package/dist/forge-payload/.base-pack/workflows/update_plan.md +2 -2
  96. package/dist/forge-payload/.base-pack/workflows/validate_task.md +6 -8
  97. package/dist/forge-payload/.base-pack/workflows-js/wfl-fix-bug.js +490 -0
  98. package/dist/forge-payload/.base-pack/workflows-js/wfl-run-sprint.js +416 -0
  99. package/dist/forge-payload/.base-pack/workflows-js/wfl-run-task.js +608 -0
  100. package/dist/forge-payload/.claude-plugin/plugin.json +1 -1
  101. package/dist/forge-payload/.schemas/_defs/locator.schema.json +13 -0
  102. package/dist/forge-payload/.schemas/bug.schema.json +1 -0
  103. package/dist/forge-payload/.schemas/config.schema.json +2 -3
  104. package/dist/forge-payload/.schemas/enum-catalog.json +2 -2
  105. package/dist/forge-payload/.schemas/event.schema.json +16 -0
  106. package/dist/forge-payload/.schemas/migrations.json +299 -0
  107. package/dist/forge-payload/.schemas/sprint.schema.json +1 -0
  108. package/dist/forge-payload/.schemas/task.schema.json +1 -0
  109. package/dist/forge-payload/commands/health.md +29 -0
  110. package/dist/forge-payload/commands/rebuild.md +143 -15
  111. package/dist/forge-payload/commands/update.md +28 -27
  112. package/dist/forge-payload/hooks/preflight-session.cjs +99 -0
  113. package/dist/forge-payload/init/phases/phase-3-materialize.md +18 -5
  114. package/dist/forge-payload/integrity.json +7 -6
  115. package/dist/forge-payload/meta/fragments/tool-discipline.md +1 -1
  116. package/dist/forge-payload/meta/personas/meta-architect.md +1 -1
  117. package/dist/forge-payload/meta/personas/meta-bug-fixer.md +1 -1
  118. package/dist/forge-payload/meta/personas/meta-collator.md +7 -7
  119. package/dist/forge-payload/meta/personas/meta-engineer.md +1 -1
  120. package/dist/forge-payload/meta/personas/meta-orchestrator.md +1 -1
  121. package/dist/forge-payload/meta/personas/meta-supervisor.md +1 -1
  122. package/dist/forge-payload/meta/tool-specs/store-cli.spec.md +1 -1
  123. package/dist/forge-payload/meta/workflows/_fragments/event-emission-schema.md +1 -1
  124. package/dist/forge-payload/meta/workflows/_fragments/friction-emit.md +1 -1
  125. package/dist/forge-payload/meta/workflows/_fragments/iron-laws.md +1 -1
  126. package/dist/forge-payload/meta/workflows/_fragments/progress-reporting.md +2 -2
  127. package/dist/forge-payload/meta/workflows/_fragments/store-cli-verbs.md +29 -5
  128. package/dist/forge-payload/meta/workflows/meta-approve.md +8 -10
  129. package/dist/forge-payload/meta/workflows/meta-bug-triage.md +13 -10
  130. package/dist/forge-payload/meta/workflows/meta-collate.md +6 -8
  131. package/dist/forge-payload/meta/workflows/meta-commit.md +7 -9
  132. package/dist/forge-payload/meta/workflows/meta-enhance.md +5 -5
  133. package/dist/forge-payload/meta/workflows/meta-fix-bug.md +35 -11
  134. package/dist/forge-payload/meta/workflows/meta-implement.md +18 -9
  135. package/dist/forge-payload/meta/workflows/meta-migrate.md +13 -14
  136. package/dist/forge-payload/meta/workflows/meta-new-sprint.md +3 -3
  137. package/dist/forge-payload/meta/workflows/meta-orchestrate.md +175 -82
  138. package/dist/forge-payload/meta/workflows/meta-plan-sprint.md +6 -6
  139. package/dist/forge-payload/meta/workflows/meta-plan-task.md +12 -6
  140. package/dist/forge-payload/meta/workflows/meta-retro.md +4 -4
  141. package/dist/forge-payload/meta/workflows/meta-retrospective.md +4 -4
  142. package/dist/forge-payload/meta/workflows/meta-review-implementation.md +8 -8
  143. package/dist/forge-payload/meta/workflows/meta-review-plan.md +8 -8
  144. package/dist/forge-payload/meta/workflows/meta-review-sprint-completion.md +3 -3
  145. package/dist/forge-payload/meta/workflows/meta-sprint-intake.md +3 -3
  146. package/dist/forge-payload/meta/workflows/meta-sprint-plan.md +6 -6
  147. package/dist/forge-payload/meta/workflows/meta-update-implementation.md +2 -2
  148. package/dist/forge-payload/meta/workflows/meta-update-plan.md +2 -2
  149. package/dist/forge-payload/meta/workflows/meta-validate.md +6 -8
  150. package/dist/forge-payload/schemas/_defs/locator.schema.json +13 -0
  151. package/dist/forge-payload/schemas/bug.schema.json +1 -0
  152. package/dist/forge-payload/schemas/config.schema.json +2 -3
  153. package/dist/forge-payload/schemas/enum-catalog.json +2 -2
  154. package/dist/forge-payload/schemas/event.schema.json +16 -0
  155. package/dist/forge-payload/schemas/sprint.schema.json +1 -0
  156. package/dist/forge-payload/schemas/structure-manifest.json +76 -73
  157. package/dist/forge-payload/schemas/task.schema.json +1 -0
  158. package/dist/forge-payload/skills/refresh-kb-links/SKILL.md +14 -7
  159. package/dist/forge-payload/tools/artifact-store.cjs +242 -0
  160. package/dist/forge-payload/tools/artifact.cjs +60 -120
  161. package/dist/forge-payload/tools/banners.cjs +29 -10
  162. package/dist/forge-payload/tools/check-structure.cjs +88 -7
  163. package/dist/forge-payload/tools/collate.cjs +16 -2
  164. package/dist/forge-payload/tools/lib/artifact-kinds.cjs +95 -0
  165. package/dist/forge-payload/tools/lib/store-nlp.cjs +6 -0
  166. package/dist/forge-payload/tools/lib/store-query-exec.cjs +39 -5
  167. package/dist/forge-payload/tools/lib/suggest.cjs +2 -1
  168. package/dist/forge-payload/tools/manage-config.cjs +5 -7
  169. package/dist/forge-payload/tools/parse-gates.cjs +73 -1
  170. package/dist/forge-payload/tools/postflight-gate.cjs +252 -0
  171. package/dist/forge-payload/tools/preflight-gate.cjs +102 -5
  172. package/dist/forge-payload/tools/store-cli.cjs +50 -15
  173. package/dist/forge-payload/tools/substitute-placeholders.cjs +5 -4
  174. package/dist/forge-payload/tools/verify-phase.cjs +17 -0
  175. package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.d.ts +5 -2
  176. package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.d.ts.map +1 -1
  177. package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js +81 -18
  178. package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js.map +1 -1
  179. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.d.ts.map +1 -1
  180. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.js +1 -0
  181. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.js.map +1 -1
  182. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.d.ts.map +1 -1
  183. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js +19 -24
  184. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js.map +1 -1
  185. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.d.ts +1 -0
  186. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.d.ts.map +1 -1
  187. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.js +14 -1
  188. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.js.map +1 -1
  189. package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts +22 -8
  190. package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts.map +1 -1
  191. package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.js.map +1 -1
  192. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  193. package/node_modules/@earendil-works/pi-ai/README.md +1 -1
  194. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +374 -122
  195. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
  196. package/node_modules/@earendil-works/pi-ai/dist/models.generated.js +424 -232
  197. package/node_modules/@earendil-works/pi-ai/dist/models.generated.js.map +1 -1
  198. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.d.ts +1 -1
  199. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.d.ts.map +1 -1
  200. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js +38 -2
  201. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
  202. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  203. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js +21 -12
  204. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js.map +1 -1
  205. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
  206. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js +6 -10
  207. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
  208. package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.d.ts.map +1 -1
  209. package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.js +1 -1
  210. package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.js.map +1 -1
  211. package/node_modules/@earendil-works/pi-ai/dist/providers/google.d.ts.map +1 -1
  212. package/node_modules/@earendil-works/pi-ai/dist/providers/google.js +5 -3
  213. package/node_modules/@earendil-works/pi-ai/dist/providers/google.js.map +1 -1
  214. package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.d.ts.map +1 -1
  215. package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.js +3 -4
  216. package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.js.map +1 -1
  217. package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.d.ts.map +1 -1
  218. package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.js +2 -3
  219. package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.js.map +1 -1
  220. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
  221. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js +159 -78
  222. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  223. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  224. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js +16 -11
  225. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js.map +1 -1
  226. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.d.ts.map +1 -1
  227. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.js +4 -1
  228. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.js.map +1 -1
  229. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
  230. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js +6 -10
  231. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js.map +1 -1
  232. package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  233. package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.js +1 -0
  234. package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.js.map +1 -1
  235. package/node_modules/@earendil-works/pi-ai/dist/stream.d.ts.map +1 -1
  236. package/node_modules/@earendil-works/pi-ai/dist/stream.js +14 -2
  237. package/node_modules/@earendil-works/pi-ai/dist/stream.js.map +1 -1
  238. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +14 -4
  239. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
  240. package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
  241. package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.d.ts +6 -0
  242. package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.d.ts.map +1 -0
  243. package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.js +34 -0
  244. package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.js.map +1 -0
  245. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.d.ts +9 -7
  246. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.d.ts.map +1 -1
  247. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.js +8 -7
  248. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.js.map +1 -1
  249. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
  250. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.js +1 -1
  251. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
  252. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.d.ts +1 -1
  253. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.d.ts.map +1 -1
  254. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.js +1 -1
  255. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.js.map +1 -1
  256. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.d.ts +10 -1
  257. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.d.ts.map +1 -1
  258. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.js +179 -79
  259. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.js.map +1 -1
  260. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  261. package/node_modules/@earendil-works/pi-coding-agent/CHANGELOG.md +94 -0
  262. package/node_modules/@earendil-works/pi-coding-agent/README.md +9 -0
  263. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.d.ts +3 -0
  264. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.d.ts.map +1 -1
  265. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.js +27 -0
  266. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.js.map +1 -1
  267. package/node_modules/@earendil-works/pi-coding-agent/dist/config.d.ts.map +1 -1
  268. package/node_modules/@earendil-works/pi-coding-agent/dist/config.js +15 -2
  269. package/node_modules/@earendil-works/pi-coding-agent/dist/config.js.map +1 -1
  270. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.d.ts +1 -0
  271. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.d.ts.map +1 -1
  272. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.js +1 -0
  273. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.js.map +1 -1
  274. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.d.ts +5 -1
  275. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  276. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js +28 -4
  277. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  278. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  279. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.js +18 -24
  280. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  281. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.d.ts +1 -1
  282. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  283. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.js +8 -2
  284. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  285. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/types.d.ts +7 -5
  286. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  287. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  288. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  289. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.js +65 -13
  290. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  291. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
  292. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.js +1 -1
  293. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  294. package/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.d.ts +9 -1
  295. package/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.d.ts.map +1 -1
  296. package/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.js +134 -11
  297. package/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.js.map +1 -1
  298. package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.d.ts +2 -0
  299. package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  300. package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.js +10 -6
  301. package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.js.map +1 -1
  302. package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.d.ts +6 -7
  303. package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  304. package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js +75 -28
  305. package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  306. package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.d.ts +2 -0
  307. package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  308. package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.js +14 -9
  309. package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  310. package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  311. package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.js +0 -3
  312. package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  313. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
  314. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit.js +7 -10
  315. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
  316. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/find.d.ts.map +1 -1
  317. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/find.js.map +1 -1
  318. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/grep.d.ts.map +1 -1
  319. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/grep.js.map +1 -1
  320. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/ls.d.ts.map +1 -1
  321. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/ls.js +5 -7
  322. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/ls.js.map +1 -1
  323. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
  324. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.js +6 -7
  325. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.js.map +1 -1
  326. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/render-utils.d.ts +5 -2
  327. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/render-utils.d.ts.map +1 -1
  328. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/render-utils.js +17 -1
  329. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/render-utils.js.map +1 -1
  330. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
  331. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.js +5 -6
  332. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.js.map +1 -1
  333. package/node_modules/@earendil-works/pi-coding-agent/dist/index.d.ts +2 -0
  334. package/node_modules/@earendil-works/pi-coding-agent/dist/index.d.ts.map +1 -1
  335. package/node_modules/@earendil-works/pi-coding-agent/dist/index.js +2 -0
  336. package/node_modules/@earendil-works/pi-coding-agent/dist/index.js.map +1 -1
  337. package/node_modules/@earendil-works/pi-coding-agent/dist/main.d.ts.map +1 -1
  338. package/node_modules/@earendil-works/pi-coding-agent/dist/main.js +69 -16
  339. package/node_modules/@earendil-works/pi-coding-agent/dist/main.js.map +1 -1
  340. package/node_modules/@earendil-works/pi-coding-agent/dist/migrations.d.ts.map +1 -1
  341. package/node_modules/@earendil-works/pi-coding-agent/dist/migrations.js +118 -1
  342. package/node_modules/@earendil-works/pi-coding-agent/dist/migrations.js.map +1 -1
  343. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts +1 -3
  344. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  345. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +2 -4
  346. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.js.map +1 -1
  347. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  348. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/user-message.js +1 -1
  349. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  350. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +3 -0
  351. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  352. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js +59 -6
  353. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  354. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  355. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme.js +10 -0
  356. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  357. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  358. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js +3 -1
  359. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  360. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts +1 -0
  361. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  362. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-types.js.map +1 -1
  363. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/deprecation.d.ts +4 -0
  364. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/deprecation.d.ts.map +1 -0
  365. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/deprecation.js +13 -0
  366. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/deprecation.js.map +1 -0
  367. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/json.d.ts +3 -0
  368. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/json.d.ts.map +1 -0
  369. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/json.js +7 -0
  370. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/json.js.map +1 -0
  371. package/node_modules/@earendil-works/pi-coding-agent/docs/custom-provider.md +13 -10
  372. package/node_modules/@earendil-works/pi-coding-agent/docs/development.md +1 -1
  373. package/node_modules/@earendil-works/pi-coding-agent/docs/extensions.md +12 -6
  374. package/node_modules/@earendil-works/pi-coding-agent/docs/models.md +25 -12
  375. package/node_modules/@earendil-works/pi-coding-agent/docs/providers.md +13 -5
  376. package/node_modules/@earendil-works/pi-coding-agent/docs/quickstart.md +1 -0
  377. package/node_modules/@earendil-works/pi-coding-agent/docs/rpc.md +2 -1
  378. package/node_modules/@earendil-works/pi-coding-agent/docs/sdk.md +6 -0
  379. package/node_modules/@earendil-works/pi-coding-agent/docs/session-format.md +1 -1
  380. package/node_modules/@earendil-works/pi-coding-agent/docs/sessions.md +8 -0
  381. package/node_modules/@earendil-works/pi-coding-agent/docs/settings.md +7 -3
  382. package/node_modules/@earendil-works/pi-coding-agent/docs/terminal-setup.md +2 -0
  383. package/node_modules/@earendil-works/pi-coding-agent/docs/tui.md +2 -2
  384. package/node_modules/@earendil-works/pi-coding-agent/docs/usage.md +9 -0
  385. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/README.md +1 -0
  386. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-anthropic/index.ts +1 -1
  387. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-anthropic/package.json +1 -1
  388. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-gitlab-duo/index.ts +54 -3
  389. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  390. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/git-merge-and-resolve.ts +115 -0
  391. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/input-transform-streaming.ts +39 -0
  392. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/sandbox/package.json +1 -1
  393. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/with-deps/package.json +1 -1
  394. package/node_modules/@earendil-works/pi-coding-agent/npm-shrinkwrap.json +443 -61
  395. package/node_modules/@earendil-works/pi-coding-agent/package.json +6 -6
  396. package/node_modules/@earendil-works/pi-tui/README.md +2 -2
  397. package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts.map +1 -1
  398. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +24 -83
  399. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js.map +1 -1
  400. package/node_modules/@earendil-works/pi-tui/dist/components/input.d.ts.map +1 -1
  401. package/node_modules/@earendil-works/pi-tui/dist/components/input.js +7 -55
  402. package/node_modules/@earendil-works/pi-tui/dist/components/input.js.map +1 -1
  403. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.d.ts +7 -1
  404. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.d.ts.map +1 -1
  405. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.js +12 -2
  406. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.js.map +1 -1
  407. package/node_modules/@earendil-works/pi-tui/dist/index.d.ts +1 -1
  408. package/node_modules/@earendil-works/pi-tui/dist/index.d.ts.map +1 -1
  409. package/node_modules/@earendil-works/pi-tui/dist/index.js.map +1 -1
  410. package/node_modules/@earendil-works/pi-tui/dist/terminal-image.d.ts +1 -1
  411. package/node_modules/@earendil-works/pi-tui/dist/terminal-image.d.ts.map +1 -1
  412. package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js +34 -7
  413. package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js.map +1 -1
  414. package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts +33 -10
  415. package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts.map +1 -1
  416. package/node_modules/@earendil-works/pi-tui/dist/terminal.js +172 -37
  417. package/node_modules/@earendil-works/pi-tui/dist/terminal.js.map +1 -1
  418. package/node_modules/@earendil-works/pi-tui/dist/utils.d.ts +6 -1
  419. package/node_modules/@earendil-works/pi-tui/dist/utils.d.ts.map +1 -1
  420. package/node_modules/@earendil-works/pi-tui/dist/utils.js +27 -15
  421. package/node_modules/@earendil-works/pi-tui/dist/utils.js.map +1 -1
  422. package/node_modules/@earendil-works/pi-tui/dist/word-navigation.d.ts +25 -0
  423. package/node_modules/@earendil-works/pi-tui/dist/word-navigation.d.ts.map +1 -0
  424. package/node_modules/@earendil-works/pi-tui/dist/word-navigation.js +96 -0
  425. package/node_modules/@earendil-works/pi-tui/dist/word-navigation.js.map +1 -0
  426. package/node_modules/@earendil-works/pi-tui/package.json +2 -2
  427. package/node_modules/@entelligentsia/forge-compress/LICENSE +21 -0
  428. package/node_modules/@entelligentsia/forge-compress/README.md +85 -0
  429. package/node_modules/@mariozechner/clipboard/Cargo.toml +3 -3
  430. package/node_modules/@mariozechner/clipboard/index.d.ts +34 -20
  431. package/node_modules/@mariozechner/clipboard/index.js +546 -257
  432. package/node_modules/@mariozechner/clipboard/package.json +5 -6
  433. package/node_modules/@mariozechner/clipboard/package.json.prepack-backup +14 -14
  434. package/node_modules/@mariozechner/clipboard/src/lib.rs +4 -9
  435. package/node_modules/@mariozechner/clipboard-linux-x64-gnu/clipboard.linux-x64-gnu.node +0 -0
  436. package/node_modules/@mariozechner/clipboard-linux-x64-gnu/package.json +2 -2
  437. package/package.json +7 -7
  438. package/dist/bin/forgecli.d.ts +0 -2
  439. package/dist/bin/forgecli.js +0 -6
  440. package/dist/bin/forgecli.js.map +0 -1
  441. package/dist/extensions/forgecli/config-tui/index.d.ts +0 -5
  442. package/dist/extensions/forgecli/config-tui/index.js +0 -5
  443. package/dist/extensions/forgecli/config-tui/index.js.map +0 -1
  444. package/dist/extensions/forgecli/loaders/persona-skill-loader.d.ts +0 -45
  445. package/dist/extensions/forgecli/loaders/persona-skill-loader.js +0 -227
  446. package/dist/extensions/forgecli/loaders/persona-skill-loader.js.map +0 -1
  447. package/dist/extensions/forgecli/loaders/template-render.d.ts +0 -20
  448. package/dist/extensions/forgecli/loaders/template-render.js +0 -85
  449. package/dist/extensions/forgecli/loaders/template-render.js.map +0 -1
  450. package/dist/extensions/forgecli/loaders/workflow-loader.d.ts +0 -41
  451. package/dist/extensions/forgecli/loaders/workflow-loader.js +0 -164
  452. package/dist/extensions/forgecli/loaders/workflow-loader.js.map +0 -1
  453. package/dist/forge-payload/.base-pack/commands/quiz-agent.md +0 -6
  454. package/dist/forge-payload/.base-pack/commands/retrospective.md +0 -6
  455. package/dist/forge-payload/.base-pack/commands/sprint-intake.md +0 -6
  456. package/dist/forge-payload/.base-pack/commands/sprint-plan.md +0 -6
  457. package/dist/forge-payload/.base-pack/workflows/fix_bug.md +0 -446
  458. package/dist/forge-payload/.base-pack/workflows/orchestrate_task.md +0 -934
  459. package/dist/forge-payload/.base-pack/workflows/run_sprint.md +0 -225
  460. package/dist/forge-payload/commands/calibrate.md +0 -10
  461. package/dist/forge-payload/commands/materialize.md +0 -119
  462. package/dist/forge-payload/commands/migrate.md +0 -12
  463. package/dist/forge-payload/commands/quiz-agent.md +0 -6
  464. package/dist/forge-payload/commands/regenerate.md +0 -6
  465. package/dist/forge-payload/commands/store-query.md +0 -6
  466. package/dist/forge-payload/commands/store-repair.md +0 -6
  467. package/dist/forge-payload/commands/update-tools.md +0 -10
  468. package/dist/forge-payload/meta/templates/meta-retrospective.md +0 -28
  469. package/dist/forge-payload/tools/prompts/sprint-plan-prompt.md +0 -70
  470. package/dist/forge-payload/tools/schemas/task-list.schema.json +0 -53
  471. package/node_modules/@earendil-works/pi-agent-core/dist/harness/execution-env.d.ts +0 -4
  472. package/node_modules/@earendil-works/pi-agent-core/dist/harness/execution-env.d.ts.map +0 -1
  473. package/node_modules/@earendil-works/pi-agent-core/dist/harness/execution-env.js +0 -3
  474. package/node_modules/@earendil-works/pi-agent-core/dist/harness/execution-env.js.map +0 -1
  475. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/jsonl.d.ts +0 -20
  476. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/jsonl.d.ts.map +0 -1
  477. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/jsonl.js +0 -92
  478. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/jsonl.js.map +0 -1
  479. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/memory.d.ts +0 -18
  480. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/memory.d.ts.map +0 -1
  481. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/memory.js +0 -42
  482. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/memory.js.map +0 -1
  483. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/shared.d.ts +0 -10
  484. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/shared.d.ts.map +0 -1
  485. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/shared.js +0 -31
  486. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/shared.js.map +0 -1
  487. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/jsonl.d.ts +0 -30
  488. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/jsonl.d.ts.map +0 -1
  489. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/jsonl.js +0 -170
  490. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/jsonl.js.map +0 -1
  491. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/memory.d.ts +0 -26
  492. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/memory.d.ts.map +0 -1
  493. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/memory.js +0 -90
  494. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/memory.js.map +0 -1
  495. package/node_modules/@mariozechner/clipboard-linux-x64-musl/README.md +0 -3
  496. package/node_modules/@mariozechner/clipboard-linux-x64-musl/clipboard.linux-x64-musl.node +0 -0
  497. package/node_modules/@mariozechner/clipboard-linux-x64-musl/package.json +0 -25
@@ -0,0 +1,490 @@
1
+ export const meta = {
2
+ name: 'wfl:fix-bug',
3
+ description: 'Code-orchestrated port of /forge:fix-bug — drive a bug through the triage→[plan-fix→review-plan→]implement→review-code→approve→commit→finalize pipeline, with Path A (short) or Path B (full) selected once from summaries.triage.route, all escalation and revision loops held in JS.',
4
+ whenToUse: 'Fix a single Forge bug through the full triage→fix→commit pipeline via a deterministic JS driver. Pass the bug id as args, e.g. args: "FORGE-BUG-001".',
5
+ phases: [
6
+ { title: 'Resolve', detail: 'read the bug record and check the pre-run status guard' },
7
+ { title: 'Triage', detail: 'one subagent reproduces the bug, records root cause, and writes summaries.triage.route=A|B' },
8
+ { title: 'Pipeline', detail: 'per phase: one subagent runs the gate + phase workflow + emits its own event; JS owns the phase index, revision counters, verdict routing, and escalation decision' },
9
+ { title: 'Finalize', detail: 'collate + preflight finalize gate; gate failure escalates without touching bug.status=fixed' },
10
+ { title: 'Report', detail: 'summarise the terminal outcome — fixed / escalated' },
11
+ ],
12
+ };
13
+
14
+ // wfl:fix-bug — a code-orchestrated port of .forge/workflows/fix_bug.md
15
+ //
16
+ // Why a script: fix_bug.md is a deterministic phase FSM with a triage-branch
17
+ // decision (Path A vs Path B), review→revision back-edges, per-phase iter caps,
18
+ // declarative pre-flight gates, and escalate-don't-continue on any failure. In the
19
+ // LLM orchestrator that loop is hand-run turn-by-turn. Here the JS holds the phase
20
+ // index, the revision counters, the verdict routing, and the escalation decision;
21
+ // subagents only run a single phase's workflow and write artifacts/events to disk.
22
+ //
23
+ // SIDE-EFFECT OWNERSHIP — READ BEFORE EDITING:
24
+ // This script has NO filesystem/shell access. Each per-phase subagent owns:
25
+ // preflight-gate, the phase workflow (which writes its own artifacts +
26
+ // {PHASE}-SUMMARY.json + status), read-verdict (review phases), token sidecar,
27
+ // friction drain, AND its own canonical phase event.
28
+ // *** DELIBERATE DEVIATION from fix_bug.md's "the orchestrator is the sole actor
29
+ // that calls store-cli emit" rule: here each phase subagent emits its OWN phase
30
+ // event. This is defensible — the subagent is the only actor that holds its own
31
+ // runtime attribution (model, provider, token usage). The JS driver cannot run
32
+ // store-cli. This is a control-flow-authoritative port with delegated telemetry,
33
+ // NOT a byte-for-byte reproduction of the emit contract.
34
+ // Split start/complete emit contract: per fix_bug.md §Event Emission, each phase
35
+ // subagent emits a start event (action="start") BEFORE executing its phase
36
+ // workflow, then a complete event (action="complete") AFTER. The JS driver
37
+ // delegates wall-time bracketing to the subagent: subagent notes startTimestamp,
38
+ // runs the workflow, then computes durationMinutes = (endMs - startMs) / 60000
39
+ // and includes it in the complete event. The start event carries a 0-duration
40
+ // placeholder (startTimestamp == endTimestamp); the complete event carries the
41
+ // real bracket. This mirrors the fix_bug.md start+complete pattern. ***
42
+ //
43
+ // MODEL TIERING: each phase dispatched on the tier fix_bug.md § Role-to-Tier
44
+ // Mapping prescribes. The Workflow agent() hook takes the tier NAME and the host
45
+ // (Claude Code) resolves it to the configured model for that tier.
46
+ //
47
+ // PATH A / PATH B: triage subagent writes summaries.triage.route = "A" or "B".
48
+ // The JS driver reads it after triage and selects the phase list. Selection is
49
+ // FINAL — no mid-pipeline switching. If route is neither "A" nor "B", escalate
50
+ // verdict_malformed.
51
+ //
52
+ // VIRTUAL SPRINT DIR: all bug events use sprintId="bugs" (virtual sprint dir).
53
+ // The event schema's bugId field carries the originating bug ID for cross-bug
54
+ // filtering at collate time.
55
+ //
56
+ // Invocation (Workflow tool): { name: 'wfl:fix-bug', args: 'FORGE-BUG-001' }
57
+ // args may also be an object: { bugId: 'FORGE-BUG-001' }
58
+
59
+ // Bug statuses that mean "do not run any phase" — fix_bug.md pre-loop guard.
60
+ // Note: terminal status for bugs is "fixed" (not "committed" — that is for tasks).
61
+ const SKIP_STATUS = ['blocked', 'escalated', 'fixed', 'abandoned']
62
+
63
+ // Phase roles whose artifact carries a **Verdict:** that routes the FSM.
64
+ // No 'validate' phase in fix_bug — drop it from the task template's list.
65
+ // NOTE: 'approve' is NOT here — fix_bug advances it on completion like a
66
+ // non-review phase (the approve workflow self-escalates if it rejects).
67
+ const REVIEW_ROLES = ['review-plan', 'review-code']
68
+
69
+ // Per-phase model tier — verbatim port of fix_bug.md § Role-to-Tier Mapping.
70
+ // Passed as the `model` opt to agent(); the host resolves the tier name to a model.
71
+ const ROLE_TIER = {
72
+ 'triage': 'sonnet',
73
+ 'plan': 'sonnet',
74
+ 'review-plan': 'opus',
75
+ 'implement': 'sonnet',
76
+ 'review-code': 'opus',
77
+ 'approve': 'opus',
78
+ 'commit': 'haiku',
79
+ 'finalize': 'haiku',
80
+ }
81
+
82
+ const tierFor = (role) => ROLE_TIER[role] || 'sonnet'
83
+
84
+ // Path A phase list (short): implement → review-code → approve → commit → finalize
85
+ // Triage is handled separately before this array — do NOT include it here.
86
+ const PHASES_A = [
87
+ { role: 'implement', command: 'implement', workflow: 'implement_plan.md', maxIterations: 1 },
88
+ { role: 'review-code', command: 'review-code', workflow: 'review_code.md', maxIterations: 3 },
89
+ { role: 'approve', command: 'approve', workflow: 'architect_approve.md', maxIterations: 1 },
90
+ { role: 'commit', command: 'commit', workflow: 'commit_task.md', maxIterations: 1 },
91
+ // finalize is NOT a subagent phase — handled inline after the loop
92
+ ]
93
+
94
+ // Path B phase list (full): plan-fix → review-plan → implement → review-code → approve → commit → finalize
95
+ // Triage is handled separately before this array — do NOT include it here.
96
+ const PHASES_B = [
97
+ { role: 'plan', command: 'plan-fix', workflow: 'plan_task.md', maxIterations: 1 },
98
+ { role: 'review-plan', command: 'review-plan', workflow: 'review_plan.md', maxIterations: 3 },
99
+ ...PHASES_A,
100
+ ]
101
+
102
+ // Schema for a single resolved bug context (pre-triage read).
103
+ const BUG_RESOLVE_SCHEMA = {
104
+ type: 'object',
105
+ additionalProperties: false,
106
+ required: ['bugId', 'bugStatus'],
107
+ properties: {
108
+ bugId: { type: 'string' },
109
+ bugStatus: { type: 'string' },
110
+ note: { type: 'string' },
111
+ },
112
+ }
113
+
114
+ // Schema for a single phase subagent return value.
115
+ const BUG_PHASE_RESULT_SCHEMA = {
116
+ type: 'object',
117
+ additionalProperties: false,
118
+ required: ['phase', 'role', 'gatePassed', 'verdict', 'escalated', 'taskStatus'],
119
+ properties: {
120
+ phase: { type: 'string' },
121
+ role: { type: 'string' },
122
+ gatePassed: { type: 'boolean' },
123
+ verdict: { type: 'string', enum: ['approved', 'revision', 'malformed', 'none'] },
124
+ escalated: { type: 'boolean' },
125
+ taskStatus: { type: 'string' }, // bug.status read back after the phase
126
+ note: { type: 'string' },
127
+ },
128
+ }
129
+
130
+ // Schema for the triage phase result.
131
+ const TRIAGE_RESULT_SCHEMA = {
132
+ type: 'object',
133
+ additionalProperties: false,
134
+ required: ['phase', 'role', 'gatePassed', 'verdict', 'escalated', 'taskStatus'],
135
+ properties: {
136
+ phase: { type: 'string' },
137
+ role: { type: 'string' },
138
+ gatePassed: { type: 'boolean' },
139
+ verdict: { type: 'string', enum: ['approved', 'revision', 'malformed', 'none'] },
140
+ escalated: { type: 'boolean' },
141
+ taskStatus: { type: 'string' },
142
+ note: { type: 'string' },
143
+ },
144
+ }
145
+
146
+ // Port of fix_bug.md: a "Revision Required" verdict routes back to the nearest
147
+ // earlier phase whose role is NOT a review role (i.e. the producer).
148
+ function revisionTarget(phases, reviewIdx) {
149
+ for (let j = reviewIdx - 1; j >= 0; j--) {
150
+ if (!REVIEW_ROLES.includes(phases[j].role)) return j
151
+ }
152
+ return 0 // degenerate pipeline with no producer before the review — loop to start
153
+ }
154
+
155
+ // runBugPhase — mirrors runPhase() from wfl-run-task.js but adapted for bug semantics:
156
+ // - --bug {bugId} instead of --task {taskId}
157
+ // - sprintId = 'bugs' (virtual sprint dir)
158
+ // - store/bugs/{bugId}.json instead of store/tasks/{taskId}.json
159
+ // - read-verdict --bug {bugId}
160
+ // The subagent owns ALL shell-dependent side-effects for this phase.
161
+ function runBugPhase(bugId, phase, iter) {
162
+ const sprintId = 'bugs' // virtual sprint dir for all emit/sidecar/progress
163
+ return agent(
164
+ [
165
+ `You are running a SINGLE pipeline phase for Forge bug ${bugId} (sprint bugs).`,
166
+ `Phase: role="${phase.role}", command="${phase.command}", workflow="${phase.workflow}", iteration=${iter}.`,
167
+ '1. PRE-FLIGHT GATE. Run `node .forge/tools/preflight-gate.cjs --phase ' + phase.role + ' --bug ' + bugId + '`.',
168
+ ' If it exits non-zero: do NOT run the phase. Set status via',
169
+ ' `node .forge/tools/store-cli.cjs update-status bug ' + bugId + ' status escalated`, emit an escalation event,',
170
+ ' and return gatePassed=false, escalated=true, verdict="none", with the gate stderr in note.',
171
+ '2. RUN THE PHASE. Read `.forge/workflows/' + phase.workflow + '` and follow it for bug ' + bugId + '.',
172
+ ' The workflow writes its own artifacts, {PHASE}-SUMMARY.json, and any bug-status changes.',
173
+ ' Also read the task-scoped slice of `engineering/MASTER_INDEX.md` for project context.',
174
+ '3. EMIT YOUR PHASE EVENTS. You are the only actor that knows your runtime attribution.',
175
+ ' 3a. BEFORE running the phase workflow: note the start timestamp (startTimestamp = new Date().toISOString()).',
176
+ ' Emit a start event via `node .forge/tools/store-cli.cjs emit bugs \'{event-json}\'`',
177
+ ' with action="start", role="' + phase.role + '", iteration=' + iter + ', startTimestamp and endTimestamp both equal to startTimestamp (0-duration placeholder).',
178
+ ' 3b. AFTER the phase workflow completes: note the end timestamp (endTimestamp = new Date().toISOString()).',
179
+ ' Compute durationMinutes = (new Date(endTimestamp) - new Date(startTimestamp)) / 60000.',
180
+ ' Emit a complete event via `node .forge/tools/store-cli.cjs emit bugs \'{event-json}\'`',
181
+ ' conforming to `.forge/schemas/event.schema.json` (role, action="complete", phase, iteration=' + iter + ',',
182
+ ' startTimestamp, endTimestamp, durationMinutes, plus your own model/provider/token usage — do NOT invent placeholder model strings).',
183
+ ' If `/cost` data is available, also write the token sidecar via the `--sidecar` form. Best-effort; skip silently if unavailable.',
184
+ ' Then drain any `.forge/cache/FRICTION-*.jsonl` friction records you produced and emit them as type "friction".',
185
+ phase.role && REVIEW_ROLES.includes(phase.role)
186
+ ? '4. READ VERDICT. This is a REVIEW phase. The phase workflow records its verdict into the store '
187
+ + 'summary (`summaries.' + phase.role + '.verdict`) via set-bug-summary — make sure that write happened. '
188
+ + 'Then resolve it with the canonical tool `node .forge/tools/read-verdict.cjs --phase ' + phase.role + ' --bug ' + bugId + '` '
189
+ + '(reads the structured summary, NOT a markdown artifact path). '
190
+ + 'Route on the STDOUT token the tool prints (approved | revision | n/a | unknown), NOT on the exit code. '
191
+ + 'Map STDOUT token → verdict: "approved"→"approved", "revision"→"revision", "n/a"→"malformed", "unknown"→"malformed". '
192
+ + 'The exit code is unreliable (exits 1 for both revision AND missing/n/a). NEVER guess.'
193
+ : '4. NON-REVIEW phase: return verdict="none".',
194
+ '5. Read `.forge/store/bugs/' + bugId + '.json` and return its final status as taskStatus, plus a one-line note.',
195
+ ].join('\n'),
196
+ { label: `${bugId}:${phase.role}:${iter}`, phase: 'Pipeline', schema: BUG_PHASE_RESULT_SCHEMA, model: tierFor(phase.role) }
197
+ )
198
+ }
199
+
200
+ // escalateBug — analogous to escalateTask() from wfl-run-task.js.
201
+ // The JS driver cannot write the store, so a tiny haiku agent performs the status
202
+ // write and event emit. Uses --bug flag and 'bugs' virtual sprint dir throughout.
203
+ function escalateBug(bugId, reason) {
204
+ return agent(
205
+ [
206
+ `Escalate Forge bug ${bugId} to a human.`,
207
+ `run \`node .forge/tools/store-cli.cjs update-status bug ${bugId} status escalated\``,
208
+ `and emit one event (sprint bugs) with verdict="escalated" and notes="${reason}".`,
209
+ `Return the bug's final status as taskStatus, gatePassed=true, verdict="none", escalated=true, phase="escalate", role="escalate".`,
210
+ ].join(' '),
211
+ { label: `${bugId}:escalate`, phase: 'Pipeline', schema: BUG_PHASE_RESULT_SCHEMA, model: 'haiku' }
212
+ )
213
+ }
214
+
215
+ // --- Main body ---
216
+
217
+ const bugId = (typeof args === 'string' ? args : args?.bugId)
218
+ if (!bugId) throw new Error('wfl:fix-bug requires a bug id — pass args: "FORGE-BUG-001"')
219
+
220
+ // Step 0 — Read the bug record to check pre-run status guard.
221
+ phase('Resolve')
222
+ const resolved = await agent(
223
+ [
224
+ `Read the bug record for ${bugId}..`,
225
+ `Run \`node .forge/tools/store-cli.cjs read bug ${bugId} --json\` and return bugId and bugStatus.`,
226
+ `Read-only — do NOT modify anything.`,
227
+ ].join(' '),
228
+ { label: `resolve:${bugId}`, phase: 'Resolve', schema: BUG_RESOLVE_SCHEMA }
229
+ )
230
+
231
+ if (!resolved) throw new Error(`Could not resolve bug record for ${bugId}`)
232
+
233
+ // Pre-loop status guard — fix_bug.md: skip at pre-loop with one bug_skipped event.
234
+ if (SKIP_STATUS.includes(resolved.bugStatus)) {
235
+ log(`⚠ ${bugId} — status is ${resolved.bugStatus}, skipping run.`)
236
+ // Emit bug_skipped event (not a silent return — Iron Law 3).
237
+ await agent(
238
+ [
239
+ `Emit a bug_skipped event for ${bugId}..`,
240
+ `Run \`node .forge/tools/store-cli.cjs emit bugs '{"type":"bug_skipped","sprintId":"bugs","bugId":"${bugId}","role":"orchestrator","action":"skipped","reason":"status=${resolved.bugStatus}","startTimestamp":"'$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)'","endTimestamp":"'$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)'","durationMinutes":0}'\`.`,
241
+ `Best-effort. Return taskStatus="${resolved.bugStatus}", gatePassed=true, verdict="none", escalated=false, phase="skip", role="orchestrator".`,
242
+ ].join(' '),
243
+ { label: `${bugId}:skip`, phase: 'Skip', schema: BUG_PHASE_RESULT_SCHEMA, model: 'haiku' }
244
+ )
245
+ return { bugId, skipped: true, bugStatus: resolved.bugStatus, results: [] }
246
+ }
247
+
248
+ log(`Bug ${bugId} — starting triage`)
249
+
250
+ // Step 1 — Triage subagent.
251
+ // Triage is handled outside the phase loop: it writes summaries.triage.route and
252
+ // determines Path A vs Path B. The orchestrator (not the subagent) owns the two
253
+ // status updates: triaged then in-progress (Iron Law 2 of fix_bug.md).
254
+ phase('Triage')
255
+ const triagePhase = { role: 'triage', command: 'triage', workflow: 'triage.md', maxIterations: 1 }
256
+ let triageResult = await agent(
257
+ [
258
+ `You are running the TRIAGE phase for Forge bug ${bugId} (sprint bugs).`,
259
+ `Phase: role="triage", command="triage", workflow="triage.md", iteration=1.`,
260
+ '1. PRE-FLIGHT GATE. Run `node .forge/tools/preflight-gate.cjs --phase triage --bug ' + bugId + '`.',
261
+ ' If it exits non-zero: do NOT run the phase. Return gatePassed=false, escalated=true, verdict="none".',
262
+ '2. RUN THE PHASE. Read `.forge/workflows/triage.md` and follow it for bug ' + bugId + '.',
263
+ ' The triage workflow writes TRIAGE.md + TRIAGE-SUMMARY.json with a route field ("A" or "B").',
264
+ ' Call `node .forge/tools/store-cli.cjs set-bug-summary ' + bugId + ' triage` with the summary.',
265
+ ' CRITICAL: write summaries.triage.route (field name is "route" NOT "path").',
266
+ ' Do NOT write bug.status in this phase — the orchestrator owns the status writes.',
267
+ '3. EMIT YOUR PHASE EVENTS. You are the only actor that knows your runtime attribution.',
268
+ ' 3a. BEFORE running the triage workflow: note the start timestamp (startTimestamp = new Date().toISOString()).',
269
+ ' Emit a start event via `node .forge/tools/store-cli.cjs emit bugs \'{event-json}\'`',
270
+ ' with action="start", role="triage", iteration=1, startTimestamp and endTimestamp both equal to startTimestamp (0-duration placeholder).',
271
+ ' 3b. AFTER the triage workflow completes: note the end timestamp (endTimestamp = new Date().toISOString()).',
272
+ ' Compute durationMinutes = (new Date(endTimestamp) - new Date(startTimestamp)) / 60000.',
273
+ ' Emit a complete event via `node .forge/tools/store-cli.cjs emit bugs \'{event-json}\'`',
274
+ ' conforming to `.forge/schemas/event.schema.json` (role, action="complete", phase, iteration=1,',
275
+ ' startTimestamp, endTimestamp, durationMinutes, plus your own model/provider/token usage — do NOT invent placeholder model strings).',
276
+ ' If `/cost` data is available, also write the token sidecar via the `--sidecar` form. Best-effort; skip silently if unavailable.',
277
+ '4. NON-REVIEW phase: return verdict="none".',
278
+ '5. Read `.forge/store/bugs/' + bugId + '.json` and return its final status as taskStatus, plus a one-line note.',
279
+ ].join('\n'),
280
+ { label: `${bugId}:triage:1`, phase: 'Triage', schema: TRIAGE_RESULT_SCHEMA, model: tierFor('triage') }
281
+ )
282
+
283
+ // Null-dispatch retry: if triage returned null, retry once then escalate.
284
+ if (!triageResult) {
285
+ triageResult = await agent(
286
+ [
287
+ `You are running the TRIAGE phase for Forge bug ${bugId} (sprint bugs). This is a retry.`,
288
+ `Phase: role="triage", command="triage", workflow="triage.md", iteration=1.`,
289
+ '1. PRE-FLIGHT GATE. Run `node .forge/tools/preflight-gate.cjs --phase triage --bug ' + bugId + '`.',
290
+ ' If it exits non-zero: return gatePassed=false, escalated=true, verdict="none".',
291
+ '2. RUN THE PHASE. Read `.forge/workflows/triage.md` and follow it for bug ' + bugId + '.',
292
+ ' Write summaries.triage.route (field name is "route" NOT "path").',
293
+ ' Do NOT write bug.status — the orchestrator owns the status writes.',
294
+ '3. Emit start and complete events (action="start" then action="complete") to sprint bugs.',
295
+ '4. Return verdict="none", taskStatus from bug record.',
296
+ ].join('\n'),
297
+ { label: `${bugId}:triage:1:retry`, phase: 'Triage', schema: TRIAGE_RESULT_SCHEMA, model: tierFor('triage') }
298
+ )
299
+ }
300
+
301
+ if (!triageResult) {
302
+ await escalateBug(bugId, 'triage dispatch returned null after retry')
303
+ return { bugId, escalated: true, bugStatus: 'escalated', results: [] }
304
+ }
305
+
306
+ if (!triageResult.gatePassed || triageResult.escalated) {
307
+ await escalateBug(bugId, triageResult.note || 'triage gate failed / self-escalated')
308
+ return { bugId, escalated: true, bugStatus: 'escalated', results: [triageResult] }
309
+ }
310
+
311
+ // Orchestrator owns both status writes after triage returns (Iron Law 2).
312
+ // Two separate calls: reported→triaged, then triaged→in-progress.
313
+ await agent(
314
+ [
315
+ `Run \`node .forge/tools/store-cli.cjs update-status bug ${bugId} status triaged\`.`,
316
+ `Then run \`node .forge/tools/store-cli.cjs update-status bug ${bugId} status in-progress\`.`,
317
+ `Return taskStatus="in-progress", gatePassed=true, verdict="none", escalated=false, phase="status-write", role="orchestrator".`,
318
+ ].join(' '),
319
+ { label: `${bugId}:status-write`, phase: 'StatusWrite', schema: BUG_PHASE_RESULT_SCHEMA, model: 'haiku' }
320
+ )
321
+
322
+ // Read summaries.triage.route to select Path A or Path B.
323
+ const routeResult = await agent(
324
+ [
325
+ `Read the bug record for ${bugId}..`,
326
+ `Run \`node .forge/tools/store-cli.cjs read bug ${bugId} --json\`.`,
327
+ `Return the value of summaries.triage.route (field name is "route" NOT "path").`,
328
+ `Return as: { bugId: "${bugId}", bugStatus: "<current status>", note: "<route value A or B>" }.`,
329
+ ].join(' '),
330
+ { label: `${bugId}:read-route`, phase: 'ReadRoute', schema: BUG_RESOLVE_SCHEMA }
331
+ )
332
+
333
+ const route = routeResult?.note?.trim()
334
+ if (route !== 'A' && route !== 'B') {
335
+ log(`⚠ ${bugId} triage — route="${route}" is neither A nor B, escalating verdict_malformed`)
336
+ await escalateBug(bugId, `verdict_malformed: summaries.triage.route="${route}" — expected "A" or "B"`)
337
+ return { bugId, escalated: true, bugStatus: 'escalated', results: [triageResult] }
338
+ }
339
+
340
+ // Path selection — decided once, no switching (Iron Law 1 of fix_bug.md).
341
+ const phases = route === 'A' ? PHASES_A : PHASES_B
342
+ log(`Bug ${bugId} — route=${route}, pipeline: ${phases.map(p => p.role).join(' → ')}`)
343
+
344
+ // Step 2 — Drive the phase FSM. JS owns sequencing, counters, routing, escalation.
345
+ const iterationCounts = {} // keyed by phase command
346
+ const results = [triageResult]
347
+ let i = 0
348
+ let escalated = false
349
+ let escalationReason = null
350
+
351
+ while (i < phases.length) {
352
+ const p = phases[i]
353
+ const iter = (iterationCounts[p.command] || 0) + 1
354
+ log(`→ ${bugId} ${p.role} [${tierFor(p.role)}] (iter ${iter})`)
355
+
356
+ // Dispatch with one retry on a null/skipped dispatch (escalate-don't-halt at phase grain).
357
+ let r = await runBugPhase(bugId, p, iter)
358
+ if (!r) r = await runBugPhase(bugId, p, iter)
359
+ if (!r) {
360
+ escalationReason = `phase ${p.role} dispatch returned null after retry`
361
+ log(`✗ ${bugId} ${p.role} — dispatch failed twice, escalating`)
362
+ escalated = true
363
+ break
364
+ }
365
+
366
+ results.push(r)
367
+
368
+ // Gate failure or subagent self-escalation (already wrote status=escalated).
369
+ if (!r.gatePassed || r.escalated) {
370
+ escalationReason = r.note || `${p.role} gate failed / self-escalated`
371
+ log(`⚠ ${bugId} ${p.role} — escalated (${escalationReason})`)
372
+ escalated = true
373
+ break
374
+ }
375
+
376
+ // Review phases route on verdict; non-review phases advance on completion.
377
+ if (REVIEW_ROLES.includes(p.role)) {
378
+ if (r.verdict === 'approved') {
379
+ log(`✓ ${bugId} ${p.role} — Approved`)
380
+ i += 1
381
+ } else if (r.verdict === 'revision') {
382
+ iterationCounts[p.command] = (iterationCounts[p.command] || 0) + 1
383
+ log(`↻ ${bugId} ${p.role} — Revision Required (iter ${iterationCounts[p.command]})`)
384
+ if (iterationCounts[p.command] >= p.maxIterations) {
385
+ escalationReason = `max iterations (${p.maxIterations}) reached at ${p.role}`
386
+ escalated = true
387
+ break
388
+ }
389
+ i = revisionTarget(phases, i) // loop back to the producing phase
390
+ } else {
391
+ // 'malformed' (or unexpected 'none' from a review phase) — never guess.
392
+ escalationReason = `verdict malformed at ${p.role}`
393
+ escalated = true
394
+ break
395
+ }
396
+ } else {
397
+ log(`✓ ${bugId} ${p.role} — completed`)
398
+ i += 1
399
+ }
400
+ }
401
+
402
+ // If the JS driver decided to escalate (not the subagent), perform the status write.
403
+ const lastWroteEscalation = results.length && results[results.length - 1].escalated
404
+ if (escalated && !lastWroteEscalation) {
405
+ await escalateBug(bugId, escalationReason)
406
+ }
407
+
408
+ if (escalated) {
409
+ log(`⚠ Bug ${bugId} escalated: ${escalationReason}`)
410
+ log(` Resume with the failing phase command after addressing the issue, or re-run wfl:fix-bug.`)
411
+ return {
412
+ bugId,
413
+ escalated: true,
414
+ bugStatus: 'escalated',
415
+ phasesRun: results.length,
416
+ results,
417
+ escalationReason,
418
+ }
419
+ }
420
+
421
+ // Step 3 — Finalize (inline, not a subagent phase per fix_bug.md § Finalize).
422
+ // Run collate.cjs {bugId} --purge-events then preflight-gate --phase finalize --bug {bugId}.
423
+ // Gate failure escalates but PRESERVES bug.status=fixed (already set by commit phase).
424
+ phase('Finalize')
425
+ log(`→ ${bugId} finalize [${tierFor('finalize')}]`)
426
+
427
+ const finalizeResult = await agent(
428
+ [
429
+ `Finalize Forge bug ${bugId}..`,
430
+ `Step 1: Run \`node .forge/tools/collate.cjs ${bugId} --purge-events\`.`,
431
+ ` This purges this bug's events from the shared bugs/ dir and embeds the cost section in INDEX.md.`,
432
+ ` Do NOT run a separate cost aggregation — collate handles it automatically.`,
433
+ `Step 2: Run \`node .forge/tools/preflight-gate.cjs --phase finalize --bug ${bugId}\`.`,
434
+ ` If the gate exits non-zero: emit one escalation event to sprint bugs with verdict="escalated"`,
435
+ ` and notes="finalize gate failed". Do NOT call update-status bug — bug.status is already "fixed".`,
436
+ ` Return escalated=true in that case.`,
437
+ `Step 3: If both steps succeeded, return gatePassed=true, escalated=false, verdict="none",`,
438
+ ` taskStatus="fixed", phase="finalize", role="finalize".`,
439
+ ` If gate failed, return gatePassed=false, escalated=true, verdict="none", taskStatus="fixed".`,
440
+ ].join('\n'),
441
+ { label: `${bugId}:finalize:1`, phase: 'Finalize', schema: BUG_PHASE_RESULT_SCHEMA, model: tierFor('finalize') }
442
+ )
443
+
444
+ results.push(finalizeResult)
445
+
446
+ // Null-dispatch guard: agent() returns null if the finalize subagent is skipped
447
+ // or errors. Without this, `finalizeResult?.escalated` short-circuits to
448
+ // undefined and the driver would fall through and report bugStatus:'fixed',
449
+ // escalated:false — declaring the run clean when finalize (collate + gate)
450
+ // never executed. Every other dispatch in this driver has a null guard; this
451
+ // is the one that was missing. Preserve bugStatus:'fixed' (commit already wrote
452
+ // it) but mark the run escalated so it is not reported green.
453
+ if (!finalizeResult) {
454
+ await escalateBug(bugId, 'finalize dispatch returned null (subagent skipped or errored)')
455
+ return {
456
+ bugId,
457
+ escalated: true,
458
+ bugStatus: 'fixed',
459
+ phasesRun: results.length,
460
+ results,
461
+ escalationReason: 'finalize dispatch returned null',
462
+ }
463
+ }
464
+
465
+ if (finalizeResult?.escalated) {
466
+ log(`⚠ ${bugId} finalize — gate failed; bug.status preserved as "fixed"`)
467
+ log(` Finalize escalation raised but bug commit is complete.`)
468
+ return {
469
+ bugId,
470
+ escalated: true,
471
+ bugStatus: 'fixed', // commit already wrote fixed; finalize gate failure does not revert
472
+ phasesRun: results.length,
473
+ results,
474
+ escalationReason: 'finalize gate failed',
475
+ }
476
+ }
477
+
478
+ log(`✓ ${bugId} finalize — complete`)
479
+
480
+ // Step 4 — Report terminal outcome.
481
+ phase('Report')
482
+ log(`🍂 Bug ${bugId} fixed — pipeline reached terminal (fixed).`)
483
+
484
+ return {
485
+ bugId,
486
+ escalated: false,
487
+ bugStatus: 'fixed',
488
+ phasesRun: results.length,
489
+ results,
490
+ }