@opengsd/gsd-pi 1.1.1-dev.74e8dd1 → 1.1.1-dev.a5a2de8

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 (329) hide show
  1. package/dist/cli.js +3 -2
  2. package/dist/help-text.js +10 -6
  3. package/dist/resources/.managed-resources-content-hash +1 -1
  4. package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +495 -0
  5. package/dist/resources/extensions/browser-tools/engine/selection.js +16 -0
  6. package/dist/resources/extensions/browser-tools/extension-manifest.json +2 -2
  7. package/dist/resources/extensions/browser-tools/index.js +57 -9
  8. package/dist/resources/extensions/browser-tools/package.json +5 -1
  9. package/dist/resources/extensions/gsd/auto/orchestrator.js +0 -1
  10. package/dist/resources/extensions/gsd/auto-dashboard.js +77 -13
  11. package/dist/resources/extensions/gsd/auto-dispatch.js +16 -0
  12. package/dist/resources/extensions/gsd/auto-post-unit.js +21 -3
  13. package/dist/resources/extensions/gsd/auto-prompts.js +63 -22
  14. package/dist/resources/extensions/gsd/auto-recovery.js +3 -4
  15. package/dist/resources/extensions/gsd/auto-runtime-state.js +3 -0
  16. package/dist/resources/extensions/gsd/auto-tool-tracking.js +1 -1
  17. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +18 -66
  18. package/dist/resources/extensions/gsd/auto-worktree.js +18 -5
  19. package/dist/resources/extensions/gsd/auto.js +9 -2
  20. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +20 -14
  21. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +28 -13
  22. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +18 -29
  23. package/dist/resources/extensions/gsd/browser-evidence.js +29 -2
  24. package/dist/resources/extensions/gsd/closeout-consistency-gate.js +61 -0
  25. package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -2
  26. package/dist/resources/extensions/gsd/commands-handlers.js +76 -11
  27. package/dist/resources/extensions/gsd/commands-mcp-status.js +2 -1
  28. package/dist/resources/extensions/gsd/dashboard-overlay.js +21 -7
  29. package/dist/resources/extensions/gsd/docs/preferences-reference.md +8 -0
  30. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +2 -2
  31. package/dist/resources/extensions/gsd/escalation.js +4 -4
  32. package/dist/resources/extensions/gsd/forensics.js +74 -2
  33. package/dist/resources/extensions/gsd/gsd-db.js +5 -2
  34. package/dist/resources/extensions/gsd/guided-flow.js +118 -175
  35. package/dist/resources/extensions/gsd/mcp-project-config.js +9 -76
  36. package/dist/resources/extensions/gsd/memory-store.js +4 -1
  37. package/dist/resources/extensions/gsd/milestone-closeout.js +3 -1
  38. package/dist/resources/extensions/gsd/pending-auto-start.js +0 -1
  39. package/dist/resources/extensions/gsd/post-unit-hooks.js +9 -0
  40. package/dist/resources/extensions/gsd/preferences-validation.js +39 -0
  41. package/dist/resources/extensions/gsd/prompt-loader.js +7 -0
  42. package/dist/resources/extensions/gsd/prompts/forensics.md +61 -1
  43. package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
  44. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
  45. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  46. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
  47. package/dist/resources/extensions/gsd/prompts/run-uat.md +25 -21
  48. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
  49. package/dist/resources/extensions/gsd/recovery-classification.js +20 -0
  50. package/dist/resources/extensions/gsd/rule-registry.js +428 -52
  51. package/dist/resources/extensions/gsd/state.js +2 -2
  52. package/dist/resources/extensions/gsd/templates/plan.md +3 -1
  53. package/dist/resources/extensions/gsd/tool-contract.js +5 -0
  54. package/dist/resources/extensions/gsd/tool-presentation-plan.js +17 -7
  55. package/dist/resources/extensions/gsd/tools/complete-slice.js +15 -1
  56. package/dist/resources/extensions/gsd/tools/complete-task.js +11 -1
  57. package/dist/resources/extensions/gsd/tools/validate-milestone.js +46 -16
  58. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +132 -18
  59. package/dist/resources/extensions/gsd/unit-tool-contracts.js +169 -0
  60. package/dist/resources/extensions/gsd/verdict-parser.js +59 -15
  61. package/dist/resources/extensions/gsd/verification-gate.js +72 -1
  62. package/dist/resources/extensions/gsd/workflow-mcp.js +3 -75
  63. package/dist/resources/extensions/shared/gsd-browser-cli.js +145 -0
  64. package/dist/rtk.d.ts +7 -1
  65. package/dist/rtk.js +27 -11
  66. package/dist/update-check.d.ts +15 -1
  67. package/dist/update-check.js +87 -12
  68. package/dist/update-cmd.d.ts +1 -0
  69. package/dist/update-cmd.js +53 -2
  70. package/dist/web/standalone/.next/BUILD_ID +1 -1
  71. package/dist/web/standalone/.next/app-path-routes-manifest.json +7 -7
  72. package/dist/web/standalone/.next/build-manifest.json +2 -2
  73. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  74. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  75. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  83. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  91. package/dist/web/standalone/.next/server/app/index.html +1 -1
  92. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app-paths-manifest.json +7 -7
  99. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  100. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  101. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  102. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  103. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  104. package/package.json +4 -2
  105. package/packages/cloud-mcp-gateway/package.json +2 -2
  106. package/packages/contracts/package.json +1 -1
  107. package/packages/daemon/package.json +4 -4
  108. package/packages/gsd-agent-core/dist/agent-session.d.ts +9 -0
  109. package/packages/gsd-agent-core/dist/agent-session.d.ts.map +1 -1
  110. package/packages/gsd-agent-core/dist/agent-session.js +32 -0
  111. package/packages/gsd-agent-core/dist/agent-session.js.map +1 -1
  112. package/packages/gsd-agent-core/dist/index.d.ts +1 -0
  113. package/packages/gsd-agent-core/dist/index.d.ts.map +1 -1
  114. package/packages/gsd-agent-core/dist/index.js +1 -0
  115. package/packages/gsd-agent-core/dist/index.js.map +1 -1
  116. package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts +2 -0
  117. package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts.map +1 -1
  118. package/packages/gsd-agent-core/dist/session/agent-session-compaction.js +8 -2
  119. package/packages/gsd-agent-core/dist/session/agent-session-compaction.js.map +1 -1
  120. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts +7 -0
  121. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts.map +1 -1
  122. package/packages/gsd-agent-core/dist/session/agent-session-host.js.map +1 -1
  123. package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts.map +1 -1
  124. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js +69 -1
  125. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js.map +1 -1
  126. package/packages/gsd-agent-core/dist/turn-latency.d.ts +47 -0
  127. package/packages/gsd-agent-core/dist/turn-latency.d.ts.map +1 -0
  128. package/packages/gsd-agent-core/dist/turn-latency.js +123 -0
  129. package/packages/gsd-agent-core/dist/turn-latency.js.map +1 -0
  130. package/packages/gsd-agent-core/package.json +6 -6
  131. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts +21 -0
  132. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts.map +1 -0
  133. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js +213 -0
  134. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js.map +1 -0
  135. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  136. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +5 -0
  137. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  138. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  139. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +20 -0
  140. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  141. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  142. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +7 -1
  143. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  144. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.d.ts.map +1 -1
  145. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js +6 -0
  146. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js.map +1 -1
  147. package/packages/gsd-agent-modes/package.json +7 -7
  148. package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -1
  149. package/packages/mcp-server/dist/remote-questions.js +23 -9
  150. package/packages/mcp-server/dist/remote-questions.js.map +1 -1
  151. package/packages/mcp-server/dist/workflow-tools.js +2 -2
  152. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  153. package/packages/mcp-server/package.json +3 -3
  154. package/packages/native/package.json +1 -1
  155. package/packages/pi-agent-core/dist/agent-loop.js +42 -3
  156. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  157. package/packages/pi-agent-core/dist/agent.d.ts +5 -1
  158. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  159. package/packages/pi-agent-core/dist/agent.js +2 -0
  160. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  161. package/packages/pi-agent-core/dist/harness/agent-harness.d.ts.map +1 -1
  162. package/packages/pi-agent-core/dist/harness/agent-harness.js +3 -1
  163. package/packages/pi-agent-core/dist/harness/agent-harness.js.map +1 -1
  164. package/packages/pi-agent-core/dist/harness/types.d.ts +1 -0
  165. package/packages/pi-agent-core/dist/harness/types.d.ts.map +1 -1
  166. package/packages/pi-agent-core/dist/harness/types.js.map +1 -1
  167. package/packages/pi-agent-core/dist/types.d.ts +6 -1
  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/models.generated.d.ts +74 -6
  176. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  177. package/packages/pi-ai/dist/models.generated.js +78 -10
  178. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  179. package/packages/pi-ai/dist/stream.js +6 -6
  180. package/packages/pi-ai/dist/stream.js.map +1 -1
  181. package/packages/pi-ai/package.json +1 -1
  182. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts +3 -0
  183. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts.map +1 -1
  184. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.js.map +1 -1
  185. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  186. package/packages/pi-coding-agent/dist/core/model-registry.js +2 -2
  187. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  188. package/packages/pi-coding-agent/dist/core/tools/bash.js +2 -2
  189. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  190. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
  191. package/packages/pi-coding-agent/dist/core/tools/edit.js +3 -2
  192. package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
  193. package/packages/pi-coding-agent/dist/core/tools/render-utils.d.ts +1 -0
  194. package/packages/pi-coding-agent/dist/core/tools/render-utils.d.ts.map +1 -1
  195. package/packages/pi-coding-agent/dist/core/tools/render-utils.js +6 -0
  196. package/packages/pi-coding-agent/dist/core/tools/render-utils.js.map +1 -1
  197. package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
  198. package/packages/pi-coding-agent/dist/core/tools/write.js +3 -2
  199. package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
  200. package/packages/pi-coding-agent/package.json +7 -7
  201. package/packages/pi-tui/package.json +1 -1
  202. package/packages/rpc-client/package.json +2 -2
  203. package/pkg/package.json +1 -1
  204. package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +579 -0
  205. package/src/resources/extensions/browser-tools/engine/selection.ts +19 -0
  206. package/src/resources/extensions/browser-tools/extension-manifest.json +2 -2
  207. package/src/resources/extensions/browser-tools/index.ts +60 -9
  208. package/src/resources/extensions/browser-tools/package.json +5 -1
  209. package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +35 -0
  210. package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +33 -0
  211. package/src/resources/extensions/gsd/auto/orchestrator.ts +0 -1
  212. package/src/resources/extensions/gsd/auto-dashboard.ts +82 -14
  213. package/src/resources/extensions/gsd/auto-dispatch.ts +19 -0
  214. package/src/resources/extensions/gsd/auto-post-unit.ts +28 -2
  215. package/src/resources/extensions/gsd/auto-prompts.ts +97 -15
  216. package/src/resources/extensions/gsd/auto-recovery.ts +3 -3
  217. package/src/resources/extensions/gsd/auto-runtime-state.ts +4 -0
  218. package/src/resources/extensions/gsd/auto-tool-tracking.ts +1 -1
  219. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +43 -74
  220. package/src/resources/extensions/gsd/auto-worktree.ts +23 -5
  221. package/src/resources/extensions/gsd/auto.ts +12 -2
  222. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +20 -14
  223. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +32 -13
  224. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +50 -54
  225. package/src/resources/extensions/gsd/browser-evidence.ts +26 -2
  226. package/src/resources/extensions/gsd/closeout-consistency-gate.ts +137 -0
  227. package/src/resources/extensions/gsd/commands/handlers/ops.ts +2 -2
  228. package/src/resources/extensions/gsd/commands-handlers.ts +76 -11
  229. package/src/resources/extensions/gsd/commands-mcp-status.ts +2 -1
  230. package/src/resources/extensions/gsd/dashboard-overlay.ts +28 -7
  231. package/src/resources/extensions/gsd/docs/preferences-reference.md +8 -0
  232. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +2 -2
  233. package/src/resources/extensions/gsd/escalation.ts +4 -4
  234. package/src/resources/extensions/gsd/forensics.ts +99 -5
  235. package/src/resources/extensions/gsd/gsd-db.ts +5 -2
  236. package/src/resources/extensions/gsd/guided-flow.ts +214 -216
  237. package/src/resources/extensions/gsd/mcp-project-config.ts +13 -78
  238. package/src/resources/extensions/gsd/memory-store.ts +4 -1
  239. package/src/resources/extensions/gsd/milestone-closeout.ts +3 -1
  240. package/src/resources/extensions/gsd/pending-auto-start.ts +0 -2
  241. package/src/resources/extensions/gsd/post-unit-hooks.ts +14 -1
  242. package/src/resources/extensions/gsd/preferences-validation.ts +36 -0
  243. package/src/resources/extensions/gsd/prompt-loader.ts +8 -0
  244. package/src/resources/extensions/gsd/prompts/forensics.md +61 -1
  245. package/src/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
  246. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
  247. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  248. package/src/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
  249. package/src/resources/extensions/gsd/prompts/run-uat.md +25 -21
  250. package/src/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
  251. package/src/resources/extensions/gsd/recovery-classification.ts +20 -0
  252. package/src/resources/extensions/gsd/rule-registry.ts +558 -58
  253. package/src/resources/extensions/gsd/rule-types.ts +2 -0
  254. package/src/resources/extensions/gsd/state.ts +2 -2
  255. package/src/resources/extensions/gsd/templates/plan.md +3 -1
  256. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +105 -4
  257. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +37 -0
  258. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +10 -2
  259. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +4 -1
  260. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +12 -2
  261. package/src/resources/extensions/gsd/tests/browser-evidence.test.ts +142 -0
  262. package/src/resources/extensions/gsd/tests/check-auto-start-pending-gate.test.ts +9 -15
  263. package/src/resources/extensions/gsd/tests/check-auto-start-ready-guard.test.ts +26 -16
  264. package/src/resources/extensions/gsd/tests/commands-dispatcher-unmerged-milestone.test.ts +21 -0
  265. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +30 -0
  266. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +42 -0
  267. package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +45 -0
  268. package/src/resources/extensions/gsd/tests/deep-planning-mode-dispatch.test.ts +53 -0
  269. package/src/resources/extensions/gsd/tests/discuss-milestone-structured-questions.test.ts +31 -0
  270. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +40 -1
  271. package/src/resources/extensions/gsd/tests/doctor-runtime-checks.test.ts +27 -0
  272. package/src/resources/extensions/gsd/tests/escalation.test.ts +16 -27
  273. package/src/resources/extensions/gsd/tests/forensics-issue-routing.test.ts +20 -0
  274. package/src/resources/extensions/gsd/tests/forensics-prompt-rendering.test.ts +3 -0
  275. package/src/resources/extensions/gsd/tests/forensics-tool-scope.test.ts +69 -0
  276. package/src/resources/extensions/gsd/tests/gate-1b-orphan-discrimination.test.ts +31 -79
  277. package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +40 -1
  278. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +86 -0
  279. package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +5 -3
  280. package/src/resources/extensions/gsd/tests/guided-flow-state-rebuild.test.ts +40 -4
  281. package/src/resources/extensions/gsd/tests/guided-flow.test.ts +12 -9
  282. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +4 -4
  283. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +8 -0
  284. package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +16 -0
  285. package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +69 -10
  286. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +32 -0
  287. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +2 -0
  288. package/src/resources/extensions/gsd/tests/memory-maintenance.test.ts +39 -8
  289. package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +63 -0
  290. package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +10 -1
  291. package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +9 -1
  292. package/src/resources/extensions/gsd/tests/new-milestone-discuss-routing.test.ts +3 -3
  293. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +9 -0
  294. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +157 -0
  295. package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +179 -0
  296. package/src/resources/extensions/gsd/tests/preferences.test.ts +29 -0
  297. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +61 -1
  298. package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +14 -0
  299. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +7 -8
  300. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +44 -0
  301. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +75 -0
  302. package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +4 -0
  303. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +36 -0
  304. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +100 -0
  305. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +139 -0
  306. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +4 -4
  307. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +19 -0
  308. package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +7 -1
  309. package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +6 -3
  310. package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +133 -0
  311. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +51 -0
  312. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +351 -0
  313. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +15 -0
  314. package/src/resources/extensions/gsd/tool-contract.ts +6 -0
  315. package/src/resources/extensions/gsd/tool-presentation-plan.ts +38 -8
  316. package/src/resources/extensions/gsd/tools/complete-slice.ts +14 -1
  317. package/src/resources/extensions/gsd/tools/complete-task.ts +20 -2
  318. package/src/resources/extensions/gsd/tools/validate-milestone.ts +46 -15
  319. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +163 -20
  320. package/src/resources/extensions/gsd/types.ts +69 -5
  321. package/src/resources/extensions/gsd/unit-tool-contracts.ts +186 -0
  322. package/src/resources/extensions/gsd/verdict-parser.ts +54 -13
  323. package/src/resources/extensions/gsd/verification-gate.ts +87 -1
  324. package/src/resources/extensions/gsd/workflow-mcp.ts +3 -75
  325. package/src/resources/extensions/shared/gsd-browser-cli.ts +172 -0
  326. package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound-corrections.test.ts +0 -246
  327. package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound.test.ts +0 -218
  328. /package/dist/web/standalone/.next/static/{eRWf-RI9bzbrwEurm_3uI → 9y3LeeR2uGr2yRj9RjY3D}/_buildManifest.js +0 -0
  329. /package/dist/web/standalone/.next/static/{eRWf-RI9bzbrwEurm_3uI → 9y3LeeR2uGr2yRj9RjY3D}/_ssgManifest.js +0 -0
