@entelligentsia/forgecli 1.0.36 → 1.0.40

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 (654) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/dist/CHANGELOG-forge-plugin.md +101 -0
  3. package/dist/CHANGELOG-pi.md +143 -0
  4. package/dist/bin/argv.d.ts +1 -1
  5. package/dist/bin/argv.js +12 -0
  6. package/dist/bin/argv.js.map +1 -1
  7. package/dist/bin/forge.js +18 -16
  8. package/dist/bin/forge.js.map +1 -1
  9. package/dist/bin/reset.d.ts +39 -0
  10. package/dist/bin/reset.js +101 -0
  11. package/dist/bin/reset.js.map +1 -0
  12. package/dist/extensions/forgecli/claude-bootstrap/bootstrap.js +56 -265
  13. package/dist/extensions/forgecli/claude-bootstrap/bootstrap.js.map +1 -1
  14. package/dist/extensions/forgecli/claude-bootstrap/uninstall.js +52 -32
  15. package/dist/extensions/forgecli/claude-bootstrap/uninstall.js.map +1 -1
  16. package/dist/extensions/forgecli/commands/reset.d.ts +16 -0
  17. package/dist/extensions/forgecli/commands/reset.js +83 -0
  18. package/dist/extensions/forgecli/commands/reset.js.map +1 -0
  19. package/dist/extensions/forgecli/forge-commands.d.ts +7 -2
  20. package/dist/extensions/forgecli/forge-commands.js +19 -5
  21. package/dist/extensions/forgecli/forge-commands.js.map +1 -1
  22. package/dist/extensions/forgecli/forge-subagent.d.ts +4 -4
  23. package/dist/extensions/forgecli/hooks/forge-permissions.js +20 -6
  24. package/dist/extensions/forgecli/hooks/forge-permissions.js.map +1 -1
  25. package/dist/extensions/forgecli/index.js +6 -3
  26. package/dist/extensions/forgecli/index.js.map +1 -1
  27. package/dist/extensions/forgecli/lib/forge-root.d.ts +6 -0
  28. package/dist/extensions/forgecli/lib/forge-root.js +52 -0
  29. package/dist/extensions/forgecli/lib/forge-root.js.map +1 -1
  30. package/dist/extensions/forgecli/lib/payload-manifest.d.ts +62 -0
  31. package/dist/extensions/forgecli/lib/payload-manifest.js +151 -0
  32. package/dist/extensions/forgecli/lib/payload-manifest.js.map +1 -0
  33. package/dist/extensions/forgecli/orchestrators/advisory-render.d.ts +9 -0
  34. package/dist/extensions/forgecli/orchestrators/advisory-render.js +107 -0
  35. package/dist/extensions/forgecli/orchestrators/advisory-render.js.map +1 -0
  36. package/dist/extensions/forgecli/orchestrators/bug/bug-phases.d.ts +3 -0
  37. package/dist/extensions/forgecli/orchestrators/bug/bug-phases.js +22 -0
  38. package/dist/extensions/forgecli/orchestrators/bug/bug-phases.js.map +1 -1
  39. package/dist/extensions/forgecli/orchestrators/bug/bug-verdict-loop.d.ts +1 -1
  40. package/dist/extensions/forgecli/orchestrators/bug/bug-verdict-loop.js +34 -2
  41. package/dist/extensions/forgecli/orchestrators/bug/bug-verdict-loop.js.map +1 -1
  42. package/dist/extensions/forgecli/orchestrators/bug/run-bug-pipeline.js +2 -2
  43. package/dist/extensions/forgecli/orchestrators/bug/run-bug-pipeline.js.map +1 -1
  44. package/dist/extensions/forgecli/orchestrators/common/recovery-menu.d.ts +24 -0
  45. package/dist/extensions/forgecli/orchestrators/common/recovery-menu.js +58 -0
  46. package/dist/extensions/forgecli/orchestrators/common/recovery-menu.js.map +1 -0
  47. package/dist/extensions/forgecli/orchestrators/common/reset-pipeline.d.ts +53 -0
  48. package/dist/extensions/forgecli/orchestrators/common/reset-pipeline.js +131 -0
  49. package/dist/extensions/forgecli/orchestrators/common/reset-pipeline.js.map +1 -0
  50. package/dist/extensions/forgecli/orchestrators/halt-advisor.js +25 -3
  51. package/dist/extensions/forgecli/orchestrators/halt-advisor.js.map +1 -1
  52. package/dist/extensions/forgecli/orchestrators/task/run-task-pipeline.js +3 -3
  53. package/dist/extensions/forgecli/orchestrators/task/run-task-pipeline.js.map +1 -1
  54. package/dist/extensions/forgecli/orchestrators/task/task-phases.d.ts +3 -0
  55. package/dist/extensions/forgecli/orchestrators/task/task-phases.js +22 -0
  56. package/dist/extensions/forgecli/orchestrators/task/task-phases.js.map +1 -1
  57. package/dist/extensions/forgecli/orchestrators/task/task-verdict-loop.d.ts +1 -1
  58. package/dist/extensions/forgecli/orchestrators/task/task-verdict-loop.js +37 -2
  59. package/dist/extensions/forgecli/orchestrators/task/task-verdict-loop.js.map +1 -1
  60. package/dist/extensions/forgecli/store/store-resolver.d.ts +15 -0
  61. package/dist/extensions/forgecli/store/store-resolver.js +118 -18
  62. package/dist/extensions/forgecli/store/store-resolver.js.map +1 -1
  63. package/dist/forge-payload/.claude-plugin/plugin.json +1 -1
  64. package/dist/forge-payload/.schemas/enum-catalog.json +2 -2
  65. package/dist/forge-payload/.schemas/migrations.json +85 -0
  66. package/dist/forge-payload/.schemas/payload-manifest.schema.json +100 -0
  67. package/dist/forge-payload/commands/check-agent.md +7 -23
  68. package/dist/forge-payload/commands/enhance.md +31 -5
  69. package/dist/forge-payload/commands/init.md +161 -97
  70. package/dist/forge-payload/commands/reset.md +117 -0
  71. package/dist/forge-payload/hooks/forge-permissions.cjs +29 -6
  72. package/dist/forge-payload/init/phases/phase-3-materialize.md +5 -1
  73. package/dist/forge-payload/integrity.json +22 -7
  74. package/dist/forge-payload/payload-manifest.json +314 -0
  75. package/dist/forge-payload/schemas/enum-catalog.json +2 -2
  76. package/dist/forge-payload/schemas/payload-manifest.schema.json +100 -0
  77. package/dist/forge-payload/schemas/structure-manifest.json +4 -2
  78. package/dist/forge-payload/tools/reset-plan.cjs +210 -0
  79. package/dist/forge-payload/tools/store.cjs +4 -1
  80. package/dist/forge-payload/tools/substitute-placeholders.cjs +10 -2
  81. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  82. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js +8 -0
  83. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js.map +1 -1
  84. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.d.ts +1 -1
  85. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.d.ts.map +1 -1
  86. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js +1 -1
  87. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js.map +1 -1
  88. package/node_modules/@earendil-works/pi-agent-core/dist/harness/execution-env.d.ts +4 -0
  89. package/node_modules/@earendil-works/pi-agent-core/dist/harness/execution-env.d.ts.map +1 -0
  90. package/node_modules/@earendil-works/pi-agent-core/dist/harness/execution-env.js +3 -0
  91. package/node_modules/@earendil-works/pi-agent-core/dist/harness/execution-env.js.map +1 -0
  92. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/jsonl.d.ts +20 -0
  93. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/jsonl.d.ts.map +1 -0
  94. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/jsonl.js +92 -0
  95. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/jsonl.js.map +1 -0
  96. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/memory.d.ts +18 -0
  97. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/memory.d.ts.map +1 -0
  98. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/memory.js +42 -0
  99. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/memory.js.map +1 -0
  100. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/shared.d.ts +10 -0
  101. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/shared.d.ts.map +1 -0
  102. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/shared.js +31 -0
  103. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/shared.js.map +1 -0
  104. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/jsonl.d.ts +30 -0
  105. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/jsonl.d.ts.map +1 -0
  106. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/jsonl.js +170 -0
  107. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/jsonl.js.map +1 -0
  108. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/memory.d.ts +26 -0
  109. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/memory.d.ts.map +1 -0
  110. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/memory.js +90 -0
  111. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/memory.js.map +1 -0
  112. package/node_modules/@earendil-works/pi-agent-core/dist/types.d.ts +6 -1
  113. package/node_modules/@earendil-works/pi-agent-core/dist/types.d.ts.map +1 -1
  114. package/node_modules/@earendil-works/pi-agent-core/dist/types.js.map +1 -1
  115. package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
  116. package/node_modules/@earendil-works/pi-ai/README.md +12 -4
  117. package/node_modules/@earendil-works/pi-ai/dist/env-api-keys.d.ts.map +1 -1
  118. package/node_modules/@earendil-works/pi-ai/dist/env-api-keys.js +3 -0
  119. package/node_modules/@earendil-works/pi-ai/dist/env-api-keys.js.map +1 -1
  120. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts +45 -0
  121. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts.map +1 -1
  122. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js +45 -0
  123. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js.map +1 -1
  124. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +1804 -815
  125. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
  126. package/node_modules/@earendil-works/pi-ai/dist/models.generated.js +2031 -1384
  127. package/node_modules/@earendil-works/pi-ai/dist/models.generated.js.map +1 -1
  128. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.d.ts.map +1 -1
  129. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js +71 -27
  130. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
  131. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.d.ts +1 -1
  132. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  133. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js +24 -16
  134. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js.map +1 -1
  135. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
  136. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js +1 -0
  137. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
  138. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
  139. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js +3 -1
  140. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  141. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  142. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js +35 -13
  143. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js.map +1 -1
  144. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.d.ts.map +1 -1
  145. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.js +2 -1
  146. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.js.map +1 -1
  147. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
  148. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js +1 -0
  149. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js.map +1 -1
  150. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +12 -4
  151. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
  152. package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
  153. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
  154. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.js +13 -1
  155. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
  156. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.d.ts.map +1 -1
  157. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.js +4 -2
  158. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.js.map +1 -1
  159. package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.d.ts +1 -1
  160. package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.d.ts.map +1 -1
  161. package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.js +3 -2
  162. package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.js.map +1 -1
  163. package/node_modules/@earendil-works/pi-ai/package.json +1 -1
  164. package/node_modules/@earendil-works/pi-coding-agent/CHANGELOG.md +143 -0
  165. package/node_modules/@earendil-works/pi-coding-agent/README.md +26 -4
  166. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.d.ts +1 -0
  167. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.d.ts.map +1 -1
  168. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.js +11 -0
  169. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.js.map +1 -1
  170. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/project-trust.d.ts +10 -0
  171. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/project-trust.d.ts.map +1 -0
  172. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/project-trust.js +48 -0
  173. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/project-trust.js.map +1 -0
  174. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/startup-ui.d.ts +17 -0
  175. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/startup-ui.d.ts.map +1 -0
  176. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/startup-ui.js +128 -0
  177. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/startup-ui.js.map +1 -0
  178. package/node_modules/@earendil-works/pi-coding-agent/dist/config.d.ts.map +1 -1
  179. package/node_modules/@earendil-works/pi-coding-agent/dist/config.js +9 -1
  180. package/node_modules/@earendil-works/pi-coding-agent/dist/config.js.map +1 -1
  181. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-runtime.d.ts +3 -1
  182. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-runtime.d.ts.map +1 -1
  183. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-runtime.js +4 -1
  184. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-runtime.js.map +1 -1
  185. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.d.ts +2 -1
  186. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.d.ts.map +1 -1
  187. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.js +2 -2
  188. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.js.map +1 -1
  189. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.d.ts +4 -1
  190. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  191. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js +16 -3
  192. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  193. package/node_modules/@earendil-works/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  194. package/node_modules/@earendil-works/pi-coding-agent/dist/core/auth-storage.js +4 -3
  195. package/node_modules/@earendil-works/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  196. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts +3 -1
  197. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  198. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/branch-summarization.js +9 -3
  199. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/branch-summarization.js.map +1 -1
  200. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/utils.d.ts +1 -1
  201. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/utils.d.ts.map +1 -1
  202. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/utils.js +1 -1
  203. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/utils.js.map +1 -1
  204. package/node_modules/@earendil-works/pi-coding-agent/dist/core/experimental.d.ts +2 -0
  205. package/node_modules/@earendil-works/pi-coding-agent/dist/core/experimental.d.ts.map +1 -0
  206. package/node_modules/@earendil-works/pi-coding-agent/dist/core/experimental.js +4 -0
  207. package/node_modules/@earendil-works/pi-coding-agent/dist/core/experimental.js.map +1 -0
  208. package/node_modules/@earendil-works/pi-coding-agent/dist/core/export-html/template.js +19 -6
  209. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
  210. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
  211. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
  212. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/loader.d.ts +1 -1
  213. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  214. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/loader.js +4 -4
  215. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  216. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.d.ts +10 -3
  217. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  218. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.js +47 -1
  219. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  220. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/types.d.ts +28 -2
  221. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  222. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  223. package/node_modules/@earendil-works/pi-coding-agent/dist/core/footer-data-provider.d.ts +2 -0
  224. package/node_modules/@earendil-works/pi-coding-agent/dist/core/footer-data-provider.d.ts.map +1 -1
  225. package/node_modules/@earendil-works/pi-coding-agent/dist/core/footer-data-provider.js +29 -1
  226. package/node_modules/@earendil-works/pi-coding-agent/dist/core/footer-data-provider.js.map +1 -1
  227. package/node_modules/@earendil-works/pi-coding-agent/dist/core/index.d.ts +1 -0
  228. package/node_modules/@earendil-works/pi-coding-agent/dist/core/index.d.ts.map +1 -1
  229. package/node_modules/@earendil-works/pi-coding-agent/dist/core/index.js +1 -0
  230. package/node_modules/@earendil-works/pi-coding-agent/dist/core/index.js.map +1 -1
  231. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  232. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.js +1 -0
  233. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  234. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.d.ts +1 -0
  235. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
  236. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.js +44 -5
  237. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  238. package/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.d.ts +3 -0
  239. package/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
  240. package/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.js +47 -13
  241. package/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.js.map +1 -1
  242. package/node_modules/@earendil-works/pi-coding-agent/dist/core/project-trust.d.ts +15 -0
  243. package/node_modules/@earendil-works/pi-coding-agent/dist/core/project-trust.d.ts.map +1 -0
  244. package/node_modules/@earendil-works/pi-coding-agent/dist/core/project-trust.js +58 -0
  245. package/node_modules/@earendil-works/pi-coding-agent/dist/core/project-trust.js.map +1 -0
  246. package/node_modules/@earendil-works/pi-coding-agent/dist/core/prompt-templates.d.ts +2 -1
  247. package/node_modules/@earendil-works/pi-coding-agent/dist/core/prompt-templates.d.ts.map +1 -1
  248. package/node_modules/@earendil-works/pi-coding-agent/dist/core/prompt-templates.js +24 -26
  249. package/node_modules/@earendil-works/pi-coding-agent/dist/core/prompt-templates.js.map +1 -1
  250. package/node_modules/@earendil-works/pi-coding-agent/dist/core/provider-attribution.d.ts +4 -0
  251. package/node_modules/@earendil-works/pi-coding-agent/dist/core/provider-attribution.d.ts.map +1 -0
  252. package/node_modules/@earendil-works/pi-coding-agent/dist/core/provider-attribution.js +72 -0
  253. package/node_modules/@earendil-works/pi-coding-agent/dist/core/provider-attribution.js.map +1 -0
  254. package/node_modules/@earendil-works/pi-coding-agent/dist/core/provider-display-names.d.ts.map +1 -1
  255. package/node_modules/@earendil-works/pi-coding-agent/dist/core/provider-display-names.js +3 -0
  256. package/node_modules/@earendil-works/pi-coding-agent/dist/core/provider-display-names.js.map +1 -1
  257. package/node_modules/@earendil-works/pi-coding-agent/dist/core/resource-loader.d.ts +13 -2
  258. package/node_modules/@earendil-works/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
  259. package/node_modules/@earendil-works/pi-coding-agent/dist/core/resource-loader.js +112 -37
  260. package/node_modules/@earendil-works/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  261. package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  262. package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.js +7 -33
  263. package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.js.map +1 -1
  264. package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  265. package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js +103 -70
  266. package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  267. package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.d.ts +20 -2
  268. package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  269. package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.js +97 -30
  270. package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  271. package/node_modules/@earendil-works/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
  272. package/node_modules/@earendil-works/pi-coding-agent/dist/core/slash-commands.js +1 -0
  273. package/node_modules/@earendil-works/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
  274. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
  275. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/bash.js +1 -1
  276. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  277. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/find.d.ts.map +1 -1
  278. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/find.js +1 -1
  279. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/find.js.map +1 -1
  280. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/grep.d.ts.map +1 -1
  281. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/grep.js +1 -1
  282. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/grep.js.map +1 -1
  283. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/ls.d.ts.map +1 -1
  284. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/ls.js +1 -1
  285. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/ls.js.map +1 -1
  286. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
  287. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.js +1 -1
  288. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.js.map +1 -1
  289. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
  290. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.js +1 -1
  291. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.js.map +1 -1
  292. package/node_modules/@earendil-works/pi-coding-agent/dist/core/trust-manager.d.ts +36 -0
  293. package/node_modules/@earendil-works/pi-coding-agent/dist/core/trust-manager.d.ts.map +1 -0
  294. package/node_modules/@earendil-works/pi-coding-agent/dist/core/trust-manager.js +202 -0
  295. package/node_modules/@earendil-works/pi-coding-agent/dist/core/trust-manager.js.map +1 -0
  296. package/node_modules/@earendil-works/pi-coding-agent/dist/index.d.ts +5 -4
  297. package/node_modules/@earendil-works/pi-coding-agent/dist/index.d.ts.map +1 -1
  298. package/node_modules/@earendil-works/pi-coding-agent/dist/index.js +2 -1
  299. package/node_modules/@earendil-works/pi-coding-agent/dist/index.js.map +1 -1
  300. package/node_modules/@earendil-works/pi-coding-agent/dist/main.d.ts.map +1 -1
  301. package/node_modules/@earendil-works/pi-coding-agent/dist/main.js +72 -32
  302. package/node_modules/@earendil-works/pi-coding-agent/dist/main.js.map +1 -1
  303. package/node_modules/@earendil-works/pi-coding-agent/dist/migrations.d.ts.map +1 -1
  304. package/node_modules/@earendil-works/pi-coding-agent/dist/migrations.js +39 -34
  305. package/node_modules/@earendil-works/pi-coding-agent/dist/migrations.js.map +1 -1
  306. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/index.d.ts +1 -1
  307. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/index.d.ts.map +1 -1
  308. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/index.js.map +1 -1
  309. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  310. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +2 -2
  311. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
  312. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/first-time-setup.d.ts +25 -0
  313. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -0
  314. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/first-time-setup.js +103 -0
  315. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/first-time-setup.js.map +1 -0
  316. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  317. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/footer.js +7 -0
  318. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  319. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/index.d.ts +2 -0
  320. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/index.d.ts.map +1 -1
  321. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/index.js +2 -0
  322. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/index.js.map +1 -1
  323. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts +1 -1
  324. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  325. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +10 -13
  326. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.js.map +1 -1
  327. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +3 -1
  328. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  329. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +20 -0
  330. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  331. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  332. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +22 -0
  333. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  334. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/trust-selector.d.ts +23 -0
  335. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/trust-selector.d.ts.map +1 -0
  336. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/trust-selector.js +91 -0
  337. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/trust-selector.js.map +1 -0
  338. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +7 -0
  339. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  340. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js +101 -5
  341. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  342. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/print-mode.d.ts.map +1 -1
  343. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/print-mode.js +1 -0
  344. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/print-mode.js.map +1 -1
  345. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  346. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js +1 -0
  347. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  348. package/node_modules/@earendil-works/pi-coding-agent/dist/package-manager-cli.d.ts +6 -2
  349. package/node_modules/@earendil-works/pi-coding-agent/dist/package-manager-cli.d.ts.map +1 -1
  350. package/node_modules/@earendil-works/pi-coding-agent/dist/package-manager-cli.js +111 -10
  351. package/node_modules/@earendil-works/pi-coding-agent/dist/package-manager-cli.js.map +1 -1
  352. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/changelog.d.ts +1 -0
  353. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/changelog.d.ts.map +1 -1
  354. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/changelog.js +78 -0
  355. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/changelog.js.map +1 -1
  356. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/git.d.ts.map +1 -1
  357. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/git.js +54 -22
  358. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/git.js.map +1 -1
  359. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/open-browser.d.ts +9 -0
  360. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/open-browser.d.ts.map +1 -0
  361. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/open-browser.js +22 -0
  362. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/open-browser.js.map +1 -0
  363. package/node_modules/@earendil-works/pi-coding-agent/docs/containerization.md +111 -0
  364. package/node_modules/@earendil-works/pi-coding-agent/docs/docs.json +8 -0
  365. package/node_modules/@earendil-works/pi-coding-agent/docs/extensions.md +67 -13
  366. package/node_modules/@earendil-works/pi-coding-agent/docs/index.md +2 -0
  367. package/node_modules/@earendil-works/pi-coding-agent/docs/models.md +4 -3
  368. package/node_modules/@earendil-works/pi-coding-agent/docs/packages.md +1 -1
  369. package/node_modules/@earendil-works/pi-coding-agent/docs/prompt-templates.md +9 -2
  370. package/node_modules/@earendil-works/pi-coding-agent/docs/providers.md +5 -0
  371. package/node_modules/@earendil-works/pi-coding-agent/docs/rpc.md +1 -1
  372. package/node_modules/@earendil-works/pi-coding-agent/docs/sdk.md +5 -0
  373. package/node_modules/@earendil-works/pi-coding-agent/docs/security.md +59 -0
  374. package/node_modules/@earendil-works/pi-coding-agent/docs/settings.md +15 -0
  375. package/node_modules/@earendil-works/pi-coding-agent/docs/skills.md +1 -1
  376. package/node_modules/@earendil-works/pi-coding-agent/docs/terminal-setup.md +36 -2
  377. package/node_modules/@earendil-works/pi-coding-agent/docs/themes.md +1 -1
  378. package/node_modules/@earendil-works/pi-coding-agent/docs/tmux.md +4 -2
  379. package/node_modules/@earendil-works/pi-coding-agent/docs/tui.md +10 -1
  380. package/node_modules/@earendil-works/pi-coding-agent/docs/usage.md +19 -2
  381. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/README.md +2 -0
  382. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-header.ts +1 -1
  383. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-anthropic/package.json +1 -1
  384. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  385. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/doom-overlay/index.ts +1 -1
  386. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/gondolin/index.ts +531 -0
  387. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/gondolin/package-lock.json +185 -0
  388. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/gondolin/package.json +19 -0
  389. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/handoff.ts +1 -1
  390. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/interactive-shell.ts +1 -1
  391. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/overlay-qa-tests.ts +152 -81
  392. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/project-trust.ts +64 -0
  393. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/qna.ts +1 -1
  394. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/question.ts +1 -1
  395. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/questionnaire.ts +1 -1
  396. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/sandbox/package.json +1 -1
  397. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/snake.ts +1 -1
  398. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/space-invaders.ts +1 -1
  399. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/summarize.ts +1 -1
  400. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/tic-tac-toe.ts +1 -1
  401. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/todo.ts +1 -1
  402. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/tools.ts +5 -0
  403. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/with-deps/package.json +1 -1
  404. package/node_modules/@earendil-works/pi-coding-agent/npm-shrinkwrap.json +12 -419
  405. package/node_modules/@earendil-works/pi-coding-agent/package.json +5 -8
  406. package/node_modules/@earendil-works/pi-tui/README.md +13 -1
  407. package/node_modules/@earendil-works/pi-tui/dist/autocomplete.d.ts +2 -0
  408. package/node_modules/@earendil-works/pi-tui/dist/autocomplete.d.ts.map +1 -1
  409. package/node_modules/@earendil-works/pi-tui/dist/autocomplete.js.map +1 -1
  410. package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts +6 -1
  411. package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts.map +1 -1
  412. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +102 -43
  413. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js.map +1 -1
  414. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.d.ts +2 -1
  415. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.d.ts.map +1 -1
  416. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.js +11 -1
  417. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.js.map +1 -1
  418. package/node_modules/@earendil-works/pi-tui/dist/fuzzy.d.ts +1 -1
  419. package/node_modules/@earendil-works/pi-tui/dist/fuzzy.d.ts.map +1 -1
  420. package/node_modules/@earendil-works/pi-tui/dist/fuzzy.js +2 -2
  421. package/node_modules/@earendil-works/pi-tui/dist/fuzzy.js.map +1 -1
  422. package/node_modules/@earendil-works/pi-tui/dist/index.d.ts +1 -1
  423. package/node_modules/@earendil-works/pi-tui/dist/index.d.ts.map +1 -1
  424. package/node_modules/@earendil-works/pi-tui/dist/index.js.map +1 -1
  425. package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts +4 -7
  426. package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts.map +1 -1
  427. package/node_modules/@earendil-works/pi-tui/dist/terminal.js +38 -77
  428. package/node_modules/@earendil-works/pi-tui/dist/terminal.js.map +1 -1
  429. package/node_modules/@earendil-works/pi-tui/dist/tui.d.ts +20 -4
  430. package/node_modules/@earendil-works/pi-tui/dist/tui.d.ts.map +1 -1
  431. package/node_modules/@earendil-works/pi-tui/dist/tui.js +244 -42
  432. package/node_modules/@earendil-works/pi-tui/dist/tui.js.map +1 -1
  433. package/node_modules/@earendil-works/pi-tui/dist/utils.d.ts +1 -0
  434. package/node_modules/@earendil-works/pi-tui/dist/utils.d.ts.map +1 -1
  435. package/node_modules/@earendil-works/pi-tui/dist/utils.js +46 -15
  436. package/node_modules/@earendil-works/pi-tui/dist/utils.js.map +1 -1
  437. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  438. package/node_modules/@mariozechner/clipboard/package.json +2 -1
  439. package/node_modules/@mariozechner/clipboard-linux-x64-musl/README.md +3 -0
  440. package/node_modules/@mariozechner/clipboard-linux-x64-musl/package.json +25 -0
  441. package/package.json +7 -6
  442. package/dist/extensions/forgecli/add-pipeline.d.ts +0 -19
  443. package/dist/extensions/forgecli/add-pipeline.js +0 -143
  444. package/dist/extensions/forgecli/add-pipeline.js.map +0 -1
  445. package/dist/extensions/forgecli/add-task.d.ts +0 -20
  446. package/dist/extensions/forgecli/add-task.js +0 -154
  447. package/dist/extensions/forgecli/add-task.js.map +0 -1
  448. package/dist/extensions/forgecli/approve.d.ts +0 -22
  449. package/dist/extensions/forgecli/approve.js +0 -152
  450. package/dist/extensions/forgecli/approve.js.map +0 -1
  451. package/dist/extensions/forgecli/banner.d.ts +0 -10
  452. package/dist/extensions/forgecli/banner.js +0 -36
  453. package/dist/extensions/forgecli/banner.js.map +0 -1
  454. package/dist/extensions/forgecli/calibrate.d.ts +0 -64
  455. package/dist/extensions/forgecli/calibrate.js +0 -481
  456. package/dist/extensions/forgecli/calibrate.js.map +0 -1
  457. package/dist/extensions/forgecli/collate.d.ts +0 -22
  458. package/dist/extensions/forgecli/collate.js +0 -134
  459. package/dist/extensions/forgecli/collate.js.map +0 -1
  460. package/dist/extensions/forgecli/commit.d.ts +0 -22
  461. package/dist/extensions/forgecli/commit.js +0 -152
  462. package/dist/extensions/forgecli/commit.js.map +0 -1
  463. package/dist/extensions/forgecli/config-command.d.ts +0 -8
  464. package/dist/extensions/forgecli/config-command.js +0 -67
  465. package/dist/extensions/forgecli/config-command.js.map +0 -1
  466. package/dist/extensions/forgecli/config-layer.d.ts +0 -53
  467. package/dist/extensions/forgecli/config-layer.js +0 -72
  468. package/dist/extensions/forgecli/config-layer.js.map +0 -1
  469. package/dist/extensions/forgecli/config-writer.d.ts +0 -16
  470. package/dist/extensions/forgecli/config-writer.js +0 -69
  471. package/dist/extensions/forgecli/config-writer.js.map +0 -1
  472. package/dist/extensions/forgecli/enhance.d.ts +0 -27
  473. package/dist/extensions/forgecli/enhance.js +0 -199
  474. package/dist/extensions/forgecli/enhance.js.map +0 -1
  475. package/dist/extensions/forgecli/fix-bug.d.ts +0 -85
  476. package/dist/extensions/forgecli/fix-bug.js +0 -1580
  477. package/dist/extensions/forgecli/fix-bug.js.map +0 -1
  478. package/dist/extensions/forgecli/forge-header.d.ts +0 -12
  479. package/dist/extensions/forgecli/forge-header.js +0 -114
  480. package/dist/extensions/forgecli/forge-header.js.map +0 -1
  481. package/dist/extensions/forgecli/forge-init.d.ts +0 -26
  482. package/dist/extensions/forgecli/forge-init.js +0 -514
  483. package/dist/extensions/forgecli/forge-init.js.map +0 -1
  484. package/dist/extensions/forgecli/forge-root.d.ts +0 -10
  485. package/dist/extensions/forgecli/forge-root.js +0 -62
  486. package/dist/extensions/forgecli/forge-root.js.map +0 -1
  487. package/dist/extensions/forgecli/forge-update-command.d.ts +0 -100
  488. package/dist/extensions/forgecli/forge-update-command.js +0 -435
  489. package/dist/extensions/forgecli/forge-update-command.js.map +0 -1
  490. package/dist/extensions/forgecli/friction-emit.d.ts +0 -99
  491. package/dist/extensions/forgecli/friction-emit.js +0 -245
  492. package/dist/extensions/forgecli/friction-emit.js.map +0 -1
  493. package/dist/extensions/forgecli/implement.d.ts +0 -22
  494. package/dist/extensions/forgecli/implement.js +0 -170
  495. package/dist/extensions/forgecli/implement.js.map +0 -1
  496. package/dist/extensions/forgecli/init-context.d.ts +0 -99
  497. package/dist/extensions/forgecli/init-context.js +0 -178
  498. package/dist/extensions/forgecli/init-context.js.map +0 -1
  499. package/dist/extensions/forgecli/init-progress.d.ts +0 -39
  500. package/dist/extensions/forgecli/init-progress.js +0 -117
  501. package/dist/extensions/forgecli/init-progress.js.map +0 -1
  502. package/dist/extensions/forgecli/input-router.d.ts +0 -33
  503. package/dist/extensions/forgecli/input-router.js +0 -136
  504. package/dist/extensions/forgecli/input-router.js.map +0 -1
  505. package/dist/extensions/forgecli/lib/halt-advisor.d.ts +0 -59
  506. package/dist/extensions/forgecli/lib/halt-advisor.js +0 -113
  507. package/dist/extensions/forgecli/lib/halt-advisor.js.map +0 -1
  508. package/dist/extensions/forgecli/lib/orchestrator-preflight.d.ts +0 -46
  509. package/dist/extensions/forgecli/lib/orchestrator-preflight.js +0 -64
  510. package/dist/extensions/forgecli/lib/orchestrator-preflight.js.map +0 -1
  511. package/dist/extensions/forgecli/materialize.d.ts +0 -16
  512. package/dist/extensions/forgecli/materialize.js +0 -195
  513. package/dist/extensions/forgecli/materialize.js.map +0 -1
  514. package/dist/extensions/forgecli/migrate.d.ts +0 -22
  515. package/dist/extensions/forgecli/migrate.js +0 -260
  516. package/dist/extensions/forgecli/migrate.js.map +0 -1
  517. package/dist/extensions/forgecli/migration-engine.d.ts +0 -117
  518. package/dist/extensions/forgecli/migration-engine.js +0 -563
  519. package/dist/extensions/forgecli/migration-engine.js.map +0 -1
  520. package/dist/extensions/forgecli/model-registry.d.ts +0 -61
  521. package/dist/extensions/forgecli/model-registry.js +0 -127
  522. package/dist/extensions/forgecli/model-registry.js.map +0 -1
  523. package/dist/extensions/forgecli/model-resolver.d.ts +0 -32
  524. package/dist/extensions/forgecli/model-resolver.js +0 -65
  525. package/dist/extensions/forgecli/model-resolver.js.map +0 -1
  526. package/dist/extensions/forgecli/model-validator.d.ts +0 -29
  527. package/dist/extensions/forgecli/model-validator.js +0 -107
  528. package/dist/extensions/forgecli/model-validator.js.map +0 -1
  529. package/dist/extensions/forgecli/orchestrator-status-bar.d.ts +0 -26
  530. package/dist/extensions/forgecli/orchestrator-status-bar.js +0 -213
  531. package/dist/extensions/forgecli/orchestrator-status-bar.js.map +0 -1
  532. package/dist/extensions/forgecli/plan.d.ts +0 -22
  533. package/dist/extensions/forgecli/plan.js +0 -167
  534. package/dist/extensions/forgecli/plan.js.map +0 -1
  535. package/dist/extensions/forgecli/quiz-agent.d.ts +0 -17
  536. package/dist/extensions/forgecli/quiz-agent.js +0 -98
  537. package/dist/extensions/forgecli/quiz-agent.js.map +0 -1
  538. package/dist/extensions/forgecli/read-command.d.ts +0 -2
  539. package/dist/extensions/forgecli/read-command.js +0 -100
  540. package/dist/extensions/forgecli/read-command.js.map +0 -1
  541. package/dist/extensions/forgecli/regenerate.d.ts +0 -40
  542. package/dist/extensions/forgecli/regenerate.js +0 -438
  543. package/dist/extensions/forgecli/regenerate.js.map +0 -1
  544. package/dist/extensions/forgecli/remove-command.d.ts +0 -17
  545. package/dist/extensions/forgecli/remove-command.js +0 -124
  546. package/dist/extensions/forgecli/remove-command.js.map +0 -1
  547. package/dist/extensions/forgecli/report-bug.d.ts +0 -25
  548. package/dist/extensions/forgecli/report-bug.js +0 -159
  549. package/dist/extensions/forgecli/report-bug.js.map +0 -1
  550. package/dist/extensions/forgecli/retrospective.d.ts +0 -20
  551. package/dist/extensions/forgecli/retrospective.js +0 -126
  552. package/dist/extensions/forgecli/retrospective.js.map +0 -1
  553. package/dist/extensions/forgecli/review-code.d.ts +0 -35
  554. package/dist/extensions/forgecli/review-code.js +0 -196
  555. package/dist/extensions/forgecli/review-code.js.map +0 -1
  556. package/dist/extensions/forgecli/review-plan.d.ts +0 -35
  557. package/dist/extensions/forgecli/review-plan.js +0 -200
  558. package/dist/extensions/forgecli/review-plan.js.map +0 -1
  559. package/dist/extensions/forgecli/run-sprint.d.ts +0 -27
  560. package/dist/extensions/forgecli/run-sprint.js +0 -716
  561. package/dist/extensions/forgecli/run-sprint.js.map +0 -1
  562. package/dist/extensions/forgecli/run-task.d.ts +0 -204
  563. package/dist/extensions/forgecli/run-task.js +0 -1403
  564. package/dist/extensions/forgecli/run-task.js.map +0 -1
  565. package/dist/extensions/forgecli/skill-curation-flag.d.ts +0 -21
  566. package/dist/extensions/forgecli/skill-curation-flag.js +0 -71
  567. package/dist/extensions/forgecli/skill-curation-flag.js.map +0 -1
  568. package/dist/extensions/forgecli/skill-curator-subagent.d.ts +0 -102
  569. package/dist/extensions/forgecli/skill-curator-subagent.js +0 -339
  570. package/dist/extensions/forgecli/skill-curator-subagent.js.map +0 -1
  571. package/dist/extensions/forgecli/skill-retriever.d.ts +0 -84
  572. package/dist/extensions/forgecli/skill-retriever.js +0 -246
  573. package/dist/extensions/forgecli/skill-retriever.js.map +0 -1
  574. package/dist/extensions/forgecli/skill-usage-tracker.d.ts +0 -91
  575. package/dist/extensions/forgecli/skill-usage-tracker.js +0 -224
  576. package/dist/extensions/forgecli/skill-usage-tracker.js.map +0 -1
  577. package/dist/extensions/forgecli/sprint-intake.d.ts +0 -10
  578. package/dist/extensions/forgecli/sprint-intake.js +0 -91
  579. package/dist/extensions/forgecli/sprint-intake.js.map +0 -1
  580. package/dist/extensions/forgecli/sprint-plan.d.ts +0 -14
  581. package/dist/extensions/forgecli/sprint-plan.js +0 -122
  582. package/dist/extensions/forgecli/sprint-plan.js.map +0 -1
  583. package/dist/extensions/forgecli/status-command.d.ts +0 -19
  584. package/dist/extensions/forgecli/status-command.js +0 -140
  585. package/dist/extensions/forgecli/status-command.js.map +0 -1
  586. package/dist/extensions/forgecli/store-error-remediation.d.ts +0 -65
  587. package/dist/extensions/forgecli/store-error-remediation.js +0 -307
  588. package/dist/extensions/forgecli/store-error-remediation.js.map +0 -1
  589. package/dist/extensions/forgecli/store-query.d.ts +0 -22
  590. package/dist/extensions/forgecli/store-query.js +0 -107
  591. package/dist/extensions/forgecli/store-query.js.map +0 -1
  592. package/dist/extensions/forgecli/store-repair.d.ts +0 -17
  593. package/dist/extensions/forgecli/store-repair.js +0 -123
  594. package/dist/extensions/forgecli/store-repair.js.map +0 -1
  595. package/dist/extensions/forgecli/store-resolver.d.ts +0 -56
  596. package/dist/extensions/forgecli/store-resolver.js +0 -263
  597. package/dist/extensions/forgecli/store-resolver.js.map +0 -1
  598. package/dist/extensions/forgecli/store-validator.d.ts +0 -16
  599. package/dist/extensions/forgecli/store-validator.js +0 -32
  600. package/dist/extensions/forgecli/store-validator.js.map +0 -1
  601. package/dist/extensions/forgecli/test-orchestrate.d.ts +0 -2
  602. package/dist/extensions/forgecli/test-orchestrate.js +0 -182
  603. package/dist/extensions/forgecli/test-orchestrate.js.map +0 -1
  604. package/dist/extensions/forgecli/thread-switcher.d.ts +0 -5
  605. package/dist/extensions/forgecli/thread-switcher.js +0 -189
  606. package/dist/extensions/forgecli/thread-switcher.js.map +0 -1
  607. package/dist/extensions/forgecli/transition-guard.d.ts +0 -20
  608. package/dist/extensions/forgecli/transition-guard.js +0 -89
  609. package/dist/extensions/forgecli/transition-guard.js.map +0 -1
  610. package/dist/extensions/forgecli/update-check.d.ts +0 -37
  611. package/dist/extensions/forgecli/update-check.js +0 -185
  612. package/dist/extensions/forgecli/update-check.js.map +0 -1
  613. package/dist/extensions/forgecli/update-tools.d.ts +0 -23
  614. package/dist/extensions/forgecli/update-tools.js +0 -135
  615. package/dist/extensions/forgecli/update-tools.js.map +0 -1
  616. package/dist/extensions/forgecli/validate.d.ts +0 -22
  617. package/dist/extensions/forgecli/validate.js +0 -152
  618. package/dist/extensions/forgecli/validate.js.map +0 -1
  619. package/dist/extensions/forgecli/viewport-events.d.ts +0 -78
  620. package/dist/extensions/forgecli/viewport-events.js +0 -243
  621. package/dist/extensions/forgecli/viewport-events.js.map +0 -1
  622. package/dist/extensions/forgecli/viewport-renderer.d.ts +0 -83
  623. package/dist/extensions/forgecli/viewport-renderer.js +0 -233
  624. package/dist/extensions/forgecli/viewport-renderer.js.map +0 -1
  625. package/dist/extensions/forgecli/viewport-theme.d.ts +0 -11
  626. package/dist/extensions/forgecli/viewport-theme.js +0 -128
  627. package/dist/extensions/forgecli/viewport-theme.js.map +0 -1
  628. package/dist/extensions/forgecli/whats-new-widget.d.ts +0 -26
  629. package/dist/extensions/forgecli/whats-new-widget.js +0 -376
  630. package/dist/extensions/forgecli/whats-new-widget.js.map +0 -1
  631. package/dist/extensions/forgecli/whats-new.d.ts +0 -120
  632. package/dist/extensions/forgecli/whats-new.js +0 -470
  633. package/dist/extensions/forgecli/whats-new.js.map +0 -1
  634. package/dist/forge-payload/.base-pack/commands/check-agent.md +0 -22
  635. package/dist/forge-payload/.base-pack/commands/enhance.md +0 -37
  636. package/dist/forge-payload/.base-pack/commands/init.md +0 -278
  637. package/dist/forge-payload/init/generation/generate-knowledge-base.md +0 -56
  638. package/dist/forge-payload/init/generation/generate-personas.md +0 -54
  639. package/dist/forge-payload/init/generation/generate-skills.md +0 -36
  640. package/dist/forge-payload/init/generation/generate-templates.md +0 -39
  641. /package/dist/forge-payload/{.base-pack/commands → commands}/approve.md +0 -0
  642. /package/dist/forge-payload/{.base-pack/commands → commands}/collate.md +0 -0
  643. /package/dist/forge-payload/{.base-pack/commands → commands}/commit.md +0 -0
  644. /package/dist/forge-payload/{.base-pack/commands → commands}/fix-bug.md +0 -0
  645. /package/dist/forge-payload/{.base-pack/commands → commands}/implement.md +0 -0
  646. /package/dist/forge-payload/{.base-pack/commands → commands}/new-sprint.md +0 -0
  647. /package/dist/forge-payload/{.base-pack/commands → commands}/plan-sprint.md +0 -0
  648. /package/dist/forge-payload/{.base-pack/commands → commands}/plan.md +0 -0
  649. /package/dist/forge-payload/{.base-pack/commands → commands}/retro.md +0 -0
  650. /package/dist/forge-payload/{.base-pack/commands → commands}/review-code.md +0 -0
  651. /package/dist/forge-payload/{.base-pack/commands → commands}/review-plan.md +0 -0
  652. /package/dist/forge-payload/{.base-pack/commands → commands}/run-sprint.md +0 -0
  653. /package/dist/forge-payload/{.base-pack/commands → commands}/run-task.md +0 -0
  654. /package/dist/forge-payload/{.base-pack/commands → commands}/validate.md +0 -0
