@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
@@ -45,6 +45,7 @@ import { classifyProject, type ProjectClassification } from "./detection.js";
45
45
  import { hasBrowserRequiredText } from "./browser-evidence.js";
46
46
  import { debugLog } from "./debug-logger.js";
47
47
  import { buildSkillActivationBlock, buildSkillDiscoveryVars } from "./skill-activation.js";
48
+ import { findMilestoneIds } from "./milestone-ids.js";
48
49
 
49
50
  export { buildSkillActivationBlock, buildSkillDiscoveryVars };
50
51
 
@@ -1428,7 +1429,7 @@ export async function checkNeedsRunUat(
1428
1429
  // If the UAT file already contains a verdict, UAT has been run — skip
1429
1430
  if (hasVerdict(uatContent)) continue;
1430
1431
  // Also check the ASSESSMENT file — the run-uat prompt writes the verdict
1431
- // there (via gsd_summary_save artifact_type:"ASSESSMENT"), not into the
1432
+ // there (via gsd_uat_result_save), not into the
1432
1433
  // UAT spec file. Without this check the unit re-dispatches indefinitely.
1433
1434
  const assessmentFile = resolveSliceFile(base, mid, sid, "ASSESSMENT");
1434
1435
  if (assessmentFile) {
@@ -1482,21 +1483,84 @@ export async function checkNeedsRunUat(
1482
1483
  * as a seed when present. The discussion agent interviews the user, writes
1483
1484
  * a full CONTEXT.md, and the phase transitions to pre-planning automatically.
1484
1485
  */
1486
+ export interface DiscussMilestonePromptOptions {
1487
+ headless?: boolean;
1488
+ commitInstruction?: string;
1489
+ fastPathInstruction?: string;
1490
+ includeDraftSeed?: boolean;
1491
+ includeContextMode?: boolean;
1492
+ }
1493
+
1494
+ export async function buildDiscussMilestoneInlinedContext(mid: string, base: string): Promise<string> {
1495
+ const inlined: string[] = [];
1496
+
1497
+ const roadmapInline = await inlineFileOptional(
1498
+ resolveMilestoneFile(base, mid, "ROADMAP"),
1499
+ relMilestoneFile(base, mid, "ROADMAP"),
1500
+ "Milestone Roadmap",
1501
+ );
1502
+ if (roadmapInline) inlined.push(roadmapInline);
1503
+
1504
+ const contextInline = await inlineFileOptional(
1505
+ resolveMilestoneFile(base, mid, "CONTEXT"),
1506
+ relMilestoneFile(base, mid, "CONTEXT"),
1507
+ "Milestone Context",
1508
+ );
1509
+ if (contextInline) inlined.push(contextInline);
1510
+
1511
+ const researchInline = await inlineFileOptional(
1512
+ resolveMilestoneFile(base, mid, "RESEARCH"),
1513
+ relMilestoneFile(base, mid, "RESEARCH"),
1514
+ "Milestone Research",
1515
+ );
1516
+ if (researchInline) inlined.push(researchInline);
1517
+
1518
+ const decisionsPath = resolveGsdRootFile(base, "DECISIONS");
1519
+ if (existsSync(decisionsPath)) {
1520
+ const decisionsContent = await loadFile(decisionsPath);
1521
+ if (decisionsContent) {
1522
+ inlined.push(`### Decisions Register\nSource: \`${relGsdRootFile("DECISIONS")}\`\n\n${decisionsContent.trim()}`);
1523
+ }
1524
+ }
1525
+
1526
+ const milestoneIds = findMilestoneIds(base);
1527
+ const currentIndex = milestoneIds.indexOf(mid);
1528
+ const priorMilestoneIds = currentIndex >= 0 ? milestoneIds.slice(0, currentIndex) : milestoneIds;
1529
+ for (const priorMid of priorMilestoneIds) {
1530
+ const summaryInline = await inlineFileOptional(
1531
+ resolveMilestoneFile(base, priorMid, "SUMMARY"),
1532
+ relMilestoneFile(base, priorMid, "SUMMARY"),
1533
+ `${priorMid} Prior Milestone Summary`,
1534
+ );
1535
+ if (summaryInline) inlined.push(summaryInline);
1536
+ }
1537
+
1538
+ return inlined.length > 0
1539
+ ? `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`
1540
+ : "## Inlined Context\n\n_(no milestone context files found yet — go in blind and ask broad questions)_";
1541
+ }
1542
+
1485
1543
  export async function buildDiscussMilestonePrompt(
1486
1544
  mid: string,
1487
1545
  midTitle: string,
1488
1546
  base: string,
1489
1547
  structuredQuestionsAvailable = "false",
1490
- { headless = false }: { headless?: boolean } = {},
1548
+ {
1549
+ headless = false,
1550
+ commitInstruction = "Do not commit planning artifacts — .gsd/ is managed externally.",
1551
+ fastPathInstruction = "",
1552
+ includeDraftSeed = true,
1553
+ includeContextMode = true,
1554
+ }: DiscussMilestonePromptOptions = {},
1491
1555
  ): Promise<string> {
1492
- const discussTemplates = inlineTemplate("context", "Context");
1556
+ const contextTemplate = inlineTemplate("context", "Context");
1493
1557
 
1494
1558
  if (headless) {
1495
1559
  const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
1496
1560
  const roadmapContent = roadmapPath ? await loadFile(roadmapPath) : null;
1497
1561
  return loadPrompt("discuss-headless", {
1498
1562
  seedContext: roadmapContent ?? "",
1499
- inlinedTemplates: discussTemplates,
1563
+ inlinedTemplates: contextTemplate,
1500
1564
  workingDirectory: base,
1501
1565
  milestoneId: mid,
1502
1566
  contextPath: relMilestoneFile(base, mid, "CONTEXT"),
@@ -1505,7 +1569,9 @@ export async function buildDiscussMilestonePrompt(
1505
1569
  });
1506
1570
  }
1507
1571
 
1508
- const contextModeInstructions = renderContextModeForPrompt("discuss-milestone", base);
1572
+ const rawInlinedContext = await buildDiscussMilestoneInlinedContext(mid, base);
1573
+ const cappedInlinedContext = capPreamble(rawInlinedContext);
1574
+ const discussTemplates = [cappedInlinedContext, contextTemplate].join("\n\n---\n\n");
1509
1575
 
1510
1576
  const basePrompt = loadPrompt("guided-discuss-milestone", {
1511
1577
  workingDirectory: base,
@@ -1513,20 +1579,22 @@ export async function buildDiscussMilestonePrompt(
1513
1579
  milestoneTitle: midTitle,
1514
1580
  inlinedTemplates: discussTemplates,
1515
1581
  structuredQuestionsAvailable,
1516
- commitInstruction: "Do not commit planning artifacts — .gsd/ is managed externally.",
1517
- fastPathInstruction: "",
1582
+ commitInstruction,
1583
+ fastPathInstruction,
1518
1584
  });
1519
- const promptWithContextMode = prependContextModeToBlock("discuss-milestone", base, basePrompt);
1585
+ const promptWithContextMode = includeContextMode
1586
+ ? prependContextModeToBlock("discuss-milestone", base, basePrompt)
1587
+ : basePrompt;
1520
1588
 
1521
1589
  // If a CONTEXT-DRAFT.md exists, append it as seed material
1522
1590
  const draftPath = resolveMilestoneFile(base, mid, "CONTEXT-DRAFT");
1523
1591
  const draftContent = draftPath ? await loadFile(draftPath) : null;
1524
1592
 
1525
- if (draftContent) {
1593
+ if (includeDraftSeed && draftContent) {
1526
1594
  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}`;
1527
1595
  }
1528
1596
 
1529
- return contextModeInstructions ? promptWithContextMode : basePrompt;
1597
+ return promptWithContextMode;
1530
1598
  }
1531
1599
 
1532
1600
  /**
@@ -2711,6 +2779,15 @@ export async function buildCompleteSlicePrompt(
2711
2779
  sliceSummaryPath,
2712
2780
  sliceUatPath,
2713
2781
  gatesToClose,
2782
+ skillActivation: buildSkillActivationBlock({
2783
+ base,
2784
+ milestoneId: mid,
2785
+ milestoneTitle: midTitle,
2786
+ sliceId: sid,
2787
+ sliceTitle: sTitle,
2788
+ extraContext: [inlinedContext],
2789
+ unitType: "complete-slice",
2790
+ }),
2714
2791
  });
2715
2792
  }
2716
2793
 
@@ -2909,13 +2986,23 @@ export async function buildValidateMilestonePrompt(
2909
2986
  if (isDbAvailable()) {
2910
2987
  const milestone = getMilestone(mid);
2911
2988
  if (milestone) {
2989
+ const escapeCell = (value: string) =>
2990
+ value.replace(/[\\|]/g, (char) => `\\${char}`).replace(/\r?\n/g, " ");
2912
2991
  const classes: string[] = [];
2913
- if (milestone.verification_contract) classes.push(`- **Contract:** ${milestone.verification_contract}`);
2914
- if (milestone.verification_integration) classes.push(`- **Integration:** ${milestone.verification_integration}`);
2915
- if (milestone.verification_operational) classes.push(`- **Operational:** ${milestone.verification_operational}`);
2916
- if (milestone.verification_uat) classes.push(`- **UAT:** ${milestone.verification_uat}`);
2992
+ if (milestone.verification_contract) classes.push(`| Contract | ${escapeCell(milestone.verification_contract)} |`);
2993
+ if (milestone.verification_integration) classes.push(`| Integration | ${escapeCell(milestone.verification_integration)} |`);
2994
+ if (milestone.verification_operational) classes.push(`| Operational | ${escapeCell(milestone.verification_operational)} |`);
2995
+ if (milestone.verification_uat) classes.push(`| UAT | ${escapeCell(milestone.verification_uat)} |`);
2917
2996
  if (classes.length > 0) {
2918
- 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")}`;
2997
+ const verificationClasses = [
2998
+ "### Verification Classes (from planning)",
2999
+ "",
3000
+ "These verification tiers were defined during milestone planning. Every row in this table must appear in `verificationClasses` with the same canonical class name.",
3001
+ "",
3002
+ "| Class | Planned Check |",
3003
+ "| --- | --- |",
3004
+ ...classes,
3005
+ ].join("\n");
2919
3006
  inlined.push(verificationClasses);
2920
3007
  trackPromptContext(contextTelemetry, "verification-classes", "inline", verificationClasses);
2921
3008
  }
@@ -101,6 +101,7 @@ import {
101
101
  } from "./preferences-models.js";
102
102
  import type { WorktreeLifecycle } from "./worktree-lifecycle.js";
103
103
  import { getSessionModelOverride } from "./session-model-override.js";
104
+ import { setAutoActiveStatus } from "./auto-dashboard.js";
104
105
 
105
106
  export interface BootstrapDeps {
106
107
  shouldUseWorktreeIsolation: (basePath?: string) => boolean;
@@ -293,6 +294,7 @@ export interface OrphanAuditAction {
293
294
  message: string;
294
295
  severity: "info" | "warning";
295
296
  branch?: string;
297
+ mainBranch?: string;
296
298
  commitsAhead?: number;
297
299
  dirtyWorktree?: boolean;
298
300
  worktreeDirExists?: boolean;
@@ -311,6 +313,27 @@ function isBlockingStrandedWorkAction(action: OrphanAuditAction): boolean {
311
313
  return action.kind === "in-progress-stranded-work" && action.blocksAuto;
312
314
  }
313
315
 
316
+ function strandedWorkEvidence(args: {
317
+ branch?: string;
318
+ commitsAhead: number;
319
+ mainBranch: string;
320
+ dirtyWorktree: boolean;
321
+ }): string[] {
322
+ const evidence: string[] = [];
323
+ if (args.branch && args.commitsAhead > 0) {
324
+ evidence.push(
325
+ `branch ${args.branch} has ${args.commitsAhead} commit(s) ahead of ${args.mainBranch}`,
326
+ );
327
+ }
328
+ if (args.dirtyWorktree) {
329
+ evidence.push("the worktree has uncommitted changes");
330
+ }
331
+ if (evidence.length === 0) {
332
+ evidence.push("physical git evidence exists");
333
+ }
334
+ return evidence;
335
+ }
336
+
314
337
  function detectWorktreeEvidence(
315
338
  basePath: string,
316
339
  milestoneId: string,
@@ -342,18 +365,7 @@ function strandedWorkMessage(args: {
342
365
  worktreeDirExists: boolean;
343
366
  recoveryMode: StrandedWorkRecoveryMode;
344
367
  }): string {
345
- const evidence: string[] = [];
346
- if (args.branch && args.commitsAhead > 0) {
347
- evidence.push(
348
- `branch ${args.branch} has ${args.commitsAhead} commit(s) ahead of ${args.mainBranch}`,
349
- );
350
- }
351
- if (args.dirtyWorktree) {
352
- evidence.push("the worktree has uncommitted changes");
353
- }
354
- if (evidence.length === 0) {
355
- evidence.push("physical git evidence exists");
356
- }
368
+ const evidence = strandedWorkEvidence(args);
357
369
 
358
370
  const wtSuffix = args.worktreeDirExists
359
371
  ? ` Worktree directory at .gsd/worktrees/${args.milestoneId}/ holds live work.`
@@ -369,6 +381,26 @@ function strandedWorkMessage(args: {
369
381
  );
370
382
  }
371
383
 
384
+ function formatStrandedWorkRecoveryMessage(action: OrphanAuditAction): string {
385
+ const recoveryMode = action.recoveryMode === "worktree"
386
+ ? "existing worktree"
387
+ : "milestone branch";
388
+ const evidence = strandedWorkEvidence({
389
+ branch: action.branch,
390
+ commitsAhead: action.commitsAhead ?? 0,
391
+ mainBranch: action.mainBranch ?? "main",
392
+ dirtyWorktree: action.dirtyWorktree ?? false,
393
+ });
394
+ const wtSuffix = action.worktreeDirExists
395
+ ? ` Worktree directory at .gsd/worktrees/${action.milestoneId}/ holds live work.`
396
+ : "";
397
+ return (
398
+ `Resuming saved milestone work for ${action.milestoneId}: ${evidence.join("; ")}.` +
399
+ wtSuffix +
400
+ ` Adopting the ${recoveryMode} before dispatching new units. Park or discard explicitly if abandoning.`
401
+ );
402
+ }
403
+
372
404
  function formatStrandedWorkBlockerMessage(
373
405
  action: OrphanAuditAction,
374
406
  activeMilestoneId: string | null,
@@ -489,6 +521,7 @@ export function auditOrphanedMilestoneBranches(
489
521
  kind: "in-progress-stranded-work",
490
522
  milestoneId,
491
523
  branch,
524
+ mainBranch,
492
525
  commitsAhead,
493
526
  dirtyWorktree: worktreeEvidence.dirty,
494
527
  worktreeDirExists: worktreeEvidence.dirExists,
@@ -643,6 +676,7 @@ export function auditOrphanedMilestoneBranches(
643
676
  pushAction({
644
677
  kind: "in-progress-stranded-work",
645
678
  milestoneId: m.id,
679
+ mainBranch,
646
680
  commitsAhead: 0,
647
681
  dirtyWorktree: true,
648
682
  worktreeDirExists: worktreeEvidence.dirExists,
@@ -1158,7 +1192,13 @@ export async function bootstrapAutoSession(
1158
1192
  for (const msg of auditResult.recovered) {
1159
1193
  ctx.ui.notify(`Orphan audit: ${msg}`, "info");
1160
1194
  }
1195
+ const deferredStrandedMessages = new Set(
1196
+ auditResult.actions
1197
+ .filter(isBlockingStrandedWorkAction)
1198
+ .map((action) => action.message),
1199
+ );
1161
1200
  for (const msg of auditResult.warnings) {
1201
+ if (deferredStrandedMessages.has(msg)) continue;
1162
1202
  const prefix = msg.startsWith("Stranded work") ? "" : "Orphan audit: ";
1163
1203
  ctx.ui.notify(`${prefix}${msg}`, "warning");
1164
1204
  }
@@ -1246,7 +1286,7 @@ export async function bootstrapAutoSession(
1246
1286
  }
1247
1287
  strandedRecoveryAction = blockingStrandedRecoveryAction;
1248
1288
  ctx.ui.notify(
1249
- `Recovering stranded work for ${strandedRecoveryAction.milestoneId} before dispatching new units.`,
1289
+ formatStrandedWorkRecoveryMessage(strandedRecoveryAction),
1250
1290
  "info",
1251
1291
  );
1252
1292
  }
@@ -1718,7 +1758,7 @@ export async function bootstrapAutoSession(
1718
1758
  snapshotSkills();
1719
1759
  }
1720
1760
 
1721
- ctx.ui.setStatus("gsd-auto", s.stepMode ? "next" : "auto");
1761
+ setAutoActiveStatus(ctx, s.stepMode ? "next" : "auto");
1722
1762
  ctx.ui.setWidget("gsd-health", undefined);
1723
1763
  const modeLabel = s.stepMode ? "Step-mode" : "Auto-mode";
1724
1764
  const pendingCount = (state.registry ?? []).filter(
@@ -1,4 +1,5 @@
1
1
  import { parseUnitId } from "./unit-id.js";
2
+ import { RUN_UAT_WORKFLOW_TOOL_NAMES } from "./tool-presentation-plan.js";
2
3
 
3
4
  export const RUN_UAT_BROWSER_TOOL_NAMES = [
4
5
  "browser_navigate",
@@ -44,7 +45,7 @@ export const AUTO_UNIT_SCOPED_TOOLS: Record<string, readonly string[]> = {
44
45
  "execute-task": ["gsd_task_complete", "gsd_decision_save"],
45
46
  "execute-task-simple": ["gsd_task_complete", "gsd_decision_save"],
46
47
  "reactive-execute": ["gsd_task_complete", "gsd_decision_save"],
47
- "run-uat": ["gsd_summary_save", ...RUN_UAT_BROWSER_TOOL_NAMES],
48
+ "run-uat": [...RUN_UAT_WORKFLOW_TOOL_NAMES, "subagent", ...RUN_UAT_BROWSER_TOOL_NAMES],
48
49
  "gate-evaluate": ["gsd_save_gate_result"],
49
50
  "rewrite-docs": ["gsd_summary_save", "gsd_decision_save"],
50
51
  "workflow-preferences": ["gsd_summary_save"],
@@ -205,6 +205,7 @@ import {
205
205
  updateProgressWidget as _updateProgressWidget,
206
206
  setCompletionProgressWidget,
207
207
  setAutoOutcomeWidget,
208
+ setAutoActiveStatus,
208
209
  updateSliceProgressCache,
209
210
  clearSliceProgressCache,
210
211
  describeNextUnit as _describeNextUnit,
@@ -2310,10 +2311,20 @@ export function createWiredAutoOrchestrationModule(
2310
2311
  async reconcileBeforeDispatch() {
2311
2312
  const activeBasePath = getLiveDispatchBasePath();
2312
2313
  const result = await reconcileBeforeDispatch(activeBasePath);
2313
- if (result.blockers.length > 0) {
2314
+ // Failure-path summaries written by gsd_summary_save create
2315
+ // artifact-db-status-divergence blockers for tasks that are still
2316
+ // pending (gsd_task_complete never ran). These tasks can still be
2317
+ // dispatched and the drift self-heals once they complete successfully.
2318
+ const hardBlockers = result.blockers.filter(
2319
+ (b) =>
2320
+ !b.includes("has SUMMARY artifact while DB status is") &&
2321
+ !b.includes("has SUMMARY on disk while DB status is") &&
2322
+ !b.includes("has task SUMMARY artifacts but no DB tasks"),
2323
+ );
2324
+ if (hardBlockers.length > 0) {
2314
2325
  return {
2315
2326
  ok: false,
2316
- reason: result.blockers[0],
2327
+ reason: hardBlockers[0],
2317
2328
  stateSnapshot: result.stateSnapshot,
2318
2329
  };
2319
2330
  }
@@ -3022,7 +3033,7 @@ export async function startAuto(
3022
3033
  ensureOrchestrationModule(ctx, pi, s.basePath || base);
3023
3034
  registerSigtermHandler(lockBase());
3024
3035
 
3025
- ctx.ui.setStatus("gsd-auto", s.stepMode ? "next" : "auto");
3036
+ setAutoActiveStatus(ctx, s.stepMode ? "next" : "auto");
3026
3037
  ctx.ui.setWidget("gsd-health", undefined);
3027
3038
  ctx.ui.notify(
3028
3039
  s.stepMode ? "Step-mode resumed." : "Auto-mode resumed.",
@@ -3351,7 +3362,7 @@ export async function dispatchHookUnit(
3351
3362
  await pauseAuto(ctx, pi);
3352
3363
  }, hookHardTimeoutMs);
3353
3364
 
3354
- ctx.ui.setStatus("gsd-auto", s.stepMode ? "next" : "auto");
3365
+ setAutoActiveStatus(ctx, s.stepMode ? "next" : "auto");
3355
3366
  ctx.ui.notify(`Running post-unit hook: ${hookName}`, "info");
3356
3367
 
3357
3368
  debugLog("dispatchHookUnit", {
@@ -413,6 +413,92 @@ export function registerDbTools(pi: ExtensionAPI): void {
413
413
  pi.registerTool(summarySaveTool);
414
414
  registerAlias(pi, summarySaveTool, "gsd_save_summary", "gsd_summary_save");
415
415
 
416
+ // ─── gsd_uat_result_save ─────────────────────────────────────────────────
417
+
418
+ const uatResultSaveExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
419
+ const { executeUatResultSave } = await loadWorkflowExecutors();
420
+ return executeUatResultSave(params, resolveWorkflowToolBasePath(_ctx, params));
421
+ };
422
+
423
+ const uatEvidenceRef = Type.Object({
424
+ kind: StringEnum(["gsd_uat_exec", "gsd_exec", "screenshot", "log", "url", "browser"], { description: "Evidence kind" }),
425
+ ref: Type.String({ description: "Evidence ID, approved .gsd path, or URL" }),
426
+ note: Type.Optional(Type.String({ description: "Short evidence note" })),
427
+ });
428
+
429
+ const uatCheck = Type.Object({
430
+ id: Type.String({ description: "Stable check ID from the UAT spec" }),
431
+ description: Type.String({ description: "Check description" }),
432
+ mode: StringEnum(["artifact", "runtime", "browser", "human-follow-up"], { description: "Evidence mode" }),
433
+ result: StringEnum(["PASS", "FAIL", "NEEDS-HUMAN"], { description: "Check result" }),
434
+ evidence: Type.Optional(Type.Array(uatEvidenceRef, { description: "Objective evidence references" })),
435
+ notes: Type.Optional(Type.String({ description: "Observed result, failure notes, or human instruction" })),
436
+ nonAutomatable: Type.Optional(Type.Boolean({ description: "True when the check is explicitly non-automatable" })),
437
+ });
438
+
439
+ const toolPresentationBlock = Type.Object({
440
+ surface: StringEnum(["provider-tools", "claude-code-sdk", "mcp", "hybrid"], { description: "Tool presentation surface" }),
441
+ model: Type.Optional(Type.Object({
442
+ provider: Type.Optional(Type.String()),
443
+ api: Type.Optional(Type.String()),
444
+ id: Type.Optional(Type.String()),
445
+ })),
446
+ presentedTools: Type.Array(Type.String(), { description: "Tool names actually presented to the model" }),
447
+ blockedTools: Type.Array(Type.Object({
448
+ name: Type.String(),
449
+ reason: Type.String(),
450
+ }), { description: "Tool names blocked from the model with reasons" }),
451
+ aliases: Type.Optional(Type.Array(Type.Object({
452
+ requested: Type.String(),
453
+ canonical: Type.String(),
454
+ }))),
455
+ fallbackToolsUsed: Type.Optional(Type.Array(Type.String())),
456
+ toolPresentationPlanId: Type.Optional(Type.String()),
457
+ notes: Type.Optional(Type.String()),
458
+ });
459
+
460
+ const uatResultSaveTool = {
461
+ name: "gsd_uat_result_save",
462
+ label: "Save UAT Result",
463
+ description:
464
+ "Save a structured UAT result for a slice. Validates evidence, writes the ASSESSMENT artifact, " +
465
+ "records attempt history, and saves the aggregate UAT gate result.",
466
+ promptSnippet: "Save structured UAT checks, evidence, verdict, and tool-presentation proof",
467
+ promptGuidelines: [
468
+ "Call gsd_uat_result_save once after all UAT checks have been executed.",
469
+ "Every PASS or FAIL check must cite objective evidence, preferably a gsd_uat_exec evidence ID.",
470
+ "Include the presented and blocked tool set in presentation so tool timing is auditable.",
471
+ "Do not use raw gsd_summary_save as a substitute for UAT results.",
472
+ ],
473
+ parameters: Type.Object({
474
+ milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
475
+ sliceId: Type.String({ description: "Slice ID (e.g. S01)" }),
476
+ uatType: StringEnum(["artifact-driven", "browser-executable", "runtime-executable", "live-runtime", "mixed", "human-experience"], { description: "Declared UAT mode" }),
477
+ verdict: StringEnum(["PASS", "FAIL", "PARTIAL"], { description: "Overall UAT verdict" }),
478
+ checks: Type.Array(uatCheck, { description: "Structured check results" }),
479
+ presentation: toolPresentationBlock,
480
+ notes: Type.Optional(Type.String({ description: "Overall verdict rationale" })),
481
+ attempt: Type.Optional(Type.String({ description: "Attempt number or auto" })),
482
+ previousAttemptId: Type.Optional(Type.String({ description: "Prior attempt ID, when retrying" })),
483
+ }),
484
+ execute: uatResultSaveExecute,
485
+ renderCall(args: any, theme: any) {
486
+ let text = theme.fg("toolTitle", theme.bold("uat_result_save "));
487
+ text += theme.fg("accent", `${args.milestoneId ?? "?"}/${args.sliceId ?? "?"}`);
488
+ if (args.verdict) text += theme.fg("dim", ` → ${args.verdict}`);
489
+ return new Text(text, 0, 0);
490
+ },
491
+ renderResult(result: any, _options: any, theme: any) {
492
+ const d = readDetails(result);
493
+ if (result.isError || d?.error) {
494
+ return new Text(theme.fg("error", formatToolErrorText(result, d)), 0, 0);
495
+ }
496
+ return new Text(theme.fg("success", `UAT ${d?.sliceId ?? ""}: ${d?.verdict ?? "saved"}`), 0, 0);
497
+ },
498
+ };
499
+
500
+ pi.registerTool(uatResultSaveTool);
501
+
416
502
  // ─── gsd_milestone_generate_id (formerly gsd_generate_milestone_id) ────
417
503
 
418
504
  const milestoneGenerateIdExecute = async (_toolCallId: string, _params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
@@ -746,7 +832,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
746
832
  recommendation: Type.String({ description: "Option id the executor recommends." }),
747
833
  recommendationRationale: Type.String({ description: "Why the recommendation — 1–2 sentences." }),
748
834
  continueWithDefault: Type.Boolean({
749
- description: "When true, loop continues (artifact logged for later review). When false, auto-mode pauses until the user resolves via /gsd escalate resolve.",
835
+ description: "When true, the recommendation is recorded as the default, but auto-mode still pauses until the user resolves via /gsd escalate resolve.",
750
836
  }),
751
837
  }, { description: "ADR-011 Phase 2: optional escalation payload. Only honored when phases.mid_execution_escalation is true." })),
752
838
  verificationEvidence: Type.Optional(Type.Array(
@@ -1009,7 +1095,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
1009
1095
  promptGuidelines: [
1010
1096
  "Use gsd_validate_milestone when all slices are done and the milestone needs validation before completion.",
1011
1097
  "Parameters: milestoneId, verdict, remediationRound, successCriteriaChecklist, sliceDeliveryAudit, crossSliceIntegration, requirementCoverage, verificationClasses (optional), verdictRationale, remediationPlan (optional).",
1012
- "If verification classes were planned, verificationClasses must include canonical class rows using the exact class names Contract, Integration, Operational, and UAT when present in planning.",
1098
+ "If verification classes were planned, verificationClasses must be a complete canonical table with one row for every applicable planned class using the exact class names Contract, Integration, Operational, and UAT. Do not submit a partial table.",
1013
1099
  "Planned verification text marked as none/not required/not applicable/N/A (including suffixed variants such as 'not required - backend-only') is treated as not applicable and does not require a class row.",
1014
1100
  "If verdict is 'needs-remediation', also provide remediationPlan and use gsd_reassess_roadmap to add remediation slices to the roadmap.",
1015
1101
  "On success, returns validationPath where VALIDATION.md was written.",
@@ -1022,7 +1108,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
1022
1108
  sliceDeliveryAudit: Type.String({ description: "Markdown table auditing each slice's claimed vs delivered output" }),
1023
1109
  crossSliceIntegration: Type.String({ description: "Markdown describing any cross-slice boundary mismatches" }),
1024
1110
  requirementCoverage: Type.String({ description: "Markdown describing any unaddressed requirements" }),
1025
- verificationClasses: Type.Optional(Type.String({ description: "Markdown describing verification class compliance and gaps using canonical class names (Contract, Integration, Operational, UAT) for each applicable planned class" })),
1111
+ verificationClasses: Type.Optional(Type.String({ description: "Complete markdown table describing verification class compliance and gaps; include one canonical row for every applicable planned class (Contract, Integration, Operational, UAT)" })),
1026
1112
  verdictRationale: Type.String({ description: "Why this verdict was chosen" }),
1027
1113
  remediationPlan: Type.Optional(Type.String({ description: "Remediation plan (required if verdict is needs-remediation)" })),
1028
1114
  }),
@@ -25,6 +25,57 @@ async function loadContextModePreferences(baseDir: string) {
25
25
  }
26
26
 
27
27
  export function registerExecTools(pi: ExtensionAPI): void {
28
+ pi.registerTool({
29
+ name: "gsd_uat_exec",
30
+ label: "UAT Exec",
31
+ description:
32
+ "Run a UAT-scoped bash/node/python check with milestone/slice/check metadata. " +
33
+ "Uses the same capped .gsd/exec evidence store as gsd_exec, but rejects commands that mutate dependencies, git state, credentials, or destructive files.",
34
+ promptSnippet: "Run one UAT check and save typed evidence under .gsd/exec",
35
+ promptGuidelines: [
36
+ "Use gsd_uat_exec for each automated UAT check.",
37
+ "Every PASS/FAIL check saved by gsd_uat_result_save must reference objective evidence from this tool or another approved GSD evidence path.",
38
+ "Do not install packages, mutate git state, edit source files, or dump credentials during UAT.",
39
+ ],
40
+ parameters: Type.Object({
41
+ milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
42
+ sliceId: Type.String({ description: "Slice ID (e.g. S01)" }),
43
+ checkId: Type.String({ description: "Stable check ID from the UAT spec (e.g. UAT-01)" }),
44
+ intent: Type.String({
45
+ description:
46
+ "UAT command intent. Use one canonical value: uat-artifact-check, uat-runtime-check, " +
47
+ "uat-browser-check, uat-service-start, or uat-log-inspection. Short aliases such as artifact, " +
48
+ "runtime, browser, service-start, and log-inspection are accepted.",
49
+ }),
50
+ runtime: Type.Optional(
51
+ Type.String({
52
+ description:
53
+ "Optional interpreter. Defaults to bash. Supported: bash, node, python; sh/shell, js/nodejs, and py/python3 aliases are accepted.",
54
+ }),
55
+ ),
56
+ script: Type.Optional(Type.String({ description: "Script body. Keep output small (log the finding, not the data)." })),
57
+ command: Type.Optional(Type.String({ description: "Alias for script; defaults to bash when runtime is omitted." })),
58
+ cmd: Type.Optional(Type.String({ description: "Short alias for script." })),
59
+ code: Type.Optional(Type.String({ description: "Alias for script, useful for node/python snippets." })),
60
+ expected: Type.Optional(Type.String({ description: "Expected outcome for this UAT check." })),
61
+ timeout_ms: Type.Optional(
62
+ Type.Number({
63
+ description: "Per-invocation timeout (ms). Capped at 600000. Default from preferences.",
64
+ minimum: 1_000,
65
+ maximum: 600_000,
66
+ }),
67
+ ),
68
+ }),
69
+ async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
70
+ const { executeUatExec } = await import("../tools/exec-tool.js");
71
+ const baseDir = resolveCtxCwd(_ctx);
72
+ return executeUatExec(params as Parameters<typeof executeUatExec>[0], {
73
+ baseDir,
74
+ preferences: await loadContextModePreferences(baseDir),
75
+ });
76
+ },
77
+ });
78
+
28
79
  pi.registerTool({
29
80
  name: "gsd_exec",
30
81
  label: "Exec (Sandboxed)",