@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 @@
1
+ {"version":3,"file":"bug-phases.js","sourceRoot":"","sources":["../../../../../src/extensions/forgecli/orchestrators/bug/bug-phases.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,+EAA+E;AAC/E,6EAA6E;AAI7E,+EAA+E;AAC/E,EAAE;AACF,6EAA6E;AAC7E,wEAAwE;AACxE,mDAAmD;AAEnD,uEAAuE;AACvE,uEAAuE;AAEvE,MAAM,CAAC,MAAM,UAAU,GAAsB;IAC5C,8EAA8E;IAC9E,sEAAsE;IACtE,uEAAuE;IACvE,0EAA0E;IAC1E,kEAAkE;IAClE,uEAAuE;IACvE,2BAA2B;IAC3B,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,EAAE;IACvG,EAAE,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,EAAE;IAC3G,EAAE,IAAI,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,EAAE;IACjH,EAAE,IAAI,EAAE,WAAW,EAAE,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,EAAE;IACjH,EAAE,IAAI,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,EAAE;IACjH,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,mBAAmB,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,EAAE;IAClH,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,EAAE;CAC3G,CAAC;AAEF,8EAA8E;AAC9E,4EAA4E;AAC5E,+EAA+E;AAC/E,oEAAoE;AACpE,MAAM,CAAC,MAAM,eAAe,GAAmD;IAC9E,MAAM,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE;IACpD,UAAU,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE;IACxD,aAAa,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,mBAAmB,EAAE;IACvE,SAAS,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,iBAAiB,EAAE;IAC/D,aAAa,EAAE,EAAE,IAAI,EAAE,wBAAwB,EAAE,IAAI,EAAE,wBAAwB,EAAE;IACjF,OAAO,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,wBAAwB,EAAE;IACjE,MAAM,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,mBAAmB,EAAE;CAC5D,CAAC;AAEF,8EAA8E;AAC9E,wDAAwD;AACxD,sEAAsE;AACtE,+DAA+D;AAE/D,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAEtD,wEAAwE;AACxE,oEAAoE;AACpE,qEAAqE;AACrE,0EAA0E;AAC1E,yEAAyE;AACzE,wEAAwE;AACxE,wEAAwE;AACxE,iEAAiE;AACjE,MAAM,UAAU,qBAAqB,CAAC,MAA0B;IAC/D,IAAI,MAAM,KAAK,UAAU;QAAE,OAAO,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IAC7D,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IACjD,OAAO,EAAE,CAAC;AACX,CAAC"}
@@ -0,0 +1,14 @@
1
+ export interface RunBugState {
2
+ bugId: string;
3
+ phaseIndex: number;
4
+ iterationCounts: Record<string, number>;
5
+ halted: boolean;
6
+ /** Set on cancellation so the resume prompt says "cancelled" vs "halted". */
7
+ status?: "cancelled" | "halted" | "running";
8
+ lastError?: string;
9
+ savedAt: string;
10
+ }
11
+ export declare function readBugState(cwd: string, bugId: string, sessionId?: string): RunBugState | null;
12
+ export declare function writeBugState(cwd: string, state: RunBugState): void;
13
+ export declare function deleteBugState(cwd: string, bugId: string): void;
14
+ export declare function isBugStateStale(state: RunBugState): boolean;
@@ -0,0 +1,100 @@
1
+ // bug-state.ts — bug-pipeline state persistence (RunBugState + the cache-file
2
+ // read/write/delete/stale helpers). Extracted VERBATIM from fix-bug.ts
3
+ // (FORGE-S31 file-size refactor); no logic changes.
4
+ import * as fs from "node:fs";
5
+ import * as path from "node:path";
6
+ import { validateId } from "../common/orchestrator-misc.js";
7
+ function bugStateFilePath(cwd, bugId, sessionId) {
8
+ if (!validateId(bugId)) {
9
+ throw new Error(`Invalid bugId for state file path: ${bugId}`);
10
+ }
11
+ const suffix = sessionId ?? process.env.FORGE_SESSION_ID ?? `${process.pid}`;
12
+ return path.join(cwd, ".forge", "cache", `fix-bug-state-${bugId}-${suffix}.json`);
13
+ }
14
+ export function readBugState(cwd, bugId, sessionId) {
15
+ // If a specific session ID is given, read that file directly.
16
+ if (sessionId || process.env.FORGE_SESSION_ID) {
17
+ const fp = bugStateFilePath(cwd, bugId, sessionId);
18
+ try {
19
+ if (!fs.existsSync(fp))
20
+ return null;
21
+ const raw = fs.readFileSync(fp, "utf8");
22
+ return JSON.parse(raw);
23
+ }
24
+ catch {
25
+ return null;
26
+ }
27
+ }
28
+ // No specific session — glob for the most recent matching state file.
29
+ // Single-writer assumption: normally only one session per bug.
30
+ const cacheDir = path.join(cwd, ".forge", "cache");
31
+ const prefix = `fix-bug-state-${bugId}-`;
32
+ let bestFile = null;
33
+ let bestMtime = 0;
34
+ try {
35
+ const entries = fs.readdirSync(cacheDir);
36
+ for (const entry of entries) {
37
+ if (!entry.startsWith(prefix) || !entry.endsWith(".json"))
38
+ continue;
39
+ const fp = path.join(cacheDir, entry);
40
+ try {
41
+ const st = fs.statSync(fp);
42
+ if (st.mtimeMs > bestMtime) {
43
+ bestMtime = st.mtimeMs;
44
+ bestFile = fp;
45
+ }
46
+ }
47
+ catch { }
48
+ }
49
+ }
50
+ catch {
51
+ return null;
52
+ }
53
+ if (!bestFile)
54
+ return null;
55
+ try {
56
+ const raw = fs.readFileSync(bestFile, "utf8");
57
+ return JSON.parse(raw);
58
+ }
59
+ catch {
60
+ return null;
61
+ }
62
+ }
63
+ export function writeBugState(cwd, state) {
64
+ // Guard: never write state for PENDING bugIds — wait for real bugId capture.
65
+ if (state.bugId.startsWith("PENDING-"))
66
+ return;
67
+ const fp = bugStateFilePath(cwd, state.bugId);
68
+ const dir = path.dirname(fp);
69
+ fs.mkdirSync(dir, { recursive: true });
70
+ fs.writeFileSync(fp, JSON.stringify(state, null, 2), "utf8");
71
+ }
72
+ export function deleteBugState(cwd, bugId) {
73
+ // Clean up all state files for this bug (all sessions)
74
+ const cacheDir = path.join(cwd, ".forge", "cache");
75
+ const statePrefix = `fix-bug-state-${bugId}-`;
76
+ const debugPrefix = `fix-bug-debug-${bugId}`;
77
+ try {
78
+ const entries = fs.readdirSync(cacheDir);
79
+ for (const entry of entries) {
80
+ if ((entry.startsWith(statePrefix) && entry.endsWith(".json")) || entry.startsWith(debugPrefix)) {
81
+ try {
82
+ fs.unlinkSync(path.join(cacheDir, entry));
83
+ }
84
+ catch {
85
+ /* non-fatal */
86
+ }
87
+ }
88
+ }
89
+ }
90
+ catch {
91
+ // non-fatal
92
+ }
93
+ }
94
+ export function isBugStateStale(state) {
95
+ const savedAt = new Date(state.savedAt).getTime();
96
+ const ageMs = Date.now() - savedAt;
97
+ const sevenDaysMs = 7 * 24 * 60 * 60 * 1000;
98
+ return ageMs > sevenDaysMs;
99
+ }
100
+ //# sourceMappingURL=bug-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bug-state.js","sourceRoot":"","sources":["../../../../../src/extensions/forgecli/orchestrators/bug/bug-state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
2
+ import type { PhaseDescriptor } from "../run-task.js";
3
+ import type { BugRecord } from "./bug-id.js";
4
+ import type { RunBugPipelineResult } from "./run-bug-types.js";
5
+ export interface MaybeSkipParams {
6
+ phase: PhaseDescriptor;
7
+ bugId: string;
8
+ cwd: string;
9
+ ctx: ExtensionCommandContext;
10
+ storeCli: string;
11
+ /** Bug record read at the top of §6a (same read the caller already did). */
12
+ bugNow: BugRecord | null;
13
+ summaryKeyByRole: Record<string, string | null>;
14
+ }
15
+ /**
16
+ * §6a — decide whether the current phase should be skipped because the bug is
17
+ * already in a done state. When skipping, writes a synthetic summary so
18
+ * downstream `after <phase>` verdict checks succeed. Returns true when the
19
+ * caller should `currentPhaseIndex++; continue;`.
20
+ */
21
+ export declare function maybeSkipPhase(p: MaybeSkipParams): boolean;
22
+ export interface CaptureTriageBugIdParams {
23
+ bugId: string;
24
+ cwd: string;
25
+ ctx: ExtensionCommandContext;
26
+ storeCli: string;
27
+ currentPhaseIndex: number;
28
+ iterationCounts: Record<string, number>;
29
+ debugLogDisabled: boolean;
30
+ toolExecutionEvents: Array<{
31
+ toolName?: string;
32
+ result?: unknown;
33
+ }>;
34
+ }
35
+ export type CaptureTriageBugIdOutcome = {
36
+ kind: "return";
37
+ result: RunBugPipelineResult;
38
+ } | {
39
+ kind: "ok";
40
+ bugId: string;
41
+ debugLogPath: string | null;
42
+ writeDebug: (rec: Record<string, unknown>) => void;
43
+ };
44
+ /**
45
+ * Post-triage bugId capture: for new bugs the triage subagent creates the bug
46
+ * record via store-cli; capture the real id by scanning tool_execution_end
47
+ * events, with a list-and-filter fallback. On success re-initializes the debug
48
+ * log under the real id and returns the updated locals. Preserves the PENDING-
49
+ * nuance: the orchestrator transcript writer keeps the PENDING entityId — this
50
+ * only updates the loop's local bugId.
51
+ */
52
+ export declare function captureTriageBugId(p: CaptureTriageBugIdParams, writeDebug: (rec: Record<string, unknown>) => void, debugLogPath: string | null): CaptureTriageBugIdOutcome;
53
+ export interface RouteAfterTriageParams {
54
+ bugId: string;
55
+ cwd: string;
56
+ ctx: ExtensionCommandContext;
57
+ storeCli: string;
58
+ currentPhaseIndex: number;
59
+ }
60
+ export type RouteAfterTriageOutcome = {
61
+ kind: "jump";
62
+ toIndex: number;
63
+ } | {
64
+ kind: "advance";
65
+ };
66
+ /**
67
+ * §6c — orchestrator-owned post-triage status transitions, then the Path A/B
68
+ * branch read from bug.summaries.triage.route. Path A skips plan-fix +
69
+ * review-plan (jumps to implement); Path B / missing / any other value advances
70
+ * normally.
71
+ */
72
+ export declare function routeAfterTriage(p: RouteAfterTriageParams): RouteAfterTriageOutcome;
@@ -0,0 +1,204 @@
1
+ // bug-triage-routing.ts — bug-specific control flow extracted VERBATIM from
2
+ // fix-bug.ts's phase loop (FORGE-S31 file-size refactor). Two self-contained
3
+ // blocks, each a pure-ish helper the pipeline switches on:
4
+ //
5
+ // 1. maybeSkipPhase — the state-aware phase-skip heuristic (§6a): skip a
6
+ // non-review phase whose output is already reflected in the bug status,
7
+ // writing a synthetic summary so downstream predecessor-verdict checks pass.
8
+ // 2. captureTriageBugId — post-triage bugId capture (§ bugId capture): read the
9
+ // real FORGE-BUG-NNN from triage events, fall back to a list-and-filter,
10
+ // then re-initialize the debug log under the real id. Preserves the
11
+ // PENDING- nuance exactly — the transcript writer keeps the PENDING entityId.
12
+ // 3. routeAfterTriage — the orchestrator-owned post-triage status transitions
13
+ // (§6c) followed by the Path A/B branch read from bug.summaries.triage.route.
14
+ // The source-introspection contract test scans the `postTriageTransitions`
15
+ // wiring here.
16
+ //
17
+ // No logic changes; the inline `continue` / `return` paths are surfaced as small
18
+ // discriminated results.
19
+ import { spawnSync } from "node:child_process";
20
+ import * as fs from "node:fs";
21
+ import * as path from "node:path";
22
+ import { loadGovernorProjectConfig } from "../../governor-config.js";
23
+ import { BUG_PHASES, postTriageTransitions } from "./bug-phases.js";
24
+ import { extractBugIdFromEvents, readBugRecord } from "./bug-id.js";
25
+ // ── 6a. Phase skip (state-aware, defense-in-depth) ─────────────
26
+ // Belt-and-suspenders alongside the explicit summaries.triage.route
27
+ // branch (handled in routeAfterTriage below). Some subagents in some
28
+ // runtimes still go end-to-end during triage instead of just triaging
29
+ // — rather than roll back the work they did, skip non-review phases
30
+ // whose output is already reflected in the bug status. Review phases
31
+ // are never skipped — they are quality gates that must always run.
32
+ //
33
+ // Post-v0.44.0: terminal status is `fixed` only. `approved` and
34
+ // `verified` are no longer valid bug status values; references removed.
35
+ const PHASE_SKIP_STATES = {
36
+ "plan-fix": new Set(["fixed"]),
37
+ implement: new Set(["fixed"]),
38
+ commit: new Set(["fixed"]), // commit writes the terminal status; skip if already there
39
+ };
40
+ /**
41
+ * §6a — decide whether the current phase should be skipped because the bug is
42
+ * already in a done state. When skipping, writes a synthetic summary so
43
+ * downstream `after <phase>` verdict checks succeed. Returns true when the
44
+ * caller should `currentPhaseIndex++; continue;`.
45
+ */
46
+ export function maybeSkipPhase(p) {
47
+ const { phase, bugId, cwd, ctx, storeCli, bugNow, summaryKeyByRole } = p;
48
+ const skipStates = PHASE_SKIP_STATES[phase.role];
49
+ if (!(skipStates && bugNow?.status && skipStates.has(bugNow.status) && !phase.isReview)) {
50
+ return false;
51
+ }
52
+ ctx.ui.notify(`⊘ forge:fix-bug — skipping ${phase.role}: bug ${bugId} is already '${bugNow.status}' (work already done).`, "info");
53
+ // Write a synthetic "approved" summary so downstream `after` predecessor
54
+ // verdict checks find a verdict and don't block review phases.
55
+ const summaryKey = summaryKeyByRole[phase.role];
56
+ if (summaryKey) {
57
+ const synthSummary = {
58
+ objective: `Phase ${phase.role} skipped — bug already ${bugNow.status}`,
59
+ findings: ["Subagent completed fix during triage (Path A); phase output implicitly satisfied."],
60
+ // Non-review phases should have verdict "n/a" — the phase
61
+ // didn't produce a gate verdict. This matches the `after
62
+ // <phase> = n/a` preflight gate contract. Review phases
63
+ // use "approved" since they are gate phases.
64
+ verdict: phase.isReview ? "approved" : "n/a",
65
+ written_at: new Date().toISOString(),
66
+ };
67
+ const synthFile = path.join(cwd, ".forge", "cache", `synthetic-summary-${bugId}-${summaryKey}.json`);
68
+ fs.writeFileSync(synthFile, JSON.stringify(synthSummary, null, 2), "utf8");
69
+ const synthResult = spawnSync("node", [storeCli, "set-bug-summary", bugId, summaryKey, synthFile], {
70
+ cwd,
71
+ encoding: "utf8",
72
+ });
73
+ if (synthResult.status !== 0) {
74
+ ctx.ui.notify(`⚠ forge:fix-bug — synthetic summary write failed for ${phase.role}: ${String(synthResult.stderr).trim()}`, "warning");
75
+ }
76
+ try {
77
+ fs.unlinkSync(synthFile);
78
+ }
79
+ catch {
80
+ /* non-fatal */
81
+ }
82
+ }
83
+ return true;
84
+ }
85
+ /**
86
+ * Post-triage bugId capture: for new bugs the triage subagent creates the bug
87
+ * record via store-cli; capture the real id by scanning tool_execution_end
88
+ * events, with a list-and-filter fallback. On success re-initializes the debug
89
+ * log under the real id and returns the updated locals. Preserves the PENDING-
90
+ * nuance: the orchestrator transcript writer keeps the PENDING entityId — this
91
+ * only updates the loop's local bugId.
92
+ */
93
+ export function captureTriageBugId(p, writeDebug, debugLogPath) {
94
+ const { cwd, ctx, storeCli, currentPhaseIndex, iterationCounts, debugLogDisabled, toolExecutionEvents } = p;
95
+ let bugId = p.bugId;
96
+ const capturedBugId = extractBugIdFromEvents(toolExecutionEvents, loadGovernorProjectConfig(cwd).prefix);
97
+ if (capturedBugId) {
98
+ ctx.ui.notify(`forge:fix-bug — captured bug ID: ${capturedBugId}`, "info");
99
+ bugId = capturedBugId;
100
+ }
101
+ else {
102
+ // Fallback: list bugs and find the most recent one created after pipeline start.
103
+ const listResult = spawnSync("node", [storeCli, "list", "bug", "--json"], { cwd, encoding: "utf8" });
104
+ if (listResult.status === 0 && listResult.stdout) {
105
+ try {
106
+ const bugs = JSON.parse(listResult.stdout);
107
+ if (Array.isArray(bugs)) {
108
+ // Find most recent bug whose reportedAt is after the pipeline start
109
+ const pipelineStartIso = new Date(parseInt(bugId.replace("PENDING-", ""))).toISOString();
110
+ const recent = bugs
111
+ .filter((b) => b.reportedAt && b.reportedAt >= pipelineStartIso)
112
+ .sort((a, b) => String(b.reportedAt).localeCompare(String(a.reportedAt)))[0];
113
+ if (recent &&
114
+ recent.bugId &&
115
+ typeof recent.bugId === "string" &&
116
+ recent.bugId.startsWith("FORGE-BUG-")) {
117
+ bugId = recent.bugId;
118
+ ctx.ui.notify(`forge:fix-bug — captured bug ID via store fallback: ${bugId}`, "info");
119
+ }
120
+ }
121
+ }
122
+ catch {
123
+ /* parse failure — fall through to assertion */
124
+ }
125
+ }
126
+ }
127
+ // Defensive guard: if bugId is still PENDING after triage, pipeline cannot proceed.
128
+ if (bugId.startsWith("PENDING-")) {
129
+ ctx.ui.notify("× forge:fix-bug — failed to capture real bug ID after triage. Cannot proceed with PENDING placeholder.", "error");
130
+ return {
131
+ kind: "return",
132
+ result: {
133
+ status: "failed",
134
+ lastPhaseIndex: currentPhaseIndex,
135
+ iterationCounts,
136
+ lastError: "bugId still PENDING after triage",
137
+ },
138
+ };
139
+ }
140
+ // Re-initialize debug log now that real bugId is available.
141
+ if (!debugLogDisabled) {
142
+ debugLogPath = path.join(cwd, ".forge", "cache", `fix-bug-debug-${bugId}.jsonl`);
143
+ const capturedPath = debugLogPath;
144
+ writeDebug = (rec) => {
145
+ try {
146
+ fs.mkdirSync(path.dirname(capturedPath), { recursive: true });
147
+ try {
148
+ const st = fs.statSync(capturedPath);
149
+ if (st.size > 10 * 1024 * 1024) {
150
+ const all = fs.readFileSync(capturedPath, "utf8");
151
+ const lines = all.split("\n");
152
+ const keep = Math.floor(lines.length * 0.8);
153
+ fs.writeFileSync(capturedPath, lines.slice(-keep).join("\n"), "utf8");
154
+ }
155
+ }
156
+ catch {
157
+ /* file may not exist yet */
158
+ }
159
+ fs.appendFileSync(capturedPath, `${JSON.stringify({ ts: new Date().toISOString(), phase: "triage", ...rec })}\n`, "utf8");
160
+ }
161
+ catch {
162
+ // non-fatal
163
+ }
164
+ };
165
+ writeDebug({ kind: "bugid_captured", bugId });
166
+ }
167
+ return { kind: "ok", bugId, debugLogPath, writeDebug };
168
+ }
169
+ /**
170
+ * §6c — orchestrator-owned post-triage status transitions, then the Path A/B
171
+ * branch read from bug.summaries.triage.route. Path A skips plan-fix +
172
+ * review-plan (jumps to implement); Path B / missing / any other value advances
173
+ * normally.
174
+ */
175
+ export function routeAfterTriage(p) {
176
+ const { bugId, cwd, ctx, storeCli, currentPhaseIndex } = p;
177
+ const bugAfterTriage = readBugRecord(bugId, storeCli, cwd);
178
+ // Orchestrator-owned post-triage transitions (meta-fix-bug.md
179
+ // step 2). Two sequential writes through store-cli (the FSM
180
+ // authority); failure warns but does not halt — the commit
181
+ // phase's status guard is the backstop.
182
+ for (const target of postTriageTransitions(bugAfterTriage?.status)) {
183
+ const upd = spawnSync("node", [storeCli, "update-status", "bug", bugId, "status", target], {
184
+ cwd,
185
+ encoding: "utf8",
186
+ });
187
+ if (upd.status !== 0) {
188
+ ctx.ui.notify(`⚠ forge:fix-bug — post-triage transition to '${target}' failed: ${(upd.stderr ?? "").toString().trim()}`, "warning");
189
+ break;
190
+ }
191
+ }
192
+ const triageSummary = bugAfterTriage?.summaries?.triage;
193
+ const route = triageSummary?.route;
194
+ if (route === "A") {
195
+ const skipUntilIndex = BUG_PHASES.findIndex((ph) => ph.role === "implement");
196
+ if (skipUntilIndex > currentPhaseIndex + 1) {
197
+ ctx.ui.notify(`⊘ forge:fix-bug — Path A selected by triage; skipping plan-fix and review-plan.`, "info");
198
+ return { kind: "jump", toIndex: skipUntilIndex };
199
+ }
200
+ }
201
+ // route === "B", missing, or any other value → fall through to standard advance
202
+ return { kind: "advance" };
203
+ }
204
+ //# sourceMappingURL=bug-triage-routing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bug-triage-routing.js","sourceRoot":"","sources":["../../../../../src/extensions/forgecli/orchestrators/bug/bug-triage-routing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
2
+ import type { MergedConfig } from "../../config/config-layer.js";
3
+ import type { OrchestratorTranscriptWriter } from "../../subagent/orchestrator-transcript.js";
4
+ import { type PhaseDescriptor } from "../run-task.js";
5
+ import type { RunBugPipelineResult } from "./run-bug-types.js";
6
+ export type BugVerdictLoopOutcome = {
7
+ kind: "advance";
8
+ } | {
9
+ kind: "loopback";
10
+ toIndex: number;
11
+ } | {
12
+ kind: "return";
13
+ result: RunBugPipelineResult;
14
+ };
15
+ export interface BugVerdictLoopParams {
16
+ phase: PhaseDescriptor;
17
+ bugId: string;
18
+ storeCli: string;
19
+ cwd: string;
20
+ forgeRoot: string;
21
+ iterationCounts: Record<string, number>;
22
+ currentPhaseIndex: number;
23
+ modelRoutingConfig: MergedConfig;
24
+ ctx: ExtensionCommandContext;
25
+ orchTranscript: OrchestratorTranscriptWriter;
26
+ /** Per-role phase-summary key map (BUG_SUMMARY_KEY_BY_ROLE). */
27
+ summaryKeyByRole: Record<string, string | null>;
28
+ /** Closure that finalizes this dispatch's OrchestratorTree node. */
29
+ finishPhaseNode: (status: "completed" | "failed" | "escalated") => void;
30
+ /** Per-phase completion-recovery guard (forge-engineering#41) — roles that
31
+ * already consumed their one set-bug-summary recovery attempt this run. */
32
+ recoveredPhases: Set<string>;
33
+ }
34
+ /**
35
+ * Evaluate the review-phase verdict and decide the loop's next move.
36
+ * Mirrors the inline block that previously lived in runBugPipelineInner.
37
+ */
38
+ export declare function handleBugReviewVerdict(p: BugVerdictLoopParams): BugVerdictLoopOutcome;
@@ -0,0 +1,166 @@
1
+ // bug-verdict-loop.ts — review-phase verdict + revision/loopback handling for
2
+ // the fix-bug pipeline. Extracted VERBATIM from fix-bug.ts's phase loop
3
+ // (FORGE-S31 file-size refactor) as a pure decision function: it performs the
4
+ // same store reads, ctx.ui notifications, state writes, transcript records,
5
+ // tree-node finalization, status-reset transition, and halt-advisor dispatch the
6
+ // inline block did, and returns a small discriminated result the caller's loop
7
+ // switches on.
8
+ //
9
+ // Behavior-preserving: no logic changes. The only structural change is that the
10
+ // inline `return {...}` paths now return `{ kind: "return"; result }`, the
11
+ // `continue` path returns `{ kind: "loopback"; toIndex }`, and the fall-through
12
+ // (approved) path returns `{ kind: "advance" }`.
13
+ import { spawnSync } from "node:child_process";
14
+ import { resolveAdvisorModel, runHaltAdvisor } from "../halt-advisor.js";
15
+ import { recoverPhaseSummary } from "../common/summary-recovery.js";
16
+ import { findPredecessorIndex } from "../run-task.js";
17
+ import { BUG_PHASES } from "./bug-phases.js";
18
+ import { readBugRecord } from "./bug-id.js";
19
+ import { writeBugState } from "./bug-state.js";
20
+ import { readBugVerdict } from "./bug-verdict.js";
21
+ /**
22
+ * Evaluate the review-phase verdict and decide the loop's next move.
23
+ * Mirrors the inline block that previously lived in runBugPipelineInner.
24
+ */
25
+ export function handleBugReviewVerdict(p) {
26
+ const { phase, bugId, storeCli, cwd, forgeRoot, iterationCounts, currentPhaseIndex, modelRoutingConfig, ctx } = p;
27
+ const { orchTranscript, finishPhaseNode, summaryKeyByRole, recoveredPhases } = p;
28
+ // Re-read bug record for latest status after subagent ran
29
+ const updatedBugRecord = readBugRecord(bugId, storeCli, cwd);
30
+ let verdict = readBugVerdict(updatedBugRecord, phase.role, summaryKeyByRole);
31
+ // Completion recovery (forge-engineering#41): a clean stop with no verdict in
32
+ // the store is most often the subagent writing the {PHASE}-SUMMARY.json
33
+ // sidecar but eliding the set-bug-summary that registers it. Register the
34
+ // sidecar ourselves (once per phase), then re-read. Phases whose verdict comes
35
+ // from bug.status (e.g. commit → summaryKey null) are not recoverable this way.
36
+ if (verdict === "missing") {
37
+ const summaryKey = summaryKeyByRole[phase.role];
38
+ if (summaryKey && !recoveredPhases.has(phase.role)) {
39
+ recoveredPhases.add(phase.role);
40
+ const rec = recoverPhaseSummary({
41
+ storeCli,
42
+ entityId: bugId,
43
+ summaryKey,
44
+ cwd,
45
+ summaryVerb: "set-bug-summary",
46
+ });
47
+ if (rec.ok) {
48
+ const recheck = readBugVerdict(readBugRecord(bugId, storeCli, cwd), phase.role, summaryKeyByRole);
49
+ if (recheck !== "missing") {
50
+ ctx.ui.notify(`⟳ forge:fix-bug — ${phase.role}: subagent skipped set-bug-summary; orchestrator registered ` +
51
+ `the '${summaryKey}' sidecar and the verdict is now present.`, "info");
52
+ verdict = recheck;
53
+ }
54
+ }
55
+ }
56
+ }
57
+ if (verdict === "missing") {
58
+ ctx.ui.notify(`× forge:fix-bug — verdict missing for phase ${phase.role} after subagent completed. Halting for advisory.`, "error");
59
+ finishPhaseNode("failed");
60
+ writeBugState(cwd, {
61
+ bugId,
62
+ phaseIndex: currentPhaseIndex,
63
+ iterationCounts,
64
+ halted: true,
65
+ lastError: `verdict missing for ${phase.role}`,
66
+ savedAt: new Date().toISOString(),
67
+ });
68
+ // A missing verdict IS a postflight-outputs failure: the canonical
69
+ // phase summary the subagent must write (e.g. summaries.code_review,
70
+ // linked via set-bug-summary) was never recorded, so there is no
71
+ // verdict to route on. Route it through the halt-recovery advisor
72
+ // (FORGE-S26-T18) — the same hand-off the preflight/postflight gate
73
+ // failures use — instead of a bare escalation. Best-effort, non-fatal.
74
+ const advisorModel = resolveAdvisorModel(modelRoutingConfig, ctx.model);
75
+ void runHaltAdvisor({
76
+ gateFailure: {
77
+ phase: phase.role,
78
+ reasonCode: "verdict-missing",
79
+ detail: `Phase '${phase.role}' completed but no verdict was found in the store. ` +
80
+ "The canonical phase summary was not written, so the orchestrator has no verdict to route on.",
81
+ remediation: "Re-run the phase and ensure the subagent's forge_store set-bug-summary call " +
82
+ 'uses args:["<bugId>", "<phaseKey>"] with the literal phase key as args[1] ' +
83
+ "(e.g. code_review), and that the call exits zero before the subagent returns.",
84
+ },
85
+ advisorModel,
86
+ taskId: bugId,
87
+ cwd,
88
+ ctx: { ui: ctx.ui },
89
+ forgeRoot,
90
+ });
91
+ return {
92
+ kind: "return",
93
+ result: {
94
+ status: "halted",
95
+ lastPhaseIndex: currentPhaseIndex,
96
+ iterationCounts,
97
+ lastError: `verdict missing for ${phase.role}`,
98
+ },
99
+ };
100
+ }
101
+ if (verdict === "revision") {
102
+ iterationCounts[phase.role] = (iterationCounts[phase.role] ?? 0) + 1;
103
+ if (iterationCounts[phase.role] >= phase.maxIterations) {
104
+ ctx.ui.notify(`× forge:fix-bug — revision cap reached for phase ${phase.role} ` +
105
+ `(${iterationCounts[phase.role]}/${phase.maxIterations} iterations). Escalating.`, "error");
106
+ finishPhaseNode("escalated");
107
+ writeBugState(cwd, {
108
+ bugId,
109
+ phaseIndex: currentPhaseIndex,
110
+ iterationCounts,
111
+ halted: true,
112
+ lastError: `revision cap reached for ${phase.role}`,
113
+ savedAt: new Date().toISOString(),
114
+ });
115
+ return {
116
+ kind: "return",
117
+ result: {
118
+ status: "escalated",
119
+ lastPhaseIndex: currentPhaseIndex,
120
+ iterationCounts,
121
+ lastError: `revision cap reached for ${phase.role}`,
122
+ },
123
+ };
124
+ }
125
+ // Transition bug back to in-progress before re-dispatching implement.
126
+ // This is required for review-code → implement and approve → implement loops.
127
+ const currentBugStatus = updatedBugRecord?.status;
128
+ if (currentBugStatus === "fixed" || currentBugStatus === "approved") {
129
+ const transitionResult = spawnSync("node", [storeCli, "update-status", "bug", bugId, "status", "in-progress"], { cwd, encoding: "utf8" });
130
+ if (transitionResult.status !== 0) {
131
+ ctx.ui.notify(`⚠ forge:fix-bug — failed to transition bug ${bugId} from ${currentBugStatus} to in-progress: ${transitionResult.stderr ?? "unknown"}`, "warning");
132
+ }
133
+ else {
134
+ ctx.ui.notify(`⟳ forge:fix-bug — transitioned bug ${bugId}: ${currentBugStatus} → in-progress`, "info");
135
+ }
136
+ }
137
+ // The review subagent itself finished cleanly — `revision`
138
+ // is its verdict, not a failure — so its node closes as
139
+ // completed before the predecessor re-dispatches under a
140
+ // fresh node ID.
141
+ finishPhaseNode("completed");
142
+ const predIndex = findPredecessorIndex(BUG_PHASES, currentPhaseIndex);
143
+ ctx.ui.notify(`⟳ forge:fix-bug — ${phase.role} returned revision; looping to ${BUG_PHASES[predIndex]?.role ?? predIndex} ` +
144
+ `(attempt ${iterationCounts[phase.role]}/${phase.maxIterations})`, "info");
145
+ orchTranscript.record({
146
+ kind: "phase-loopback",
147
+ ts: new Date().toISOString(),
148
+ fromPhase: phase.role,
149
+ toPhase: BUG_PHASES[predIndex]?.role ?? String(predIndex),
150
+ fromPhaseIndex: currentPhaseIndex,
151
+ toPhaseIndex: predIndex,
152
+ reason: `${phase.role} returned revision (attempt ${iterationCounts[phase.role]}/${phase.maxIterations})`,
153
+ });
154
+ writeBugState(cwd, {
155
+ bugId,
156
+ phaseIndex: predIndex,
157
+ iterationCounts,
158
+ halted: false,
159
+ savedAt: new Date().toISOString(),
160
+ });
161
+ return { kind: "loopback", toIndex: predIndex };
162
+ }
163
+ // verdict === "approved": fall through to advance
164
+ return { kind: "advance" };
165
+ }
166
+ //# sourceMappingURL=bug-verdict-loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bug-verdict-loop.js","sourceRoot":"","sources":["../../../../../src/extensions/forgecli/orchestrators/bug/bug-verdict-loop.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { BugRecord } from "./bug-id.js";
2
+ export type BugVerdict = "approved" | "revision" | "n/a" | "missing";
3
+ export declare function readBugVerdict(bugRecord: BugRecord | null, phaseRole: string, summaryKeyByRole: Record<string, string | null>): BugVerdict;