@@ -4,7 +4,7 @@
4
4
  "version": "1.0.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
- "test": "node --test tests/*.test.mjs"
7
+ "test": "node --import ../gsd/tests/resolve-ts.mjs --experimental-strip-types --test tests/*.test.mjs"
8
8
  },
9
9
  "pi": {
10
10
  "extensions": [
@@ -12,10 +12,14 @@
12
12
  ]
13
13
  },
14
14
  "peerDependencies": {
15
+ "@opengsd/gsd-browser": ">=0.1.27",
15
16
  "playwright": ">=1.40.0",
16
17
  "sharp": ">=0.33.0"
17
18
  },
18
19
  "peerDependenciesMeta": {
20
+ "@opengsd/gsd-browser": {
21
+ "optional": true
22
+ },
19
23
  "playwright": {
20
24
  "optional": true
21
25
  },
@@ -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",
@@ -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.
@@ -642,26 +675,57 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
642
675
  cachedWidth = width;
643
676
  return lines;
644
677
  }
645
- // ── Mode: small — header + active work progress ───────────────
678
+ // ── Mode: small — dense horizontal grid ───────────────────────
646
679
  if (widgetMode === "small") {
647
- lines.push("");
648
- // Action line
649
- const target = task ? `${task.id}: ${task.title}` : unitId;
650
- const actionLeft = `${pad}${theme.fg("accent", "▸")} ${theme.fg("accent", verb)} ${theme.fg("text", target)}`;
651
- lines.push(rightAlign(actionLeft, theme.fg("dim", phaseLabel), width));
652
- // Progress bar
680
+ lines.length = 0;
681
+ lines.push(...ui.bar());
653
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 ?? "--";
654
709
  if (shouldRenderRoadmapProgress(roadmapSlices)) {
655
710
  const { done, total, activeSliceTasks } = roadmapSlices;
656
- 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)));
657
712
  const bar = renderProgressBar(theme, done, total, barWidth);
