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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (329) hide show
  1. package/dist/cli.js +3 -2
  2. package/dist/help-text.js +10 -6
  3. package/dist/resources/.managed-resources-content-hash +1 -1
  4. package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +495 -0
  5. package/dist/resources/extensions/browser-tools/engine/selection.js +16 -0
  6. package/dist/resources/extensions/browser-tools/extension-manifest.json +2 -2
  7. package/dist/resources/extensions/browser-tools/index.js +57 -9
  8. package/dist/resources/extensions/browser-tools/package.json +5 -1
  9. package/dist/resources/extensions/gsd/auto/orchestrator.js +0 -1
  10. package/dist/resources/extensions/gsd/auto-dashboard.js +77 -13
  11. package/dist/resources/extensions/gsd/auto-dispatch.js +16 -0
  12. package/dist/resources/extensions/gsd/auto-post-unit.js +21 -3
  13. package/dist/resources/extensions/gsd/auto-prompts.js +63 -22
  14. package/dist/resources/extensions/gsd/auto-recovery.js +3 -4
  15. package/dist/resources/extensions/gsd/auto-runtime-state.js +3 -0
  16. package/dist/resources/extensions/gsd/auto-tool-tracking.js +1 -1
  17. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +18 -66
  18. package/dist/resources/extensions/gsd/auto-worktree.js +18 -5
  19. package/dist/resources/extensions/gsd/auto.js +9 -2
  20. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +20 -14
  21. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +28 -13
  22. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +18 -29
  23. package/dist/resources/extensions/gsd/browser-evidence.js +29 -2
  24. package/dist/resources/extensions/gsd/closeout-consistency-gate.js +61 -0
  25. package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -2
  26. package/dist/resources/extensions/gsd/commands-handlers.js +76 -11
  27. package/dist/resources/extensions/gsd/commands-mcp-status.js +2 -1
  28. package/dist/resources/extensions/gsd/dashboard-overlay.js +21 -7
  29. package/dist/resources/extensions/gsd/docs/preferences-reference.md +8 -0
  30. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +2 -2
  31. package/dist/resources/extensions/gsd/escalation.js +4 -4
  32. package/dist/resources/extensions/gsd/forensics.js +74 -2
  33. package/dist/resources/extensions/gsd/gsd-db.js +5 -2
  34. package/dist/resources/extensions/gsd/guided-flow.js +118 -175
  35. package/dist/resources/extensions/gsd/mcp-project-config.js +9 -76
  36. package/dist/resources/extensions/gsd/memory-store.js +4 -1
  37. package/dist/resources/extensions/gsd/milestone-closeout.js +3 -1
  38. package/dist/resources/extensions/gsd/pending-auto-start.js +0 -1
  39. package/dist/resources/extensions/gsd/post-unit-hooks.js +9 -0
  40. package/dist/resources/extensions/gsd/preferences-validation.js +39 -0
  41. package/dist/resources/extensions/gsd/prompt-loader.js +7 -0
  42. package/dist/resources/extensions/gsd/prompts/forensics.md +61 -1
  43. package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
  44. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
  45. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  46. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
  47. package/dist/resources/extensions/gsd/prompts/run-uat.md +25 -21
  48. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
  49. package/dist/resources/extensions/gsd/recovery-classification.js +20 -0
  50. package/dist/resources/extensions/gsd/rule-registry.js +428 -52
  51. package/dist/resources/extensions/gsd/state.js +2 -2
  52. package/dist/resources/extensions/gsd/templates/plan.md +3 -1
  53. package/dist/resources/extensions/gsd/tool-contract.js +5 -0
  54. package/dist/resources/extensions/gsd/tool-presentation-plan.js +17 -7
  55. package/dist/resources/extensions/gsd/tools/complete-slice.js +15 -1
  56. package/dist/resources/extensions/gsd/tools/complete-task.js +11 -1
  57. package/dist/resources/extensions/gsd/tools/validate-milestone.js +46 -16
  58. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +132 -18
  59. package/dist/resources/extensions/gsd/unit-tool-contracts.js +169 -0
  60. package/dist/resources/extensions/gsd/verdict-parser.js +59 -15
  61. package/dist/resources/extensions/gsd/verification-gate.js +72 -1
  62. package/dist/resources/extensions/gsd/workflow-mcp.js +3 -75
  63. package/dist/resources/extensions/shared/gsd-browser-cli.js +145 -0
  64. package/dist/rtk.d.ts +7 -1
  65. package/dist/rtk.js +27 -11
  66. package/dist/update-check.d.ts +15 -1
  67. package/dist/update-check.js +87 -12
  68. package/dist/update-cmd.d.ts +1 -0
  69. package/dist/update-cmd.js +53 -2
  70. package/dist/web/standalone/.next/BUILD_ID +1 -1
  71. package/dist/web/standalone/.next/app-path-routes-manifest.json +7 -7
  72. package/dist/web/standalone/.next/build-manifest.json +2 -2
  73. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  74. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  75. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  83. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  91. package/dist/web/standalone/.next/server/app/index.html +1 -1
  92. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app-paths-manifest.json +7 -7
  99. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  100. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  101. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  102. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  103. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  104. package/package.json +4 -2
  105. package/packages/cloud-mcp-gateway/package.json +2 -2
  106. package/packages/contracts/package.json +1 -1
  107. package/packages/daemon/package.json +4 -4
  108. package/packages/gsd-agent-core/dist/agent-session.d.ts +9 -0
  109. package/packages/gsd-agent-core/dist/agent-session.d.ts.map +1 -1
  110. package/packages/gsd-agent-core/dist/agent-session.js +32 -0
  111. package/packages/gsd-agent-core/dist/agent-session.js.map +1 -1
  112. package/packages/gsd-agent-core/dist/index.d.ts +1 -0
  113. package/packages/gsd-agent-core/dist/index.d.ts.map +1 -1
  114. package/packages/gsd-agent-core/dist/index.js +1 -0
  115. package/packages/gsd-agent-core/dist/index.js.map +1 -1
  116. package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts +2 -0
  117. package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts.map +1 -1
  118. package/packages/gsd-agent-core/dist/session/agent-session-compaction.js +8 -2
  119. package/packages/gsd-agent-core/dist/session/agent-session-compaction.js.map +1 -1
  120. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts +7 -0
  121. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts.map +1 -1
  122. package/packages/gsd-agent-core/dist/session/agent-session-host.js.map +1 -1
  123. package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts.map +1 -1
  124. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js +69 -1
  125. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js.map +1 -1
  126. package/packages/gsd-agent-core/dist/turn-latency.d.ts +47 -0
  127. package/packages/gsd-agent-core/dist/turn-latency.d.ts.map +1 -0
  128. package/packages/gsd-agent-core/dist/turn-latency.js +123 -0
  129. package/packages/gsd-agent-core/dist/turn-latency.js.map +1 -0
  130. package/packages/gsd-agent-core/package.json +6 -6
  131. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts +21 -0
  132. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts.map +1 -0
  133. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js +213 -0
  134. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js.map +1 -0
  135. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  136. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +5 -0
  137. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  138. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  139. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +20 -0
  140. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  141. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  142. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +7 -1
  143. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  144. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.d.ts.map +1 -1
  145. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js +6 -0
  146. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js.map +1 -1
  147. package/packages/gsd-agent-modes/package.json +7 -7
  148. package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -1
  149. package/packages/mcp-server/dist/remote-questions.js +23 -9
  150. package/packages/mcp-server/dist/remote-questions.js.map +1 -1
  151. package/packages/mcp-server/dist/workflow-tools.js +2 -2
  152. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  153. package/packages/mcp-server/package.json +3 -3
  154. package/packages/native/package.json +1 -1
  155. package/packages/pi-agent-core/dist/agent-loop.js +42 -3
  156. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  157. package/packages/pi-agent-core/dist/agent.d.ts +5 -1
  158. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  159. package/packages/pi-agent-core/dist/agent.js +2 -0
  160. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  161. package/packages/pi-agent-core/dist/harness/agent-harness.d.ts.map +1 -1
  162. package/packages/pi-agent-core/dist/harness/agent-harness.js +3 -1
  163. package/packages/pi-agent-core/dist/harness/agent-harness.js.map +1 -1
  164. package/packages/pi-agent-core/dist/harness/types.d.ts +1 -0
  165. package/packages/pi-agent-core/dist/harness/types.d.ts.map +1 -1
  166. package/packages/pi-agent-core/dist/harness/types.js.map +1 -1
  167. package/packages/pi-agent-core/dist/types.d.ts +6 -1
  168. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  169. package/packages/pi-agent-core/dist/types.js.map +1 -1
  170. package/packages/pi-agent-core/package.json +1 -1
  171. package/packages/pi-ai/dist/api-registry.d.ts +2 -0
  172. package/packages/pi-ai/dist/api-registry.d.ts.map +1 -1
  173. package/packages/pi-ai/dist/api-registry.js +23 -0
  174. package/packages/pi-ai/dist/api-registry.js.map +1 -1
  175. package/packages/pi-ai/dist/models.generated.d.ts +74 -6
  176. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  177. package/packages/pi-ai/dist/models.generated.js +78 -10
  178. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  179. package/packages/pi-ai/dist/stream.js +6 -6
  180. package/packages/pi-ai/dist/stream.js.map +1 -1
  181. package/packages/pi-ai/package.json +1 -1
  182. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts +3 -0
  183. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts.map +1 -1
  184. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.js.map +1 -1
  185. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  186. package/packages/pi-coding-agent/dist/core/model-registry.js +2 -2
  187. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  188. package/packages/pi-coding-agent/dist/core/tools/bash.js +2 -2
  189. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  190. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
  191. package/packages/pi-coding-agent/dist/core/tools/edit.js +3 -2
  192. package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
  193. package/packages/pi-coding-agent/dist/core/tools/render-utils.d.ts +1 -0
  194. package/packages/pi-coding-agent/dist/core/tools/render-utils.d.ts.map +1 -1
  195. package/packages/pi-coding-agent/dist/core/tools/render-utils.js +6 -0
  196. package/packages/pi-coding-agent/dist/core/tools/render-utils.js.map +1 -1
  197. package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
  198. package/packages/pi-coding-agent/dist/core/tools/write.js +3 -2
  199. package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
  200. package/packages/pi-coding-agent/package.json +7 -7
  201. package/packages/pi-tui/package.json +1 -1
  202. package/packages/rpc-client/package.json +2 -2
  203. package/pkg/package.json +1 -1
  204. package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +579 -0
  205. package/src/resources/extensions/browser-tools/engine/selection.ts +19 -0
  206. package/src/resources/extensions/browser-tools/extension-manifest.json +2 -2
  207. package/src/resources/extensions/browser-tools/index.ts +60 -9
  208. package/src/resources/extensions/browser-tools/package.json +5 -1
  209. package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +35 -0
  210. package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +33 -0
  211. package/src/resources/extensions/gsd/auto/orchestrator.ts +0 -1
  212. package/src/resources/extensions/gsd/auto-dashboard.ts +82 -14
  213. package/src/resources/extensions/gsd/auto-dispatch.ts +19 -0
  214. package/src/resources/extensions/gsd/auto-post-unit.ts +28 -2
  215. package/src/resources/extensions/gsd/auto-prompts.ts +97 -15
  216. package/src/resources/extensions/gsd/auto-recovery.ts +3 -3
  217. package/src/resources/extensions/gsd/auto-runtime-state.ts +4 -0
  218. package/src/resources/extensions/gsd/auto-tool-tracking.ts +1 -1
  219. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +43 -74
  220. package/src/resources/extensions/gsd/auto-worktree.ts +23 -5
  221. package/src/resources/extensions/gsd/auto.ts +12 -2
  222. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +20 -14
  223. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +32 -13
  224. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +50 -54
  225. package/src/resources/extensions/gsd/browser-evidence.ts +26 -2
  226. package/src/resources/extensions/gsd/closeout-consistency-gate.ts +137 -0
  227. package/src/resources/extensions/gsd/commands/handlers/ops.ts +2 -2
  228. package/src/resources/extensions/gsd/commands-handlers.ts +76 -11
  229. package/src/resources/extensions/gsd/commands-mcp-status.ts +2 -1
  230. package/src/resources/extensions/gsd/dashboard-overlay.ts +28 -7
  231. package/src/resources/extensions/gsd/docs/preferences-reference.md +8 -0
  232. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +2 -2
  233. package/src/resources/extensions/gsd/escalation.ts +4 -4
  234. package/src/resources/extensions/gsd/forensics.ts +99 -5
  235. package/src/resources/extensions/gsd/gsd-db.ts +5 -2
  236. package/src/resources/extensions/gsd/guided-flow.ts +214 -216
  237. package/src/resources/extensions/gsd/mcp-project-config.ts +13 -78
  238. package/src/resources/extensions/gsd/memory-store.ts +4 -1
  239. package/src/resources/extensions/gsd/milestone-closeout.ts +3 -1
  240. package/src/resources/extensions/gsd/pending-auto-start.ts +0 -2
  241. package/src/resources/extensions/gsd/post-unit-hooks.ts +14 -1
  242. package/src/resources/extensions/gsd/preferences-validation.ts +36 -0
  243. package/src/resources/extensions/gsd/prompt-loader.ts +8 -0
  244. package/src/resources/extensions/gsd/prompts/forensics.md +61 -1
  245. package/src/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
  246. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
  247. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  248. package/src/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
  249. package/src/resources/extensions/gsd/prompts/run-uat.md +25 -21
  250. package/src/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
  251. package/src/resources/extensions/gsd/recovery-classification.ts +20 -0
  252. package/src/resources/extensions/gsd/rule-registry.ts +558 -58
  253. package/src/resources/extensions/gsd/rule-types.ts +2 -0
  254. package/src/resources/extensions/gsd/state.ts +2 -2
  255. package/src/resources/extensions/gsd/templates/plan.md +3 -1
  256. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +105 -4
  257. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +37 -0
  258. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +10 -2
  259. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +4 -1
  260. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +12 -2
  261. package/src/resources/extensions/gsd/tests/browser-evidence.test.ts +142 -0
  262. package/src/resources/extensions/gsd/tests/check-auto-start-pending-gate.test.ts +9 -15
  263. package/src/resources/extensions/gsd/tests/check-auto-start-ready-guard.test.ts +26 -16
  264. package/src/resources/extensions/gsd/tests/commands-dispatcher-unmerged-milestone.test.ts +21 -0
  265. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +30 -0
  266. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +42 -0
  267. package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +45 -0
  268. package/src/resources/extensions/gsd/tests/deep-planning-mode-dispatch.test.ts +53 -0
  269. package/src/resources/extensions/gsd/tests/discuss-milestone-structured-questions.test.ts +31 -0
  270. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +40 -1
  271. package/src/resources/extensions/gsd/tests/doctor-runtime-checks.test.ts +27 -0
  272. package/src/resources/extensions/gsd/tests/escalation.test.ts +16 -27
  273. package/src/resources/extensions/gsd/tests/forensics-issue-routing.test.ts +20 -0
  274. package/src/resources/extensions/gsd/tests/forensics-prompt-rendering.test.ts +3 -0
  275. package/src/resources/extensions/gsd/tests/forensics-tool-scope.test.ts +69 -0
  276. package/src/resources/extensions/gsd/tests/gate-1b-orphan-discrimination.test.ts +31 -79
  277. package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +40 -1
  278. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +86 -0
  279. package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +5 -3
  280. package/src/resources/extensions/gsd/tests/guided-flow-state-rebuild.test.ts +40 -4
  281. package/src/resources/extensions/gsd/tests/guided-flow.test.ts +12 -9
  282. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +4 -4
  283. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +8 -0
  284. package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +16 -0
  285. package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +69 -10
  286. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +32 -0
  287. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +2 -0
  288. package/src/resources/extensions/gsd/tests/memory-maintenance.test.ts +39 -8
  289. package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +63 -0
  290. package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +10 -1
  291. package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +9 -1
  292. package/src/resources/extensions/gsd/tests/new-milestone-discuss-routing.test.ts +3 -3
  293. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +9 -0
  294. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +157 -0
  295. package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +179 -0
  296. package/src/resources/extensions/gsd/tests/preferences.test.ts +29 -0
  297. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +61 -1
  298. package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +14 -0
  299. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +7 -8
  300. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +44 -0
  301. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +75 -0
  302. package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +4 -0
  303. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +36 -0
  304. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +100 -0
  305. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +139 -0
  306. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +4 -4
  307. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +19 -0
  308. package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +7 -1
  309. package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +6 -3
  310. package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +133 -0
  311. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +51 -0
  312. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +351 -0
  313. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +15 -0
  314. package/src/resources/extensions/gsd/tool-contract.ts +6 -0
  315. package/src/resources/extensions/gsd/tool-presentation-plan.ts +38 -8
  316. package/src/resources/extensions/gsd/tools/complete-slice.ts +14 -1
  317. package/src/resources/extensions/gsd/tools/complete-task.ts +20 -2
  318. package/src/resources/extensions/gsd/tools/validate-milestone.ts +46 -15
  319. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +163 -20
  320. package/src/resources/extensions/gsd/types.ts +69 -5
  321. package/src/resources/extensions/gsd/unit-tool-contracts.ts +186 -0
  322. package/src/resources/extensions/gsd/verdict-parser.ts +54 -13
  323. package/src/resources/extensions/gsd/verification-gate.ts +87 -1
  324. package/src/resources/extensions/gsd/workflow-mcp.ts +3 -75
  325. package/src/resources/extensions/shared/gsd-browser-cli.ts +172 -0
  326. package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound-corrections.test.ts +0 -246
  327. package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound.test.ts +0 -218
  328. /package/dist/web/standalone/.next/static/{eRWf-RI9bzbrwEurm_3uI → 9y3LeeR2uGr2yRj9RjY3D}/_buildManifest.js +0 -0
  329. /package/dist/web/standalone/.next/static/{eRWf-RI9bzbrwEurm_3uI → 9y3LeeR2uGr2yRj9RjY3D}/_ssgManifest.js +0 -0
