@opengsd/gsd-pi 1.1.1-dev.3ea310e → 1.1.1-dev.595401e

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 (314) hide show
  1. package/dist/resources/.managed-resources-content-hash +1 -1
  2. package/dist/resources/extensions/gsd/auto/orchestrator.js +0 -1
  3. package/dist/resources/extensions/gsd/auto/phases.js +4 -3
  4. package/dist/resources/extensions/gsd/auto-dashboard.js +92 -17
  5. package/dist/resources/extensions/gsd/auto-dispatch.js +5 -0
  6. package/dist/resources/extensions/gsd/auto-post-unit.js +132 -8
  7. package/dist/resources/extensions/gsd/auto-prompts.js +68 -22
  8. package/dist/resources/extensions/gsd/auto-start.js +41 -12
  9. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +2 -1
  10. package/dist/resources/extensions/gsd/auto.js +12 -5
  11. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +82 -3
  12. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +43 -0
  13. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +30 -9
  14. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +16 -10
  15. package/dist/resources/extensions/gsd/browser-evidence.js +29 -2
  16. package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -1
  17. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +3 -1
  18. package/dist/resources/extensions/gsd/commands-verdict.js +1 -1
  19. package/dist/resources/extensions/gsd/config-overlay.js +2 -1
  20. package/dist/resources/extensions/gsd/dashboard-overlay.js +21 -7
  21. package/dist/resources/extensions/gsd/docs/preferences-reference.md +8 -0
  22. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +2 -2
  23. package/dist/resources/extensions/gsd/error-classifier.js +2 -1
  24. package/dist/resources/extensions/gsd/escalation.js +4 -4
  25. package/dist/resources/extensions/gsd/exec-sandbox.js +2 -0
  26. package/dist/resources/extensions/gsd/forensics.js +74 -2
  27. package/dist/resources/extensions/gsd/gsd-db.js +5 -2
  28. package/dist/resources/extensions/gsd/guided-flow.js +29 -68
  29. package/dist/resources/extensions/gsd/memory-store.js +4 -1
  30. package/dist/resources/extensions/gsd/post-unit-hooks.js +9 -0
  31. package/dist/resources/extensions/gsd/preferences-validation.js +39 -0
  32. package/dist/resources/extensions/gsd/prompt-loader.js +7 -0
  33. package/dist/resources/extensions/gsd/prompts/forensics.md +61 -1
  34. package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
  35. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
  36. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  37. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
  38. package/dist/resources/extensions/gsd/prompts/run-uat.md +48 -24
  39. package/dist/resources/extensions/gsd/prompts/system.md +3 -1
  40. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
  41. package/dist/resources/extensions/gsd/rule-registry.js +428 -52
  42. package/dist/resources/extensions/gsd/safety/destructive-guard.js +3 -0
  43. package/dist/resources/extensions/gsd/skill-activation.js +20 -3
  44. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +18 -1
  45. package/dist/resources/extensions/gsd/state-reconciliation/index.js +6 -0
  46. package/dist/resources/extensions/gsd/state.js +3 -3
  47. package/dist/resources/extensions/gsd/templates/plan.md +3 -1
  48. package/dist/resources/extensions/gsd/tools/complete-task.js +11 -1
  49. package/dist/resources/extensions/gsd/tools/exec-tool.js +109 -0
  50. package/dist/resources/extensions/gsd/tools/validate-milestone.js +46 -16
  51. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +403 -3
  52. package/dist/resources/extensions/gsd/unit-context-manifest.js +8 -3
  53. package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
  54. package/dist/resources/extensions/gsd/verdict-parser.js +59 -15
  55. package/dist/resources/extensions/gsd/verification-gate.js +72 -1
  56. package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +1 -1
  57. package/dist/resources/extensions/gsd/workflow-mcp.js +5 -1
  58. package/dist/rtk.d.ts +7 -1
  59. package/dist/rtk.js +27 -11
  60. package/dist/web/standalone/.next/BUILD_ID +1 -1
  61. package/dist/web/standalone/.next/app-path-routes-manifest.json +7 -7
  62. package/dist/web/standalone/.next/build-manifest.json +2 -2
  63. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  64. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  65. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  66. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  67. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  68. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  69. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  73. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/index.html +1 -1
  81. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app-paths-manifest.json +7 -7
  88. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  89. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  90. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  91. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  92. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  93. package/package.json +3 -2
  94. package/packages/cloud-mcp-gateway/package.json +2 -2
  95. package/packages/contracts/dist/workflow.d.ts +14 -0
  96. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  97. package/packages/contracts/dist/workflow.js +16 -0
  98. package/packages/contracts/dist/workflow.js.map +1 -1
  99. package/packages/contracts/package.json +1 -1
  100. package/packages/daemon/package.json +4 -4
  101. package/packages/gsd-agent-core/dist/agent-session.d.ts +9 -0
  102. package/packages/gsd-agent-core/dist/agent-session.d.ts.map +1 -1
  103. package/packages/gsd-agent-core/dist/agent-session.js +32 -0
  104. package/packages/gsd-agent-core/dist/agent-session.js.map +1 -1
  105. package/packages/gsd-agent-core/dist/index.d.ts +1 -0
  106. package/packages/gsd-agent-core/dist/index.d.ts.map +1 -1
  107. package/packages/gsd-agent-core/dist/index.js +1 -0
  108. package/packages/gsd-agent-core/dist/index.js.map +1 -1
  109. package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts +2 -0
  110. package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts.map +1 -1
  111. package/packages/gsd-agent-core/dist/session/agent-session-compaction.js +8 -2
  112. package/packages/gsd-agent-core/dist/session/agent-session-compaction.js.map +1 -1
  113. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts +7 -0
  114. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts.map +1 -1
  115. package/packages/gsd-agent-core/dist/session/agent-session-host.js.map +1 -1
  116. package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts.map +1 -1
  117. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js +69 -1
  118. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js.map +1 -1
  119. package/packages/gsd-agent-core/dist/turn-latency.d.ts +47 -0
  120. package/packages/gsd-agent-core/dist/turn-latency.d.ts.map +1 -0
  121. package/packages/gsd-agent-core/dist/turn-latency.js +123 -0
  122. package/packages/gsd-agent-core/dist/turn-latency.js.map +1 -0
  123. package/packages/gsd-agent-core/package.json +6 -6
  124. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts +21 -0
  125. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts.map +1 -0
  126. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js +213 -0
  127. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js.map +1 -0
  128. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  129. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  130. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +10 -0
  131. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
  132. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts +1 -0
  133. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  134. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +89 -31
  135. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  136. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  137. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +7 -1
  138. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  139. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.d.ts.map +1 -1
  140. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js +6 -0
  141. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js.map +1 -1
  142. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts +1 -1
  143. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts.map +1 -1
  144. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js +1 -1
  145. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js.map +1 -1
  146. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  147. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +1 -0
  148. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
  149. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.d.ts.map +1 -1
  150. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js +5 -0
  151. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js.map +1 -1
  152. package/packages/gsd-agent-modes/package.json +7 -7
  153. package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -1
  154. package/packages/mcp-server/dist/remote-questions.js +23 -9
  155. package/packages/mcp-server/dist/remote-questions.js.map +1 -1
  156. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  157. package/packages/mcp-server/dist/workflow-tools.js +84 -2
  158. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  159. package/packages/mcp-server/package.json +3 -3
  160. package/packages/native/package.json +1 -1
  161. package/packages/pi-agent-core/dist/agent-loop.js +38 -0
  162. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  163. package/packages/pi-agent-core/dist/agent.d.ts +5 -1
  164. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  165. package/packages/pi-agent-core/dist/agent.js +2 -0
  166. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  167. package/packages/pi-agent-core/dist/types.d.ts +3 -0
  168. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  169. package/packages/pi-agent-core/dist/types.js.map +1 -1
  170. package/packages/pi-agent-core/package.json +1 -1
  171. package/packages/pi-ai/dist/api-registry.d.ts +2 -0
  172. package/packages/pi-ai/dist/api-registry.d.ts.map +1 -1
  173. package/packages/pi-ai/dist/api-registry.js +23 -0
  174. package/packages/pi-ai/dist/api-registry.js.map +1 -1
  175. package/packages/pi-ai/dist/image-models.generated.d.ts +15 -0
  176. package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
  177. package/packages/pi-ai/dist/image-models.generated.js +15 -0
  178. package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
  179. package/packages/pi-ai/dist/models.generated.d.ts +86 -18
  180. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  181. package/packages/pi-ai/dist/models.generated.js +108 -40
  182. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  183. package/packages/pi-ai/dist/stream.js +6 -6
  184. package/packages/pi-ai/dist/stream.js.map +1 -1
  185. package/packages/pi-ai/package.json +1 -1
  186. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  187. package/packages/pi-coding-agent/dist/core/model-registry.js +2 -2
  188. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  189. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
  190. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  191. package/packages/pi-coding-agent/dist/core/settings-manager.js +11 -0
  192. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  193. package/packages/pi-coding-agent/package.json +7 -7
  194. package/packages/pi-tui/dist/terminal.d.ts +1 -0
  195. package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
  196. package/packages/pi-tui/dist/terminal.js +8 -4
  197. package/packages/pi-tui/dist/terminal.js.map +1 -1
  198. package/packages/pi-tui/package.json +1 -1
  199. package/packages/rpc-client/package.json +2 -2
  200. package/pkg/package.json +1 -1
  201. package/src/resources/extensions/gsd/auto/orchestrator.ts +0 -1
  202. package/src/resources/extensions/gsd/auto/phases.ts +5 -3
  203. package/src/resources/extensions/gsd/auto-dashboard.ts +98 -18
  204. package/src/resources/extensions/gsd/auto-dispatch.ts +5 -0
  205. package/src/resources/extensions/gsd/auto-post-unit.ts +164 -7
  206. package/src/resources/extensions/gsd/auto-prompts.ts +102 -15
  207. package/src/resources/extensions/gsd/auto-start.ts +54 -14
  208. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +2 -1
  209. package/src/resources/extensions/gsd/auto.ts +15 -4
  210. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +89 -3
  211. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +51 -0
  212. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +51 -14
  213. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +21 -10
  214. package/src/resources/extensions/gsd/browser-evidence.ts +26 -2
  215. package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -1
  216. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +4 -1
  217. package/src/resources/extensions/gsd/commands-verdict.ts +1 -1
  218. package/src/resources/extensions/gsd/config-overlay.ts +3 -1
  219. package/src/resources/extensions/gsd/dashboard-overlay.ts +28 -7
  220. package/src/resources/extensions/gsd/docs/preferences-reference.md +8 -0
  221. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +2 -2
  222. package/src/resources/extensions/gsd/error-classifier.ts +2 -1
  223. package/src/resources/extensions/gsd/escalation.ts +4 -4
  224. package/src/resources/extensions/gsd/exec-sandbox.ts +4 -0
  225. package/src/resources/extensions/gsd/forensics.ts +99 -5
  226. package/src/resources/extensions/gsd/gsd-db.ts +5 -2
  227. package/src/resources/extensions/gsd/guided-flow.ts +90 -82
  228. package/src/resources/extensions/gsd/memory-store.ts +4 -1
  229. package/src/resources/extensions/gsd/post-unit-hooks.ts +14 -1
  230. package/src/resources/extensions/gsd/preferences-types.ts +1 -1
  231. package/src/resources/extensions/gsd/preferences-validation.ts +36 -0
  232. package/src/resources/extensions/gsd/prompt-loader.ts +8 -0
  233. package/src/resources/extensions/gsd/prompts/forensics.md +61 -1
  234. package/src/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
  235. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
  236. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  237. package/src/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
  238. package/src/resources/extensions/gsd/prompts/run-uat.md +48 -24
  239. package/src/resources/extensions/gsd/prompts/system.md +3 -1
  240. package/src/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
  241. package/src/resources/extensions/gsd/rule-registry.ts +558 -58
  242. package/src/resources/extensions/gsd/rule-types.ts +2 -0
  243. package/src/resources/extensions/gsd/safety/destructive-guard.ts +3 -0
  244. package/src/resources/extensions/gsd/skill-activation.ts +20 -2
  245. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +20 -0
  246. package/src/resources/extensions/gsd/state-reconciliation/index.ts +6 -0
  247. package/src/resources/extensions/gsd/state-reconciliation/types.ts +1 -0
  248. package/src/resources/extensions/gsd/state.ts +3 -3
  249. package/src/resources/extensions/gsd/templates/plan.md +3 -1
  250. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +156 -4
  251. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +37 -0
  252. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +16 -3
  253. package/src/resources/extensions/gsd/tests/browser-evidence.test.ts +142 -0
  254. package/src/resources/extensions/gsd/tests/commands-dispatcher-validation-block.test.ts +38 -3
  255. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +6 -2
  256. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +30 -0
  257. package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +45 -0
  258. package/src/resources/extensions/gsd/tests/deep-planning-mode-dispatch.test.ts +53 -0
  259. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +8 -0
  260. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +8 -0
  261. package/src/resources/extensions/gsd/tests/discuss-milestone-structured-questions.test.ts +31 -0
  262. package/src/resources/extensions/gsd/tests/doctor-runtime-checks.test.ts +27 -0
  263. package/src/resources/extensions/gsd/tests/escalation.test.ts +16 -27
  264. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +18 -0
  265. package/src/resources/extensions/gsd/tests/exec-tool.test.ts +69 -0
  266. package/src/resources/extensions/gsd/tests/forensics-issue-routing.test.ts +20 -0
  267. package/src/resources/extensions/gsd/tests/forensics-prompt-rendering.test.ts +3 -0
  268. package/src/resources/extensions/gsd/tests/forensics-tool-scope.test.ts +69 -0
  269. package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +40 -1
  270. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +86 -0
  271. package/src/resources/extensions/gsd/tests/guided-flow.test.ts +12 -9
  272. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +4 -4
  273. package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +66 -10
  274. package/src/resources/extensions/gsd/tests/memory-maintenance.test.ts +39 -8
  275. package/src/resources/extensions/gsd/tests/new-milestone-discuss-routing.test.ts +3 -3
  276. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +54 -7
  277. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +9 -0
  278. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +157 -0
  279. package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +179 -0
  280. package/src/resources/extensions/gsd/tests/preferences.test.ts +29 -0
  281. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +53 -1
  282. package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +14 -0
  283. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +18 -1
  284. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +7 -8
  285. package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +36 -0
  286. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +35 -0
  287. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +1 -1
  288. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +75 -0
  289. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +55 -0
  290. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +191 -0
  291. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +84 -10
  292. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +12 -2
  293. package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +29 -6
  294. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +29 -6
  295. package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +6 -3
  296. package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +133 -0
  297. package/src/resources/extensions/gsd/tests/validation-block-guard.test.ts +21 -0
  298. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +51 -0
  299. package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +2 -2
  300. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +213 -0
  301. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +25 -0
  302. package/src/resources/extensions/gsd/tools/complete-task.ts +20 -2
  303. package/src/resources/extensions/gsd/tools/exec-tool.ts +130 -0
  304. package/src/resources/extensions/gsd/tools/validate-milestone.ts +46 -15
  305. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +489 -3
  306. package/src/resources/extensions/gsd/types.ts +67 -4
  307. package/src/resources/extensions/gsd/unit-context-manifest.ts +14 -5
  308. package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
  309. package/src/resources/extensions/gsd/verdict-parser.ts +54 -13
  310. package/src/resources/extensions/gsd/verification-gate.ts +87 -1
  311. package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +1 -1
  312. package/src/resources/extensions/gsd/workflow-mcp.ts +5 -1
  313. /package/dist/web/standalone/.next/static/{xACmObbrDjwLriepRgaa9 → IDKjyRHLIaumjgonPcYiX}/_buildManifest.js +0 -0
  314. /package/dist/web/standalone/.next/static/{xACmObbrDjwLriepRgaa9 → IDKjyRHLIaumjgonPcYiX}/_ssgManifest.js +0 -0