658
- let meta = `${theme.fg("text", `${done}`)}${theme.fg("dim", `/${total} slices`)}`;
713
+ sliceValue = `${bar} ${theme.fg("text", `${done}/${total}`)}`;
659
714
  if (activeSliceTasks && activeSliceTasks.total > 0) {
660
- const tn = Math.min(activeSliceTasks.done + 1, activeSliceTasks.total);
661
- 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}`)}`;
662
719
  }
663
- lines.push(`${pad}${bar} ${meta}`);
664
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);
665
729
  lines.push(...ui.bar());
666
730
  cachedLines = lines;
667
731
  cachedWidth = width;
@@ -35,6 +35,7 @@ import { probeGitConflictState } from "./git-conflict-state.js";
35
35
  import { runTurnGitAction } from "./git-service.js";
36
36
  import { parseUnitId } from "./unit-id.js";
37
37
  import { resolveExpectedArtifactPath } from "./auto-artifact-paths.js";
38
+ import { checkCloseoutConsistencyGate, formatCloseoutConsistencyBlock, } from "./closeout-consistency-gate.js";
38
39
  function resolveExistingExpectedArtifact(unitType, unitId, basePath) {
39
40
  const artifactPath = resolveExpectedArtifactPath(unitType, unitId, basePath);
40
41
  return artifactPath && existsSync(artifactPath) ? artifactPath : null;
@@ -443,6 +444,7 @@ export const DISPATCH_RULES = [
443
444
  unitType: "discuss-milestone",
444
445
  unitId: mid,
445
446
  prompt: await buildDiscussMilestonePrompt(mid, midTitle, basePath, structuredQuestionsAvailable, { headless: !!process.env.GSD_HEADLESS }),
447
+ pauseAfterDispatch: !process.env.GSD_HEADLESS,
446
448
  };
447
449
  },