@@ -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,284 @@ 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 merges canonical plan ID and read-only tools when presentation lacks plan ID", async () => {
709
+ const base = makeTmpBase();
710
+ const worktree = join(base, ".gsd", "worktrees", "M001");
711
+ const worktreeExecDir = join(worktree, ".gsd", "exec");
712
+ const evidenceId = "uat-no-plan-id-evidence";
713
+ try {
714
+ openTestDb(base);
715
+ seedMilestone("M001", "Milestone One");
716
+ seedSlice("M001", "S05", "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: "S05",
726
+ checkId: "UAT-01",
727
+ intent: "uat-artifact-check",
728
+ },
729
+ }),
730
+ "utf-8",
731
+ );
732
+
733
+ const result = await inProjectDir(worktree, () => executeUatResultSave({
734
+ milestoneId: "M001",
735
+ sliceId: "S05",
736
+ uatType: "artifact-driven",
737
+ verdict: "PASS",
738
+ checks: [{
739
+ id: "UAT-01",
740
+ description: "Presentation plan ID absent from provider call",
741
+ mode: "artifact",
742
+ result: "PASS",
743
+ evidence: [{ kind: "gsd_uat_exec", ref: evidenceId }],
744
+ notes: "Canonical merge should apply even when toolPresentationPlanId is absent.",
745
+ }],
746
+ presentation: {
747
+ surface: "mcp",
748
+ presentedTools: [
749
+ "gsd_uat_exec",
750
+ "gsd_uat_result_save",
751
+ "gsd_resume",
752
+ "gsd_milestone_status",
753
+ "gsd_journal_query",
754
+ ],
755
+ blockedTools: [
756
+ { name: "gsd_exec", reason: "forbidden during run-uat" },
757
+ { name: "gsd_summary_save", reason: "forbidden during run-uat" },
758
+ { name: "gsd_save_gate_result", reason: "forbidden during run-uat" },
759
+ ],
760
+ },
761
+ notes: "Provider omitted toolPresentationPlanId; executor must canonicalize.",
762
+ } as unknown as Parameters<typeof executeUatResultSave>[0], worktree));
763
+
764
+ assert.equal(result.isError, undefined);
765
+ assert.equal(result.details.verdict, "PASS");
766
+
767
+ const attempt = JSON.parse(readFileSync(
768
+ join(base, ".gsd", "uat", "M001", "S05", "attempt-1.json"),
769
+ "utf-8",
770
+ )) as { presentation?: { toolPresentationPlanId?: string; presentedTools?: string[] } };
771
+ assert.equal(attempt.presentation?.toolPresentationPlanId, "run-uat/default-v1");
772
+ assert.ok(attempt.presentation?.presentedTools?.includes("read"), "read-only tool must be merged in");
773
+ assert.ok(attempt.presentation?.presentedTools?.includes("gsd_uat_result_save"));
774
+ } finally {
775
+ closeDatabase();
776
+ cleanup(base);
777
+ }
778
+ });
779
+
780
+ test("executeUatResultSave rejects saved UAT without fresh UAT-owned evidence", async () => {
781
+ const base = makeTmpBase();
782
+ const worktree = join(base, ".gsd", "worktrees", "M001");
783
+ const worktreeExecDir = join(worktree, ".gsd", "exec");
784
+ const evidenceId = "generic-exec-evidence";
785
+ try {
786
+ openTestDb(base);
787
+ seedMilestone("M001", "Milestone One");
788
+ seedSlice("M001", "S04", "complete");
789
+ mkdirSync(worktreeExecDir, { recursive: true });
790
+ writeFileSync(
791
+ join(worktreeExecDir, `${evidenceId}.meta.json`),
792
+ JSON.stringify({
793
+ id: evidenceId,
794
+ metadata: { kind: "exec" },
795
+ }),
796
+ "utf-8",
797
+ );
798
+
799
+ const result = await inProjectDir(worktree, () => executeUatResultSave({
800
+ milestoneId: "M001",
801
+ sliceId: "S04",
802
+ uatType: "artifact-driven",
803
+ verdict: "PASS",
804
+ checks: [{
805
+ id: "UAT-01",
806
+ description: "Static artifact contract passes",
807
+ mode: "artifact",
808
+ result: "PASS",
809
+ evidence: [{ kind: "gsd_exec", ref: evidenceId }],
810
+ notes: "Generic evidence should not satisfy fresh UAT evidence.",
811
+ }],
812
+ notes: "UAT should not pass without fresh UAT-owned evidence.",
813
+ } as unknown as Parameters<typeof executeUatResultSave>[0], worktree));
814
+
815
+ assert.equal(result.isError, true);
816
+ assert.match(String(result.content[0]?.text), /fresh gsd_uat_exec evidence/);
817
+ } finally {
818
+ closeDatabase();
819
+ cleanup(base);
820
+ }
821
+ });
822
+
823
+ test("executeUatResultSave rejects an unrecognized uatType", async () => {
824
+ const base = makeTmpBase();
825
+ const worktree = join(base, ".gsd", "worktrees", "M001");
826
+ try {
827
+ openTestDb(base);
828
+ mkdirSync(worktree, { recursive: true });
829
+ seedMilestone("M001", "Milestone One");
830
+ seedSlice("M001", "S06", "complete");
831
+
832
+ const result = await inProjectDir(worktree, () => executeUatResultSave({
833
+ milestoneId: "M001",
834
+ sliceId: "S06",
835
+ uatType: "hallucinated-mode",
836
+ verdict: "PASS",
837
+ checks: [{
838
+ id: "UAT-01",
839
+ description: "Static artifact contract passes",
840
+ mode: "artifact",
841
+ result: "PASS",
842
+ evidence: [{ kind: "gsd_uat_exec", ref: "some-ref" }],
843
+ }],
844
+ notes: "Should fail before evidence validation.",
845
+ } as unknown as Parameters<typeof executeUatResultSave>[0], worktree));
846
+
847
+ assert.equal(result.isError, true);
848
+ assert.match(String(result.content[0]?.text), /uatType must be one of/);
849
+ } finally {
850
+ closeDatabase();
851
+ cleanup(base);
852
+ }
853
+ });
854
+
855
+ test("executeUatResultSave rejects artifact-driven PASS with human follow-up checks", async () => {
856
+ const base = makeTmpBase();
857
+ const worktree = join(base, ".gsd", "worktrees", "M001");
858
+ const evidenceId = "uat-artifact-nonautomatable";
859
+ const worktreeExecDir = join(worktree, ".gsd", "exec");
860
+ try {
861
+ openTestDb(base);
862
+ seedMilestone("M001", "Milestone One");
863
+ seedSlice("M001", "S01", "complete");
864
+ mkdirSync(worktreeExecDir, { recursive: true });
865
+ writeFileSync(
866
+ join(worktreeExecDir, `${evidenceId}.meta.json`),
867
+ JSON.stringify({
868
+ id: evidenceId,
869
+ metadata: {
870
+ kind: "uat_exec",
871
+ milestoneId: "M001",
872
+ sliceId: "S01",
873
+ checkId: "UAT-01",
874
+ intent: "uat-artifact-check",
875
+ },
876
+ }),
877
+ "utf-8",
878
+ );
879
+
880
+ const result = await inProjectDir(worktree, () => executeUatResultSave({
881
+ milestoneId: "M001",
882
+ sliceId: "S01",
883
+ uatType: "artifact-driven",
884
+ verdict: "PASS",
885
+ checks: [
886
+ {
887
+ id: "UAT-01",
888
+ description: "Static contract passes",
889
+ mode: "artifact",
890
+ result: "PASS",
891
+ evidence: [{ kind: "gsd_uat_exec", ref: evidenceId }],
892
+ notes: "Artifact check passed.",
893
+ },
894
+ {
895
+ id: "UAT-02",
896
+ description: "Browser polish is deferred to the next slice",
897
+ mode: "human-follow-up",
898
+ result: "NEEDS-HUMAN",
899
+ notes: "Out of scope for this artifact-driven UAT.",
900
+ nonAutomatable: true,
901
+ },
902
+ ],
903
+ presentation: {
904
+ surface: "mcp",
905
+ presentedTools: [
906
+ "gsd_uat_exec",
907
+ "gsd_uat_result_save",
908
+ "gsd_resume",
909
+ "gsd_milestone_status",
910
+ "gsd_journal_query",
911
+ ],
912
+ blockedTools: [
913
+ { name: "gsd_exec", reason: "forbidden during run-uat" },
914
+ { name: "gsd_summary_save", reason: "forbidden during run-uat" },
915
+ { name: "gsd_save_gate_result", reason: "forbidden during run-uat" },
916
+ ],
917
+ },
918
+ notes: "UAT passed; non-automatable browser polish is deferred.",
919
+ }, worktree));
920
+
921
+ assert.equal(result.isError, true);
922
+ assert.match(String(result.content[0]?.text), /artifact-driven UAT cannot PASS with human-only checks/);
923
+ } finally {
924
+ closeDatabase();
925
+ cleanup(base);
926
+ }
927
+ });
928
+
590
929
  test("executeSliceComplete coerces string enrichment entries and writes summary/UAT artifacts", async () => {
591
930
  const base = makeTmpBase();
592
931
  try {
@@ -1279,6 +1618,10 @@ test("executeSummarySave blocks final root artifacts while approval gate is pend
1279
1618
 
1280
1619
  assert.equal(result.isError, true);
1281
1620
  assert.equal(result.details.error, "root_artifact_write_blocked");
1621
+ assert.equal(
1622
+ result.details.displayReason,
1623
+ "Approval confirmation required before saving final project setup artifacts.",
1624
+ );
1282
1625
  assert.match(result.content[0].text, /has not been confirmed/);
1283
1626
  assert.equal(existsSync(join(base, ".gsd", "REQUIREMENTS.md")), false);
1284
1627
 
@@ -1321,6 +1664,10 @@ test("executeSummarySave requires verified root approval in deep mode", async ()
1321
1664
 
1322
1665
  assert.equal(blocked.isError, true);
1323
1666
  assert.equal(blocked.details.error, "root_artifact_write_blocked");
1667
+ assert.equal(
1668
+ blocked.details.displayReason,
1669
+ "Approval confirmation required before saving final project setup artifacts.",
1670
+ );
1324
1671
  assert.match(blocked.content[0].text, /fail-closed/);
1325
1672
  assert.equal(existsSync(join(base, ".gsd", "PROJECT.md")), false);
1326
1673
 
@@ -1537,6 +1884,10 @@ test("executeSummarySave CONTEXT HARD BLOCK clears after write-gate state file i
1537
1884
  content: "# Context\n\ncontent",
1538
1885
  }, base));
1539
1886
  assert.equal(blocked.isError, true, "should be blocked without depth verification");
1887
+ assert.equal(
1888
+ blocked.details.displayReason,
1889
+ "Depth check required before writing milestone context.",
1890
+ );
1540
1891
  assert.match(
1541
1892
  blocked.content[0].text,
1542
1893
  /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,18 @@
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_READ_ONLY_TOOL_NAMES,
6
+ RUN_UAT_TOOL_PRESENTATION_PLAN_ID,
7
+ RUN_UAT_WORKFLOW_TOOL_NAMES,
8
+ } from "./unit-tool-contracts.js";
9
+
10
+ export {
11
+ RUN_UAT_READ_ONLY_TOOL_NAMES,
12
+ RUN_UAT_TOOL_PRESENTATION_PLAN_ID,
13
+ RUN_UAT_WORKFLOW_TOOL_NAMES,
14
+ } from "./unit-tool-contracts.js";
15
+
4
16
  export type ToolPresentationSurface = "provider-tools" | "claude-code-sdk" | "mcp" | "hybrid";
5
17
 
6
18
  export interface ToolPresentationModel {
@@ -20,14 +32,6 @@ export interface ToolPresentationPlan {
20
32
  diagnostics: string[];
21
33
  }
22
34
 
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;
30
-
31
35
  export const RUN_UAT_FORBIDDEN_TOOL_NAMES = [
32
36
  "edit",
33
37
  "write",
@@ -105,10 +109,36 @@ function addBlockedTool(
105
109
  export function buildRunUatCanonicalToolNames(options: { includeBrowserTools?: readonly string[] } = {}): string[] {
106
110
  return dedupe([
107
111
  ...RUN_UAT_WORKFLOW_TOOL_NAMES,
112
+ ...RUN_UAT_READ_ONLY_TOOL_NAMES,
108
113
  ...(options.includeBrowserTools ?? []),
109
114
  ]);
110
115
  }
111
116
 
117
+ export function buildRunUatResultPresentation(options: {
118
+ surface?: ToolPresentationSurface;
119
+ includeBrowserTools?: readonly string[];
120
+ presentedTools?: readonly string[];
121
+ } = {}): {
122
+ surface: ToolPresentationSurface;
123
+ presentedTools: string[];
124
+ blockedTools: Array<{ name: string; reason: string }>;
125
+ toolPresentationPlanId: string;
126
+ } {
127
+ const presentedTools = options.presentedTools
128
+ ? dedupe(options.presentedTools)
129
+ : buildRunUatCanonicalToolNames({ includeBrowserTools: options.includeBrowserTools });
130
+ const blockedTools = RUN_UAT_FORBIDDEN_TOOL_NAMES
131
+ .filter((toolName) => !toolName.includes("*"))
132
+ .map((name) => ({ name, reason: "forbidden during run-uat" }));
133
+
134
+ return {
135
+ surface: options.surface ?? "mcp",
136
+ presentedTools,
137
+ blockedTools,
138
+ toolPresentationPlanId: RUN_UAT_TOOL_PRESENTATION_PLAN_ID,
139
+ };
140
+ }
141
+
112
142
  export function resolveToolPresentationPlan(options: {
113
143
  phase: string;
114
144
  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
@@ -12,7 +12,7 @@
12
12
 
13
13
  import { join } from "node:path";
14
14
 
15
- import type { CompleteTaskParams } from "../types.js";
15
+ import type { CompleteTaskParams, EscalationArtifact } from "../types.js";
16
16
  import { isClosedStatus } from "../status-guards.js";
17
17
  import {
18
18
  transaction,
@@ -48,6 +48,14 @@ export interface CompleteTaskResult {
48
48
  sliceId: string;
49
49
  milestoneId: string;
50
50
  summaryPath: string;
51
+ escalation?: {
52
+ artifactPath: string;
53
+ question: string;
54
+ options: EscalationArtifact["options"];
55
+ recommendation: string;
56
+ recommendationRationale: string;
57
+ continueWithDefault: boolean;
58
+ };
51
59
  /**
52
60
  * True when this call re-completed an already-closed task from a turn that
53
61
  * had been superseded by timeout recovery or cancellation. The underlying
@@ -407,9 +415,18 @@ export async function handleCompleteTask(
407
415
  // overwrite it; gate rows are UPSERT-keyed per task and will also be
408
416
  // overwritten. This restores the invariant that deriveState() sees a
409
417
  // consistent "task not done" view so the loop re-dispatches the task.
418
+ let escalationMetadata: CompleteTaskResult["escalation"] | undefined;
410
419
  if (validatedEscalationArtifact) {
411
420
  try {
412
- writeEscalationArtifact(artifactBasePath, validatedEscalationArtifact);
421
+ const escalationPath = writeEscalationArtifact(artifactBasePath, validatedEscalationArtifact);
422
+ escalationMetadata = {
423
+ artifactPath: escalationPath,
424
+ question: validatedEscalationArtifact.question,
425
+ options: validatedEscalationArtifact.options,
426
+ recommendation: validatedEscalationArtifact.recommendation,
427
+ recommendationRationale: validatedEscalationArtifact.recommendationRationale,
428
+ continueWithDefault: validatedEscalationArtifact.continueWithDefault,
429
+ };
413
430
  } catch (escalationErr) {
414
431
  const msg = `complete-task escalation write failed for ${params.milestoneId}/${params.sliceId}/${params.taskId}: ${(escalationErr as Error).message}`;
415
432
  logWarning("tool", msg);
@@ -477,6 +494,7 @@ export async function handleCompleteTask(
477
494
  sliceId: params.sliceId,
478
495
  milestoneId: params.milestoneId,
479
496
  summaryPath,
497
+ ...(escalationMetadata ? { escalation: escalationMetadata } : {}),
480
498
  ...(projectionStale ? { stale: true } : {}),
481
499
  };
482
500
  }