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

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 +30 -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 +8 -8
  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 +8 -8
  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 -23
  176. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  177. package/packages/pi-ai/dist/models.generated.js +82 -31
  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 +72 -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 +73 -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 +410 -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 +63 -7
  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 → h4TGni4xJzlZjGkxaT6uU}/_buildManifest.js +0 -0
  329. /package/dist/web/standalone/.next/static/{eRWf-RI9bzbrwEurm_3uI → h4TGni4xJzlZjGkxaT6uU}/_ssgManifest.js +0 -0
@@ -75,6 +75,11 @@ test("closeout executors reject phase escalation from the wrong active auto unit
75
75
  const milestone = await executeCompleteMilestone({} as Parameters<typeof executeCompleteMilestone>[0], "/tmp/project");
76
76
  assert.equal(milestone.isError, true);
77
77
  assert.match(String(milestone.details.error), /complete_milestone may only run from complete-milestone/);
78
+
79
+ const uat = await executeUatResultSave({} as Parameters<typeof executeUatResultSave>[0], "/tmp/project");
80
+ assert.equal(uat.isError, true);
81
+ assert.match(String(uat.details.error), /save_uat_result may only run from run-uat/);
82
+ assert.match(String(uat.details.error), /Tool Contract failure/);
78
83
  } finally {
79
84
  autoSession.reset();
80
85
  }
@@ -235,6 +240,62 @@ test("executeTaskComplete derives missing verification from evidence", async ()
235
240
  }
236
241
  });
237
242
 