448
450
  },
@@ -578,6 +580,7 @@ export const DISPATCH_RULES = [
578
580
  unitType: "discuss-milestone",
579
581
  unitId: mid,
580
582
  prompt: await buildDiscussMilestonePrompt(mid, midTitle, basePath, structuredQuestionsAvailable, { headless: !!process.env.GSD_HEADLESS }),
583
+ pauseAfterDispatch: !process.env.GSD_HEADLESS,
581
584
  };
582
585
  },
583
586
  },
@@ -617,6 +620,7 @@ export const DISPATCH_RULES = [
617
620
  unitType: "discuss-project",
618
621
  unitId: "PROJECT",
619
622
  prompt: await buildDiscussProjectPrompt(basePath, structuredQuestionsAvailable),
623
+ pauseAfterDispatch: !process.env.GSD_HEADLESS,
620
624
  };
621
625
  },
622
626
  },
@@ -642,6 +646,7 @@ export const DISPATCH_RULES = [
642
646
  unitType: "discuss-requirements",
643
647
  unitId: "REQUIREMENTS",
644
648
  prompt: await buildDiscussRequirementsPrompt(basePath, structuredQuestionsAvailable),
649
+ pauseAfterDispatch: !process.env.GSD_HEADLESS,
645
650
  };
646
651
  },
647
652
  },
@@ -757,6 +762,7 @@ export const DISPATCH_RULES = [
757
762
  unitType: "discuss-milestone",
758
763
  unitId: mid,
759
764
  prompt: await buildDiscussMilestonePrompt(mid, midTitle, basePath, structuredQuestionsAvailable, { headless: !!process.env.GSD_HEADLESS }),
765
+ pauseAfterDispatch: !process.env.GSD_HEADLESS,
760
766
  };
761
767
  },
762
768
  },
@@ -1350,6 +1356,16 @@ export const DISPATCH_RULES = [
1350
1356
  prompt: await buildCompleteMilestonePrompt(mid, midTitle, basePath),
1351
1357
  };
1352
1358
  }
1359
+ if (milestone) {
1360
+ const closeoutGate = checkCloseoutConsistencyGate(mid, { refreshFromDisk: true });
1361
+ if (!closeoutGate.ok) {
1362
+ return {
1363
+ action: "stop",
1364
+ reason: formatCloseoutConsistencyBlock(closeoutGate),
1365
+ level: "warning",
1366
+ };
1367
+ }
1368
+ }
1353
1369
  }