@@ -1 +1 @@
1
- 3a34fcd8ba090855
1
+ e81bc72bf9d51027
@@ -256,7 +256,6 @@ export class AutoOrchestrator {
256
256
  this.status.activeUnit = { unitType: decision.unitType, unitId: decision.unitId };
257
257
  this.status.phase = "running";
258
258
  this.lastAdvanceKey = nextKey;
259
- this.lastFinalizedUnitKey = null;
260
259
  this.bumpTransition();
261
260
  await this.deps.runtime.journalTransition({
262
261
  name: "advance",
@@ -51,13 +51,13 @@ import { resolveManifest } from "../unit-context-manifest.js";
51
51
  import { createWorktreeSafetyModule } from "../worktree-safety.js";
52
52
  import { isSuspiciousGhostCompletion } from "../auto-unit-closeout.js";
53
53
  import { decideVerificationRetry, verificationRetryKey } from "./verification-retry-policy.js";
54
- import { buildPhaseHandoffOutcome, setAutoOutcomeWidget } from "../auto-dashboard.js";
54
+ import { buildPhaseHandoffOutcome, setAutoActiveStatus, setAutoOutcomeWidget } from "../auto-dashboard.js";
55
55
  import { getConsecutiveDispatchBlocker } from "../dispatch-guard.js";
56
56
  import { captureRootDirtySnapshot, detectRootWriteLeak, formatRootWriteLeakMessage, } from "../root-write-leak-guard.js";
57
57
  import { classifyError, isTransient } from "../error-classifier.js";
58
58
  export const STUCK_WINDOW_SIZE = 6;
59
59
  const STUCK_RECOVERY_ATTEMPTS_KEY = "stuck_recovery_attempts";
60
- const ZERO_TOOL_PROVIDER_ERROR_PREFIX_RE = /^(?:api error(?::|$|\s*\()|provider error(?::|$|\s*\()|request failed\b|(?:http\s*)?(?:429|500|502|503)\b|\b(?:econnreset|etimedout|econnrefused|epipe)\b|socket hang up\b|fetch failed\b|(?:network|connection|server) error(?::|$)|connection (?:reset|refused)(?::|$|\s+by\b)|dns\b.*(?:fail|error|timeout)|unexpected eof\b|stream idle timeout\b|partial response received\b|stream_exhausted\b|terminated(?::|$)|(?:connection|stream|request)\b.{0,40}\bterminated\b|other side closed\b|rate.?limit(?:ed| exceeded| reached| error)|too many requests\b|you(?:'ve| have) hit your limit\b|usage limit\b|out of extra usage\b|service.?unavailable\b|internal(?: server)? error(?::|$)|internal(?:[_-]server)?[_-]error\b|server[_-]error\b|(?:provider|server|api|model|codex|claude|openai|anthropic|gemini)\b.{0,80}\boverloaded\b|overloaded\b.{0,80}\b(?:provider|server|api|model)\b|context (?:window|length) exceed|context window exceed)/i;
60
+ const ZERO_TOOL_PROVIDER_ERROR_PREFIX_RE = /^(?:api error(?::|$|\s*\()|provider error(?::|$|\s*\()|request failed\b|(?:http\s*)?(?:429|500|502|503)\b|\b(?:econnreset|etimedout|econnrefused|epipe)\b|socket hang up\b|fetch failed\b|(?:network|connection|server) error(?::|$)|connection (?:reset|refused)(?::|$|\s+by\b)|dns\b.*(?:fail|error|timeout)|unexpected eof\b|stream idle timeout\b|partial response received\b|stream_exhausted\b|terminated(?::|$)|(?:connection|stream|request)\b.{0,40}\bterminated\b|other side closed\b|rate.?limit(?:ed| exceeded| reached| error)|too many requests\b|you(?:'ve| have) (?:hit|reached) your (?:\w+ )?limit\b|.*\b(?:usage|session|weekly|daily|monthly|quota) limit\b|limit\b.{0,40}\bresets?\b|out of extra usage\b|service.?unavailable\b|internal(?: server)? error(?::|$)|internal(?:[_-]server)?[_-]error\b|server[_-]error\b|(?:provider|server|api|model|codex|claude|openai|anthropic|gemini)\b.{0,80}\boverloaded\b|overloaded\b.{0,80}\b(?:provider|server|api|model)\b|context (?:window|length) exceed|context window exceed)/i;
61
61
  const ZERO_TOOL_PROVIDER_ERROR_SIGNAL_RE = /(?:\b(?:http|status(?: code)?|code|error:)\s*(?:429|500|502|503)\b|\b(?:api|provider) error\s*[:(]?\s*(?:429|500|502|503)\b|\b(?:typeerror|error):\s*(?:fetch failed\b|socket hang up\b|terminated(?::|$)|connection (?:reset|refused)(?::|$|\s+by\b)|(?:network|connection|server) error(?::|$)|stream idle timeout\b|partial response received\b|unexpected eof\b)|\b(?:server_error|api_error|stream_exhausted(?:_without_result)?)\b|\b(?:econnreset|etimedout|econnrefused|epipe)\b|context (?:window|length) exceed|context window exceed)/i;
62
62
  function classifyZeroToolProviderMessage(message) {
63
63
  const firstLine = message.trim().split(/\r?\n/, 1)[0]?.trim() ?? "";
@@ -67,6 +67,7 @@ function classifyZeroToolProviderMessage(message) {
67
67
  return null;
68
68
  return classifyError(firstLine);
69
69
  }
70
+ export const _classifyZeroToolProviderMessageForTest = classifyZeroToolProviderMessage;
70
71
  export function resolveDispatchRecoveryAttempts(unitRecoveryCount, unitType, unitId) {
71
72
  return (unitRecoveryCount.get(`${unitType}/${unitId}`) ?? 0) > 0
72
73
  ? 0
@@ -1582,7 +1583,7 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
1582
1583
  const dispatchKey = `${unitType}/${unitId}`;
1583
1584
  const nextDispatchCount = (s.unitDispatchCount.get(dispatchKey) ?? 0) + 1;
1584
1585
  // Status bar (widget + preconditions deferred until after model selection — see #2899)
1585
- ctx.ui.setStatus("gsd-auto", s.stepMode ? "next" : "auto");
1586
+ setAutoActiveStatus(ctx, s.stepMode ? "next" : "auto");
1586
1587
  if (mid)
1587
1588
  deps.updateSliceProgressCache(s.basePath, mid, state.activeSlice?.id);
1588
1589
  // ── Safety harness: reset evidence + create checkpoint ──
@@ -1,6 +1,6 @@
1
1
  // gsd-pi + src/resources/extensions/gsd/auto-dashboard.ts - Auto-mode progress widget rendering and dashboard helpers.
2
2
  import { getActiveHook } from "./post-unit-hooks.js";
3
- import { getLedger } from "./metrics.js";
3
+ import { getLedger, getProjectTotals } from "./metrics.js";
4
4
  import { getErrorMessage } from "./error-utils.js";
5
5
  import { nativeIsRepo } from "./native-git-bridge.js";
6
6
  import { isDbAvailable, getMilestoneSlices, getSliceTasks } from "./gsd-db.js";
@@ -196,6 +196,39 @@ export function formatRuntimeHealthSignal(record, now = Date.now()) {
196
196
  export function shouldRenderRoadmapProgress(progress) {
197
197
  return !!progress && progress.total > 0;
198
198
  }
199
+ function widgetGridLabel(theme, text, color = "borderAccent") {
200
+ return theme.fg(color, theme.bold(text.toUpperCase()));
201
+ }
202
+ function widgetGridColumn(content, width) {
203
+ return padRightVisible(truncateToWidth(content, width, "…"), width);
204
+ }
205
+ function widgetGridColumns(theme, width, parts) {
206
+ if (parts.length === 0)
207
+ return "";
208
+ const gap = theme.fg("dim", " │ ");
209
+ const gapWidth = visibleWidth(gap) * (parts.length - 1);
210
+ const available = Math.max(parts.length * 8, width - gapWidth);
211
+ const base = Math.floor(available / parts.length);
212
+ let remaining = available - base * parts.length;
213
+ const columns = parts.map((part) => {
214
+ const columnWidth = base + (remaining > 0 ? 1 : 0);
215
+ remaining--;
216
+ return widgetGridColumn(part, columnWidth);
217
+ });
218
+ return truncateToWidth(columns.join(gap), width, "…");
219
+ }
220
+ function formatSmallWidgetSpend() {
221
+ const ledger = getLedger();
222
+ if (!ledger || ledger.units.length === 0)
223
+ return "--";
224
+ const totals = getProjectTotals(ledger.units);
225
+ const parts = [];
226
+ if (totals.tokens.total > 0)
227
+ parts.push(formatWidgetTokens(totals.tokens.total));
228
+ if (totals.cost > 0)
229
+ parts.push(`$${totals.cost.toFixed(2)}`);
230
+ return parts.length > 0 ? parts.join(" · ") : "--";
231
+ }
199
232
  // ─── ETA Estimation ──────────────────────────────────────────────────────────
200
233
  /**
201
234
  * Estimate remaining time based on average unit duration from the metrics ledger.
@@ -369,8 +402,9 @@ export const hideFooter = (_tui, theme, footerData) => ({
369
402
  invalidate() { },
370
403
  dispose() { },
371
404
  });
405
+ export const DEFAULT_WIDGET_MODE = "small";
372
406
  const WIDGET_MODES = ["full", "small", "min", "off"];
373
- let widgetMode = "full";
407
+ let widgetMode = DEFAULT_WIDGET_MODE;
374
408
  let widgetModeInitialized = false;
375
409
  let widgetModePreferencePath = null;
376
410
  function safeReadTextFile(path) {
@@ -473,10 +507,19 @@ export function getWidgetMode(projectPath, globalPath) {
473
507
  }
474
508
  /** Test-only reset for widget mode caching. */
475
509
  export function _resetWidgetModeForTests() {
476
- widgetMode = "full";
510
+ widgetMode = DEFAULT_WIDGET_MODE;
477
511
  widgetModeInitialized = false;
478
512
  widgetModePreferencePath = null;
479
513
  }
514
+ function clearAutoOutcomeWidget(ctx) {
515
+ if (!ctx.hasUI)
516
+ return;
517
+ ctx.ui.setWidget("gsd-outcome", undefined);
518
+ }
519
+ export function setAutoActiveStatus(ctx, status) {
520
+ ctx.ui.setStatus("gsd-auto", status);
521
+ clearAutoOutcomeWidget(ctx);
522
+ }
480
523
  export function updateProgressWidget(ctx, unitType, unitId, state, accessors, tierBadge) {
481
524
  if (!ctx.hasUI)
482
525
  return;
@@ -495,7 +538,7 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
495
538
  ctx.ui.setStatus("gsd-step", undefined);
496
539
  }
497
540
  if (!accessors.isSessionSwitching()) {
498
- ctx.ui.setWidget("gsd-outcome", undefined);
541
+ clearAutoOutcomeWidget(ctx);
499
542
  }
500
543
  const verb = unitVerb(unitType);
501
544
  const phaseLabel = unitPhaseLabel(unitType);
@@ -548,6 +591,7 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
548
591
  logWarning("dashboard", `DB status update failed: ${err instanceof Error ? err.message : String(err)}`);
549
592
  }
550
593
  }, 15_000);
594
+ progressRefreshTimer.unref?.();
551
595
  return {
552
596
  render(width) {
553
597
  if (cachedLines && cachedWidth === width)
@@ -631,26 +675,57 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
631
675
  cachedWidth = width;
632
676
  return lines;
633
677
  }
634
- // ── Mode: small — header + active work progress ───────────────
678
+ // ── Mode: small — dense horizontal grid ───────────────────────
635
679
  if (widgetMode === "small") {
636
- lines.push("");
637
- // Action line
638
- const target = task ? `${task.id}: ${task.title}` : unitId;
639
- const actionLeft = `${pad}${theme.fg("accent", "▸")} ${theme.fg("accent", verb)} ${theme.fg("text", target)}`;
640
- lines.push(rightAlign(actionLeft, theme.fg("dim", phaseLabel), width));
641
- // Progress bar
680
+ lines.length = 0;
681
+ lines.push(...ui.bar());
642
682
  const roadmapSlices = mid ? getRoadmapSlicesSync() : null;
683
+ const unitLabel = unitId || [mid?.id, slice?.id, task?.id].filter(Boolean).join("/");
684
+ const statusParts = [
685
+ spinner,
686
+ theme.fg("success", modeTag),
687
+ theme.fg(stateColor, activeState),
688
+ ];
689
+ if (runtimeSignal?.summary) {
690
+ statusParts.push(theme.fg(healthColor, healthSummary));
691
+ }
692
+ else if (healthLevel !== "green") {
693
+ statusParts.push(`${theme.fg(healthColor, healthIcon)} ${theme.fg(healthColor, healthSummary)}`);
694
+ }
695
+ const timeValue = [elapsed, etaShort].filter(Boolean).join(" · ") || "--";
696
+ const rowOne = widgetGridColumns(theme, width, [
697
+ `${widgetGridLabel(theme, "status", "border")} ${statusParts.join(" ")}`,
698
+ `${widgetGridLabel(theme, "unit")} ${theme.fg("text", unitLabel || "--")}`,
699
+ `${widgetGridLabel(theme, "spend", "border")} ${theme.fg("dim", formatSmallWidgetSpend())}`,
700
+ `${widgetGridLabel(theme, "time")} ${theme.fg("dim", timeValue)}`,
701
+ ]);
702
+ const target = task
703
+ ? `${task.id}: ${task.title}`
704
+ : slice
705
+ ? `${slice.id}: ${slice.title}`
706
+ : unitId;
707
+ let taskValue = task?.id ?? "--";
708
+ let sliceValue = slice?.id ?? "--";
643
709
  if (shouldRenderRoadmapProgress(roadmapSlices)) {
644
710
  const { done, total, activeSliceTasks } = roadmapSlices;
645
- const barWidth = Math.max(6, Math.min(18, Math.floor(width * 0.25)));
711
+ const barWidth = Math.max(4, Math.min(14, Math.floor(width * 0.12)));
646
712
  const bar = renderProgressBar(theme, done, total, barWidth);
647
- let meta = `${theme.fg("text", `${done}`)}${theme.fg("dim", `/${total} slices`)}`;
713
+ sliceValue = `${bar} ${theme.fg("text", `${done}/${total}`)}`;
648
714
  if (activeSliceTasks && activeSliceTasks.total > 0) {
649
- const tn = Math.min(activeSliceTasks.done + 1, activeSliceTasks.total);
650
- meta += `${theme.fg("dim", " · task ")}${theme.fg("accent", `${tn}`)}${theme.fg("dim", `/${activeSliceTasks.total}`)}`;
715
+ const taskNum = isHook
716
+ ? Math.max(activeSliceTasks.done, 1)
717
+ : Math.min(activeSliceTasks.done + 1, activeSliceTasks.total);
718
+ taskValue = `${theme.fg("accent", `${taskNum}`)}${theme.fg("dim", `/${activeSliceTasks.total}`)}`;
651
719
  }
652
- lines.push(`${pad}${bar} ${meta}`);
653
720
  }
721
+ const rowTwo = widgetGridColumns(theme, width, [
722
+ `${widgetGridLabel(theme, "phase", "border")} ${theme.fg("dim", unitType)}`,
723
+ `${widgetGridLabel(theme, "work")} ${theme.fg("text", target || "--")}`,
724
+ `${widgetGridLabel(theme, "task", "border")} ${taskValue}`,
725
+ `${widgetGridLabel(theme, "slice")} ${sliceValue}`,
726
+ ]);
727
+ lines.push(rowOne);
728
+ lines.push(rowTwo);
654
729
  lines.push(...ui.bar());
655
730
  cachedLines = lines;
656
731
  cachedWidth = width;
@@ -789,7 +864,7 @@ export function setCompletionProgressWidget(ctx, snapshot) {
789
864
  if (!ctx.hasUI)
790
865
  return;
791
866
  const widgetKey = "gsd-progress";
792
- ctx.ui.setWidget("gsd-outcome", undefined);
867
+ clearAutoOutcomeWidget(ctx);
793
868
  if (typeof ctx.ui?.setHeader === "function") {
794
869
  ctx.ui.setHeader(() => ({
795
870
  render() { return []; },
@@ -443,6 +443,7 @@ export const DISPATCH_RULES = [
443
443
  unitType: "discuss-milestone",
444
444
  unitId: mid,
445
445
  prompt: await buildDiscussMilestonePrompt(mid, midTitle, basePath, structuredQuestionsAvailable, { headless: !!process.env.GSD_HEADLESS }),
446
+ pauseAfterDispatch: !process.env.GSD_HEADLESS,
446
447
  };
447
448
  },
448
449
  },
@@ -578,6 +579,7 @@ export const DISPATCH_RULES = [
578
579
  unitType: "discuss-milestone",
579
580
  unitId: mid,
580
581
  prompt: await buildDiscussMilestonePrompt(mid, midTitle, basePath, structuredQuestionsAvailable, { headless: !!process.env.GSD_HEADLESS }),
582
+ pauseAfterDispatch: !process.env.GSD_HEADLESS,
581
583
  };
582
584
  },
583
585
  },
@@ -617,6 +619,7 @@ export const DISPATCH_RULES = [
617
619
  unitType: "discuss-project",
618
620
  unitId: "PROJECT",
619
621
  prompt: await buildDiscussProjectPrompt(basePath, structuredQuestionsAvailable),
622
+ pauseAfterDispatch: !process.env.GSD_HEADLESS,
620
623
  };
621
624
  },
622
625
  },
@@ -642,6 +645,7 @@ export const DISPATCH_RULES = [
642
645
  unitType: "discuss-requirements",
643
646
  unitId: "REQUIREMENTS",
644
647
  prompt: await buildDiscussRequirementsPrompt(basePath, structuredQuestionsAvailable),
648
+ pauseAfterDispatch: !process.env.GSD_HEADLESS,
645
649
  };
646
650
  },
647
651
  },
@@ -757,6 +761,7 @@ export const DISPATCH_RULES = [
757
761
  unitType: "discuss-milestone",
758
762
  unitId: mid,
759
763
  prompt: await buildDiscussMilestonePrompt(mid, midTitle, basePath, structuredQuestionsAvailable, { headless: !!process.env.GSD_HEADLESS }),
764
+ pauseAfterDispatch: !process.env.GSD_HEADLESS,
760
765
  };
761
766
  },
762
767
  },
@@ -32,7 +32,7 @@ import { isDbAvailable, getDbPath, refreshOpenDatabaseFromDisk, getTask, getSlic
32
32
  import { renderPlanCheckboxes, renderRoadmapFromDb } from "./markdown-renderer.js";
33
33
  import { parseRoadmap as parseLegacyRoadmap } from "./parsers-legacy.js";
34
34
  import { consumeSignal } from "./session-status-io.js";
35
- import { checkPostUnitHooks, isRetryPending, consumeRetryTrigger, persistHookState, resolveHookArtifactPath, } from "./post-unit-hooks.js";
35
+ import { checkPostUnitHooks, consumeHookFailure, isRetryPending, consumeRetryTrigger, consumeGateBlock, persistHookState, resolveHookArtifactPath, } from "./post-unit-hooks.js";
36
36
  import { hasPendingCaptures, loadPendingCaptures, revertExecutorResolvedCaptures } from "./captures.js";
37
37
  import { debugLog } from "./debug-logger.js";
38
38
  import { runSafely } from "./auto-utils.js";
@@ -323,6 +323,41 @@ function stripKnownIdPrefix(value, id) {
323
323
  return raw.slice(id.length + 1).trim() || undefined;
324
324
  return raw;
325
325
  }
326
+ function parseReactiveBatchTaskIds(unitId) {
327
+ const { task: batchPart } = parseUnitId(unitId);
328
+ if (!batchPart?.startsWith("reactive+"))
329
+ return [];
330
+ const rawIds = batchPart
331
+ .slice("reactive+".length)
332
+ .split(",")
333
+ .map((taskId) => taskId.trim().toUpperCase())
334
+ .filter(Boolean);
335
+ const unique = new Set();
336
+ for (const taskId of rawIds) {
337
+ unique.add(taskId);
338
+ }
339
+ return [...unique];
340
+ }
341
+ function dedupePaths(values) {
342
+ const seen = new Set();
343
+ const result = [];
344
+ for (const value of values) {
345
+ if (!seen.has(value)) {
346
+ seen.add(value);
347
+ result.push(value);
348
+ }
349
+ }
350
+ return result;
351
+ }
352
+ function getPlannedKeyFiles(tasks) {
353
+ return dedupePaths(tasks.flatMap((taskRow) => [
354
+ ...(taskRow.expected_output ?? []),
355
+ ...(taskRow.files ?? []),
356
+ ...(taskRow.key_files ?? []),
357
+ ]));
358
+ }
359
+ export const _parseReactiveBatchTaskIdsForTest = parseReactiveBatchTaskIds;
360
+ export const _getPlannedKeyFilesForTest = getPlannedKeyFiles;
326
361
  function resolveVerificationFailureMarkerPath(unitType, unitId, basePath) {
327
362
  const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
328
363
  switch (unitType) {
@@ -402,6 +437,34 @@ async function buildTaskCommitContextForUnit(basePath, unitId) {
402
437
  issueNumber: ghIssueNumber,
403
438
  };
404
439
  }
440
+ async function buildReactiveTaskCommitContext(_basePath, unitId) {
441
+ const { milestone: mid, slice: sid } = parseUnitId(unitId);
442
+ if (!mid || !sid || !isDbAvailable())
443
+ return undefined;
444
+ const batchTaskIds = parseReactiveBatchTaskIds(unitId);
445
+ if (batchTaskIds.length === 0)
446
+ return undefined;
447
+ const milestone = getMilestone(mid);
448
+ const slice = getSlice(mid, sid);
449
+ const taskRows = batchTaskIds
450
+ .map((tid) => getTask(mid, sid, tid))
451
+ .filter((taskRow) => taskRow !== null);
452
+ const keyFiles = getPlannedKeyFiles(taskRows);
453
+ if (taskRows.length === 0 || keyFiles.length === 0)
454
+ return undefined;
455
+ const taskLabel = taskRows.map((row) => row.id).join(",");
456
+ return {
457
+ taskId: `${sid}/${taskLabel}`,
458
+ taskDisplayId: "reactive-batch",
459
+ taskTitle: `Reactive batch: ${taskLabel}`,
460
+ milestoneId: mid,
461
+ milestoneTitle: stripKnownIdPrefix(milestone?.title, mid),
462
+ sliceId: sid,
463
+ sliceTitle: stripKnownIdPrefix(slice?.title, sid),
464
+ oneLiner: `Reactive execute for ${taskLabel}`,
465
+ keyFiles,
466
+ };
467
+ }
405
468
  async function runPostUnitGitHubSyncIfNeeded(basePath, unit) {
406
469
  if (unit.type === "complete-milestone")
407
470
  return;
@@ -761,6 +824,9 @@ export async function autoCommitUnit(basePath, unitType, unitId, ctx) {
761
824
  if (unitType === "execute-task") {
762
825
  taskContext = await buildTaskCommitContextForUnit(basePath, unitId);
763
826
  }
827
+ else if (unitType === "reactive-execute") {
828
+ taskContext = await buildReactiveTaskCommitContext(basePath, unitId);
829
+ }
764
830
  _resetHasChangesCache();
765
831
  if (LIFECYCLE_ONLY_UNITS.has(unitType)) {
766
832
  return null;
@@ -812,6 +878,22 @@ async function runCloseoutGitAction(pctx, unit, opts) {
812
878
  targetRepositories = getTask(mid, sid, tid)?.target_repositories;
813
879
  }
814
880
  }
881
+ else if (turnAction === "commit" && unit.type === "reactive-execute") {
882
+ taskContext = await buildReactiveTaskCommitContext(s.basePath, unit.id);
883
+ const { milestone: mid, slice: sid } = parseUnitId(unit.id);
884
+ if (mid && sid && isDbAvailable()) {
885
+ const repositories = new Set();
886
+ for (const tid of parseReactiveBatchTaskIds(unit.id)) {
887
+ const taskRow = getTask(mid, sid, tid);
888
+ for (const repoId of taskRow?.target_repositories ?? []) {
889
+ repositories.add(repoId);
890
+ }
891
+ }
892
+ if (repositories.size > 0) {
893
+ targetRepositories = [...repositories];
894
+ }
895
+ }
896
+ }
815
897
  // Invalidate the nativeHasChanges cache before auto-commit (#1853).
816
898
  // The cache has a 10-second TTL and is keyed by basePath. A stale
817
899
  // `false` result causes autoCommit to skip staging entirely.
@@ -1206,12 +1288,19 @@ export async function postUnitPreVerification(pctx, opts) {
1206
1288
  if (safetyConfig.enabled) {
1207
1289
  const { milestone: sMid, slice: sSid, task: sTid } = parseUnitId(s.currentUnit.id);
1208
1290
  // File change validation (execute-task only, after unit execution)
1209
- if (safetyConfig.file_change_validation && s.currentUnit.type === "execute-task" && sMid && sSid && sTid && isDbAvailable()) {
1291
+ if (safetyConfig.file_change_validation && s.currentUnit.type === "execute-task" && sMid && sSid && sTid) {
1210
1292
  try {
1211
- const taskRow = getTask(sMid, sSid, sTid);
1212
- if (taskRow) {
1213
- const expectedOutput = taskRow.expected_output ?? [];
1214
- const plannedFiles = taskRow.files ?? [];
1293
+ const sliceTaskRows = isDbAvailable()
1294
+ ? getSliceTasks(sMid, sSid).filter((t) => isClosedStatus(t.status) || t.id === sTid)
1295
+ : [];
1296
+ if (sliceTaskRows.length > 0) {
1297
+ const expectedOutput = getPlannedKeyFiles(sliceTaskRows.map((taskRow) => ({
1298
+ expected_output: taskRow.expected_output,
1299
+ files: taskRow.files,
1300
+ })));
1301
+ const plannedFiles = getPlannedKeyFiles(sliceTaskRows.map((taskRow) => ({
1302
+ files: taskRow.files,
1303
+ })));
1215
1304
  const audit = validateFileChanges(s.basePath, expectedOutput, plannedFiles, safetyConfig.file_change_allowlist);
1216
1305
  if (audit && audit.violations.length > 0) {
1217
1306
  const warnings = audit.violations.filter(v => v.severity === "warning");
@@ -1223,6 +1312,23 @@ export async function postUnitPreVerification(pctx, opts) {
1223
1312
  }
1224
1313
  }
1225
1314
  }
1315
+ else {
1316
+ const taskRow = getTask(sMid, sSid, sTid);
1317
+ if (taskRow) {
1318
+ const expectedOutput = taskRow.expected_output ?? [];
1319
+ const plannedFiles = taskRow.files ?? [];
1320
+ const audit = validateFileChanges(s.basePath, expectedOutput, plannedFiles, safetyConfig.file_change_allowlist);
1321
+ if (audit && audit.violations.length > 0) {
1322
+ const warnings = audit.violations.filter(v => v.severity === "warning");
1323
+ for (const v of warnings) {
1324
+ logWarning("safety", `file-change: ${v.file} — ${v.reason}`);
1325
+ }
1326
+ if (warnings.length > 0) {
1327
+ ctx.ui.notify(`Safety: ${warnings.length} unexpected file change(s) outside task plan`, "warning");
1328
+ }
1329
+ }
1330
+ }
1331
+ }
1226
1332
  }
1227
1333
  catch (e) {
1228
1334
  debugLog("postUnit", { phase: "safety-file-change", error: String(e) });
@@ -1754,18 +1860,25 @@ export async function postUnitPostVerification(pctx) {
1754
1860
  // ── Post-unit hooks ──
1755
1861
  if (s.currentUnit && !s.stepMode) {
1756
1862
  const hookUnit = checkPostUnitHooks(s.currentUnit.type, s.currentUnit.id, s.basePath);
1863
+ persistHookState(s.basePath);
1757
1864
  if (hookUnit) {
1758
1865
  if (s.currentUnit) {
1759
1866
  await closeoutUnit(ctx, s.basePath, s.currentUnit.type, s.currentUnit.id, s.currentUnit.startedAt, buildSnapshotOpts(s.currentUnit.type, s.currentUnit.id));
1760
1867
  }
1761
- persistHookState(s.basePath);
1762
1868
  return enqueueSidecar(s, ctx, { kind: "hook", unitType: hookUnit.unitType, unitId: hookUnit.unitId, prompt: hookUnit.prompt, model: hookUnit.model }, { hookName: hookUnit.hookName });
1763
1869
  }
1870
+ const hookFailure = consumeHookFailure();
1871
+ if (hookFailure) {
1872
+ ctx.ui.notify(`Post-unit hook ${hookFailure.hookName} failed for ${hookFailure.unitId}: ${hookFailure.reason}. Pausing auto-mode.`, "warning");
1873
+ await pauseAuto(ctx, pi);
1874
+ return "stopped";
1875
+ }
1764
1876
  // Check if a hook requested a retry of the trigger unit
1765
1877
  if (isRetryPending()) {
1766
1878
  const trigger = consumeRetryTrigger();
1767
1879
  if (trigger) {
1768
- ctx.ui.notify(`Hook requested retry of ${trigger.unitType} ${trigger.unitId} — resetting task state.`, "info");
1880
+ persistHookState(s.basePath);
1881
+ ctx.ui.notify(`Hook requested retry of ${trigger.unitType} ${trigger.unitId} — resetting trigger unit state.`, "info");
1769
1882
  await s.orchestration?.retryActiveUnit({
1770
1883
  unitType: trigger.unitType,
1771
1884
  unitId: trigger.unitId,
@@ -1812,6 +1925,17 @@ export async function postUnitPostVerification(pctx) {
1812
1925
  // Fall through to normal dispatch — deriveState will re-derive the unit
1813
1926
  }
1814
1927
  }
1928
+ const gateBlock = consumeGateBlock();
1929
+ if (gateBlock) {
1930
+ persistHookState(s.basePath);
1931
+ const verdict = gateBlock.verdict ? ` verdict=${gateBlock.verdict};` : "";
1932
+ const artifact = gateBlock.artifact ? ` artifact=${gateBlock.artifact};` : "";
1933
+ const message = `Post-unit gate "${gateBlock.hookName}" blocked ${gateBlock.triggerUnitType} ${gateBlock.triggerUnitId}:` +
1934
+ `${verdict}${artifact} ${gateBlock.reason}. Run /gsd status to inspect, then /gsd auto after recovery.`;
1935
+ ctx.ui.notify(message, "warning");
1936
+ await pauseAuto(ctx, pi);
1937
+ return "stopped";
1938
+ }
1815
1939
  }
1816
1940
  // ── Fast-path stop detection (#3487) ──
1817
1941
  // Before waiting for triage, check if any PENDING captures contain explicit
@@ -30,6 +30,7 @@ import { classifyProject } from "./detection.js";
30
30
  import { hasBrowserRequiredText } from "./browser-evidence.js";
31
31
  import { debugLog } from "./debug-logger.js";
32
32
  import { buildSkillActivationBlock, buildSkillDiscoveryVars } from "./skill-activation.js";
33
+ import { findMilestoneIds } from "./milestone-ids.js";
33
34
  export { buildSkillActivationBlock, buildSkillDiscoveryVars };
34
35
  // ─── Preamble Cap ─────────────────────────────────────────────────────────────
35
36
  /**
@@ -1270,7 +1271,7 @@ export async function checkNeedsRunUat(base, mid, state, prefs) {
1270
1271
  if (hasVerdict(uatContent))
1271
1272
  continue;
1272
1273
  // Also check the ASSESSMENT file — the run-uat prompt writes the verdict
1273
- // there (via gsd_summary_save artifact_type:"ASSESSMENT"), not into the
1274
+ // there (via gsd_uat_result_save), not into the
1274
1275
  // UAT spec file. Without this check the unit re-dispatches indefinitely.
1275
1276
  const assessmentFile = resolveSliceFile(base, mid, sid, "ASSESSMENT");
1276
1277
  if (assessmentFile) {
@@ -1325,21 +1326,44 @@ export async function checkNeedsRunUat(base, mid, state, prefs) {
1325
1326
  }
1326
1327
  return null;
1327
1328
  }
1328
- // ─── Prompt Builders ──────────────────────────────────────────────────────
1329
- /**
1330
- * Build a prompt for the discuss-milestone unit type.
1331
- * Loads the guided-discuss-milestone template and inlines the CONTEXT-DRAFT
1332
- * as a seed when present. The discussion agent interviews the user, writes
1333
- * a full CONTEXT.md, and the phase transitions to pre-planning automatically.
1334
- */
1335
- export async function buildDiscussMilestonePrompt(mid, midTitle, base, structuredQuestionsAvailable = "false", { headless = false } = {}) {
1336
- const discussTemplates = inlineTemplate("context", "Context");
1329
+ export async function buildDiscussMilestoneInlinedContext(mid, base) {
1330
+ const inlined = [];
1331
+ const roadmapInline = await inlineFileOptional(resolveMilestoneFile(base, mid, "ROADMAP"), relMilestoneFile(base, mid, "ROADMAP"), "Milestone Roadmap");
1332
+ if (roadmapInline)
1333
+ inlined.push(roadmapInline);
1334
+ const contextInline = await inlineFileOptional(resolveMilestoneFile(base, mid, "CONTEXT"), relMilestoneFile(base, mid, "CONTEXT"), "Milestone Context");
1335
+ if (contextInline)
1336
+ inlined.push(contextInline);
1337
+ const researchInline = await inlineFileOptional(resolveMilestoneFile(base, mid, "RESEARCH"), relMilestoneFile(base, mid, "RESEARCH"), "Milestone Research");
1338
+ if (researchInline)
1339
+ inlined.push(researchInline);
1340
+ const decisionsPath = resolveGsdRootFile(base, "DECISIONS");
1341
+ if (existsSync(decisionsPath)) {
1342
+ const decisionsContent = await loadFile(decisionsPath);
1343
+ if (decisionsContent) {
1344
+ inlined.push(`### Decisions Register\nSource: \`${relGsdRootFile("DECISIONS")}\`\n\n${decisionsContent.trim()}`);
1345
+ }
1346
+ }
1347
+ const milestoneIds = findMilestoneIds(base);
1348
+ const currentIndex = milestoneIds.indexOf(mid);
1349
+ const priorMilestoneIds = currentIndex >= 0 ? milestoneIds.slice(0, currentIndex) : milestoneIds;
1350
+ for (const priorMid of priorMilestoneIds) {
1351
+ const summaryInline = await inlineFileOptional(resolveMilestoneFile(base, priorMid, "SUMMARY"), relMilestoneFile(base, priorMid, "SUMMARY"), `${priorMid} Prior Milestone Summary`);
1352
+ if (summaryInline)
1353
+ inlined.push(summaryInline);
1354
+ }
1355
+ return inlined.length > 0
1356
+ ? `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`
1357
+ : "## Inlined Context\n\n_(no milestone context files found yet — go in blind and ask broad questions)_";
1358
+ }
1359
+ export async function buildDiscussMilestonePrompt(mid, midTitle, base, structuredQuestionsAvailable = "false", { headless = false, commitInstruction = "Do not commit planning artifacts — .gsd/ is managed externally.", fastPathInstruction = "", includeDraftSeed = true, includeContextMode = true, } = {}) {
1360
+ const contextTemplate = inlineTemplate("context", "Context");
1337
1361
  if (headless) {
1338
1362
  const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
1339
1363
  const roadmapContent = roadmapPath ? await loadFile(roadmapPath) : null;
1340
1364
  return loadPrompt("discuss-headless", {
1341
1365
  seedContext: roadmapContent ?? "",
1342
- inlinedTemplates: discussTemplates,
1366
+ inlinedTemplates: contextTemplate,
1343
1367
  workingDirectory: base,
1344
1368
  milestoneId: mid,
1345
1369
  contextPath: relMilestoneFile(base, mid, "CONTEXT"),
@@ -1347,24 +1371,28 @@ export async function buildDiscussMilestonePrompt(mid, midTitle, base, structure
1347
1371
  multiMilestoneCommitInstruction: "Do not commit planning artifacts — .gsd/ is managed externally.",
1348
1372
  });
1349
1373
  }
1350
- const contextModeInstructions = renderContextModeForPrompt("discuss-milestone", base);
1374
+ const rawInlinedContext = await buildDiscussMilestoneInlinedContext(mid, base);
1375
+ const cappedInlinedContext = capPreamble(rawInlinedContext);
1376
+ const discussTemplates = [cappedInlinedContext, contextTemplate].join("\n\n---\n\n");
1351
1377
  const basePrompt = loadPrompt("guided-discuss-milestone", {
1352
1378
  workingDirectory: base,
1353
1379
  milestoneId: mid,
1354
1380
  milestoneTitle: midTitle,
1355
1381
  inlinedTemplates: discussTemplates,
1356
1382
  structuredQuestionsAvailable,
1357
- commitInstruction: "Do not commit planning artifacts — .gsd/ is managed externally.",
1358
- fastPathInstruction: "",
1383
+ commitInstruction,
1384
+ fastPathInstruction,
1359
1385
  });
1360
- const promptWithContextMode = prependContextModeToBlock("discuss-milestone", base, basePrompt);
1386
+ const promptWithContextMode = includeContextMode
1387
+ ? prependContextModeToBlock("discuss-milestone", base, basePrompt)
1388
+ : basePrompt;
1361
1389
  // If a CONTEXT-DRAFT.md exists, append it as seed material
1362
1390
  const draftPath = resolveMilestoneFile(base, mid, "CONTEXT-DRAFT");
1363
1391
  const draftContent = draftPath ? await loadFile(draftPath) : null;
1364
- if (draftContent) {
1392
+ if (includeDraftSeed && draftContent) {
1365
1393
  return `${promptWithContextMode}\n\n## Prior Discussion (Draft Seed)\n\nThe following draft was captured from a prior multi-milestone discussion. Use it as seed material — the user has already provided this context. Start with a brief reflection on what the draft covers, then probe for any gaps or open questions before writing the full CONTEXT.md.\n\n${draftContent}`;
1366
1394
  }
1367
- return contextModeInstructions ? promptWithContextMode : basePrompt;
1395
+ return promptWithContextMode;
1368
1396
  }
1369
1397
  /**
1370
1398
  * Build a prompt for the workflow-preferences unit type (deep mode).
@@ -2351,6 +2379,15 @@ export async function buildCompleteSlicePrompt(mid, midTitle, sid, sTitle, base,
2351
2379
  sliceSummaryPath,
2352
2380
  sliceUatPath,
2353
2381
  gatesToClose,
2382
+ skillActivation: buildSkillActivationBlock({
2383
+ base,
2384
+ milestoneId: mid,
2385
+ milestoneTitle: midTitle,
2386
+ sliceId: sid,
2387
+ sliceTitle: sTitle,
2388
+ extraContext: [inlinedContext],
2389
+ unitType: "complete-slice",
2390
+ }),
2354
2391
  });
2355
2392
  }
2356
2393
  export async function buildCompleteMilestonePrompt(mid, midTitle, base, level) {
@@ -2531,17 +2568,26 @@ export async function buildValidateMilestonePrompt(mid, midTitle, base, level) {
2531
2568
  if (isDbAvailable()) {
2532
2569
  const milestone = getMilestone(mid);
2533
2570
  if (milestone) {
2571
+ const escapeCell = (value) => value.replace(/[\\|]/g, (char) => `\\${char}`).replace(/\r?\n/g, " ");
2534
2572
  const classes = [];
2535
2573
  if (milestone.verification_contract)
2536
- classes.push(`- **Contract:** ${milestone.verification_contract}`);
2574
+ classes.push(`| Contract | ${escapeCell(milestone.verification_contract)} |`);
2537
2575
  if (milestone.verification_integration)
2538
- classes.push(`- **Integration:** ${milestone.verification_integration}`);
2576
+ classes.push(`| Integration | ${escapeCell(milestone.verification_integration)} |`);
2539
2577
  if (milestone.verification_operational)
2540
- classes.push(`- **Operational:** ${milestone.verification_operational}`);
2578
+ classes.push(`| Operational | ${escapeCell(milestone.verification_operational)} |`);
2541
2579
  if (milestone.verification_uat)
2542
- classes.push(`- **UAT:** ${milestone.verification_uat}`);
2580
+ classes.push(`| UAT | ${escapeCell(milestone.verification_uat)} |`);
2543
2581
  if (classes.length > 0) {
2544
- const verificationClasses = `### Verification Classes (from planning)\n\nThese verification tiers were defined during milestone planning. Each non-empty class must be checked for evidence during validation.\n\n${classes.join("\n")}`;
2582
+ const verificationClasses = [
2583
+ "### Verification Classes (from planning)",
2584
+ "",
2585
+ "These verification tiers were defined during milestone planning. Every row in this table must appear in `verificationClasses` with the same canonical class name.",
2586
+ "",
2587
+ "| Class | Planned Check |",
2588
+ "| --- | --- |",
2589
+ ...classes,
2590
+ ].join("\n");
2545
2591
  inlined.push(verificationClasses);
2546
2592
  trackPromptContext(contextTelemetry, "verification-classes", "inline", verificationClasses);
2547
2593
  }