243
+ test("executeTaskComplete surfaces escalation questions and metadata", async () => {
244
+ const base = makeTmpBase();
245
+ try {
246
+ openTestDb(base);
247
+ writeFileSync(join(base, ".gsd", "PREFERENCES.md"), [
248
+ "---",
249
+ "version: 1",
250
+ "phases:",
251
+ " mid_execution_escalation: true",
252
+ "---",
253
+ ].join("\n"));
254
+ const planDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
255
+ mkdirSync(planDir, { recursive: true });
256
+ writeFileSync(join(planDir, "S01-PLAN.md"), "# S01\n\n- [ ] **T01: Demo** `est:5m`\n");
257
+
258
+ const result = await inProjectDir(base, () => executeTaskComplete({
259
+ milestoneId: "M001",
260
+ sliceId: "S01",
261
+ taskId: "T01",
262
+ oneLiner: "Completed task",
263
+ narrative: "Did the work but found an ambiguity.",
264
+ verification: "npm test",
265
+ escalation: {
266
+ question: "Should the cache use write-through or write-back?",
267
+ options: [
268
+ { id: "A", label: "Write-through", tradeoffs: "Simpler reads; slower writes." },
269
+ { id: "B", label: "Write-back", tradeoffs: "Faster writes; more flush complexity." },
270
+ ],
271
+ recommendation: "A",
272
+ recommendationRationale: "Current usage favors correctness over write latency.",
273
+ continueWithDefault: true,
274
+ },
275
+ }, base));
276
+
277
+ assert.equal(result.details.operation, "complete_task");
278
+ assert.match(
279
+ String(result.content[0]?.text),
280
+ /Task completed with escalation decision required: Should the cache use write-through or write-back\?/,
281
+ );
282
+ assert.match(String(result.content[0]?.text), /Resolve with: \/gsd escalate resolve T01/);
283
+ assert.equal((result.details.escalation as { question?: string }).question, "Should the cache use write-through or write-back?");
284
+
285
+ const db = _getAdapter();
286
+ assert.ok(db, "DB should be open");
287
+ const row = db!.prepare(
288
+ "SELECT escalation_pending, escalation_awaiting_review, escalation_artifact_path FROM tasks WHERE milestone_id = ? AND slice_id = ? AND id = ?",
289
+ ).get("M001", "S01", "T01") as Record<string, unknown> | undefined;
290
+ assert.equal(row?.escalation_pending, 0);
291
+ assert.equal(row?.escalation_awaiting_review, 1);
292
+ assert.ok(String(row?.escalation_artifact_path ?? "").endsWith("T01-ESCALATION.json"));
293
+ } finally {
294
+ closeDatabase();
295
+ cleanup(base);
296
+ }
297
+ });
298
+
238
299
  test("executeTaskComplete returns a tool error when verification cannot be derived", async () => {
239
300
  const base = makeTmpBase();
240
301
  try {
@@ -587,6 +648,343 @@ test("executeUatResultSave accepts gsd_uat_exec evidence written in a milestone
587
648
  }
588
649
  });
589
650
 
651
+ test("executeUatResultSave supplies canonical presentation and normalizes verdict casing", async () => {
652
+ const base = makeTmpBase();
653
+ const worktree = join(base, ".gsd", "worktrees", "M001");
654
+ const worktreeExecDir = join(worktree, ".gsd", "exec");
655
+ const evidenceId = "uat-lowercase-verdict";
656
+ try {
657
+ openTestDb(base);
658
+ seedMilestone("M001", "Milestone One");
659
+ seedSlice("M001", "S03", "complete");
660
+ mkdirSync(worktreeExecDir, { recursive: true });
661
+ writeFileSync(
662
+ join(worktreeExecDir, `${evidenceId}.meta.json`),
663
+ JSON.stringify({
664
+ id: evidenceId,
665
+ metadata: {
666
+ kind: "uat_exec",
667
+ milestoneId: "M001",
668
+ sliceId: "S03",
669
+ checkId: "UAT-01",
670
+ intent: "uat-artifact-check",
671
+ },
672
+ }),
673
+ "utf-8",
674
+ );
675
+
676
+ const result = await inProjectDir(worktree, () => executeUatResultSave({
677
+ milestoneId: "M001",
678
+ sliceId: "S03",
679
+ uatType: "artifact-driven",
680
+ verdict: "pass",
681
+ checks: [{
682
+ id: "UAT-01",
683
+ description: "Static artifact contract passes",
684
+ mode: "artifact",
685
+ result: "PASS",
686
+ evidence: [{ kind: "gsd_uat_exec", ref: evidenceId }],
687
+ notes: "Artifact check passed.",
688
+ }],
689
+ notes: "UAT passed with canonical presentation supplied by the executor.",
690
+ } as unknown as Parameters<typeof executeUatResultSave>[0], worktree));
691
+
692
+ assert.equal(result.isError, undefined);
693
+ assert.equal(result.details.verdict, "PASS");
694
+
695
+ const attempt = JSON.parse(readFileSync(
696
+ join(base, ".gsd", "uat", "M001", "S03", "attempt-1.json"),
697
+ "utf-8",
698
+ )) as { presentation?: { toolPresentationPlanId?: string; presentedTools?: string[] } };
699
+ assert.equal(attempt.presentation?.toolPresentationPlanId, "run-uat/default-v1");
700
+ assert.ok(attempt.presentation?.presentedTools?.includes("gsd_uat_result_save"));
701
+ assert.ok(attempt.presentation?.presentedTools?.includes("read"));
702
+ } finally {
703
+ closeDatabase();
704
+ cleanup(base);
705
+ }
706
+ });
707
+
708
+ test("executeUatResultSave supplies direct browser tools for browser-executable UAT", async () => {
709
+ const base = makeTmpBase();
710
+ const worktree = join(base, ".gsd", "worktrees", "M001");
711
+ const worktreeExecDir = join(worktree, ".gsd", "exec");
712
+ const evidenceId = "uat-direct-browser-evidence";
713
+ try {
714
+ openTestDb(base);
715
+ seedMilestone("M001", "Milestone One");
716
+ seedSlice("M001", "S06", "complete");
717
+ mkdirSync(worktreeExecDir, { recursive: true });
718
+ writeFileSync(
719
+ join(worktreeExecDir, `${evidenceId}.meta.json`),
720
+ JSON.stringify({
721
+ id: evidenceId,
722
+ metadata: {
723
+ kind: "uat_exec",
724
+ milestoneId: "M001",
725
+ sliceId: "S06",
726
+ checkId: "UAT-01",
727
+ intent: "uat-browser-check",
728
+ },
729
+ }),
730
+ "utf-8",
731
+ );
732
+
733
+ const result = await inProjectDir(worktree, () => executeUatResultSave({
734
+ milestoneId: "M001",
735
+ sliceId: "S06",
736
+ uatType: "browser-executable",
737
+ verdict: "PASS",
738
+ checks: [{
739
+ id: "UAT-01",
740
+ description: "Browser flow used managed gsd-browser tools",
741
+ mode: "browser",
742
+ result: "PASS",
743
+ evidence: [{ kind: "gsd_uat_exec", ref: evidenceId }],
744
+ notes: "Browser check passed.",
745
+ }],
746
+ notes: "UAT passed with managed browser evidence.",
747
+ } as unknown as Parameters<typeof executeUatResultSave>[0], worktree));
748
+
749
+ assert.equal(result.isError, undefined);
750
+ const attempt = JSON.parse(readFileSync(
751
+ join(base, ".gsd", "uat", "M001", "S06", "attempt-1.json"),
752
+ "utf-8",
753
+ )) as { presentation?: { presentedTools?: string[] } };
754
+
755
+ assert.ok(attempt.presentation?.presentedTools?.includes("browser_navigate"));
756
+ assert.ok(attempt.presentation?.presentedTools?.includes("browser_assert"));
757
+ assert.equal(
758
+ attempt.presentation?.presentedTools?.some((toolName) => toolName.startsWith("mcp__gsd-browser__")),
759
+ false,
760
+ );
761
+ } finally {
762
+ closeDatabase();
763
+ cleanup(base);
764
+ }
765
+ });
766
+
767
+ test("executeUatResultSave merges canonical plan ID and read-only tools when presentation lacks plan ID", async () => {
768
+ const base = makeTmpBase();
769
+ const worktree = join(base, ".gsd", "worktrees", "M001");
770
+ const worktreeExecDir = join(worktree, ".gsd", "exec");
771
+ const evidenceId = "uat-no-plan-id-evidence";
772
+ try {
773
+ openTestDb(base);
774
+ seedMilestone("M001", "Milestone One");
775
+ seedSlice("M001", "S05", "complete");
776
+ mkdirSync(worktreeExecDir, { recursive: true });
777
+ writeFileSync(
778
+ join(worktreeExecDir, `${evidenceId}.meta.json`),
779
+ JSON.stringify({
780
+ id: evidenceId,
781
+ metadata: {
782
+ kind: "uat_exec",
783
+ milestoneId: "M001",
784
+ sliceId: "S05",
785
+ checkId: "UAT-01",
786
+ intent: "uat-artifact-check",
787
+ },
788
+ }),
789
+ "utf-8",
790
+ );
791
+
792
+ const result = await inProjectDir(worktree, () => executeUatResultSave({
793
+ milestoneId: "M001",
794
+ sliceId: "S05",
795
+ uatType: "artifact-driven",
796
+ verdict: "PASS",
797
+ checks: [{
798
+ id: "UAT-01",
799
+ description: "Presentation plan ID absent from provider call",
800
+ mode: "artifact",
801
+ result: "PASS",
802
+ evidence: [{ kind: "gsd_uat_exec", ref: evidenceId }],
803
+ notes: "Canonical merge should apply even when toolPresentationPlanId is absent.",
804
+ }],
805
+ presentation: {
806
+ surface: "mcp",
807
+ presentedTools: [
808
+ "gsd_uat_exec",
809
+ "gsd_uat_result_save",
810
+ "gsd_resume",
811
+ "gsd_milestone_status",
812
+ "gsd_journal_query",
813
+ ],
814
+ blockedTools: [
815
+ { name: "gsd_exec", reason: "forbidden during run-uat" },
816
+ { name: "gsd_summary_save", reason: "forbidden during run-uat" },
817
+ { name: "gsd_save_gate_result", reason: "forbidden during run-uat" },
818
+ ],
819
+ },
820
+ notes: "Provider omitted toolPresentationPlanId; executor must canonicalize.",
821
+ } as unknown as Parameters<typeof executeUatResultSave>[0], worktree));
822
+
823
+ assert.equal(result.isError, undefined);
824
+ assert.equal(result.details.verdict, "PASS");
825
+
826
+ const attempt = JSON.parse(readFileSync(
827
+ join(base, ".gsd", "uat", "M001", "S05", "attempt-1.json"),
828
+ "utf-8",
829
+ )) as { presentation?: { toolPresentationPlanId?: string; presentedTools?: string[] } };
830
+ assert.equal(attempt.presentation?.toolPresentationPlanId, "run-uat/default-v1");
831
+ assert.ok(attempt.presentation?.presentedTools?.includes("read"), "read-only tool must be merged in");
832
+ assert.ok(attempt.presentation?.presentedTools?.includes("gsd_uat_result_save"));
833
+ } finally {
834
+ closeDatabase();
835
+ cleanup(base);
836
+ }
837
+ });
838
+
839
+ test("executeUatResultSave rejects saved UAT without fresh UAT-owned evidence", async () => {
840
+ const base = makeTmpBase();
841
+ const worktree = join(base, ".gsd", "worktrees", "M001");
842
+ const worktreeExecDir = join(worktree, ".gsd", "exec");
843
+ const evidenceId = "generic-exec-evidence";
844
+ try {
845
+ openTestDb(base);
846
+ seedMilestone("M001", "Milestone One");
847
+ seedSlice("M001", "S04", "complete");
848
+ mkdirSync(worktreeExecDir, { recursive: true });
849
+ writeFileSync(
850
+ join(worktreeExecDir, `${evidenceId}.meta.json`),
851
+ JSON.stringify({
852
+ id: evidenceId,
853
+ metadata: { kind: "exec" },
854
+ }),
855
+ "utf-8",
856
+ );
857
+
858
+ const result = await inProjectDir(worktree, () => executeUatResultSave({
859
+ milestoneId: "M001",
860
+ sliceId: "S04",
861
+ uatType: "artifact-driven",
862
+ verdict: "PASS",
863
+ checks: [{
864
+ id: "UAT-01",
865
+ description: "Static artifact contract passes",
866
+ mode: "artifact",
867
+ result: "PASS",
868
+ evidence: [{ kind: "gsd_exec", ref: evidenceId }],
869
+ notes: "Generic evidence should not satisfy fresh UAT evidence.",
870
+ }],
871
+ notes: "UAT should not pass without fresh UAT-owned evidence.",
872
+ } as unknown as Parameters<typeof executeUatResultSave>[0], worktree));
873
+
874
+ assert.equal(result.isError, true);
875
+ assert.match(String(result.content[0]?.text), /fresh gsd_uat_exec evidence/);
876
+ } finally {
877
+ closeDatabase();
878
+ cleanup(base);
879
+ }
880
+ });
881
+
882
+ test("executeUatResultSave rejects an unrecognized uatType", async () => {
883
+ const base = makeTmpBase();
884
+ const worktree = join(base, ".gsd", "worktrees", "M001");
885
+ try {
886
+ openTestDb(base);
887
+ mkdirSync(worktree, { recursive: true });
888
+ seedMilestone("M001", "Milestone One");
889
+ seedSlice("M001", "S06", "complete");
890
+
891
+ const result = await inProjectDir(worktree, () => executeUatResultSave({
892
+ milestoneId: "M001",
893
+ sliceId: "S06",
894
+ uatType: "hallucinated-mode",
895
+ verdict: "PASS",
896
+ checks: [{
897
+ id: "UAT-01",
898
+ description: "Static artifact contract passes",
899
+ mode: "artifact",
900
+ result: "PASS",
901
+ evidence: [{ kind: "gsd_uat_exec", ref: "some-ref" }],
902
+ }],
903
+ notes: "Should fail before evidence validation.",
904
+ } as unknown as Parameters<typeof executeUatResultSave>[0], worktree));
905
+
906
+ assert.equal(result.isError, true);
907
+ assert.match(String(result.content[0]?.text), /uatType must be one of/);
908
+ } finally {
909
+ closeDatabase();
910
+ cleanup(base);
911
+ }
912
+ });
913
+
914
+ test("executeUatResultSave rejects artifact-driven PASS with human follow-up checks", async () => {
915
+ const base = makeTmpBase();
916
+ const worktree = join(base, ".gsd", "worktrees", "M001");
917
+ const evidenceId = "uat-artifact-nonautomatable";
918
+ const worktreeExecDir = join(worktree, ".gsd", "exec");
919
+ try {
920
+ openTestDb(base);
921
+ seedMilestone("M001", "Milestone One");
922
+ seedSlice("M001", "S01", "complete");
923
+ mkdirSync(worktreeExecDir, { recursive: true });
924
+ writeFileSync(
925
+ join(worktreeExecDir, `${evidenceId}.meta.json`),
926
+ JSON.stringify({
927
+ id: evidenceId,
928
+ metadata: {
929
+ kind: "uat_exec",
930
+ milestoneId: "M001",
931
+ sliceId: "S01",
932
+ checkId: "UAT-01",
933
+ intent: "uat-artifact-check",
934
+ },
935
+ }),
936
+ "utf-8",
937
+ );
938
+
939
+ const result = await inProjectDir(worktree, () => executeUatResultSave({
940
+ milestoneId: "M001",
941
+ sliceId: "S01",
942
+ uatType: "artifact-driven",
943
+ verdict: "PASS",
944
+ checks: [
945
+ {
946
+ id: "UAT-01",
947
+ description: "Static contract passes",
948
+ mode: "artifact",
949
+ result: "PASS",
950
+ evidence: [{ kind: "gsd_uat_exec", ref: evidenceId }],
951
+ notes: "Artifact check passed.",
952
+ },
953
+ {
954
+ id: "UAT-02",
955
+ description: "Browser polish is deferred to the next slice",
956
+ mode: "human-follow-up",
957
+ result: "NEEDS-HUMAN",
958
+ notes: "Out of scope for this artifact-driven UAT.",
959
+ nonAutomatable: true,
960
+ },
961
+ ],
962
+ presentation: {
963
+ surface: "mcp",
964
+ presentedTools: [
965
+ "gsd_uat_exec",
966
+ "gsd_uat_result_save",
967
+ "gsd_resume",
968
+ "gsd_milestone_status",
969
+ "gsd_journal_query",
970
+ ],
971
+ blockedTools: [
972
+ { name: "gsd_exec", reason: "forbidden during run-uat" },
973
+ { name: "gsd_summary_save", reason: "forbidden during run-uat" },
974
+ { name: "gsd_save_gate_result", reason: "forbidden during run-uat" },
975
+ ],
976
+ },
977
+ notes: "UAT passed; non-automatable browser polish is deferred.",
978
+ }, worktree));
979
+
980
+ assert.equal(result.isError, true);
981
+ assert.match(String(result.content[0]?.text), /artifact-driven UAT cannot PASS with human-only checks/);
982
+ } finally {
983
+ closeDatabase();
984
+ cleanup(base);
985
+ }
986
+ });
987
+
590
988
  test("executeSliceComplete coerces string enrichment entries and writes summary/UAT artifacts", async () => {
591
989
  const base = makeTmpBase();
592
990
  try {
@@ -1279,6 +1677,10 @@ test("executeSummarySave blocks final root artifacts while approval gate is pend
1279
1677
 
1280
1678
  assert.equal(result.isError, true);
1281
1679
  assert.equal(result.details.error, "root_artifact_write_blocked");
1680
+ assert.equal(
1681
+ result.details.displayReason,
1682
+ "Approval confirmation required before saving final project setup artifacts.",
1683
+ );
1282
1684
  assert.match(result.content[0].text, /has not been confirmed/);
1283
1685
  assert.equal(existsSync(join(base, ".gsd", "REQUIREMENTS.md")), false);
1284
1686
 
@@ -1321,6 +1723,10 @@ test("executeSummarySave requires verified root approval in deep mode", async ()
1321
1723
 
1322
1724
  assert.equal(blocked.isError, true);
1323
1725
  assert.equal(blocked.details.error, "root_artifact_write_blocked");
1726
+ assert.equal(
1727
+ blocked.details.displayReason,
1728
+ "Approval confirmation required before saving final project setup artifacts.",
1729
+ );
1324
1730
  assert.match(blocked.content[0].text, /fail-closed/);
1325
1731
  assert.equal(existsSync(join(base, ".gsd", "PROJECT.md")), false);
1326
1732
 
@@ -1537,6 +1943,10 @@ test("executeSummarySave CONTEXT HARD BLOCK clears after write-gate state file i
1537
1943
  content: "# Context\n\ncontent",
1538
1944
  }, base));
1539
1945
  assert.equal(blocked.isError, true, "should be blocked without depth verification");
1946
+ assert.equal(
1947
+ blocked.details.displayReason,
1948
+ "Depth check required before writing milestone context.",
1949
+ );
1540
1950
  assert.match(
1541
1951
  blocked.content[0].text,
1542
1952
  /HARD BLOCK/,
@@ -9,6 +9,7 @@ import test from 'node:test';
9
9
  import assert from 'node:assert/strict';
10
10
  import { join, sep } from 'node:path';
11
11
 
12
+ import { GSD_PHASE_SCOPE_DISPLAY_REASON } from '../auto-unit-tool-scope.ts';
12
13
  import { ALLOWED_PLANNING_DISPATCH_AGENTS, shouldBlockPlanningUnit } from '../bootstrap/write-gate.ts';
13
14
  import { extractSubagentAgentClasses } from '../bootstrap/subagent-input.ts';
14
15
  import { isDeterministicPolicyError } from '../auto-tool-tracking.ts';
@@ -65,6 +66,19 @@ test('planning-unit: deterministic block reason is suitable for retry short-circ
65
66
  assert.strictEqual(isDeterministicPolicyError(r.reason!), true);
66
67
  });
67
68
 
69
+ test('planning-unit: blocked tool-policy calls include UI-safe display reason', () => {
70
+ const r = shouldBlockPlanningUnit(
71
+ 'edit',
72
+ 'src/main.ts',
73
+ BASE,
74
+ 'discuss-milestone',
75
+ PLANNING,
76
+ );
77
+ assert.strictEqual(r.block, true);
78
+ assert.match(r.reason!, /HARD BLOCK/);
79
+ assert.strictEqual(r.displayReason, GSD_PHASE_SCOPE_DISPLAY_REASON);
80
+ });
81
+
68
82
  test('planning-unit: blocks write to user source via relative path', () => {
69
83
  const r = shouldBlockPlanningUnit('write', 'src/main.ts', BASE, 'plan-milestone', PLANNING);
70
84
  assert.strictEqual(r.block, true);
@@ -367,6 +381,7 @@ test('auto-unit scope: execute-task allows only its task completion lifecycle to
367
381
  assert.strictEqual(blocked.block, true);
368
382
  assert.match(blocked.reason!, /HARD BLOCK/);
369
383
  assert.match(blocked.reason!, /gsd_save_gate_result/);
384
+ assert.strictEqual(blocked.displayReason, GSD_PHASE_SCOPE_DISPLAY_REASON);
370
385
  assert.strictEqual(isDeterministicPolicyError(blocked.reason!), true);
371
386
  });
372
387
 
@@ -8,12 +8,14 @@ import {
8
8
  type ToolsPolicy,
9
9
  } from "./unit-context-manifest.js";
10
10
  import { getRequiredWorkflowToolsForAutoUnit } from "./workflow-mcp.js";
11
+ import { getUnitToolSurfaceContract } from "./unit-tool-contracts.js";
11
12
 
12
13
  export interface UnitToolContract {
13
14
  unitType: string;
14
15
  contextMode: ContextModePolicy;
15
16
  toolsPolicy: ToolsPolicy;
16
17
  requiredWorkflowTools: readonly string[];
18
+ forbiddenWorkflowTools: readonly { name: string; reason: string }[];
17
19
  promptObligations: readonly string[];
18
20
  validationRules: readonly string[];
19
21
  closeoutTools: readonly string[];
@@ -30,6 +32,7 @@ export type ToolContractResult =
30
32
 
31
33
  export function compileUnitToolContract(unitType: string): ToolContractResult {
32
34
  const manifest = resolveManifest(unitType);
35
+ const surfaceContract = getUnitToolSurfaceContract(unitType);
33
36
  if (!manifest) {
34
37
  return {
35
38
  ok: false,
@@ -39,6 +42,8 @@ export function compileUnitToolContract(unitType: string): ToolContractResult {
39
42
  }
40
43
 
41
44
  const requiredWorkflowTools = getRequiredWorkflowToolsForAutoUnit(unitType);
45
+ const forbiddenWorkflowTools = Object.entries(surfaceContract?.forbiddenGsdTools ?? {})
46
+ .map(([name, reason]) => ({ name, reason }));
42
47
  const closeoutTools = requiredWorkflowTools.filter((tool) =>
43
48
  /^gsd_(?:task|slice|milestone|complete|validate|save|summary)/.test(tool),
44
49
  );
@@ -58,6 +63,7 @@ export function compileUnitToolContract(unitType: string): ToolContractResult {
58
63
  contextMode: manifest.contextMode,
59
64
  toolsPolicy: manifest.tools,
60
65
  requiredWorkflowTools,
66
+ forbiddenWorkflowTools,
61
67
  promptObligations: [
62
68
  `context-mode:${manifest.contextMode}`,
63
69
  `tools-policy:${manifest.tools.mode}`,
@@ -1,6 +1,20 @@
1
1
  // Project/App: gsd-pi
2
2
  // File Purpose: Resolve phase-aware tool surfaces for GSD model presentations.
3
3
 
4
+ import {
5
+ RUN_UAT_BROWSER_TOOL_NAMES,
6
+ RUN_UAT_READ_ONLY_TOOL_NAMES,
7
+ RUN_UAT_TOOL_PRESENTATION_PLAN_ID,
8
+ RUN_UAT_WORKFLOW_TOOL_NAMES,
9
+ } from "./unit-tool-contracts.js";
10
+
11
+ export {
12
+ RUN_UAT_BROWSER_TOOL_NAMES,
13
+ RUN_UAT_READ_ONLY_TOOL_NAMES,
14
+ RUN_UAT_TOOL_PRESENTATION_PLAN_ID,
15
+ RUN_UAT_WORKFLOW_TOOL_NAMES,
16
+ } from "./unit-tool-contracts.js";
17
+
4
18
  export type ToolPresentationSurface = "provider-tools" | "claude-code-sdk" | "mcp" | "hybrid";
5
19
 
6
20
  export interface ToolPresentationModel {
@@ -20,13 +34,12 @@ export interface ToolPresentationPlan {
20
34
  diagnostics: string[];
21
35
  }
22
36
 
23
- export const RUN_UAT_WORKFLOW_TOOL_NAMES = [
24
- "gsd_uat_exec",
25
- "gsd_uat_result_save",
26
- "gsd_resume",
27
- "gsd_milestone_status",
28
- "gsd_journal_query",
29
- ] as const;
37
+ export interface RunUatResultPresentation {
38
+ surface: ToolPresentationSurface;
39
+ presentedTools: string[];
40
+ blockedTools: Array<{ name: string; reason: string }>;
41
+ toolPresentationPlanId: string;
42
+ }
30
43
 
31
44
  export const RUN_UAT_FORBIDDEN_TOOL_NAMES = [
32
45
  "edit",
@@ -105,10 +118,53 @@ function addBlockedTool(
105
118
  export function buildRunUatCanonicalToolNames(options: { includeBrowserTools?: readonly string[] } = {}): string[] {
106
119
  return dedupe([
107
120
  ...RUN_UAT_WORKFLOW_TOOL_NAMES,
121
+ ...RUN_UAT_READ_ONLY_TOOL_NAMES,
108
122
  ...(options.includeBrowserTools ?? []),
109
123
  ]);
110
124
  }
111
125
 
126
+ export function runUatBrowserToolsForType(uatType: string | undefined): readonly string[] {
127
+ return uatType === "browser-executable" ? RUN_UAT_BROWSER_TOOL_NAMES : [];
128
+ }
129
+
130
+ export function runUatPresentationSurfaceForType(uatType: string | undefined): ToolPresentationSurface {
131
+ return uatType === "browser-executable" ? "hybrid" : "mcp";
132
+ }
133
+
134
+ export function buildRunUatPresentationForType(
135
+ uatType: string | undefined,
136
+ options: {
137
+ surface?: ToolPresentationSurface;
138
+ presentedTools?: readonly string[];
139
+ } = {},
140
+ ): RunUatResultPresentation {
141
+ return buildRunUatResultPresentation({
142
+ ...options,
143
+ surface: options.surface ?? runUatPresentationSurfaceForType(uatType),
144
+ includeBrowserTools: runUatBrowserToolsForType(uatType),
145
+ });
146
+ }
147
+
148
+ export function buildRunUatResultPresentation(options: {
149
+ surface?: ToolPresentationSurface;
150
+ includeBrowserTools?: readonly string[];
151
+ presentedTools?: readonly string[];
152
+ } = {}): RunUatResultPresentation {
153
+ const presentedTools = options.presentedTools
154
+ ? dedupe(options.presentedTools)
155
+ : buildRunUatCanonicalToolNames({ includeBrowserTools: options.includeBrowserTools });
156
+ const blockedTools = RUN_UAT_FORBIDDEN_TOOL_NAMES
157
+ .filter((toolName) => !toolName.includes("*"))
158
+ .map((name) => ({ name, reason: "forbidden during run-uat" }));
159
+
160
+ return {
161
+ surface: options.surface ?? "mcp",
162
+ presentedTools,
163
+ blockedTools,
164
+ toolPresentationPlanId: RUN_UAT_TOOL_PRESENTATION_PLAN_ID,
165
+ };
166
+ }
167
+
112
168
  export function resolveToolPresentationPlan(options: {
113
169
  phase: string;
114
170
  surface: ToolPresentationSurface;
@@ -217,7 +217,7 @@ ${params.narrative}
217
217
 
218
218
  ## Verification
219
219
 
220
- ${params.verification}
220
+ ${params.verification ?? ""}
221
221
 
222
222
  ## Requirements Advanced
223
223
 
@@ -440,6 +440,19 @@ export async function handleCompleteSlice(
440
440
  const parsed = parseRequirementSection(existingSummaryMd, "Requirements Invalidated or Re-scoped", "what");
441
441
  if (parsed.length > 0) effectiveParams.requirementsInvalidated = parsed as Array<{ id: string; what: string }>;
442
442
  }
443
+ if (effectiveParams.verification === undefined) {
444
+ const headingLine = "## Verification\n\n";
445
+ const start = existingSummaryMd.indexOf(headingLine);
446
+ if (start !== -1) {
447
+ const contentStart = start + headingLine.length;
448
+ const nextHeading = existingSummaryMd.indexOf("\n\n## ", contentStart);
449
+ const prior = nextHeading === -1
450
+ ? existingSummaryMd.slice(contentStart)
451
+ : existingSummaryMd.slice(contentStart, nextHeading);
452
+ const trimmed = prior.trim();
453
+ if (trimmed) effectiveParams.verification = trimmed;
454
+ }
455
+ }
443
456
  }
444
457
 
445
458
  // Render summary markdown