1354
1370
  return {
1355
1371
  action: "stop",
@@ -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";
@@ -1860,18 +1860,25 @@ export async function postUnitPostVerification(pctx) {
1860
1860
  // ── Post-unit hooks ──
1861
1861
  if (s.currentUnit && !s.stepMode) {
1862
1862
  const hookUnit = checkPostUnitHooks(s.currentUnit.type, s.currentUnit.id, s.basePath);
1863
+ persistHookState(s.basePath);
1863
1864
  if (hookUnit) {
1864
1865
  if (s.currentUnit) {
1865
1866
  await closeoutUnit(ctx, s.basePath, s.currentUnit.type, s.currentUnit.id, s.currentUnit.startedAt, buildSnapshotOpts(s.currentUnit.type, s.currentUnit.id));
1866
1867
  }
1867
- persistHookState(s.basePath);
1868
1868
  return enqueueSidecar(s, ctx, { kind: "hook", unitType: hookUnit.unitType, unitId: hookUnit.unitId, prompt: hookUnit.prompt, model: hookUnit.model }, { hookName: hookUnit.hookName });
1869
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
+ }
1870
1876
  // Check if a hook requested a retry of the trigger unit
1871
1877
  if (isRetryPending()) {
1872
1878
  const trigger = consumeRetryTrigger();
1873
1879
  if (trigger) {
1874
- 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");
1875
1882
  await s.orchestration?.retryActiveUnit({
1876
1883
  unitType: trigger.unitType,
1877
1884
  unitId: trigger.unitId,
@@ -1918,6 +1925,17 @@ export async function postUnitPostVerification(pctx) {
1918
1925
  // Fall through to normal dispatch — deriveState will re-derive the unit
1919
1926
  }
1920
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
+ }
1921
1939
  }
1922
1940
  // ── Fast-path stop detection (#3487) ──
1923
1941
  // Before waiting for triage, check if any PENDING captures contain explicit
@@ -30,6 +30,8 @@ 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";
34
+ import { buildRunUatResultPresentation, RUN_UAT_TOOL_PRESENTATION_PLAN_ID } from "./tool-presentation-plan.js";
33
35
  export { buildSkillActivationBlock, buildSkillDiscoveryVars };
34
36
  // ─── Preamble Cap ─────────────────────────────────────────────────────────────
35
37
  /**
@@ -1270,7 +1272,7 @@ export async function checkNeedsRunUat(base, mid, state, prefs) {
1270
1272
  if (hasVerdict(uatContent))
1271
1273
  continue;
1272
1274
  // Also check the ASSESSMENT file — the run-uat prompt writes the verdict
1273
- // there (via gsd_summary_save artifact_type:"ASSESSMENT"), not into the
1275
+ // there (via gsd_uat_result_save), not into the
1274
1276
  // UAT spec file. Without this check the unit re-dispatches indefinitely.
1275
1277
  const assessmentFile = resolveSliceFile(base, mid, sid, "ASSESSMENT");
1276
1278
  if (assessmentFile) {
@@ -1325,21 +1327,44 @@ export async function checkNeedsRunUat(base, mid, state, prefs) {
1325
1327
  }
1326
1328
  return null;
1327
1329
  }
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");
1330
+ export async function buildDiscussMilestoneInlinedContext(mid, base) {
1331
+ const inlined = [];
1332
+ const roadmapInline = await inlineFileOptional(resolveMilestoneFile(base, mid, "ROADMAP"), relMilestoneFile(base, mid, "ROADMAP"), "Milestone Roadmap");
1333
+ if (roadmapInline)
1334
+ inlined.push(roadmapInline);
1335
+ const contextInline = await inlineFileOptional(resolveMilestoneFile(base, mid, "CONTEXT"), relMilestoneFile(base, mid, "CONTEXT"), "Milestone Context");
1336
+ if (contextInline)
1337
+ inlined.push(contextInline);
1338
+ const researchInline = await inlineFileOptional(resolveMilestoneFile(base, mid, "RESEARCH"), relMilestoneFile(base, mid, "RESEARCH"), "Milestone Research");
1339
+ if (researchInline)
1340
+ inlined.push(researchInline);
1341
+ const decisionsPath = resolveGsdRootFile(base, "DECISIONS");
1342
+ if (existsSync(decisionsPath)) {
1343
+ const decisionsContent = await loadFile(decisionsPath);
1344
+ if (decisionsContent) {
1345
+ inlined.push(`### Decisions Register\nSource: \`${relGsdRootFile("DECISIONS")}\`\n\n${decisionsContent.trim()}`);
1346
+ }
1347
+ }
1348
+ const milestoneIds = findMilestoneIds(base);
1349
+ const currentIndex = milestoneIds.indexOf(mid);
1350
+ const priorMilestoneIds = currentIndex >= 0 ? milestoneIds.slice(0, currentIndex) : milestoneIds;
1351
+ for (const priorMid of priorMilestoneIds) {
1352
+ const summaryInline = await inlineFileOptional(resolveMilestoneFile(base, priorMid, "SUMMARY"), relMilestoneFile(base, priorMid, "SUMMARY"), `${priorMid} Prior Milestone Summary`);
1353
+ if (summaryInline)
1354
+ inlined.push(summaryInline);
1355
+ }
1356
+ return inlined.length > 0
1357
+ ? `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`
1358
+ : "## Inlined Context\n\n_(no milestone context files found yet — go in blind and ask broad questions)_";
1359
+ }
1360
+ 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, } = {}) {
1361
+ const contextTemplate = inlineTemplate("context", "Context");
1337
1362
  if (headless) {
1338
1363
  const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
1339
1364
  const roadmapContent = roadmapPath ? await loadFile(roadmapPath) : null;
1340
1365
  return loadPrompt("discuss-headless", {
1341
1366
  seedContext: roadmapContent ?? "",
1342
- inlinedTemplates: discussTemplates,
1367
+ inlinedTemplates: contextTemplate,
1343
1368
  workingDirectory: base,
1344
1369
  milestoneId: mid,
1345
1370
  contextPath: relMilestoneFile(base, mid, "CONTEXT"),
@@ -1347,24 +1372,28 @@ export async function buildDiscussMilestonePrompt(mid, midTitle, base, structure
1347
1372
  multiMilestoneCommitInstruction: "Do not commit planning artifacts — .gsd/ is managed externally.",
1348
1373
  });
1349
1374
  }
1350
- const contextModeInstructions = renderContextModeForPrompt("discuss-milestone", base);
1375
+ const rawInlinedContext = await buildDiscussMilestoneInlinedContext(mid, base);
1376
+ const cappedInlinedContext = capPreamble(rawInlinedContext);
1377
+ const discussTemplates = [cappedInlinedContext, contextTemplate].join("\n\n---\n\n");
1351
1378
  const basePrompt = loadPrompt("guided-discuss-milestone", {
1352
1379
  workingDirectory: base,
1353
1380
  milestoneId: mid,
1354
1381
  milestoneTitle: midTitle,
1355
1382
  inlinedTemplates: discussTemplates,
1356
1383
  structuredQuestionsAvailable,
1357
- commitInstruction: "Do not commit planning artifacts — .gsd/ is managed externally.",
1358
- fastPathInstruction: "",
1384
+ commitInstruction,
1385
+ fastPathInstruction,
1359
1386
  });
1360
- const promptWithContextMode = prependContextModeToBlock("discuss-milestone", base, basePrompt);
1387
+ const promptWithContextMode = includeContextMode
1388
+ ? prependContextModeToBlock("discuss-milestone", base, basePrompt)
1389
+ : basePrompt;
1361
1390
  // If a CONTEXT-DRAFT.md exists, append it as seed material
1362
1391
  const draftPath = resolveMilestoneFile(base, mid, "CONTEXT-DRAFT");
1363
1392
  const draftContent = draftPath ? await loadFile(draftPath) : null;
1364
- if (draftContent) {
1393
+ if (includeDraftSeed && draftContent) {
1365
1394
  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
1395
  }
1367
- return contextModeInstructions ? promptWithContextMode : basePrompt;
1396
+ return promptWithContextMode;
1368
1397
  }
1369
1398
  /**
1370
1399
  * Build a prompt for the workflow-preferences unit type (deep mode).
@@ -2540,17 +2569,26 @@ export async function buildValidateMilestonePrompt(mid, midTitle, base, level) {
2540
2569
  if (isDbAvailable()) {
2541
2570
  const milestone = getMilestone(mid);
2542
2571
  if (milestone) {
2572
+ const escapeCell = (value) => value.replace(/[\\|]/g, (char) => `\\${char}`).replace(/\r?\n/g, " ");
2543
2573
  const classes = [];
2544
2574
  if (milestone.verification_contract)
2545
- classes.push(`- **Contract:** ${milestone.verification_contract}`);
2575
+ classes.push(`| Contract | ${escapeCell(milestone.verification_contract)} |`);
2546
2576
  if (milestone.verification_integration)
2547
- classes.push(`- **Integration:** ${milestone.verification_integration}`);
2577
+ classes.push(`| Integration | ${escapeCell(milestone.verification_integration)} |`);
2548
2578
  if (milestone.verification_operational)
2549
- classes.push(`- **Operational:** ${milestone.verification_operational}`);
2579
+ classes.push(`| Operational | ${escapeCell(milestone.verification_operational)} |`);
2550
2580
  if (milestone.verification_uat)
2551
- classes.push(`- **UAT:** ${milestone.verification_uat}`);
2581
+ classes.push(`| UAT | ${escapeCell(milestone.verification_uat)} |`);
2552
2582
  if (classes.length > 0) {
2553
- 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")}`;
2583
+ const verificationClasses = [
2584
+ "### Verification Classes (from planning)",
2585
+ "",
2586
+ "These verification tiers were defined during milestone planning. Every row in this table must appear in `verificationClasses` with the same canonical class name.",
2587
+ "",
2588
+ "| Class | Planned Check |",
2589
+ "| --- | --- |",
2590
+ ...classes,
2591
+ ].join("\n");
2554
2592
  inlined.push(verificationClasses);
2555
2593
  trackPromptContext(contextTelemetry, "verification-classes", "inline", verificationClasses);
2556
2594
  }
@@ -2902,6 +2940,7 @@ export async function buildRunUatPrompt(mid, sliceId, uatPath, uatContent, base)
2902
2940
  emitPromptContextTelemetry("run-uat", contextTelemetry, inlinedContext);
2903
2941
  const uatResultPath = join(base, relSliceFile(base, mid, sliceId, "ASSESSMENT"));
2904
2942
  const uatType = resolveEffectiveUatType(uatContent);
2943
+ const canonicalPresentation = JSON.stringify(buildRunUatResultPresentation(), null, 2);
2905
2944
  return loadPrompt("run-uat", {
2906
2945
  workingDirectory: base,
2907
2946
  milestoneId: mid,
@@ -2909,6 +2948,8 @@ export async function buildRunUatPrompt(mid, sliceId, uatPath, uatContent, base)
2909
2948
  uatPath,
2910
2949
  uatResultPath,
2911
2950
  uatType,
2951
+ toolPresentationPlanId: RUN_UAT_TOOL_PRESENTATION_PLAN_ID,
2952
+ canonicalPresentation,
2912
2953
  inlinedContext,
2913
2954
  skillActivation: buildSkillActivationBlock({
2914
2955
  base,
@@ -32,6 +32,7 @@ import { isGsdWorktreePath } from "./worktree-root.js";
32
32
  import { resolveCanonicalMilestoneRoot } from "./worktree-manager.js";
33
33
  import { hasImplementationArtifacts } from "./milestone-implementation-evidence.js";
34
34
  import { loadAllCaptures, loadPendingCaptures } from "./captures.js";
35
+ import { checkCloseoutConsistencyGate } from "./closeout-consistency-gate.js";
35
36
  // Re-export so existing consumers of auto-recovery.ts keep working.
36
37
  export { resolveExpectedArtifactPath, diagnoseExpectedArtifact };
37
38
  export { classifyMilestoneSummaryContent, } from "./milestone-summary-classifier.js";
@@ -571,10 +572,8 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
571
572
  return false;
572
573
  const { milestone: mid } = parseUnitId(unitId);
573
574
  if (mid && isDbAvailable()) {
574
- const dbMilestone = getMilestone(mid);
575
- if (!dbMilestone)
576
- return false;
577
- if (!isClosedStatus(dbMilestone.status) && summaryOutcome !== "success")
575
+ const closeoutGate = checkCloseoutConsistencyGate(mid, { refreshFromDisk: true });
576
+ if (!closeoutGate.ok)
578
577
  return false;
579
578
  }
580
579
  if (hasImplementationArtifacts(base, mid) === "absent")
@@ -20,6 +20,9 @@ export function isAutoActive() {
20
20
  export function isAutoPaused() {
21
21
  return autoSession.paused;
22
22
  }
23
+ export function isAutoCompletionStopInProgress() {
24
+ return autoSession.completionStopInProgress;
25
+ }
23
26
  export function markToolStart(toolCallId, toolName) {
24
27
  markTrackedToolStart(toolCallId, autoSession.active, toolName);
25
28
  }
@@ -83,7 +83,7 @@ export function clearInFlightTools() {
83
83
  * from the tool handler. When these errors occur, retrying the same unit will
84
84
  * produce the same failure, so the retry loop must be broken.
85
85
  */
86
- const TOOL_INVOCATION_ERROR_RE = /Validation failed for tool|Expected ',' or '\}'(?: after property value)?(?: in JSON)?|Unexpected end of JSON|Unexpected token.*in JSON|does not provide an export named|Named export .* not found|Cannot find module|ERR_MODULE_NOT_FOUND|ERR_MODULE_NOT_EXPORTED|ERR_PACKAGE_PATH_NOT_EXPORTED/i;
86
+ const TOOL_INVOCATION_ERROR_RE = /Validation failed for tool|Input validation error|Invalid arguments for tool|MCP error -32602|No such tool available|Expected ',' or '\}'(?: after property value)?(?: in JSON)?|Unexpected end of JSON|Unexpected token.*in JSON|does not provide an export named|Named export .* not found|Cannot find module|ERR_MODULE_NOT_FOUND|ERR_MODULE_NOT_EXPORTED|ERR_PACKAGE_PATH_NOT_EXPORTED/i;
87
87
  const DETERMINISTIC_POLICY_ERROR_RE = /(?:^|\b)(?:HARD BLOCK:|Blocked: \/gsd queue is a planning tool|Direct writes to \.gsd\/STATE\.md and \.gsd\/gsd\.db are blocked|This is a mechanical gate)/i;
88
88
  /**
89
89
  * Returns true if the error message indicates a deterministic invocation or
@@ -1,57 +1,6 @@
1
1
  import { parseUnitId } from "./unit-id.js";
2
- import { RUN_UAT_WORKFLOW_TOOL_NAMES } from "./tool-presentation-plan.js";
3
- export const RUN_UAT_BROWSER_TOOL_NAMES = [
4
- "browser_navigate",
5
- "browser_click",
6
- "browser_type",
7
- "browser_fill_form",
8
- "browser_click_ref",
9
- "browser_fill_ref",
10
- "browser_wait_for",
11
- "browser_assert",
12
- "browser_verify",
13
- "browser_screenshot",
14
- "browser_snapshot_refs",
15
- "browser_find",
16
- "browser_get_console_logs",
17
- "browser_get_network_logs",
18
- "browser_evaluate",
19
- "browser_reload",
20
- "browser_batch",
21
- "browser_act",
22
- ];
23
- export const AUTO_UNIT_SCOPED_TOOLS = {
24
- "research-milestone": ["gsd_summary_save", "gsd_decision_save"],
25
- "plan-milestone": ["gsd_plan_milestone", "gsd_decision_save", "gsd_requirement_update"],
26
- "discuss-milestone": [
27
- "gsd_summary_save",
28
- "gsd_decision_save",
29
- "gsd_requirement_save",
30
- "gsd_requirement_update",
31
- "gsd_plan_milestone",
32
- "gsd_milestone_generate_id",
33
- ],
34
- "discuss-slice": ["gsd_summary_save", "gsd_decision_save"],
35
- "validate-milestone": ["gsd_validate_milestone", "gsd_reassess_roadmap", "subagent"],
36
- "complete-milestone": ["gsd_complete_milestone", "subagent"],
37
- "research-slice": ["gsd_summary_save", "gsd_decision_save"],
38
- "plan-slice": ["gsd_plan_slice", "gsd_plan_task", "gsd_decision_save"],
39
- "refine-slice": ["gsd_plan_slice", "gsd_plan_task", "gsd_decision_save"],
40
- "replan-slice": ["gsd_replan_slice", "gsd_plan_task", "gsd_decision_save"],
41
- "complete-slice": ["gsd_slice_complete", "gsd_task_reopen", "gsd_replan_slice", "gsd_decision_save", "gsd_requirement_update", "subagent"],
42
- "reassess-roadmap": ["gsd_reassess_roadmap"],
43
- "execute-task": ["gsd_task_complete", "gsd_decision_save"],
44
- "execute-task-simple": ["gsd_task_complete", "gsd_decision_save"],
45
- "reactive-execute": ["gsd_task_complete", "gsd_decision_save"],
46
- "run-uat": [...RUN_UAT_WORKFLOW_TOOL_NAMES, "subagent", ...RUN_UAT_BROWSER_TOOL_NAMES],
47
- "gate-evaluate": ["gsd_save_gate_result"],
48
- "rewrite-docs": ["gsd_summary_save", "gsd_decision_save"],
49
- "workflow-preferences": ["gsd_summary_save"],
50
- "discuss-project": ["gsd_summary_save", "gsd_decision_save", "gsd_requirement_save"],
51
- "discuss-requirements": ["gsd_requirement_save", "gsd_summary_save"],
52
- "research-decision": ["gsd_summary_save"],
53
- "research-project": ["gsd_summary_save", "gsd_decision_save"],
54
- };
2
+ import { AUTO_UNIT_SCOPED_TOOLS, getForbiddenGsdToolReason, } from "./unit-tool-contracts.js";
3
+ export { AUTO_UNIT_SCOPED_TOOLS, RUN_UAT_BROWSER_TOOL_NAMES, } from "./unit-tool-contracts.js";
55
4
  const WORKFLOW_TOOL_ALIASES = {
56
5
  gsd_save_decision: "gsd_decision_save",
57
6
  gsd_update_requirement: "gsd_requirement_update",
@@ -88,6 +37,7 @@ const SCOPED_GSD_LIFECYCLE_TOOLS = new Set([
88
37
  ]
89
38
  .filter((tool) => tool.startsWith("gsd_"))
90
39
  .map(canonicalWorkflowToolName));
40
+ export const GSD_PHASE_SCOPE_DISPLAY_REASON = "This GSD phase only allows its scoped workflow tools.";
91
41
  function stripMcpToolPrefix(toolName) {
92
42
  if (!toolName.startsWith("mcp__"))
93
43
  return toolName;
@@ -103,11 +53,18 @@ export function isWorkflowAliasTool(toolName) {
103
53
  }
104
54
  function hardBlockReason(unitType, what) {
105
55
  return [
106
- `HARD BLOCK: unit "${unitType}" is constrained by auto-unit tool scope — ${what}.`,
56
+ `HARD BLOCK: Tool Contract failure for unit "${unitType}" — ${what}.`,
107
57
  "This is a mechanical phase-boundary gate. You MUST NOT proceed, retry the same call,",
108
58
  "or route around this block; the orchestrator owns phase transitions.",
109
59
  ].join(" ");
110
60
  }
61
+ function hardBlock(unitType, what) {
62
+ return {
63
+ block: true,
64
+ reason: hardBlockReason(unitType, what),
65
+ displayReason: GSD_PHASE_SCOPE_DISPLAY_REASON,
66
+ };
67
+ }
111
68
  function allowedGsdToolsForUnit(unitType) {
112
69
  return [...new Set((AUTO_UNIT_SCOPED_TOOLS[unitType] ?? [])
113
70
  .filter((tool) => tool.startsWith("gsd_"))
@@ -143,20 +100,14 @@ function shouldBlockTaskCompletionScope(unitType, unitId, toolName, input) {
143
100
  actualTask === expected.task) {
144
101
  return { block: false };
145
102
  }
146
- return {
147
- block: true,
148
- reason: hardBlockReason(unitType, `gsd_task_complete may only complete the active task ${expected.milestone}/${expected.slice}/${expected.task}; requested ${actualMilestone}/${actualSlice}/${actualTask}`),
149
- };
103
+ return hardBlock(unitType, `gsd_task_complete may only complete the active task ${expected.milestone}/${expected.slice}/${expected.task}; requested ${actualMilestone}/${actualSlice}/${actualTask}`);
150
104
  }
151
105
  export function shouldBlockAutoUnitToolCall(unitType, toolName, input, unitId) {
152
106
  const scopedTools = AUTO_UNIT_SCOPED_TOOLS[unitType];
153
107
  if (!scopedTools)
154
108
  return { block: false };
155
109
  if (isNativeWorkflowTool(toolName)) {
156
- return {
157
- block: true,
158
- reason: hardBlockReason(unitType, "native Workflow is not permitted inside a dispatched GSD auto-mode unit"),
159
- };
110
+ return hardBlock(unitType, "native Workflow is not permitted inside a dispatched GSD auto-mode unit");
160
111
  }
161
112
  const taskScope = shouldBlockTaskCompletionScope(unitType, unitId, toolName, input);
162
113
  if (taskScope.block)
@@ -167,8 +118,9 @@ export function shouldBlockAutoUnitToolCall(unitType, toolName, input, unitId) {
167
118
  const allowedTools = allowedGsdToolsForUnit(unitType);
168
119
  if (allowedTools.includes(canonicalTool))
169
120
  return { block: false };
170
- return {
171
- block: true,
172
- reason: hardBlockReason(unitType, `GSD lifecycle tool "${canonicalTool}" is not permitted; allowed GSD tools: ${allowedTools.length > 0 ? allowedTools.join(", ") : "(none)"}`),
173
- };
121
+ const forbiddenReason = getForbiddenGsdToolReason(unitType, canonicalTool);
122
+ if (forbiddenReason) {
123
+ return hardBlock(unitType, `GSD lifecycle tool "${canonicalTool}" is not permitted; ${forbiddenReason} Fix unit-tool-contracts.ts or the ${unitType} prompt.`);
124
+ }
125
+ return hardBlock(unitType, `GSD lifecycle tool "${canonicalTool}" is not permitted; allowed GSD tools: ${allowedTools.length > 0 ? allowedTools.join(", ") : "(none)"}`);
174
126
  }
@@ -26,6 +26,7 @@ import { MILESTONE_ID_RE } from "./milestone-ids.js";
26
26
  import { runWorktreePostCreateHook } from "./worktree-post-create-hook.js";
27
27
  import { classifyProject } from "./detection.js";
28
28
  import { nativeGetCurrentBranch, nativeDetectMainBranch, nativeWorkingTreeStatus, nativeAddAllWithExclusions, nativeCommit, nativeCheckoutBranch, nativeMergeSquash, nativeConflictFiles, nativeAddPaths, nativeRmForce, nativeBranchDelete, nativeBranchForceReset, nativeBranchExists, nativeDiffNumstat, nativeUpdateRef, nativeIsAncestor, nativeMergeAbort, nativeWorktreeList, nativeLsFiles, } from "./native-git-bridge.js";
29
+ import { CLOSEOUT_CONSISTENCY_BLOCKED_REASON, checkCloseoutConsistencyGate, formatCloseoutConsistencyBlock, } from "./closeout-consistency-gate.js";
29
30
  import { gsdHome } from "./gsd-home.js";
30
31
  import { createWorkspace } from "./workspace.js";
31
32
  import { _finalizeProjectionForMergeImpl, _projectRootToWorktreeImpl, _projectWorktreeToRootImpl, } from "./worktree-state-projection.js";
@@ -1513,17 +1514,29 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
1513
1514
  // symlink layout) — ATTACHing a WAL-mode file to itself corrupts the
1514
1515
  // database (#2823).
1515
1516
  if (isDbAvailable()) {
1517
+ const contract = resolveGsdPathContract(worktreeCwd, originalBasePath_);
1518
+ const worktreeDbPath = join(contract.worktreeGsd ?? join(worktreeCwd, ".gsd"), "gsd.db");
1519
+ const mainDbPath = contract.projectDb;
1516
1520
  try {
1517
- const contract = resolveGsdPathContract(worktreeCwd, originalBasePath_);
1518
- const worktreeDbPath = join(contract.worktreeGsd ?? join(worktreeCwd, ".gsd"), "gsd.db");
1519
- const mainDbPath = contract.projectDb;
1521
+ const activeDbPath = getDbPath();
1522
+ if (activeDbPath && _shouldReconcileWorktreeDb(activeDbPath, mainDbPath)) {
1523
+ closeDatabase();
1524
+ if (!openDatabase(mainDbPath)) {
1525
+ throw new Error(`cannot open project DB at ${mainDbPath}`);
1526
+ }
1527
+ }
1520
1528
  if (_shouldReconcileWorktreeDb(worktreeDbPath, mainDbPath)) {
1521
1529
  reconcileWorktreeDb(mainDbPath, worktreeDbPath);
1522
1530
  }
1523
1531
  }
1524
1532
  catch (err) {
1525
- /* non-fatal */
1526
- logError("worktree", `DB reconciliation failed: ${err instanceof Error ? err.message : String(err)}`);
1533
+ const message = `DB reconciliation failed before milestone ${milestoneId} merge: ${err instanceof Error ? err.message : String(err)}`;
1534
+ logError("worktree", message);
1535
+ throw new GSDError(GSD_GIT_ERROR, `${message}. Recovery reason: ${CLOSEOUT_CONSISTENCY_BLOCKED_REASON}.`);
1536
+ }
1537
+ const closeoutGate = checkCloseoutConsistencyGate(milestoneId);
1538
+ if (!closeoutGate.ok) {
1539
+ throw new GSDError(GSD_GIT_ERROR, formatCloseoutConsistencyBlock(closeoutGate));
1527
1540
  }
1528
1541
  }
1529
1542
  // 2. Get completed slices for commit message