@@ -1,1403 +0,0 @@
1
- // run-task.ts — /forge:run-task native Orchestrator handler (FORGE-S21-T02).
2
- //
3
- // Promotes /forge:run-task from stub to a full TS-driven Orchestrator-archetype
4
- // native handler. Reads `.forge/workflows/orchestrate_task.md`, chains phases
5
- // (plan → review-plan → implement → review-code → validate → approve →
6
- // writeback → commit) by spawning a fresh runForgeSubagent per phase (IL10).
7
- //
8
- // Iron Laws enforced here:
9
- // IL1 — code only under forge-cli/src/extensions/forgecli/
10
- // IL6 — no shell-string interpolation; all external calls via spawnSync argv arrays
11
- // IL7 — every failure path emits ctx.ui.notify and returns; no silent continuation
12
- // IL10 — ALL LLM dispatch goes through runForgeSubagent (NO sendKickoff calls here)
13
- //
14
- // sendKickoff is NEVER called from this file.
15
- // Audit-grep: grep -n "sendKickoff(" run-task.ts must return empty.
16
- import { spawnSync } from "node:child_process";
17
- import * as fs from "node:fs";
18
- import * as path from "node:path";
19
- import { fileURLToPath } from "node:url";
20
- import { assertAudience, CallerContextStore } from "./audience-gate.js";
21
- import { loadLayeredConfig } from "./config-layer.js";
22
- import { buildGovernorFactory } from "./context-governor.js";
23
- import { buildForgeCompactionFactory } from "./context-governor-compaction.js";
24
- import { loadForgePersona, runForgeSubagent } from "./forge-subagent.js";
25
- import { getSubagentTools } from "./forge-tools.js";
26
- import { readPersonaDir, readPipelineNames } from "./lib/catalog-helpers.js";
27
- import { discoverForgeConfigCached } from "./lib/forge-config.js";
28
- import { resolveAdvisorModel, runHaltAdvisor } from "./lib/halt-advisor.js";
29
- import { checkMaterialization } from "./lib/manifest-checker.js";
30
- import { runOrchestratorPreflight } from "./lib/orchestrator-preflight.js";
31
- import { isStateStale as isJsonStateStale, readJsonState, taskStateFilePath, writeJsonState, } from "./lib/state-helpers.js";
32
- import { resolveModelForPhase } from "./model-resolver.js";
33
- import { loadWorkflow } from "./parsers/workflow-loader.js";
34
- import { getSessionRegistry } from "./session-registry.js";
35
- import { getOrchestratorTree } from "./orchestrator-tree.js";
36
- import { OrchestratorTranscriptWriter } from "./subagent/orchestrator-transcript.js";
37
- import { resolveToCanonicalId, resolveToolDir } from "./store-resolver.js";
38
- import { attachViewportObserver } from "./viewport-events.js";
39
- import { fmtPhaseSummary } from "./viewport-renderer.js";
40
- // ── Non-interactive helpers ───────────────────────────────────────────────
41
- export function isNonInteractive() {
42
- return process.env.FORGE_YES === "1" || process.env.FORGE_NON_INTERACTIVE === "1";
43
- }
44
- export const PHASES = [
45
- { role: "plan", workflowFile: "plan_task", personaNoun: "engineer", isReview: false, maxIterations: 1 },
46
- { role: "review-plan", workflowFile: "review_plan", personaNoun: "supervisor", isReview: true, maxIterations: 3 },
47
- { role: "implement", workflowFile: "implement_plan", personaNoun: "engineer", isReview: false, maxIterations: 1 },
48
- { role: "review-code", workflowFile: "review_code", personaNoun: "supervisor", isReview: true, maxIterations: 3 },
49
- { role: "validate", workflowFile: "validate_task", personaNoun: "qa-engineer", isReview: true, maxIterations: 3 },
50
- { role: "approve", workflowFile: "architect_approve", personaNoun: "architect", isReview: true, maxIterations: 3 },
51
- { role: "writeback", workflowFile: "collator_agent", personaNoun: "collator", isReview: false, maxIterations: 1 },
52
- { role: "commit", workflowFile: "commit_task", personaNoun: "engineer", isReview: false, maxIterations: 1 },
53
- ];
54
- // Map phase.role → canonical summary key written by base-pack workflows
55
- // (see forge/forge/tools/store-cli.cjs VALID_SUMMARY_PHASES). Phases whose
56
- // workflows do not write a summaries entry (e.g. approve, which transitions
57
- // task.status=approved instead) map to null and are verdict-checked via
58
- // task status rather than the summaries map.
59
- export const SUMMARY_KEY_BY_ROLE = {
60
- plan: "plan",
61
- "review-plan": "review_plan",
62
- implement: "implementation",
63
- "review-code": "code_review",
64
- validate: "validation",
65
- approve: null,
66
- };
67
- /** Validate that an ID contains no path-traversal characters. */
68
- export function validateId(id) {
69
- return /^[A-Za-z0-9_-]+$/.test(id) && !id.includes("..");
70
- }
71
- // FORGE-S25-T16 (N-H-B): state helpers delegate to lib/state-helpers.ts.
72
- // Public API (readState, writeState, deleteState, isStateStale) is preserved —
73
- // run-sprint.ts imports readState as readTaskState from this file.
74
- function stateFilePath(cwd, taskId) {
75
- if (!validateId(taskId)) {
76
- throw new Error(`Invalid taskId for state file path: ${taskId}`);
77
- }
78
- return taskStateFilePath(cwd, taskId);
79
- }
80
- export function readState(cwd, taskId) {
81
- return readJsonState(stateFilePath(cwd, taskId));
82
- }
83
- export function writeState(cwd, state) {
84
- writeJsonState(stateFilePath(cwd, state.taskId), state);
85
- }
86
- export function deleteState(cwd, taskId) {
87
- const fp = stateFilePath(cwd, taskId);
88
- try {
89
- if (fs.existsSync(fp))
90
- fs.unlinkSync(fp);
91
- }
92
- catch {
93
- // non-fatal
94
- }
95
- }
96
- export function isStateStale(state) {
97
- return isJsonStateStale(state.savedAt);
98
- }
99
- /**
100
- * Format an ISO timestamp for human display in the user's local timezone.
101
- * Falls back to the raw ISO string if parsing fails.
102
- */
103
- export function formatLocalTime(iso) {
104
- const d = new Date(iso);
105
- if (Number.isNaN(d.getTime()))
106
- return iso;
107
- const date = d.toLocaleString(undefined, {
108
- year: "numeric",
109
- month: "short",
110
- day: "2-digit",
111
- hour: "2-digit",
112
- minute: "2-digit",
113
- second: "2-digit",
114
- hour12: false,
115
- });
116
- // Append short timezone abbreviation for unambiguous reading.
117
- const tz = new Intl.DateTimeFormat(undefined, { timeZoneName: "short" })
118
- .formatToParts(d)
119
- .find((p) => p.type === "timeZoneName")?.value ?? "";
120
- return tz ? `${date} ${tz}` : date;
121
- }
122
- export function readVerdict(taskId, phaseRole, storeCli, cwd) {
123
- const result = spawnSync("node", [storeCli, "read", "task", taskId], { cwd, encoding: "utf8" });
124
- if (result.status !== 0)
125
- return "missing";
126
- try {
127
- const raw = typeof result.stdout === "string" ? result.stdout : String(result.stdout);
128
- const record = JSON.parse(raw);
129
- // Phases like `approve` do not write a summaries entry; they
130
- // transition task.status to "approved" instead. For those, the
131
- // verdict source is task.status.
132
- const summaryKey = SUMMARY_KEY_BY_ROLE[phaseRole];
133
- if (summaryKey === null) {
134
- return record.status === "approved" ? "approved" : "missing";
135
- }
136
- // Verdict lookup with three fallbacks:
137
- // 1. Canonical mapped summary key (e.g. "code_review" for review-code).
138
- // 2. Underscore-swapped phase role ("review_code") — legacy/defensive.
139
- // 3. Raw hyphenated phase role ("review-code") — defensive only.
140
- const summaries = record.summaries ?? {};
141
- const underscoreKey = phaseRole.replace(/-/g, "_");
142
- const candidates = [summaryKey ?? "", underscoreKey, phaseRole].filter(Boolean);
143
- let verdict;
144
- for (const k of candidates) {
145
- if (summaries[k]?.verdict) {
146
- verdict = summaries[k].verdict;
147
- break;
148
- }
149
- }
150
- if (!verdict)
151
- return "missing";
152
- if (verdict === "approved")
153
- return "approved";
154
- if (verdict === "revision")
155
- return "revision";
156
- return "missing";
157
- }
158
- catch {
159
- return "missing";
160
- }
161
- }
162
- export function readTaskRecord(taskId, storeCli, cwd) {
163
- const result = spawnSync("node", [storeCli, "read", "task", taskId], { cwd, encoding: "utf8" });
164
- if (result.status !== 0)
165
- return null;
166
- try {
167
- const raw = typeof result.stdout === "string" ? result.stdout : String(result.stdout);
168
- return JSON.parse(raw);
169
- }
170
- catch {
171
- return null;
172
- }
173
- }
174
- // Map phase.role → action token used in event.action / eventId.
175
- export function actionForRole(role) {
176
- return role.replace(/-/g, "_");
177
- }
178
- export function isoCompact(ms) {
179
- return new Date(ms)
180
- .toISOString()
181
- .replace(/[-:]/g, "")
182
- .replace(/\.\d{3}Z$/, "Z");
183
- }
184
- export function buildPhaseEvent(ec) {
185
- const action = actionForRole(ec.phase.role);
186
- const entityId = ec.entityType === "bug" ? ec.bugId : ec.taskId;
187
- const eventId = `${isoCompact(ec.startMs)}_${entityId}_${ec.phase.personaNoun}_${action}`;
188
- const durationMs = Math.max(0, ec.endMs - ec.startMs);
189
- const event = {
190
- eventId,
191
- sprintId: ec.sprintId,
192
- role: ec.phase.role,
193
- action: `/forge:${action.replace(/_/g, "-")}`,
194
- phase: ec.phase.role,
195
- iteration: ec.iteration,
196
- startTimestamp: new Date(ec.startMs).toISOString(),
197
- endTimestamp: new Date(ec.endMs).toISOString(),
198
- durationMinutes: Math.round((durationMs / 60000) * 100) / 100,
199
- model: ec.model,
200
- provider: ec.provider,
201
- };
202
- if (ec.entityType === "bug") {
203
- event.bugId = ec.bugId;
204
- }
205
- else {
206
- event.taskId = ec.taskId;
207
- }
208
- if (ec.usage.input > 0 || ec.usage.output > 0 || ec.usage.cacheRead > 0 || ec.usage.cacheWrite > 0) {
209
- event.inputTokens = ec.usage.input;
210
- event.outputTokens = ec.usage.output;
211
- event.cacheReadTokens = ec.usage.cacheRead;
212
- event.cacheWriteTokens = ec.usage.cacheWrite;
213
- event.tokenSource = "reported";
214
- }
215
- if (ec.judgement && typeof ec.judgement === "object") {
216
- const j = ec.judgement;
217
- if (typeof j.verdict === "string")
218
- event.verdict = j.verdict;
219
- if (typeof j.notes === "string")
220
- event.notes = j.notes;
221
- }
222
- return event;
223
- }
224
- export function emitEvent(storeCli, cwd, sprintId, event) {
225
- const result = spawnSync("node", [storeCli, "emit", sprintId, JSON.stringify(event)], {
226
- cwd,
227
- encoding: "utf8",
228
- });
229
- return { ok: result.status === 0, stderr: typeof result.stderr === "string" ? result.stderr : "" };
230
- }
231
- /**
232
- * Emit a phase event for an INCOMPLETE attempt (cancelled / failed) so its
233
- * provider-billed tokens reach the store. Bug B: the cancel and halt-on-failure
234
- * branches used to return without emitting, so collate's COST_REPORT
235
- * under-counted real spend by exactly the aborted passes (CART-S02-T03
236
- * baseline: 259,950 tokens across two aborted plan attempts, invisible).
237
- *
238
- * The event is the canonical phase event (schema-unchanged) with
239
- * `verdict: "aborted" | "failed"` marking the outcome.
240
- *
241
- * Zero-token attempts are skipped — there is no spend to account, and a
242
- * token-less event would be flagged as a husk by collate's ingestion-quality
243
- * pass. Never throws: emission must not perturb the cancel/halt return paths.
244
- *
245
- * @param opts.decorate Optional event mutation hook applied before emit
246
- * (fix-bug uses it for the BUG_TYPE_TOKENS `type` field).
247
- * @returns true when the event was emitted and store-cli accepted it.
248
- */
249
- export function emitIncompletePhaseEvent(opts) {
250
- try {
251
- const { emitCtx, outcome } = opts;
252
- const u = emitCtx.usage;
253
- if (u.input + u.output + u.cacheRead + u.cacheWrite <= 0) {
254
- opts.onDebug?.({ kind: "incomplete_emit_skipped", reason: "no-tokens", outcome });
255
- return false;
256
- }
257
- const judgement = { verdict: outcome };
258
- if (opts.notes)
259
- judgement.notes = opts.notes;
260
- const event = buildPhaseEvent({ ...emitCtx, judgement });
261
- opts.decorate?.(event);
262
- const res = emitEvent(emitCtx.storeCli, emitCtx.cwd, emitCtx.sprintId, event);
263
- opts.onDebug?.(res.ok
264
- ? { kind: "incomplete_emit_ok", eventId: event.eventId, outcome }
265
- : { kind: "incomplete_emit_failed", stderr: res.stderr, outcome });
266
- return res.ok;
267
- }
268
- catch (err) {
269
- const msg = err instanceof Error ? err.message : String(err);
270
- opts.onDebug?.({ kind: "incomplete_emit_failed", stderr: msg, outcome: opts.outcome });
271
- return false;
272
- }
273
- }
274
- export function judgementFromSummary(record, phaseRole, summaryKeyByRole) {
275
- if (!record || !record.summaries)
276
- return undefined;
277
- const keyMap = summaryKeyByRole ?? SUMMARY_KEY_BY_ROLE;
278
- const summaryKey = keyMap[phaseRole];
279
- if (!summaryKey)
280
- return undefined;
281
- const blob = record.summaries[summaryKey];
282
- return blob && typeof blob === "object" ? blob : undefined;
283
- }
284
- // Drain .forge/cache/FRICTION-{phase}.jsonl: stamp each judgement-only record
285
- // with the subagent's runtime attribution and emit as event type "friction".
286
- // Truncate only after all emits succeed (Plan-11 open-question A.3).
287
- export function drainFrictionFile(frictionPath, ec) {
288
- if (!fs.existsSync(frictionPath))
289
- return { emitted: 0, failed: 0 };
290
- const raw = fs.readFileSync(frictionPath, "utf8");
291
- const lines = raw.split("\n").filter((l) => l.trim().length > 0);
292
- if (lines.length === 0)
293
- return { emitted: 0, failed: 0 };
294
- let emitted = 0;
295
- let failed = 0;
296
- for (let i = 0; i < lines.length; i++) {
297
- let judgement;
298
- try {
299
- judgement = JSON.parse(lines[i]);
300
- }
301
- catch {
302
- failed++;
303
- continue;
304
- }
305
- const action = actionForRole(ec.phase.role);
306
- const entityId = ec.entityType === "bug" ? ec.bugId : ec.taskId;
307
- const eventId = `${isoCompact(ec.startMs)}_${entityId}_${ec.phase.personaNoun}_friction_${i}`;
308
- const event = {
309
- eventId,
310
- sprintId: ec.sprintId,
311
- role: ec.phase.role,
312
- action: `/forge:${action.replace(/_/g, "-")}`,
313
- phase: ec.phase.role,
314
- iteration: ec.iteration,
315
- startTimestamp: new Date(ec.startMs).toISOString(),
316
- endTimestamp: new Date(ec.endMs).toISOString(),
317
- durationMinutes: Math.round(((ec.endMs - ec.startMs) / 60000) * 100) / 100,
318
- model: ec.model,
319
- provider: ec.provider,
320
- type: "friction",
321
- workflow: typeof judgement.workflow === "string" ? judgement.workflow : ec.phase.role,
322
- persona: typeof judgement.persona === "string" ? judgement.persona : ec.phase.personaNoun,
323
- issue: judgement.issue,
324
- };
325
- if (ec.entityType === "bug") {
326
- event.bugId = ec.bugId;
327
- }
328
- else {
329
- event.taskId = ec.taskId;
330
- }
331
- if (judgement.subkind !== undefined)
332
- event.subkind = judgement.subkind;
333
- if (judgement.evidence !== undefined)
334
- event.evidence = judgement.evidence;
335
- if (judgement.notes !== undefined)
336
- event.notes = judgement.notes;
337
- const r = emitEvent(ec.storeCli, ec.cwd, ec.sprintId, event);
338
- if (r.ok)
339
- emitted++;
340
- else
341
- failed++;
342
- }
343
- if (failed === 0) {
344
- try {
345
- fs.unlinkSync(frictionPath);
346
- }
347
- catch {
348
- /* non-fatal */
349
- }
350
- }
351
- return { emitted, failed };
352
- }
353
- // ── Find predecessor non-review phase for revision loop ───────────────────
354
- export function findPredecessorIndex(phases, reviewIndex) {
355
- for (let i = reviewIndex - 1; i >= 0; i--) {
356
- if (!phases[i].isReview)
357
- return i;
358
- }
359
- return 0;
360
- }
361
- // Phase ordering for summary injection — earlier phases first.
362
- const PHASE_ORDER = ["plan", "review_plan", "implementation", "code_review", "validation"];
363
- export function buildSummariesBlock(summaries) {
364
- if (!summaries)
365
- return "";
366
- const lines = [];
367
- for (const key of PHASE_ORDER) {
368
- const raw = summaries[key];
369
- if (!raw || typeof raw !== "object")
370
- continue;
371
- const s = raw;
372
- const parts = [`### ${key}`];
373
- if (s.objective)
374
- parts.push(`Objective: ${s.objective}`);
375
- if (s.verdict)
376
- parts.push(`Verdict: ${s.verdict}`);
377
- if (s.key_changes?.length)
378
- parts.push(`Key changes: ${s.key_changes.join("; ")}`);
379
- if (s.findings?.length)
380
- parts.push(`Findings: ${s.findings.join("; ")}`);
381
- if (s.artifact_ref)
382
- parts.push(`Full artifact: ${s.artifact_ref}`);
383
- lines.push(parts.join("\n"));
384
- }
385
- if (lines.length === 0)
386
- return "";
387
- return ["## Prior phase summaries (carry-forward)", "", ...lines].join("\n");
388
- }
389
- export function composeTaskBody(subWorkflowMd, taskId, summariesBlock) {
390
- const parts = [`Read the workflow below and follow it. Task ID: ${taskId}.`, "", "---", ""];
391
- if (summariesBlock) {
392
- parts.push(summariesBlock, "", "---", "");
393
- }
394
- parts.push(subWorkflowMd.trim());
395
- return parts.join("\n");
396
- }
397
- export function runPreflightGate(preflightGate, role, taskId, cwd, entityType) {
398
- const outcome = runPreflightGateWithData(preflightGate, role, taskId, cwd, entityType);
399
- return outcome.result;
400
- }
401
- /**
402
- * Run postflight-gate.cjs after a phase subagent returns, before FSM advance.
403
- * Mirrors runPreflightGateWithData — same argv-array discipline, same structured-JSON
404
- * parsing from stdout on exit 1.
405
- *
406
- * Returns:
407
- * "ok" — gate passed (or no outputs block for this phase); advance may proceed.
408
- * "unsatisfied" — gate failed; do NOT advance FSM; halt and call runHaltAdvisor.
409
- * "error" — gate binary missing or parse error; treat as pass-through (additive).
410
- */
411
- export function runPostflightGate(postflightGate, role, taskId, cwd) {
412
- if (!fs.existsSync(postflightGate)) {
413
- // postflight-gate.cjs not present in this forgeRoot — pass through (additive).
414
- return { result: "ok", gateFailure: null };
415
- }
416
- const spawnResult = spawnSync("node", [postflightGate, "--phase", role, "--task", taskId], { cwd, encoding: "utf8" });
417
- if (spawnResult.status === 0)
418
- return { result: "ok", gateFailure: null };
419
- if (spawnResult.status === 2)
420
- return { result: "error", gateFailure: null };
421
- // Exit 1: parse structured JSON from stdout
422
- let gateFailure = null;
423
- try {
424
- const stdout = typeof spawnResult.stdout === "string" ? spawnResult.stdout.trim() : "";
425
- if (stdout) {
426
- const parsed = JSON.parse(stdout);
427
- if (parsed && typeof parsed.reasonCode === "string") {
428
- gateFailure = parsed;
429
- }
430
- }
431
- }
432
- catch {
433
- // stdout not valid JSON — gate failure but no structured data
434
- }
435
- return { result: "unsatisfied", gateFailure };
436
- }
437
- /**
438
- * Upgraded variant that returns structured failure data alongside the status enum.
439
- * Callers that need the advisory data should use this function directly.
440
- */
441
- export function runPreflightGateWithData(preflightGate, role, taskId, cwd, entityType) {
442
- const entityFlag = entityType === "bug" ? "--bug" : "--task";
443
- const spawnResult = spawnSync("node", [preflightGate, "--phase", role, entityFlag, taskId], { cwd, encoding: "utf8" });
444
- if (spawnResult.status === 0)
445
- return { result: "proceed", gateFailure: null };
446
- if (spawnResult.status === 2)
447
- return { result: "escalate", gateFailure: null };
448
- // Exit 1: parse structured JSON from stdout
449
- let gateFailure = null;
450
- try {
451
- const stdout = typeof spawnResult.stdout === "string" ? spawnResult.stdout.trim() : "";
452
- if (stdout) {
453
- const parsed = JSON.parse(stdout);
454
- if (parsed && typeof parsed.reasonCode === "string") {
455
- gateFailure = parsed;
456
- }
457
- }
458
- }
459
- catch {
460
- // stdout not valid JSON — gate failure but no structured data
461
- }
462
- return { result: "halt", gateFailure };
463
- }
464
- // ── Per-task orchestrator pipeline (FORGE-S21-T03 extracted) ──────────────
465
- // The entire phase loop was inline in registerRunTask. It is now a standalone
466
- // exported function so that run-sprint.ts can delegate per-task execution
467
- // without duplicating phase-loop logic. registerRunTask becomes a thin
468
- // wrapper: config discovery, resume detection, then delegate to runTaskPipeline.
469
- const STATUS_KEY = "forge:run-task";
470
- const MESSAGE_KEY = "forge:run-task:message";
471
- // extractTurnPreview moved to viewport-renderer.ts; re-exported below for
472
- // backwards-compatibility with existing imports (e.g. tests).
473
- export { extractTurnPreview } from "./viewport-renderer.js";
474
- // ── runTaskPipeline ──────────────────────────────────────────────────────
475
- export async function runTaskPipeline(opts) {
476
- const { taskId, cwd, ctx, forgeRoot, storeCli, preflightGate, registry, resumeFromState, onPhaseEvent } = opts;
477
- // Bridge: OrchestratorTree for the dashboard overlay.
478
- const tree = getOrchestratorTree();
479
- // Load per-phase model routing config once at task entry (Plan 16 Slice 2).
480
- // Empty / absent config produces inherit for every phase — no behaviour change.
481
- // N-B-E: surface schema errors to caller (Decision 9 — orchestrators fail-fast).
482
- // See doc/decisions/layered-config-error-policy.md.
483
- const { merged: modelRoutingConfig, errors: layeredConfigErrors } = loadLayeredConfig(cwd);
484
- if (layeredConfigErrors.length > 0) {
485
- for (const e of layeredConfigErrors) {
486
- ctx.ui.notify(`× forge:run-task — forge-cli config schema error: ${e}`, "error");
487
- }
488
- return {
489
- status: "failed",
490
- lastPhaseIndex: 0,
491
- iterationCounts: {},
492
- lastError: `forge-cli config schema errors: ${layeredConfigErrors.join("; ")}`,
493
- };
494
- }
495
- // Pre-flight model config validation (Plan 16 Slice 3).
496
- // Warns on unknown persona names / unavailable models; errors on unresolvable
497
- // overrides / unknown pipelines. With FORGE_STRICT_MODELS=1, warnings → errors.
498
- // FORGE-S25-T17: delegated to lib/orchestrator-preflight.ts (H-13).
499
- {
500
- const personasDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..", "forge-payload", ".base-pack", "personas");
501
- const personaCatalogue = readPersonaDir(personasDir);
502
- const forgeCfgPath = path.join(cwd, ".forge", "config.json");
503
- const pipelineCatalogue = readPipelineNames(forgeCfgPath);
504
- const availableModels = ctx.modelRegistry?.getAvailable?.() ?? [];
505
- const preflightResult = runOrchestratorPreflight({
506
- mode: "task",
507
- ctx,
508
- notifyPrefix: "forge:run-task",
509
- personaCatalogue,
510
- pipelineCatalogue,
511
- modelRoutingConfig,
512
- availableModels: availableModels.map((m) => ({ provider: m.provider, id: m.id })),
513
- });
514
- if (!preflightResult.proceed) {
515
- return preflightResult.result;
516
- }
517
- }
518
- // Determine starting phase from resumeFromState (if provided) or phase 0.
519
- let currentPhaseIndex = resumeFromState?.phaseIndex ?? 0;
520
- const iterationCounts = resumeFromState?.iterationCounts ?? {};
521
- // Track model/provider from last successful subagent result (REVIEW FIX #1).
522
- let lastModel;
523
- let lastProvider;
524
- // Resolve the task's sprintId once for prompt-cache session affinity. All
525
- // phases in this task share the cache key `forge:${sprintId}` so the
526
- // system-prompt + project orientation prefix (which is identical across
527
- // personas) stays warm on Anthropic and shares a stable prompt_cache_key
528
- // on OpenAI. Falls back to a task-scoped key if the task is unattached.
529
- const taskRecordAtStart = readTaskRecord(taskId, storeCli, cwd);
530
- const cacheSessionId = taskRecordAtStart?.sprintId ? `forge:${taskRecordAtStart.sprintId}` : `forge:task:${taskId}`;
531
- // ── Orchestrator transcript ──────────────────────────────────────────
532
- // FORGE-BUG-040 follow-up: one JSONL file per pipeline run, ISO-prefixed
533
- // in its filename so review-loop iterations preserve their own logs
534
- // instead of overwriting. Captures every ctx.ui.notify line plus
535
- // structured phase-boundary events.
536
- const orchTranscript = new OrchestratorTranscriptWriter({
537
- cwd,
538
- entityKind: "task",
539
- entityId: taskId,
540
- });
541
- const __origNotify = ctx.ui.notify.bind(ctx.ui);
542
- ctx.ui.notify = ((msg, level) => {
543
- __origNotify(msg, level);
544
- orchTranscript.record({
545
- kind: "notify",
546
- ts: new Date().toISOString(),
547
- level: (level ?? "info"),
548
- message: typeof msg === "string" ? msg : String(msg),
549
- });
550
- });
551
- const pipelineStartMs = Date.now();
552
- try {
553
- while (currentPhaseIndex < PHASES.length) {
554
- // ── Between-phase cancellation gate ────────────────────────────
555
- if (opts.signal?.aborted) {
556
- ctx.ui.notify(`⊘ forge:run-task — ${taskId} cancelled by user.`, "info");
557
- registry.completePhase(taskId, PHASES[currentPhaseIndex]?.role ?? "unknown", "cancelled");
558
- registry.confirmCancelled(taskId);
559
- // ADR-S21-01: preserve state file so cancelled runs are resumable
560
- // from the beginning of the cancelled phase (not deleted).
561
- writeState(cwd, {
562
- taskId,
563
- phaseIndex: currentPhaseIndex,
564
- iterationCounts,
565
- halted: false,
566
- status: "cancelled",
567
- lastError: undefined,
568
- savedAt: new Date().toISOString(),
569
- });
570
- return { status: "cancelled", lastPhaseIndex: currentPhaseIndex, iterationCounts };
571
- }
572
- const phase = PHASES[currentPhaseIndex];
573
- if (!phase) {
574
- ctx.ui.notify(`× forge:run-task — invalid phase index ${currentPhaseIndex}`, "error");
575
- return {
576
- status: "failed",
577
- lastPhaseIndex: currentPhaseIndex,
578
- iterationCounts,
579
- lastError: `invalid phase index ${currentPhaseIndex}`,
580
- };
581
- }
582
- ctx.ui.setStatus?.(STATUS_KEY, `run-task ${taskId}: phase ${currentPhaseIndex + 1}/${PHASES.length} (${phase.role})`);
583
- ctx.ui.notify(`→ ${taskId}: ${phase.role} (phase ${currentPhaseIndex + 1}/${PHASES.length})`, "info");
584
- orchTranscript.record({
585
- kind: "phase-start",
586
- ts: new Date().toISOString(),
587
- phase: phase.role,
588
- phaseIndex: currentPhaseIndex,
589
- phaseCount: PHASES.length,
590
- attempt: (iterationCounts[phase.role] ?? 0) + 1,
591
- workflowFile: phase.workflowFile,
592
- persona: phase.personaNoun,
593
- });
594
- const subWorkflowPath = path.join(cwd, ".forge", "workflows", `${phase.workflowFile}.md`);
595
- // ── Read sub-workflow ─────────────────────────────────────────
596
- let subWorkflowMd;
597
- let subWorkflowAudience = "any";
598
- try {
599
- const loaded = loadWorkflow(subWorkflowPath);
600
- subWorkflowMd = loaded.rawMarkdown;
601
- subWorkflowAudience = loaded.audience;
602
- }
603
- catch (err) {
604
- const e = err;
605
- ctx.ui.notify(`× forge:run-task — failed to read sub-workflow for ${phase.role}: ${e.message ?? "unknown"}`, "error");
606
- writeState(cwd, {
607
- taskId,
608
- phaseIndex: currentPhaseIndex,
609
- iterationCounts,
610
- halted: true,
611
- lastError: `sub-workflow read failed: ${e.message ?? "unknown"}`,
612
- savedAt: new Date().toISOString(),
613
- });
614
- return {
615
- status: "failed",
616
- lastPhaseIndex: currentPhaseIndex,
617
- iterationCounts,
618
- lastError: `sub-workflow read failed: ${e.message ?? "unknown"}`,
619
- };
620
- }
621
- // ── 6a. Preflight gate ────────────────────────────────────────
622
- if (fs.existsSync(preflightGate)) {
623
- const preflightOutcome = runPreflightGateWithData(preflightGate, phase.role, taskId, cwd);
624
- if (preflightOutcome.result === "halt") {
625
- // Render structured failure reason if available.
626
- if (preflightOutcome.gateFailure) {
627
- ctx.ui.notify(`× forge:run-task — preflight gate failed for phase ${phase.role} ` +
628
- `[${preflightOutcome.gateFailure.reasonCode}]: ${preflightOutcome.gateFailure.detail}`, "error");
629
- }
630
- else {
631
- ctx.ui.notify(`× forge:run-task — preflight gate failed for phase ${phase.role} (exit 1); halting.`, "error");
632
- }
633
- writeState(cwd, {
634
- taskId,
635
- phaseIndex: currentPhaseIndex,
636
- iterationCounts,
637
- halted: true,
638
- lastError: `preflight gate exit 1 for ${phase.role}`,
639
- savedAt: new Date().toISOString(),
640
- });
641
- // Spawn halt-recovery advisor (Tier 1, best-effort — non-fatal).
642
- if (preflightOutcome.gateFailure) {
643
- const advisorModel = resolveAdvisorModel(modelRoutingConfig, ctx.model);
644
- void runHaltAdvisor({
645
- gateFailure: preflightOutcome.gateFailure,
646
- advisorModel,
647
- taskId,
648
- cwd,
649
- ctx: { ui: ctx.ui },
650
- forgeRoot,
651
- });
652
- }
653
- return {
654
- status: "halted",
655
- lastPhaseIndex: currentPhaseIndex,
656
- iterationCounts,
657
- lastError: `preflight gate exit 1 for ${phase.role}`,
658
- };
659
- }
660
- if (preflightOutcome.result === "escalate") {
661
- ctx.ui.notify(`× forge:run-task — preflight gate escalated for phase ${phase.role} (exit 2); manual intervention required.`, "error");
662
- writeState(cwd, {
663
- taskId,
664
- phaseIndex: currentPhaseIndex,
665
- iterationCounts,
666
- halted: true,
667
- lastError: `preflight gate exit 2 (escalate) for ${phase.role}`,
668
- savedAt: new Date().toISOString(),
669
- });
670
- return {
671
- status: "escalated",
672
- lastPhaseIndex: currentPhaseIndex,
673
- iterationCounts,
674
- lastError: `preflight gate exit 2 (escalate) for ${phase.role}`,
675
- };
676
- }
677
- }
678
- // ── 6. Materialization-marker check ───────────────────────────
679
- const markerCheck = checkMaterialization(subWorkflowPath, subWorkflowMd);
680
- if (!markerCheck.ok) {
681
- for (const marker of markerCheck.missing) {
682
- ctx.ui.notify(`× workflow regression: ${marker} not found in ${subWorkflowPath}`, "error");
683
- }
684
- return {
685
- status: "failed",
686
- lastPhaseIndex: currentPhaseIndex,
687
- iterationCounts,
688
- lastError: `materialization markers missing: ${markerCheck.missing.join(", ")}`,
689
- };
690
- }
691
- // ── 5. Audience check ─────────────────────────────────────────
692
- // Wrap with CallerContextStore.asSubagent so assertAudience treats
693
- // this as a subagent context (IL10: we ARE dispatching from subagent chain).
694
- const audienceOk = CallerContextStore.asSubagent(phase.role, () => assertAudience({ workflowName: phase.workflowFile, audience: subWorkflowAudience }, ctx));
695
- if (!audienceOk) {
696
- writeState(cwd, {
697
- taskId,
698
- phaseIndex: currentPhaseIndex,
699
- iterationCounts,
700
- halted: true,
701
- lastError: `audience check failed for ${phase.workflowFile}`,
702
- savedAt: new Date().toISOString(),
703
- });
704
- return {
705
- status: "failed",
706
- lastPhaseIndex: currentPhaseIndex,
707
- iterationCounts,
708
- lastError: `audience check failed for ${phase.workflowFile}`,
709
- };
710
- }
711
- // ── Persona load ──────────────────────────────────────────────
712
- let persona;
713
- try {
714
- persona = loadForgePersona(phase.personaNoun, cwd);
715
- }
716
- catch (err) {
717
- const e = err;
718
- ctx.ui.notify(`× forge:run-task — persona '${phase.personaNoun}' not found for phase ${phase.role}: ${e.message ?? "unknown"}. ` +
719
- "Run /forge:regenerate to materialize persona files.", "error");
720
- writeState(cwd, {
721
- taskId,
722
- phaseIndex: currentPhaseIndex,
723
- iterationCounts,
724
- halted: true,
725
- lastError: `persona load failed: ${e.message ?? "unknown"}`,
726
- savedAt: new Date().toISOString(),
727
- });
728
- return {
729
- status: "failed",
730
- lastPhaseIndex: currentPhaseIndex,
731
- iterationCounts,
732
- lastError: `persona load failed: ${e.message ?? "unknown"}`,
733
- };
734
- }
735
- // ── 4. Dispatch via runForgeSubagent (IL10) ───────────────────
736
- // NEVER sendKickoff here — that would reproduce issue #30 (same-context inline = no fork).
737
- // Read fresh task record to carry forward prior phase summaries (forge-cli#19).
738
- const taskRecordForSummaries = currentPhaseIndex > 0 ? readTaskRecord(taskId, storeCli, cwd) : null;
739
- const summariesBlock = buildSummariesBlock(taskRecordForSummaries?.summaries);
740
- const taskBody = composeTaskBody(subWorkflowMd, taskId, summariesBlock || undefined);
741
- // Log whether carry-forward summaries were injected (forge-cli#19).
742
- if (summariesBlock) {
743
- const debugCarryPath = path.join(cwd, ".forge", "cache", `run-task-debug-${taskId}.jsonl`);
744
- try {
745
- fs.mkdirSync(path.dirname(debugCarryPath), { recursive: true });
746
- fs.appendFileSync(debugCarryPath, `${JSON.stringify({ ts: new Date().toISOString(), phase: phase.role, kind: "carry_forward_injected", summariesLength: summariesBlock.length, summariesBlock })}\n`, "utf8");
747
- }
748
- catch { /* best-effort debug log */ }
749
- }
750
- // Resolve per-phase model from layered config (Plan 16 Slice 2).
751
- // Pipeline name "default" matches the Forge plugin's shipped pipeline.
752
- // When config is absent or cascade bottoms out, resolves to inherit
753
- // (model: undefined) — setModel is skipped and pi's current model is used.
754
- const modelResolution = resolveModelForPhase("default", phase.role, phase.personaNoun, modelRoutingConfig);
755
- const phaseStart = Date.now();
756
- // Stabilization debug log — every subagent event appended as JSONL.
757
- const debugLogPath = path.join(cwd, ".forge", "cache", `run-task-debug-${taskId}.jsonl`);
758
- const writeDebug = (rec) => {
759
- try {
760
- fs.mkdirSync(path.dirname(debugLogPath), { recursive: true });
761
- fs.appendFileSync(debugLogPath, `${JSON.stringify({ ts: new Date().toISOString(), phase: phase.role, ...rec })}\n`, "utf8");
762
- }
763
- catch {
764
- // non-fatal; debug log is best-effort
765
- }
766
- };
767
- writeDebug({ kind: "phase_start", phaseIndex: currentPhaseIndex });
768
- writeDebug({
769
- kind: "requested_model",
770
- requested: modelResolution.model ?? null,
771
- source: modelResolution.source,
772
- persona: phase.personaNoun,
773
- });
774
- registry.startPhase(taskId, phase.role, currentPhaseIndex);
775
- // Bridge: register phase in OrchestratorTree.
776
- const iteration = (opts.resumeFromState?.iterationCounts?.[phase.role] ?? 0) + 1;
777
- const phaseNodeId = `${taskId}:${phase.role}:${iteration}`;
778
- tree.startNode(phaseNodeId, {
779
- parentId: taskId,
780
- label: `${phase.role}:${iteration}`,
781
- kind: "leaf",
782
- promptPreview: taskBody.slice(0, 200),
783
- });
784
- // Capture the first stream-observed model on turn_end (IL10 visibility).
785
- // If pi auto-substitutes or setModel silently no-ops, this line will diverge
786
- // from requested_model — exactly the diagnostic signal we want.
787
- let modelObservedLogged = false;
788
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
789
- const wrappedOnEvent = (event) => {
790
- if (!modelObservedLogged && event?.type === "turn_end" && typeof event?.message?.model === "string") {
791
- modelObservedLogged = true;
792
- writeDebug({
793
- kind: "model_observed",
794
- provider: event.message.provider ?? null,
795
- model: event.message.model,
796
- });
797
- }
798
- observer.onEvent(event);
799
- };
800
- const refreshStatus = () => {
801
- if (process.env.FORGE_VERBOSE !== "1")
802
- return;
803
- const elapsed = Math.floor((Date.now() - phaseStart) / 1000);
804
- const tail = observer.state.lastTool ? ` · ${observer.state.lastTool}` : "";
805
- ctx.ui.setStatus?.(STATUS_KEY, `run-task ${taskId}: ${phase.role} · t${observer.state.turn} · tools ${observer.state.toolCount}${observer.state.errCount ? ` · err ${observer.state.errCount}` : ""} · ${elapsed}s${tail}`);
806
- };
807
- const observer = attachViewportObserver({
808
- registry,
809
- sessionId: taskId,
810
- phaseRole: phase.role,
811
- beginHeader: `─── phase ${currentPhaseIndex + 1}/${PHASES.length} ${phase.role} begin · ${taskId} ───`,
812
- writeDebug,
813
- notify: (msg, level) => ctx.ui.notify(msg, level),
814
- setStatusVerbose: process.env.FORGE_VERBOSE === "1" ? (k, v) => ctx.ui.setStatus?.(k, v) : undefined,
815
- verboseKeys: { messageKey: MESSAGE_KEY },
816
- afterEach: refreshStatus,
817
- });
818
- // ── Context governor injection (completes FORGE-S30-T07) ──────
819
- // Per-phase factories built HERE because only the pipeline knows the
820
- // `${personaNoun}/${role}` phase key — pi never sets persona/phase on
821
- // ExtensionContext, and the parent session's registerHookDispatcher
822
- // governor never sees subagent tool traffic (dormant-governor defect,
823
- // CART-S02-T03 benchmark). Flag-gated: FORGE_CTX_GOVERNOR=1.
824
- // buildGovernorFactory — Mechanisms A/B/C/D in the subagent
825
- // buildForgeCompactionFactory — Mechanism E with warm-tier path opts
826
- // (previously injected from index.ts with NO opts → warm-tier dead)
827
- const phaseKey = `${phase.personaNoun}/${phase.role}`;
828
- const sprintIdForSummaries = /^(.*)-T\d+$/.exec(taskId)?.[1];
829
- const governorFactories = process.env.FORGE_CTX_GOVERNOR === "1"
830
- ? [
831
- buildGovernorFactory({ phaseKey, cwd }),
832
- buildForgeCompactionFactory({
833
- cwd,
834
- phaseKey,
835
- entityId: taskId,
836
- sprintId: sprintIdForSummaries,
837
- }),
838
- ]
839
- : [];
840
- const phaseExtensionFactories = [...(opts.extensionFactories ?? []), ...governorFactories];
841
- let result;
842
- try {
843
- // FORGE-BUG-040: wrap the runForgeSubagent dispatch in the phase
844
- // caller context (parity with fix-bug.ts) so the phase-ownership
845
- // guard can verify tool calls from the subagent. Single setter
846
- // of phase context for the task pipeline.
847
- result = await CallerContextStore.asSubagent(phase.role, () => runForgeSubagent({
848
- persona,
849
- task: taskBody,
850
- cwd,
851
- exportTag: `${taskId}__${phase.role}`,
852
- cacheSessionId,
853
- streamFn: opts.streamFnFactory?.({ kind: "task-phase", persona: persona.name, phase: phase.role, taskId }),
854
- onEvent: wrappedOnEvent,
855
- requestedModel: modelResolution.model,
856
- modelRegistry: ctx.modelRegistry,
857
- signal: opts.signal,
858
- customTools: opts.forgeToolDefs ? getSubagentTools(opts.forgeToolDefs, persona.name) : undefined,
859
- extensionFactories: phaseExtensionFactories.length > 0 ? phaseExtensionFactories : undefined,
860
- }));
861
- }
862
- catch (err) {
863
- const e = err;
864
- ctx.ui.notify(`× forge:run-task — runForgeSubagent threw for phase ${phase.role}: ${e.message ?? "unknown"}`, "error");
865
- writeState(cwd, {
866
- taskId,
867
- phaseIndex: currentPhaseIndex,
868
- iterationCounts,
869
- halted: true,
870
- lastError: `runForgeSubagent threw: ${e.message ?? "unknown"}`,
871
- savedAt: new Date().toISOString(),
872
- });
873
- return {
874
- status: "failed",
875
- lastPhaseIndex: currentPhaseIndex,
876
- iterationCounts,
877
- lastError: `runForgeSubagent threw: ${e.message ?? "unknown"}`,
878
- };
879
- }
880
- // ── Post-subagent abort detection ─────────────────────────────────
881
- // If the abort signal fired during the subagent run, treat it as
882
- // cancellation regardless of the exit code (subagent may have been
883
- // mid-turn when aborted — exitCode could be 0 or 1).
884
- // This check MUST come before halt-on-failure so that
885
- // stopReason="aborted" + exitCode=1 is classified as cancellation,
886
- // not a phase failure.
887
- if (result.stopReason === "aborted" || opts.signal?.aborted) {
888
- ctx.ui.notify(`⊘ forge:run-task — ${taskId} phase ${phase.role} cancelled.`, "info");
889
- registry.completePhase(taskId, phase.role, "cancelled");
890
- tree.completeNode(phaseNodeId, "cancelled");
891
- registry.confirmCancelled(taskId);
892
- // Bug B: account the billed tokens of this aborted attempt before returning.
893
- {
894
- const abortSprintId = readTaskRecord(taskId, storeCli, cwd)?.sprintId;
895
- if (abortSprintId) {
896
- emitIncompletePhaseEvent({
897
- emitCtx: {
898
- entityType: "task",
899
- taskId,
900
- sprintId: abortSprintId,
901
- phase,
902
- iteration: (iterationCounts[phase.role] ?? 0) + 1,
903
- startMs: phaseStart,
904
- endMs: Date.now(),
905
- model: result.model ?? "unknown",
906
- provider: result.provider ?? "unknown",
907
- usage: {
908
- input: result.usage.input,
909
- output: result.usage.output,
910
- cacheRead: result.usage.cacheRead,
911
- cacheWrite: result.usage.cacheWrite,
912
- },
913
- judgement: undefined,
914
- storeCli,
915
- cwd,
916
- },
917
- outcome: "aborted",
918
- notes: result.errorMessage ?? result.stopReason ?? undefined,
919
- onDebug: writeDebug,
920
- });
921
- }
922
- else {
923
- writeDebug({ kind: "incomplete_emit_skipped", reason: "no-sprintId", outcome: "aborted" });
924
- }
925
- }
926
- // ADR-S21-01: preserve state file so cancelled runs are resumable
927
- writeState(cwd, {
928
- taskId,
929
- phaseIndex: currentPhaseIndex,
930
- iterationCounts,
931
- halted: false,
932
- status: "cancelled",
933
- lastError: undefined,
934
- savedAt: new Date().toISOString(),
935
- });
936
- return { status: "cancelled", lastPhaseIndex: currentPhaseIndex, iterationCounts };
937
- }
938
- // ── Halt-on-failure ───────────────────────────────────────────
939
- if (result.exitCode !== 0) {
940
- ctx.ui.notify(`× forge:run-task — phase ${phase.role} failed (exit ${result.exitCode})` +
941
- (result.errorMessage ? `: ${result.errorMessage}` : "") +
942
- (result.stopReason ? ` [${result.stopReason}]` : ""), "error");
943
- // Bug B: account the billed tokens of this failed attempt before returning.
944
- {
945
- const failSprintId = readTaskRecord(taskId, storeCli, cwd)?.sprintId;
946
- if (failSprintId) {
947
- emitIncompletePhaseEvent({
948
- emitCtx: {
949
- entityType: "task",
950
- taskId,
951
- sprintId: failSprintId,
952
- phase,
953
- iteration: (iterationCounts[phase.role] ?? 0) + 1,
954
- startMs: phaseStart,
955
- endMs: Date.now(),
956
- model: result.model ?? "unknown",
957
- provider: result.provider ?? "unknown",
958
- usage: {
959
- input: result.usage.input,
960
- output: result.usage.output,
961
- cacheRead: result.usage.cacheRead,
962
- cacheWrite: result.usage.cacheWrite,
963
- },
964
- judgement: undefined,
965
- storeCli,
966
- cwd,
967
- },
968
- outcome: "failed",
969
- notes: result.errorMessage ?? result.stopReason ?? undefined,
970
- onDebug: writeDebug,
971
- });
972
- }
973
- else {
974
- writeDebug({ kind: "incomplete_emit_skipped", reason: "no-sprintId", outcome: "failed" });
975
- }
976
- }
977
- writeState(cwd, {
978
- taskId,
979
- phaseIndex: currentPhaseIndex,
980
- iterationCounts,
981
- halted: true,
982
- lastError: result.errorMessage ?? result.stopReason ?? "subagent exit non-zero",
983
- savedAt: new Date().toISOString(),
984
- });
985
- return {
986
- status: "failed",
987
- lastPhaseIndex: currentPhaseIndex,
988
- iterationCounts,
989
- lastError: result.errorMessage ?? result.stopReason ?? "subagent exit non-zero",
990
- };
991
- }
992
- // Capture model/provider from subagent result (REVIEW FIX #1).
993
- if (result.model)
994
- lastModel = result.model;
995
- if (result.provider)
996
- lastProvider = result.provider;
997
- // Phase-complete liveliness ping (counts + duration).
998
- {
999
- const elapsed = Math.floor((Date.now() - phaseStart) / 1000);
1000
- const { turn, toolCount, errCount, cumUsage } = observer.state;
1001
- ctx.ui.notify(`✓ ${phase.role}: ${turn} turn${turn === 1 ? "" : "s"} · ${toolCount} tool call${toolCount === 1 ? "" : "s"}${errCount ? ` · ${errCount} err` : ""} · ${elapsed}s`, "info");
1002
- orchTranscript.record({
1003
- kind: "phase-end",
1004
- ts: new Date().toISOString(),
1005
- phase: phase.role,
1006
- phaseIndex: currentPhaseIndex,
1007
- attempt: (iterationCounts[phase.role] ?? 0) + 1,
1008
- verdict: "n/a",
1009
- elapsedMs: Date.now() - phaseStart,
1010
- turns: turn,
1011
- toolCount,
1012
- errCount,
1013
- });
1014
- const { cumCompression } = observer.state;
1015
- registry.appendTail(taskId, phase.role, fmtPhaseSummary({
1016
- role: phase.role,
1017
- turns: turn,
1018
- tools: toolCount,
1019
- errors: errCount,
1020
- wallSeconds: elapsed,
1021
- usage: cumUsage,
1022
- model: result.model,
1023
- provider: result.provider,
1024
- compression: cumCompression.tokensSaved > 0 ? cumCompression : undefined,
1025
- }));
1026
- }
1027
- // ── Plan 11 / Slice 2: orchestrator emits phase event ─────────
1028
- const phaseEndMs = Date.now();
1029
- const taskRecord = readTaskRecord(taskId, storeCli, cwd);
1030
- const sprintId = taskRecord?.sprintId;
1031
- if (!sprintId) {
1032
- ctx.ui.notify(`⚠ forge:run-task — could not resolve sprintId for ${taskId}; ` +
1033
- `skipping orchestrator emit for phase ${phase.role}`, "warning");
1034
- writeDebug({ kind: "emit_skipped", reason: "no-sprintId" });
1035
- }
1036
- else {
1037
- const phaseIteration = (iterationCounts[phase.role] ?? 0) + 1;
1038
- const emitCtx = {
1039
- entityType: "task",
1040
- taskId,
1041
- sprintId,
1042
- phase,
1043
- iteration: phaseIteration,
1044
- startMs: phaseStart,
1045
- endMs: phaseEndMs,
1046
- model: result.model ?? "unknown",
1047
- provider: result.provider ?? "unknown",
1048
- usage: {
1049
- input: result.usage.input,
1050
- output: result.usage.output,
1051
- cacheRead: result.usage.cacheRead,
1052
- cacheWrite: result.usage.cacheWrite,
1053
- },
1054
- judgement: judgementFromSummary(taskRecord, phase.role),
1055
- storeCli,
1056
- cwd,
1057
- };
1058
- const phaseEvent = buildPhaseEvent(emitCtx);
1059
- const emitResult = emitEvent(storeCli, cwd, sprintId, phaseEvent);
1060
- if (!emitResult.ok) {
1061
- ctx.ui.notify(`⚠ forge:run-task — phase event emit failed for ${phase.role}: ${emitResult.stderr.trim()}`, "warning");
1062
- writeDebug({ kind: "emit_failed", stderr: emitResult.stderr });
1063
- }
1064
- else {
1065
- writeDebug({ kind: "emit_ok", eventId: phaseEvent.eventId });
1066
- }
1067
- // Notify sprint-level observer (FORGE-S21-T03).
1068
- if (onPhaseEvent)
1069
- onPhaseEvent(phaseEvent);
1070
- // Drain friction file for this phase, if any.
1071
- const frictionPath = path.join(cwd, ".forge", "cache", `FRICTION-${phase.role}.jsonl`);
1072
- const drain = drainFrictionFile(frictionPath, emitCtx);
1073
- if (drain.emitted + drain.failed > 0) {
1074
- writeDebug({ kind: "friction_drain", ...drain });
1075
- if (drain.failed > 0) {
1076
- ctx.ui.notify(`⚠ forge:run-task — friction drain for ${phase.role}: ${drain.emitted} ok, ${drain.failed} failed`, "warning");
1077
- }
1078
- }
1079
- }
1080
- // ── 6b. Verdict check (review phases only) ────────────────────
1081
- if (phase.isReview) {
1082
- const verdict = readVerdict(taskId, phase.role, storeCli, cwd);
1083
- if (verdict === "missing") {
1084
- ctx.ui.notify(`× forge:run-task — verdict missing for phase ${phase.role} after subagent completed. ` +
1085
- "Subagent may have crashed or failed to write summaries. Halting for advisory.", "error");
1086
- writeState(cwd, {
1087
- taskId,
1088
- phaseIndex: currentPhaseIndex,
1089
- iterationCounts,
1090
- halted: true,
1091
- lastError: `verdict missing for ${phase.role}`,
1092
- savedAt: new Date().toISOString(),
1093
- });
1094
- // A missing verdict IS a postflight-outputs failure: the canonical
1095
- // phase summary the subagent must write (e.g. summaries.code_review)
1096
- // was never recorded, so there is no verdict to route on. review-phase
1097
- // workflows declare no `outputs` block, so runPostflightGate is a
1098
- // pass-through here — this readVerdict check is the effective gate.
1099
- // Route it through the halt-recovery advisor (FORGE-S26-T18), the same
1100
- // hand-off the postflight-gate-unsatisfied branch uses, instead of a
1101
- // bare escalation — so the strongest configured model can diagnose the
1102
- // missing-summary cause. Best-effort, non-fatal (FORGE-S26-T19 parity).
1103
- const gateFailure = {
1104
- phase: phase.role,
1105
- reasonCode: "verdict-missing",
1106
- detail: `Phase '${phase.role}' completed but no verdict was found in the store. ` +
1107
- "The canonical phase summary was not written, so the orchestrator has no verdict to route on.",
1108
- remediation: "Re-run the phase and ensure the subagent's forge_store set-summary call " +
1109
- 'uses args:["<recordId>", "<phaseKey>"] with the literal phase key as args[1] ' +
1110
- "(e.g. code_review), and that the call exits zero before the subagent returns.",
1111
- };
1112
- const advisorModel = resolveAdvisorModel(modelRoutingConfig, ctx.model);
1113
- void runHaltAdvisor({
1114
- gateFailure,
1115
- advisorModel,
1116
- taskId,
1117
- cwd,
1118
- ctx: { ui: ctx.ui },
1119
- forgeRoot,
1120
- });
1121
- return {
1122
- status: "halted",
1123
- lastPhaseIndex: currentPhaseIndex,
1124
- iterationCounts,
1125
- lastError: `verdict missing for ${phase.role}`,
1126
- };
1127
- }
1128
- if (verdict === "revision") {
1129
- // Increment iteration count for this review phase
1130
- iterationCounts[phase.role] = (iterationCounts[phase.role] ?? 0) + 1;
1131
- if (iterationCounts[phase.role] >= phase.maxIterations) {
1132
- ctx.ui.notify(`× forge:run-task — revision cap reached for phase ${phase.role} ` +
1133
- `(${iterationCounts[phase.role]}/${phase.maxIterations} iterations). Escalating.`, "error");
1134
- writeState(cwd, {
1135
- taskId,
1136
- phaseIndex: currentPhaseIndex,
1137
- iterationCounts,
1138
- halted: true,
1139
- lastError: `revision cap reached for ${phase.role}`,
1140
- savedAt: new Date().toISOString(),
1141
- });
1142
- return {
1143
- status: "escalated",
1144
- lastPhaseIndex: currentPhaseIndex,
1145
- iterationCounts,
1146
- lastError: `revision cap reached for ${phase.role}`,
1147
- };
1148
- }
1149
- // Loop back to predecessor non-review phase
1150
- const predIndex = findPredecessorIndex(PHASES, currentPhaseIndex);
1151
- ctx.ui.notify(`⟳ forge:run-task — ${phase.role} returned revision; looping to ${PHASES[predIndex]?.role ?? predIndex} ` +
1152
- `(attempt ${iterationCounts[phase.role]}/${phase.maxIterations})`, "info");
1153
- orchTranscript.record({
1154
- kind: "phase-loopback",
1155
- ts: new Date().toISOString(),
1156
- fromPhase: phase.role,
1157
- toPhase: PHASES[predIndex]?.role ?? String(predIndex),
1158
- fromPhaseIndex: currentPhaseIndex,
1159
- toPhaseIndex: predIndex,
1160
- reason: `${phase.role} returned revision (attempt ${iterationCounts[phase.role]}/${phase.maxIterations})`,
1161
- });
1162
- // Write intermediate state (not halted — still running)
1163
- writeState(cwd, {
1164
- taskId,
1165
- phaseIndex: predIndex,
1166
- iterationCounts,
1167
- halted: false,
1168
- savedAt: new Date().toISOString(),
1169
- });
1170
- currentPhaseIndex = predIndex;
1171
- continue;
1172
- }
1173
- // verdict === "approved": fall through to advance
1174
- }
1175
- // Postflight gate: evaluate `outputs` block after subagent returns,
1176
- // before FSM status advance (FORGE-S26-T19). Hard enforcement in forge-cli;
1177
- // plugin LLM route treats postflight as advisory. On UNSATISFIED: do not
1178
- // advance currentPhaseIndex, halt, hand off to existing runHaltAdvisor.
1179
- {
1180
- const postflightGatePath = preflightGate.replace("preflight-gate.cjs", "postflight-gate.cjs");
1181
- const postflightOutcome = runPostflightGate(postflightGatePath, phase.role, taskId, cwd);
1182
- if (postflightOutcome.result === "unsatisfied") {
1183
- if (postflightOutcome.gateFailure) {
1184
- ctx.ui.notify(`× forge:run-task — postflight gate failed for phase ${phase.role} ` +
1185
- `[${postflightOutcome.gateFailure.reasonCode}]: ${postflightOutcome.gateFailure.detail}`, "error");
1186
- }
1187
- else {
1188
- ctx.ui.notify(`× forge:run-task — postflight gate failed for phase ${phase.role}; halting.`, "error");
1189
- }
1190
- // Do NOT advance FSM — write state at current phaseIndex (halted)
1191
- writeState(cwd, {
1192
- taskId,
1193
- phaseIndex: currentPhaseIndex,
1194
- iterationCounts,
1195
- halted: true,
1196
- lastError: `postflight gate exit 1 for ${phase.role}`,
1197
- savedAt: new Date().toISOString(),
1198
- });
1199
- // Spawn halt-recovery advisor (Tier 1, best-effort — non-fatal).
1200
- if (postflightOutcome.gateFailure) {
1201
- const advisorModel = resolveAdvisorModel(modelRoutingConfig, ctx.model);
1202
- void runHaltAdvisor({
1203
- gateFailure: postflightOutcome.gateFailure,
1204
- advisorModel,
1205
- taskId,
1206
- cwd,
1207
- ctx: { ui: ctx.ui },
1208
- forgeRoot,
1209
- });
1210
- }
1211
- return {
1212
- status: "halted",
1213
- lastPhaseIndex: currentPhaseIndex,
1214
- iterationCounts,
1215
- lastError: `postflight gate exit 1 for ${phase.role}`,
1216
- };
1217
- }
1218
- // "ok" or "error" — proceed to advance
1219
- }
1220
- // ── Advance to next phase ─────────────────────────────────────
1221
- registry.completePhase(taskId, phase.role, "completed");
1222
- tree.completeNode(phaseNodeId, "completed");
1223
- tree.setNodeUsage(phaseNodeId, { input: result.usage.input, output: result.usage.output, cacheRead: result.usage.cacheRead });
1224
- if (result.model)
1225
- tree.setNodeModel(phaseNodeId, result.model, result.provider ?? "");
1226
- writeState(cwd, {
1227
- taskId,
1228
- phaseIndex: currentPhaseIndex,
1229
- iterationCounts,
1230
- halted: false,
1231
- savedAt: new Date().toISOString(),
1232
- });
1233
- currentPhaseIndex++;
1234
- }
1235
- // ── All phases complete ───────────────────────────────────────────
1236
- deleteState(cwd, taskId);
1237
- orchTranscript.record({
1238
- kind: "pipeline-end",
1239
- ts: new Date().toISOString(),
1240
- outcome: "complete",
1241
- elapsedMs: Date.now() - pipelineStartMs,
1242
- });
1243
- return {
1244
- status: "completed",
1245
- lastPhaseIndex: PHASES.length - 1,
1246
- iterationCounts,
1247
- model: lastModel,
1248
- provider: lastProvider,
1249
- };
1250
- }
1251
- finally {
1252
- ctx.ui.notify = __origNotify;
1253
- }
1254
- }
1255
- export function registerRunTask(pi, options = {}) {
1256
- pi.registerCommand("forge:run-task", {
1257
- description: "Run the full task pipeline (plan → review → implement → validate → approve → commit). " +
1258
- "Usage: /forge:run-task <TASK_ID>. " +
1259
- "Orchestrator archetype: each phase is an isolated subagent session (IL10).",
1260
- async handler(args, ctx) {
1261
- const cwd = options.cwd ?? process.cwd();
1262
- let taskId = args.trim();
1263
- if (!taskId) {
1264
- ctx.ui.notify("× forge:run-task — task ID required. Usage: /forge:run-task <TASK_ID>", "error");
1265
- return;
1266
- }
1267
- ctx.ui.setStatus?.(STATUS_KEY, `run-task ${taskId}: initializing…`);
1268
- // ── Discover forge config ────────────────────────────────────────
1269
- const forgeConfig = discoverForgeConfigCached(cwd);
1270
- if (!forgeConfig) {
1271
- ctx.ui.notify("× forge:run-task — no Forge project found at cwd. Run /forge:init first.", "error");
1272
- ctx.ui.setStatus?.(STATUS_KEY, undefined);
1273
- ctx.ui.setStatus?.(MESSAGE_KEY, undefined);
1274
- return;
1275
- }
1276
- const forgeRoot = forgeConfig.forgeRoot;
1277
- // ── Resolve task ID (prefix-normalize, suffix-match, NLP fallback) ──
1278
- // Handles unprefixed IDs like "S22-T03" → "FORGE-S22-T03".
1279
- // Issue #20: unprefixed task IDs silently poisoned substitutions.
1280
- // NOTE: resolveToCanonicalId may surface ctx.ui.select (disambiguation)
1281
- // or ctx.ui.confirm prompts. The session must NOT be registered yet
1282
- // at this point — the chip strip would appear before the user has
1283
- // chosen which task they meant, stealing arrow keys from the dialog.
1284
- const toolDir = resolveToolDir(forgeRoot);
1285
- const resolvedTaskId = await resolveToCanonicalId(taskId, toolDir, cwd, "task", {
1286
- ctx,
1287
- commandLabel: "forge:run-task",
1288
- });
1289
- if (!resolvedTaskId) {
1290
- // Error already emitted by resolver
1291
- ctx.ui.setStatus?.(STATUS_KEY, undefined);
1292
- ctx.ui.setStatus?.(MESSAGE_KEY, undefined);
1293
- return;
1294
- }
1295
- // Replace raw arg with canonical ID for all subsequent operations
1296
- // (state files, store reads, preflight gates, orchestrator emits).
1297
- // Issue #20: unprefixed task IDs silently poisoned substitutions.
1298
- taskId = resolvedTaskId;
1299
- // Update status with canonical ID so the user sees the resolved form.
1300
- ctx.ui.setStatus?.(STATUS_KEY, `run-task ${taskId}: ready`);
1301
- // Tool paths
1302
- const storeCli = path.join(forgeRoot, "tools", "store-cli.cjs");
1303
- const preflightGate = path.join(forgeRoot, "tools", "preflight-gate.cjs");
1304
- // ── Resume detection ─────────────────────────────────────────────
1305
- const existing = readState(cwd, taskId);
1306
- let resumeFromState;
1307
- if (existing) {
1308
- if (isStateStale(existing)) {
1309
- // Stale state: notify + offer purge
1310
- ctx.ui.notify(`⚠ forge:run-task — cached state for ${taskId} is stale (>7 days old, saved at ${formatLocalTime(existing.savedAt)}). ` +
1311
- "Offering purge.", "warning");
1312
- if (!isNonInteractive()) {
1313
- const purge = await ctx.ui.confirm(`Purge stale state for ${taskId}?`, "The cached state is older than 7 days. Purge and restart from the beginning?");
1314
- if (purge) {
1315
- deleteState(cwd, taskId);
1316
- }
1317
- else {
1318
- ctx.ui.notify("forge:run-task — stale state kept; aborting.", "info");
1319
- ctx.ui.setStatus?.(STATUS_KEY, undefined);
1320
- ctx.ui.setStatus?.(MESSAGE_KEY, undefined);
1321
- return;
1322
- }
1323
- }
1324
- else {
1325
- // Non-interactive: auto-abort on stale state
1326
- ctx.ui.notify("forge:run-task — stale state; non-interactive mode auto-aborting.", "info");
1327
- ctx.ui.setStatus?.(STATUS_KEY, undefined);
1328
- ctx.ui.setStatus?.(MESSAGE_KEY, undefined);
1329
- return;
1330
- }
1331
- }
1332
- else {
1333
- // Fresh state: offer resume for ALL non-stale states — halted=true
1334
- // (explicit failure), halted=false (cancelled/interrupted), and
1335
- // any state with existing.status set (ADR-S21-01).
1336
- const stateStatus = existing.status ?? (existing.halted ? "halted" : "interrupted");
1337
- const statusLabel = stateStatus === "cancelled" ? "cancelled" : stateStatus === "halted" ? "halted" : "interrupted";
1338
- const phaseRole = PHASES[existing.phaseIndex]?.role ?? existing.phaseIndex;
1339
- if (!isNonInteractive()) {
1340
- const resume = await ctx.ui.confirm(`Resume ${taskId}?`, `Cached state — phase ${existing.phaseIndex} (${phaseRole}), ${statusLabel}, ` +
1341
- `saved at ${formatLocalTime(existing.savedAt)}. Resume from here?`);
1342
- if (resume) {
1343
- resumeFromState = existing;
1344
- ctx.ui.notify(`forge:run-task — resuming ${taskId} from phase ${phaseRole} (${statusLabel})`, "info");
1345
- }
1346
- else {
1347
- deleteState(cwd, taskId);
1348
- }
1349
- }
1350
- else {
1351
- // Non-interactive: auto-resume from state (no confirmation).
1352
- // Cancelled/interrupted states are valid resume points.
1353
- resumeFromState = existing;
1354
- ctx.ui.notify(`forge:run-task — resuming ${taskId} from phase ${phaseRole} (${statusLabel})`, "info");
1355
- }
1356
- }
1357
- }
1358
- // ── Register session & delegate to pipeline ────────────────────
1359
- // Session registration MUST happen after all interactive disambiguation
1360
- // (resolveToCanonicalId, resume confirm) so the chip strip doesn't appear
1361
- // before the user has confirmed which task they meant — the strip would
1362
- // steal arrow keys from ctx.ui.select / ctx.ui.confirm dialogs.
1363
- const registry = getSessionRegistry();
1364
- registry.startSession(taskId);
1365
- // Bridge: also register in OrchestratorTree for the dashboard overlay.
1366
- const tree = getOrchestratorTree();
1367
- tree.startNode(taskId, { label: taskId, kind: "orchestrator" });
1368
- const signal = registry.getAbortSignal(taskId);
1369
- const pipelineResult = await runTaskPipeline({
1370
- taskId,
1371
- cwd,
1372
- ctx,
1373
- forgeRoot,
1374
- storeCli,
1375
- preflightGate,
1376
- registry,
1377
- resumeFromState,
1378
- signal,
1379
- forgeToolDefs: options.forgeToolDefs,
1380
- extensionFactories: options.extensionFactories,
1381
- });
1382
- // ── Handle result ────────────────────────────────────────────────
1383
- if (pipelineResult.status === "completed") {
1384
- registry.completeSession(taskId, "completed");
1385
- tree.completeNode(taskId, "completed");
1386
- ctx.ui.notify(`〇 forge:run-task — ${taskId} pipeline complete (${PHASES.length} phases).`, "info");
1387
- }
1388
- else if (pipelineResult.status === "cancelled") {
1389
- // confirmCancelled was already called by the pipeline, but
1390
- // completeSession("cancelled") ensures the session ends cleanly.
1391
- registry.completeSession(taskId, "cancelled");
1392
- tree.completeNode(taskId, "cancelled");
1393
- }
1394
- else {
1395
- registry.completeSession(taskId, "failed");
1396
- tree.completeNode(taskId, "failed");
1397
- }
1398
- ctx.ui.setStatus?.(STATUS_KEY, undefined);
1399
- ctx.ui.setStatus?.(MESSAGE_KEY, undefined);
1400
- },
1401
- });
1402
- }
1403
- //# sourceMappingURL=run-task.js.map