@opengsd/gsd-pi 1.1.1-dev.616a1a1 → 1.1.1-dev.9bb7453

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 (395) 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/claude-code-cli/stream-adapter.js +167 -16
  10. package/dist/resources/extensions/gsd/auto/orchestrator.js +0 -1
  11. package/dist/resources/extensions/gsd/auto/phases.js +4 -3
  12. package/dist/resources/extensions/gsd/auto-dashboard.js +92 -17
  13. package/dist/resources/extensions/gsd/auto-dispatch.js +44 -0
  14. package/dist/resources/extensions/gsd/auto-post-unit.js +134 -10
  15. package/dist/resources/extensions/gsd/auto-prompts.js +68 -22
  16. package/dist/resources/extensions/gsd/auto-recovery.js +4 -4
  17. package/dist/resources/extensions/gsd/auto-runtime-state.js +3 -0
  18. package/dist/resources/extensions/gsd/auto-start.js +94 -15
  19. package/dist/resources/extensions/gsd/auto-tool-tracking.js +1 -1
  20. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +2 -1
  21. package/dist/resources/extensions/gsd/auto.js +31 -6
  22. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +83 -4
  23. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +43 -0
  24. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +39 -14
  25. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +16 -10
  26. package/dist/resources/extensions/gsd/browser-evidence.js +29 -2
  27. package/dist/resources/extensions/gsd/commands/catalog.js +6 -1
  28. package/dist/resources/extensions/gsd/commands/handlers/core.js +6 -2
  29. package/dist/resources/extensions/gsd/commands/handlers/ops.js +9 -5
  30. package/dist/resources/extensions/gsd/commands-handlers.js +76 -11
  31. package/dist/resources/extensions/gsd/commands-maintenance.js +172 -2
  32. package/dist/resources/extensions/gsd/commands-mcp-status.js +109 -60
  33. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +3 -1
  34. package/dist/resources/extensions/gsd/commands-verdict.js +1 -1
  35. package/dist/resources/extensions/gsd/config-overlay.js +2 -1
  36. package/dist/resources/extensions/gsd/dashboard-overlay.js +21 -7
  37. package/dist/resources/extensions/gsd/docs/preferences-reference.md +8 -0
  38. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +2 -2
  39. package/dist/resources/extensions/gsd/error-classifier.js +2 -1
  40. package/dist/resources/extensions/gsd/escalation.js +4 -4
  41. package/dist/resources/extensions/gsd/exec-sandbox.js +2 -0
  42. package/dist/resources/extensions/gsd/forensics.js +74 -2
  43. package/dist/resources/extensions/gsd/gsd-db.js +42 -6
  44. package/dist/resources/extensions/gsd/guided-flow.js +30 -69
  45. package/dist/resources/extensions/gsd/mcp-filter.js +3 -0
  46. package/dist/resources/extensions/gsd/mcp-project-config.js +76 -84
  47. package/dist/resources/extensions/gsd/memory-store.js +4 -1
  48. package/dist/resources/extensions/gsd/migration-auto-check.js +2 -2
  49. package/dist/resources/extensions/gsd/post-unit-hooks.js +9 -0
  50. package/dist/resources/extensions/gsd/preferences-validation.js +39 -0
  51. package/dist/resources/extensions/gsd/prompt-loader.js +7 -0
  52. package/dist/resources/extensions/gsd/prompts/forensics.md +61 -1
  53. package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
  54. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
  55. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  56. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
  57. package/dist/resources/extensions/gsd/prompts/run-uat.md +48 -24
  58. package/dist/resources/extensions/gsd/prompts/system.md +3 -1
  59. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
  60. package/dist/resources/extensions/gsd/rule-registry.js +428 -52
  61. package/dist/resources/extensions/gsd/safety/destructive-guard.js +3 -0
  62. package/dist/resources/extensions/gsd/skill-activation.js +20 -3
  63. package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +4 -2
  64. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +1 -1
  65. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +18 -1
  66. package/dist/resources/extensions/gsd/state-reconciliation/index.js +6 -0
  67. package/dist/resources/extensions/gsd/state.js +17 -14
  68. package/dist/resources/extensions/gsd/templates/plan.md +3 -1
  69. package/dist/resources/extensions/gsd/tool-presentation-plan.js +120 -0
  70. package/dist/resources/extensions/gsd/tools/complete-slice.js +15 -1
  71. package/dist/resources/extensions/gsd/tools/complete-task.js +11 -1
  72. package/dist/resources/extensions/gsd/tools/exec-tool.js +109 -0
  73. package/dist/resources/extensions/gsd/tools/plan-slice.js +14 -9
  74. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +2 -2
  75. package/dist/resources/extensions/gsd/tools/validate-milestone.js +46 -16
  76. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +403 -3
  77. package/dist/resources/extensions/gsd/unit-context-manifest.js +8 -3
  78. package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
  79. package/dist/resources/extensions/gsd/verdict-parser.js +59 -15
  80. package/dist/resources/extensions/gsd/verification-gate.js +72 -1
  81. package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +3 -1
  82. package/dist/resources/extensions/gsd/workflow-mcp.js +5 -1
  83. package/dist/resources/extensions/gsd/worktree-lifecycle.js +24 -0
  84. package/dist/resources/extensions/mcp-client/manager.js +31 -1
  85. package/dist/resources/extensions/shared/gsd-browser-cli.js +145 -0
  86. package/dist/rtk.d.ts +7 -1
  87. package/dist/rtk.js +27 -11
  88. package/dist/update-check.d.ts +15 -1
  89. package/dist/update-check.js +87 -12
  90. package/dist/update-cmd.d.ts +1 -0
  91. package/dist/update-cmd.js +53 -2
  92. package/dist/web/standalone/.next/BUILD_ID +1 -1
  93. package/dist/web/standalone/.next/app-path-routes-manifest.json +6 -6
  94. package/dist/web/standalone/.next/build-manifest.json +2 -2
  95. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  96. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  97. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  105. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  113. package/dist/web/standalone/.next/server/app/index.html +1 -1
  114. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  118. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app-paths-manifest.json +6 -6
  121. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  122. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  124. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  125. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  126. package/package.json +5 -3
  127. package/packages/cloud-mcp-gateway/package.json +2 -2
  128. package/packages/contracts/dist/workflow.d.ts +14 -0
  129. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  130. package/packages/contracts/dist/workflow.js +16 -0
  131. package/packages/contracts/dist/workflow.js.map +1 -1
  132. package/packages/contracts/package.json +1 -1
  133. package/packages/daemon/package.json +4 -4
  134. package/packages/gsd-agent-core/dist/agent-session.d.ts +9 -0
  135. package/packages/gsd-agent-core/dist/agent-session.d.ts.map +1 -1
  136. package/packages/gsd-agent-core/dist/agent-session.js +32 -0
  137. package/packages/gsd-agent-core/dist/agent-session.js.map +1 -1
  138. package/packages/gsd-agent-core/dist/index.d.ts +1 -0
  139. package/packages/gsd-agent-core/dist/index.d.ts.map +1 -1
  140. package/packages/gsd-agent-core/dist/index.js +1 -0
  141. package/packages/gsd-agent-core/dist/index.js.map +1 -1
  142. package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts +2 -0
  143. package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts.map +1 -1
  144. package/packages/gsd-agent-core/dist/session/agent-session-compaction.js +8 -2
  145. package/packages/gsd-agent-core/dist/session/agent-session-compaction.js.map +1 -1
  146. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts +7 -0
  147. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts.map +1 -1
  148. package/packages/gsd-agent-core/dist/session/agent-session-host.js.map +1 -1
  149. package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts.map +1 -1
  150. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js +69 -1
  151. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js.map +1 -1
  152. package/packages/gsd-agent-core/dist/turn-latency.d.ts +47 -0
  153. package/packages/gsd-agent-core/dist/turn-latency.d.ts.map +1 -0
  154. package/packages/gsd-agent-core/dist/turn-latency.js +123 -0
  155. package/packages/gsd-agent-core/dist/turn-latency.js.map +1 -0
  156. package/packages/gsd-agent-core/package.json +6 -6
  157. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts +21 -0
  158. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts.map +1 -0
  159. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js +213 -0
  160. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js.map +1 -0
  161. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  162. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  163. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +10 -0
  164. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
  165. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts +1 -0
  166. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  167. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +92 -31
  168. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  169. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  170. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +7 -1
  171. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  172. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.d.ts.map +1 -1
  173. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js +6 -0
  174. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js.map +1 -1
  175. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.d.ts.map +1 -1
  176. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.js +2 -0
  177. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.js.map +1 -1
  178. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts +1 -1
  179. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts.map +1 -1
  180. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js +1 -1
  181. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js.map +1 -1
  182. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  183. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +1 -0
  184. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
  185. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.d.ts.map +1 -1
  186. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js +5 -0
  187. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js.map +1 -1
  188. package/packages/gsd-agent-modes/package.json +7 -7
  189. package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -1
  190. package/packages/mcp-server/dist/remote-questions.js +23 -9
  191. package/packages/mcp-server/dist/remote-questions.js.map +1 -1
  192. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  193. package/packages/mcp-server/dist/workflow-tools.js +84 -2
  194. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  195. package/packages/mcp-server/package.json +3 -3
  196. package/packages/native/package.json +1 -1
  197. package/packages/pi-agent-core/dist/agent-loop.js +38 -0
  198. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  199. package/packages/pi-agent-core/dist/agent.d.ts +5 -1
  200. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  201. package/packages/pi-agent-core/dist/agent.js +2 -0
  202. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  203. package/packages/pi-agent-core/dist/types.d.ts +3 -0
  204. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  205. package/packages/pi-agent-core/dist/types.js.map +1 -1
  206. package/packages/pi-agent-core/package.json +1 -1
  207. package/packages/pi-ai/dist/api-registry.d.ts +2 -0
  208. package/packages/pi-ai/dist/api-registry.d.ts.map +1 -1
  209. package/packages/pi-ai/dist/api-registry.js +23 -0
  210. package/packages/pi-ai/dist/api-registry.js.map +1 -1
  211. package/packages/pi-ai/dist/image-models.generated.d.ts +15 -0
  212. package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
  213. package/packages/pi-ai/dist/image-models.generated.js +15 -0
  214. package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
  215. package/packages/pi-ai/dist/models.generated.d.ts +406 -17
  216. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  217. package/packages/pi-ai/dist/models.generated.js +484 -116
  218. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  219. package/packages/pi-ai/dist/stream.js +6 -6
  220. package/packages/pi-ai/dist/stream.js.map +1 -1
  221. package/packages/pi-ai/package.json +1 -1
  222. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  223. package/packages/pi-coding-agent/dist/core/model-registry.js +2 -2
  224. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  225. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
  226. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  227. package/packages/pi-coding-agent/dist/core/settings-manager.js +11 -0
  228. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  229. package/packages/pi-coding-agent/package.json +7 -7
  230. package/packages/pi-tui/dist/terminal.d.ts +1 -0
  231. package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
  232. package/packages/pi-tui/dist/terminal.js +8 -4
  233. package/packages/pi-tui/dist/terminal.js.map +1 -1
  234. package/packages/pi-tui/package.json +1 -1
  235. package/packages/rpc-client/package.json +2 -2
  236. package/pkg/package.json +1 -1
  237. package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +579 -0
  238. package/src/resources/extensions/browser-tools/engine/selection.ts +19 -0
  239. package/src/resources/extensions/browser-tools/extension-manifest.json +2 -2
  240. package/src/resources/extensions/browser-tools/index.ts +60 -9
  241. package/src/resources/extensions/browser-tools/package.json +5 -1
  242. package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +35 -0
  243. package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +33 -0
  244. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +196 -16
  245. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +239 -63
  246. package/src/resources/extensions/gsd/auto/orchestrator.ts +0 -1
  247. package/src/resources/extensions/gsd/auto/phases.ts +5 -3
  248. package/src/resources/extensions/gsd/auto-dashboard.ts +98 -18
  249. package/src/resources/extensions/gsd/auto-dispatch.ts +53 -0
  250. package/src/resources/extensions/gsd/auto-post-unit.ts +166 -9
  251. package/src/resources/extensions/gsd/auto-prompts.ts +102 -15
  252. package/src/resources/extensions/gsd/auto-recovery.ts +4 -4
  253. package/src/resources/extensions/gsd/auto-runtime-state.ts +4 -0
  254. package/src/resources/extensions/gsd/auto-start.ts +112 -17
  255. package/src/resources/extensions/gsd/auto-tool-tracking.ts +1 -1
  256. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +2 -1
  257. package/src/resources/extensions/gsd/auto.ts +47 -5
  258. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +90 -4
  259. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +51 -0
  260. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +60 -19
  261. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +21 -10
  262. package/src/resources/extensions/gsd/browser-evidence.ts +26 -2
  263. package/src/resources/extensions/gsd/commands/catalog.ts +6 -1
  264. package/src/resources/extensions/gsd/commands/handlers/core.ts +6 -2
  265. package/src/resources/extensions/gsd/commands/handlers/ops.ts +9 -5
  266. package/src/resources/extensions/gsd/commands-handlers.ts +76 -11
  267. package/src/resources/extensions/gsd/commands-maintenance.ts +197 -2
  268. package/src/resources/extensions/gsd/commands-mcp-status.ts +136 -58
  269. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +4 -1
  270. package/src/resources/extensions/gsd/commands-verdict.ts +1 -1
  271. package/src/resources/extensions/gsd/config-overlay.ts +3 -1
  272. package/src/resources/extensions/gsd/dashboard-overlay.ts +28 -7
  273. package/src/resources/extensions/gsd/docs/preferences-reference.md +8 -0
  274. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +2 -2
  275. package/src/resources/extensions/gsd/error-classifier.ts +2 -1
  276. package/src/resources/extensions/gsd/escalation.ts +4 -4
  277. package/src/resources/extensions/gsd/exec-sandbox.ts +4 -0
  278. package/src/resources/extensions/gsd/forensics.ts +99 -5
  279. package/src/resources/extensions/gsd/gsd-db.ts +46 -8
  280. package/src/resources/extensions/gsd/guided-flow.ts +91 -83
  281. package/src/resources/extensions/gsd/mcp-filter.ts +3 -0
  282. package/src/resources/extensions/gsd/mcp-project-config.ts +105 -88
  283. package/src/resources/extensions/gsd/memory-store.ts +4 -1
  284. package/src/resources/extensions/gsd/migration-auto-check.ts +2 -2
  285. package/src/resources/extensions/gsd/post-unit-hooks.ts +14 -1
  286. package/src/resources/extensions/gsd/preferences-types.ts +1 -1
  287. package/src/resources/extensions/gsd/preferences-validation.ts +36 -0
  288. package/src/resources/extensions/gsd/prompt-loader.ts +8 -0
  289. package/src/resources/extensions/gsd/prompts/forensics.md +61 -1
  290. package/src/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
  291. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
  292. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  293. package/src/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
  294. package/src/resources/extensions/gsd/prompts/run-uat.md +48 -24
  295. package/src/resources/extensions/gsd/prompts/system.md +3 -1
  296. package/src/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
  297. package/src/resources/extensions/gsd/rule-registry.ts +558 -58
  298. package/src/resources/extensions/gsd/rule-types.ts +2 -0
  299. package/src/resources/extensions/gsd/safety/destructive-guard.ts +3 -0
  300. package/src/resources/extensions/gsd/skill-activation.ts +20 -2
  301. package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +4 -2
  302. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +1 -1
  303. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +20 -0
  304. package/src/resources/extensions/gsd/state-reconciliation/index.ts +6 -0
  305. package/src/resources/extensions/gsd/state-reconciliation/types.ts +1 -0
  306. package/src/resources/extensions/gsd/state.ts +18 -14
  307. package/src/resources/extensions/gsd/templates/plan.md +3 -1
  308. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +156 -4
  309. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +123 -0
  310. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +143 -2
  311. package/src/resources/extensions/gsd/tests/auto-start-project-milestone-reconcile.test.ts +24 -2
  312. package/src/resources/extensions/gsd/tests/browser-evidence.test.ts +142 -0
  313. package/src/resources/extensions/gsd/tests/commands-dispatcher-validation-block.test.ts +38 -3
  314. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +6 -2
  315. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +30 -0
  316. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +42 -0
  317. package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +45 -0
  318. package/src/resources/extensions/gsd/tests/deep-planning-mode-dispatch.test.ts +53 -0
  319. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +8 -0
  320. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +50 -13
  321. package/src/resources/extensions/gsd/tests/discuss-milestone-structured-questions.test.ts +31 -0
  322. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +60 -0
  323. package/src/resources/extensions/gsd/tests/doctor-runtime-checks.test.ts +27 -0
  324. package/src/resources/extensions/gsd/tests/escalation.test.ts +16 -27
  325. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +18 -0
  326. package/src/resources/extensions/gsd/tests/exec-tool.test.ts +69 -0
  327. package/src/resources/extensions/gsd/tests/forensics-issue-routing.test.ts +20 -0
  328. package/src/resources/extensions/gsd/tests/forensics-prompt-rendering.test.ts +3 -0
  329. package/src/resources/extensions/gsd/tests/forensics-tool-scope.test.ts +69 -0
  330. package/src/resources/extensions/gsd/tests/gsd-rebuild.test.ts +199 -0
  331. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +75 -0
  332. package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +40 -1
  333. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +86 -0
  334. package/src/resources/extensions/gsd/tests/guided-flow.test.ts +12 -9
  335. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +4 -4
  336. package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +66 -10
  337. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +13 -6
  338. package/src/resources/extensions/gsd/tests/mcp-filter.test.ts +15 -0
  339. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +100 -0
  340. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +179 -0
  341. package/src/resources/extensions/gsd/tests/memory-maintenance.test.ts +39 -8
  342. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +3 -3
  343. package/src/resources/extensions/gsd/tests/new-milestone-discuss-routing.test.ts +3 -3
  344. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +54 -7
  345. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +9 -0
  346. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +39 -1
  347. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +157 -0
  348. package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +179 -0
  349. package/src/resources/extensions/gsd/tests/preferences.test.ts +29 -0
  350. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +53 -1
  351. package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +14 -0
  352. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +18 -1
  353. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +7 -8
  354. package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +36 -0
  355. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +35 -0
  356. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +1 -1
  357. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +75 -0
  358. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +100 -0
  359. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +55 -0
  360. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +6 -2
  361. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +191 -0
  362. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +84 -10
  363. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +19 -0
  364. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +12 -2
  365. package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +7 -1
  366. package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +29 -6
  367. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +29 -6
  368. package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +6 -3
  369. package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +133 -0
  370. package/src/resources/extensions/gsd/tests/validation-block-guard.test.ts +21 -0
  371. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +51 -0
  372. package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +17 -2
  373. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +213 -0
  374. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +25 -0
  375. package/src/resources/extensions/gsd/tool-presentation-plan.ts +167 -0
  376. package/src/resources/extensions/gsd/tools/complete-slice.ts +14 -1
  377. package/src/resources/extensions/gsd/tools/complete-task.ts +20 -2
  378. package/src/resources/extensions/gsd/tools/exec-tool.ts +130 -0
  379. package/src/resources/extensions/gsd/tools/plan-slice.ts +14 -9
  380. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +2 -2
  381. package/src/resources/extensions/gsd/tools/validate-milestone.ts +46 -15
  382. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +489 -3
  383. package/src/resources/extensions/gsd/types.ts +69 -5
  384. package/src/resources/extensions/gsd/unit-context-manifest.ts +14 -5
  385. package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
  386. package/src/resources/extensions/gsd/verdict-parser.ts +54 -13
  387. package/src/resources/extensions/gsd/verification-gate.ts +87 -1
  388. package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +2 -1
  389. package/src/resources/extensions/gsd/workflow-mcp.ts +5 -1
  390. package/src/resources/extensions/gsd/worktree-lifecycle.ts +26 -0
  391. package/src/resources/extensions/mcp-client/manager.ts +33 -1
  392. package/src/resources/extensions/mcp-client/tests/manager.test.ts +35 -0
  393. package/src/resources/extensions/shared/gsd-browser-cli.ts +172 -0
  394. /package/dist/web/standalone/.next/static/{L9N5SPFi7f-Ne4u2uXzCe → jBtwT9v1u2lUA3UEOy_ZH}/_buildManifest.js +0 -0
  395. /package/dist/web/standalone/.next/static/{L9N5SPFi7f-Ne4u2uXzCe → jBtwT9v1u2lUA3UEOy_ZH}/_ssgManifest.js +0 -0
@@ -10,19 +10,21 @@ import {
10
10
  getMilestone,
11
11
  getSliceStatusSummary,
12
12
  getSliceTaskCounts,
13
+ insertGateRun,
13
14
  readTransaction,
14
15
  saveGateResult,
16
+ upsertQualityGate,
15
17
  } from "../gsd-db.js";
16
18
  import { GATE_REGISTRY } from "../gate-registry.js";
17
19
  import { generateRequirementsMd, saveArtifactToDb } from "../db-writer.js";
18
20
  import { clearPathCache, resolveGsdPathContract, resolveMilestoneFile, resolveSliceFile } from "../paths.js";
19
21
  import { saveFile, clearParseCache } from "../files.js";
20
- import { unlinkSync } from "node:fs";
21
- import { join } from "node:path";
22
+ import { existsSync, readdirSync, readFileSync, unlinkSync } from "node:fs";
23
+ import { isAbsolute, join, resolve } from "node:path";
22
24
  import type { CompleteMilestoneParams } from "./complete-milestone.js";
23
25
  import { handleCompleteMilestone } from "./complete-milestone.js";
24
26
  import { handleCompleteTask } from "./complete-task.js";
25
- import type { CompleteSliceParams } from "../types.js";
27
+ import type { CompleteSliceParams, EscalationOption } from "../types.js";
26
28
  import { handleCompleteSlice } from "./complete-slice.js";
27
29
  import type { PlanMilestoneParams } from "./plan-milestone.js";
28
30
  import { handlePlanMilestone } from "./plan-milestone.js";
@@ -45,6 +47,12 @@ import { invalidateStateCache } from "../state.js";
45
47
  import { loadEffectiveGSDPreferences } from "../preferences.js";
46
48
  import { parseProject } from "../schemas/parsers.js";
47
49
  import { getAutoRuntimeSnapshot } from "../auto-runtime-state.js";
50
+ import {
51
+ canonicalWorkflowToolName,
52
+ parseMcpToolName,
53
+ RUN_UAT_FORBIDDEN_TOOL_NAMES,
54
+ RUN_UAT_WORKFLOW_TOOL_NAMES,
55
+ } from "../tool-presentation-plan.js";
48
56
 
49
57
  export const SUPPORTED_SUMMARY_ARTIFACT_TYPES = [
50
58
  "SUMMARY",
@@ -339,6 +347,14 @@ type VerificationEvidenceInput =
339
347
  }
340
348
  | string;
341
349
 
350
+ interface TaskEscalationInput {
351
+ question: string;
352
+ options: EscalationOption[];
353
+ recommendation: string;
354
+ recommendationRationale: string;
355
+ continueWithDefault: boolean;
356
+ }
357
+
342
358
  export interface TaskCompleteParams {
343
359
  taskId: string;
344
360
  sliceId: string;
@@ -351,6 +367,7 @@ export interface TaskCompleteParams {
351
367
  keyFiles?: string[];
352
368
  keyDecisions?: string[];
353
369
  blockerDiscovered?: boolean;
370
+ escalation?: TaskEscalationInput;
354
371
  verificationEvidence?: VerificationEvidenceInput[];
355
372
  }
356
373
 
@@ -409,6 +426,56 @@ export interface SaveGateResultParams {
409
426
  findings?: string;
410
427
  }
411
428
 
429
+ export type UatType =
430
+ | "artifact-driven"
431
+ | "browser-executable"
432
+ | "runtime-executable"
433
+ | "live-runtime"
434
+ | "mixed"
435
+ | "human-experience";
436
+
437
+ export type UatVerdict = "PASS" | "FAIL" | "PARTIAL";
438
+ export type UatCheckResult = "PASS" | "FAIL" | "NEEDS-HUMAN";
439
+
440
+ export interface UatEvidenceRef {
441
+ kind: "gsd_uat_exec" | "gsd_exec" | "screenshot" | "log" | "url" | "browser";
442
+ ref: string;
443
+ note?: string;
444
+ }
445
+
446
+ export interface UatCheckResultInput {
447
+ id: string;
448
+ description: string;
449
+ mode: "artifact" | "runtime" | "browser" | "human-follow-up";
450
+ result: UatCheckResult;
451
+ evidence?: UatEvidenceRef[];
452
+ notes?: string;
453
+ nonAutomatable?: boolean;
454
+ }
455
+
456
+ export interface UatPresentationInput {
457
+ surface: "provider-tools" | "claude-code-sdk" | "mcp" | "hybrid";
458
+ model?: { provider?: string; api?: string; id?: string };
459
+ presentedTools: string[];
460
+ blockedTools: Array<{ name: string; reason: string }>;
461
+ aliases?: Array<{ requested: string; canonical: string }>;
462
+ fallbackToolsUsed?: string[];
463
+ toolPresentationPlanId?: string;
464
+ notes?: string;
465
+ }
466
+
467
+ export interface UatResultSaveParams {
468
+ milestoneId: string;
469
+ sliceId: string;
470
+ uatType: UatType;
471
+ verdict: UatVerdict;
472
+ checks: UatCheckResultInput[];
473
+ presentation: UatPresentationInput;
474
+ notes?: string;
475
+ attempt?: number | string | "auto";
476
+ previousAttemptId?: string;
477
+ }
478
+
412
479
  export async function executeTaskComplete(
413
480
  params: TaskCompleteParams,
414
481
  basePath: string = process.cwd(),
@@ -453,6 +520,28 @@ export async function executeTaskComplete(
453
520
  isError: true,
454
521
  };
455
522
  }
523
+ if (result.escalation) {
524
+ const recommended = result.escalation.options.find((option) => option.id === result.escalation?.recommendation);
525
+ const optionIds = result.escalation.options.map((option) => option.id).join("|");
526
+ return {
527
+ content: [{
528
+ type: "text",
529
+ text: [
530
+ `Task completed with escalation decision required: ${result.escalation.question}`,
531
+ `Recommendation: ${result.escalation.recommendation}${recommended ? ` (${recommended.label})` : ""} — ${result.escalation.recommendationRationale}`,
532
+ `Resolve with: /gsd escalate resolve ${result.taskId} <${optionIds}|accept|reject-blocker> [rationale...]`,
533
+ ].join("\n"),
534
+ }],
535
+ details: {
536
+ operation: "complete_task",
537
+ taskId: result.taskId,
538
+ sliceId: result.sliceId,
539
+ milestoneId: result.milestoneId,
540
+ summaryPath: result.summaryPath,
541
+ escalation: result.escalation,
542
+ },
543
+ };
544
+ }
456
545
  return {
457
546
  content: [{ type: "text", text: `Completed task ${result.taskId} (${result.sliceId}/${result.milestoneId})` }],
458
547
  details: {
@@ -907,6 +996,403 @@ export async function executeSaveGateResult(
907
996
  }
908
997
  }
909
998
 
999
+ function errorResult(operation: string, message: string, error: string): ToolExecutionResult {
1000
+ return {
1001
+ content: [{ type: "text", text: `Error: ${message}` }],
1002
+ details: { operation, error },
1003
+ isError: true,
1004
+ };
1005
+ }
1006
+
1007
+ function isNonEmptyString(value: unknown): value is string {
1008
+ return typeof value === "string" && value.trim().length > 0;
1009
+ }
1010
+
1011
+ function ensureUatRequiredFields(params: UatResultSaveParams): string | null {
1012
+ if (!isNonEmptyString(params.milestoneId)) return "milestoneId is required";
1013
+ if (!isNonEmptyString(params.sliceId)) return "sliceId is required";
1014
+ if (!isNonEmptyString(params.uatType)) return "uatType is required";
1015
+ if (!["PASS", "FAIL", "PARTIAL"].includes(params.verdict)) return "verdict must be PASS, FAIL, or PARTIAL";
1016
+ if (!Array.isArray(params.checks) || params.checks.length === 0) return "checks must contain at least one UAT check";
1017
+ if (!params.presentation || !Array.isArray(params.presentation.presentedTools)) return "presentation.presentedTools is required";
1018
+ if (!Array.isArray(params.presentation.blockedTools)) return "presentation.blockedTools is required";
1019
+ return null;
1020
+ }
1021
+
1022
+ function approvedEvidenceRoots(basePath: string): string[] {
1023
+ const contract = resolveGsdPathContract(basePath);
1024
+ return [contract.worktreeGsd, contract.projectGsd].filter((root): root is string => typeof root === "string");
1025
+ }
1026
+
1027
+ function approvedBrowserArtifactRoots(basePath: string): string[] {
1028
+ const contract = resolveGsdPathContract(basePath);
1029
+ const roots = [contract.workRoot, contract.projectRoot].map((root) => join(root, ".artifacts", "browser"));
1030
+ return [...new Set(roots)];
1031
+ }
1032
+
1033
+ function pathStartsWithin(parent: string, target: string): boolean {
1034
+ const normalizedParent = parent.replace(/\\/g, "/").replace(/\/+$/, "");
1035
+ const normalizedTarget = target.replace(/\\/g, "/").replace(/\/+$/, "");
1036
+ return normalizedTarget === normalizedParent || normalizedTarget.startsWith(`${normalizedParent}/`);
1037
+ }
1038
+
1039
+ function pushUnique(paths: string[], candidate: string): void {
1040
+ if (!paths.includes(candidate)) paths.push(candidate);
1041
+ }
1042
+
1043
+ function execMetaPathCandidates(basePath: string, ref: string): string[] {
1044
+ const trimmed = ref.trim();
1045
+ const candidates: string[] = [];
1046
+ const execDirs = approvedEvidenceRoots(basePath).map((root) => join(root, "exec"));
1047
+ const normalizedRef = trimmed.replace(/\\/g, "/");
1048
+ const pathLike = normalizedRef.endsWith(".meta.json") || normalizedRef.includes("/.gsd/exec/");
1049
+
1050
+ if (pathLike) {
1051
+ const rawPath = isAbsolute(trimmed) ? resolve(trimmed) : resolve(basePath, trimmed);
1052
+ pushUnique(candidates, rawPath);
1053
+
1054
+ const relativeExecMarker = ".gsd/exec/";
1055
+ const markerIndex = normalizedRef.indexOf(relativeExecMarker);
1056
+ if (markerIndex >= 0) {
1057
+ const execRelative = normalizedRef.slice(markerIndex + relativeExecMarker.length);
1058
+ for (const execDir of execDirs) {
1059
+ pushUnique(candidates, join(execDir, execRelative));
1060
+ }
1061
+ }
1062
+
1063
+ return candidates.filter((candidate) =>
1064
+ execDirs.some((execDir) => pathStartsWithin(execDir, candidate))
1065
+ );
1066
+ }
1067
+
1068
+ for (const execDir of execDirs) {
1069
+ pushUnique(candidates, join(execDir, `${trimmed}.meta.json`));
1070
+ }
1071
+ return candidates;
1072
+ }
1073
+
1074
+ function resolveExecMetaPath(basePath: string, ref: string): string | null {
1075
+ for (const candidate of execMetaPathCandidates(basePath, ref)) {
1076
+ if (existsSync(candidate)) return candidate;
1077
+ }
1078
+ return null;
1079
+ }
1080
+
1081
+ function evidencePathIsApproved(basePath: string, ref: string): boolean {
1082
+ const normalizedRef = ref.replace(/\\/g, "/");
1083
+ if (normalizedRef.startsWith(".gsd/exec/") || normalizedRef.startsWith(".gsd/uat/")) return true;
1084
+ if (normalizedRef.startsWith(".artifacts/browser/")) {
1085
+ const resolvedRef = resolve(basePath, ref);
1086
+ return approvedBrowserArtifactRoots(basePath).some((root) => pathStartsWithin(root, resolvedRef));
1087
+ }
1088
+ const gsdEvidenceApproved = approvedEvidenceRoots(basePath).some((root) => {
1089
+ return pathStartsWithin(join(root, "exec"), ref) || pathStartsWithin(join(root, "uat"), ref);
1090
+ });
1091
+ if (gsdEvidenceApproved) return true;
1092
+ return approvedBrowserArtifactRoots(basePath).some((root) => pathStartsWithin(root, ref));
1093
+ }
1094
+
1095
+ function validateEvidenceRef(basePath: string, evidence: UatEvidenceRef): string | null {
1096
+ if (!isNonEmptyString(evidence.ref)) return "evidence.ref is required";
1097
+ if (evidence.kind === "gsd_uat_exec" || evidence.kind === "gsd_exec") {
1098
+ const path = resolveExecMetaPath(basePath, evidence.ref.trim());
1099
+ if (!path) return `missing gsd_exec metadata for evidence id "${evidence.ref}"`;
1100
+ if (evidence.kind === "gsd_uat_exec") {
1101
+ try {
1102
+ const meta = JSON.parse(readFileSync(path, "utf-8")) as { metadata?: { kind?: unknown } };
1103
+ if (meta.metadata?.kind !== "uat_exec") return `evidence id "${evidence.ref}" is not typed as uat_exec`;
1104
+ } catch {
1105
+ return `invalid gsd_exec metadata JSON for evidence id "${evidence.ref}"`;
1106
+ }
1107
+ }
1108
+ return null;
1109
+ }
1110
+ if (evidence.kind === "url") {
1111
+ try {
1112
+ const parsed = new URL(evidence.ref);
1113
+ return parsed.protocol === "http:" || parsed.protocol === "https:"
1114
+ ? null
1115
+ : `invalid URL evidence ref "${evidence.ref}"`;
1116
+ } catch {
1117
+ return `invalid URL evidence ref "${evidence.ref}"`;
1118
+ }
1119
+ }
1120
+ return evidencePathIsApproved(basePath, evidence.ref)
1121
+ ? null
1122
+ : `evidence ref "${evidence.ref}" is outside approved evidence locations`;
1123
+ }
1124
+
1125
+ function validateUatChecks(basePath: string, params: UatResultSaveParams): string | null {
1126
+ for (const check of params.checks) {
1127
+ if (!isNonEmptyString(check.id)) return "every check must have a non-empty id";
1128
+ if (!isNonEmptyString(check.description)) return `check ${check.id} must have a description`;
1129
+ if (!["artifact", "runtime", "browser", "human-follow-up"].includes(check.mode)) {
1130
+ return `check ${check.id} has invalid mode "${check.mode}"`;
1131
+ }
1132
+ if (!["PASS", "FAIL", "NEEDS-HUMAN"].includes(check.result)) {
1133
+ return `check ${check.id} has invalid result "${check.result}"`;
1134
+ }
1135
+ if (check.result === "PASS" || check.result === "FAIL") {
1136
+ if (!Array.isArray(check.evidence) || check.evidence.length === 0) {
1137
+ return `check ${check.id} is ${check.result} but has no objective evidence`;
1138
+ }
1139
+ for (const evidence of check.evidence) {
1140
+ const error = validateEvidenceRef(basePath, evidence);
1141
+ if (error) return `check ${check.id}: ${error}`;
1142
+ }
1143
+ } else if (!isNonEmptyString(check.notes)) {
1144
+ return `check ${check.id} is NEEDS-HUMAN but has no manual instruction or reason`;
1145
+ }
1146
+ }
1147
+ return null;
1148
+ }
1149
+
1150
+ function validateUatMode(params: UatResultSaveParams): string | null {
1151
+ const modes = new Set(params.checks.map((check) => check.mode));
1152
+ const hasHuman = params.checks.some((check) => check.result === "NEEDS-HUMAN");
1153
+ if (params.uatType === "artifact-driven" && hasHuman && params.verdict === "PASS") {
1154
+ return "artifact-driven UAT cannot PASS with human-only checks";
1155
+ }
1156
+ if (
1157
+ hasHuman &&
1158
+ params.verdict === "PASS" &&
1159
+ !["human-experience", "mixed", "live-runtime"].includes(params.uatType) &&
1160
+ !params.checks.every((check) => check.result !== "NEEDS-HUMAN" || check.nonAutomatable === true)
1161
+ ) {
1162
+ return "NEEDS-HUMAN checks can only coexist with PASS for human-experience, mixed, live-runtime, or explicitly non-automatable checks";
1163
+ }
1164
+ if (params.uatType === "runtime-executable" && !modes.has("runtime")) {
1165
+ return "runtime-executable UAT requires at least one runtime check";
1166
+ }
1167
+ if (params.uatType === "browser-executable" && !modes.has("browser")) {
1168
+ return "browser-executable UAT requires at least one browser check";
1169
+ }
1170
+ if (params.uatType === "live-runtime" && !modes.has("runtime") && !modes.has("browser")) {
1171
+ return "live-runtime UAT requires runtime or browser evidence";
1172
+ }
1173
+ return null;
1174
+ }
1175
+
1176
+ function quoteToolNames(toolNames: readonly string[]): string {
1177
+ return toolNames.map((toolName) => `"${toolName}"`).join(", ");
1178
+ }
1179
+
1180
+ function validateCanonicalPresentation(params: UatResultSaveParams): string | null {
1181
+ const aliasHints: Record<string, string> = {
1182
+ gsd_save_summary: "gsd_summary_save",
1183
+ gsd_complete_task: "gsd_task_complete",
1184
+ gsd_complete_slice: "gsd_slice_complete",
1185
+ gsd_milestone_complete: "gsd_complete_milestone",
1186
+ };
1187
+ const errors: string[] = [];
1188
+ for (const toolName of params.presentation.presentedTools) {
1189
+ const baseName = parseMcpToolName(toolName)?.tool ?? toolName;
1190
+ const canonical = aliasHints[baseName];
1191
+ if (canonical) errors.push(`presentation tool "${toolName}" uses an alias; use canonical "${canonical}"`);
1192
+ }
1193
+
1194
+ const presentedCanonical = new Set(
1195
+ params.presentation.presentedTools.map((toolName) =>
1196
+ canonicalWorkflowToolName(parseMcpToolName(toolName)?.tool ?? toolName)
1197
+ ),
1198
+ );
1199
+ const missingRequiredTools = RUN_UAT_WORKFLOW_TOOL_NAMES.filter(
1200
+ (requiredTool) => !presentedCanonical.has(requiredTool),
1201
+ );
1202
+ if (missingRequiredTools.length === 1) {
1203
+ errors.push(`presentation is missing required UAT tool "${missingRequiredTools[0]}"`);
1204
+ } else if (missingRequiredTools.length > 1) {
1205
+ errors.push(`presentation is missing required UAT tools ${quoteToolNames(missingRequiredTools)}`);
1206
+ }
1207
+
1208
+ const forbiddenCanonical = new Set(
1209
+ RUN_UAT_FORBIDDEN_TOOL_NAMES
1210
+ .filter((toolName) => !toolName.includes("*"))
1211
+ .map((toolName) => canonicalWorkflowToolName(parseMcpToolName(toolName)?.tool ?? toolName)),
1212
+ );
1213
+ const forbiddenPresentedTools: string[] = [];
1214
+ for (const toolName of params.presentation.presentedTools) {
1215
+ const canonical = canonicalWorkflowToolName(parseMcpToolName(toolName)?.tool ?? toolName);
1216
+ if (toolName === "mcp__gsd-workflow__*" || forbiddenCanonical.has(canonical)) {
1217
+ forbiddenPresentedTools.push(toolName);
1218
+ }
1219
+ }
1220
+ if (forbiddenPresentedTools.length === 1) {
1221
+ errors.push(`presentation includes forbidden run-uat tool "${forbiddenPresentedTools[0]}"`);
1222
+ } else if (forbiddenPresentedTools.length > 1) {
1223
+ errors.push(`presentation includes forbidden run-uat tools ${quoteToolNames(forbiddenPresentedTools)}`);
1224
+ }
1225
+
1226
+ const blockedCanonical = new Set(
1227
+ params.presentation.blockedTools.map((entry) =>
1228
+ canonicalWorkflowToolName(parseMcpToolName(entry.name)?.tool ?? entry.name)
1229
+ ),
1230
+ );
1231
+ const missingBlockedTools = ["gsd_exec", "gsd_summary_save", "gsd_save_gate_result"].filter(
1232
+ (blockedTool) => !blockedCanonical.has(blockedTool),
1233
+ );
1234
+ if (missingBlockedTools.length === 1) {
1235
+ errors.push(`presentation must record "${missingBlockedTools[0]}" as blocked during run-uat`);
1236
+ } else if (missingBlockedTools.length > 1) {
1237
+ errors.push(`presentation must record ${quoteToolNames(missingBlockedTools)} as blocked during run-uat`);
1238
+ }
1239
+ return errors.length > 0 ? errors.join("; ") : null;
1240
+ }
1241
+
1242
+ function nextUatAttempt(basePath: string, milestoneId: string, sliceId: string): number {
1243
+ const contract = resolveGsdPathContract(basePath);
1244
+ const dir = join(contract.projectGsd, "uat", milestoneId, sliceId);
1245
+ if (!existsSync(dir)) return 1;
1246
+ let max = 0;
1247
+ for (const entry of readdirSync(dir)) {
1248
+ const match = /^attempt-(\d+)\.json$/.exec(entry);
1249
+ if (match) max = Math.max(max, Number(match[1]));
1250
+ }
1251
+ return max + 1;
1252
+ }
1253
+
1254
+ function escapeMarkdownTableCell(value: unknown): string {
1255
+ return String(value ?? "")
1256
+ .replace(/[\\|]/g, (char) => `\\${char}`)
1257
+ .replace(/\r?\n/g, "<br>");
1258
+ }
1259
+
1260
+ function renderUatAssessment(params: UatResultSaveParams, attempt: number, gateVerdict: "pass" | "flag"): string {
1261
+ const lines = [
1262
+ "---",
1263
+ `sliceId: ${params.sliceId}`,
1264
+ `uatType: ${params.uatType}`,
1265
+ `verdict: ${params.verdict}`,
1266
+ `attempt: ${attempt}`,
1267
+ `date: ${new Date().toISOString()}`,
1268
+ "---",
1269
+ "",
1270
+ `# UAT Result - ${params.sliceId}`,
1271
+ "",
1272
+ "## Checks",
1273
+ "",
1274
+ "| Check | Mode | Result | Evidence | Notes |",
1275
+ "|-------|------|--------|----------|-------|",
1276
+ ...params.checks.map((check) => {
1277
+ const evidence = (check.evidence ?? []).map((entry) => `${entry.kind}:${entry.ref}`).join("<br>") || "-";
1278
+ return `| ${escapeMarkdownTableCell(check.description)} | ${escapeMarkdownTableCell(check.mode)} | ${escapeMarkdownTableCell(check.result)} | ${escapeMarkdownTableCell(evidence)} | ${escapeMarkdownTableCell(check.notes)} |`;
1279
+ }),
1280
+ "",
1281
+ "## Overall Verdict",
1282
+ "",
1283
+ `${params.verdict} - ${params.notes ?? "UAT result saved."}`,
1284
+ "",
1285
+ "## Tool Presentation",
1286
+ "",
1287
+ "```json",
1288
+ JSON.stringify(params.presentation, null, 2),
1289
+ "```",
1290
+ "",
1291
+ "## Gate",
1292
+ "",
1293
+ `Aggregate UAT gate saved as ${gateVerdict}.`,
1294
+ ];
1295
+ return `${lines.join("\n")}\n`;
1296
+ }
1297
+
1298
+ async function saveUatAttemptArtifact(basePath: string, params: UatResultSaveParams, attempt: number): Promise<string> {
1299
+ const contract = resolveGsdPathContract(basePath);
1300
+ const relativePath = `uat/${params.milestoneId}/${params.sliceId}/attempt-${attempt}.json`;
1301
+ await saveFile(join(contract.projectGsd, relativePath), `${JSON.stringify({ ...params, attempt }, null, 2)}\n`);
1302
+ return relativePath;
1303
+ }
1304
+
1305
+ export async function executeUatResultSave(
1306
+ params: UatResultSaveParams,
1307
+ basePath: string = process.cwd(),
1308
+ ): Promise<ToolExecutionResult> {
1309
+ const dbAvailable = await ensureDbOpen(basePath);
1310
+ if (!dbAvailable) return errorResult("save_uat_result", "GSD database is not available.", "db_unavailable");
1311
+
1312
+ const requiredError = ensureUatRequiredFields(params);
1313
+ if (requiredError) return errorResult("save_uat_result", requiredError, "invalid_params");
1314
+ const presentationError = validateCanonicalPresentation(params);
1315
+ if (presentationError) return errorResult("save_uat_result", presentationError, "alias_tool_name");
1316
+ const checkError = validateUatChecks(basePath, params);
1317
+ if (checkError) return errorResult("save_uat_result", checkError, "invalid_evidence");
1318
+ const modeError = validateUatMode(params);
1319
+ if (modeError) return errorResult("save_uat_result", modeError, "uat_mode_mismatch");
1320
+
1321
+ try {
1322
+ const attempt = params.attempt === "auto" || params.attempt === undefined
1323
+ ? nextUatAttempt(basePath, params.milestoneId, params.sliceId)
1324
+ : typeof params.attempt === "string"
1325
+ ? Number.parseInt(params.attempt, 10)
1326
+ : params.attempt;
1327
+ if (!Number.isInteger(attempt) || attempt < 1) {
1328
+ return errorResult("save_uat_result", "attempt must be a positive integer or auto", "invalid_attempt");
1329
+ }
1330
+ const gateVerdict = params.verdict === "PASS" ? "pass" : "flag";
1331
+ const rationale = params.notes ?? `UAT ${params.verdict} for ${params.sliceId}.`;
1332
+ const assessment = renderUatAssessment(params, attempt, gateVerdict);
1333
+ const summary = await executeSummarySave(
1334
+ {
1335
+ milestone_id: params.milestoneId,
1336
+ slice_id: params.sliceId,
1337
+ artifact_type: "ASSESSMENT",
1338
+ content: assessment,
1339
+ },
1340
+ basePath,
1341
+ );
1342
+ if (summary.isError) return summary;
1343
+ const attemptPath = await saveUatAttemptArtifact(basePath, params, attempt);
1344
+ const evaluatedAt = new Date().toISOString();
1345
+ upsertQualityGate({
1346
+ milestoneId: params.milestoneId,
1347
+ sliceId: params.sliceId,
1348
+ gateId: "UAT",
1349
+ scope: "slice",
1350
+ taskId: "",
1351
+ status: "complete",
1352
+ verdict: gateVerdict,
1353
+ rationale,
1354
+ findings: assessment,
1355
+ evaluatedAt,
1356
+ });
1357
+ insertGateRun({
1358
+ traceId: `uat:${params.milestoneId}:${params.sliceId}`,
1359
+ turnId: `uat:${params.sliceId}:attempt-${attempt}`,
1360
+ gateId: "UAT",
1361
+ gateType: "uat",
1362
+ unitType: "run-uat",
1363
+ unitId: `run-uat:${params.milestoneId}/${params.sliceId}`,
1364
+ milestoneId: params.milestoneId,
1365
+ sliceId: params.sliceId,
1366
+ outcome: params.verdict === "PASS" ? "pass" : "fail",
1367
+ failureClass: params.verdict === "PASS" ? "none" : "verification",
1368
+ rationale,
1369
+ findings: assessment,
1370
+ attempt,
1371
+ maxAttempts: attempt,
1372
+ retryable: params.verdict !== "PASS",
1373
+ evaluatedAt,
1374
+ });
1375
+ invalidateStateCache();
1376
+ return {
1377
+ content: [{ type: "text", text: `UAT result saved for ${params.milestoneId}/${params.sliceId}: ${params.verdict}` }],
1378
+ details: {
1379
+ operation: "save_uat_result",
1380
+ milestoneId: params.milestoneId,
1381
+ sliceId: params.sliceId,
1382
+ verdict: params.verdict,
1383
+ gateVerdict,
1384
+ attempt,
1385
+ attemptPath,
1386
+ recommendedNextUnit: params.verdict === "PASS" ? null : "reactive-execute",
1387
+ },
1388
+ };
1389
+ } catch (err) {
1390
+ const msg = err instanceof Error ? err.message : String(err);
1391
+ logError("tool", `gsd_uat_result_save failed: ${msg}`, { tool: "gsd_uat_result_save", error: String(err) });
1392
+ return errorResult("save_uat_result", `saving UAT result failed: ${msg}`, msg);
1393
+ }
1394
+ }
1395
+
910
1396
  export async function executePlanMilestone(
911
1397
  params: PlanMilestoneExecutorParams,
912
1398
  basePath: string = process.cwd(),
@@ -270,6 +270,29 @@ export interface GSDActiveUnit {
270
270
 
271
271
  // ─── Post-Unit Hook Types ─────────────────────────────────────────────────
272
272
 
273
+ export type PostUnitHookCriticality = "advisory" | "blocking";
274
+
275
+ export type PostUnitHookOutcomeVerdict =
276
+ | "pass"
277
+ | "advisory"
278
+ | "needs-rework"
279
+ | "needs-remediation"
280
+ | "needs-attention";
281
+
282
+ export type PostUnitHookOnBlockAction =
283
+ | "retry-unit"
284
+ | "retry-task"
285
+ | "queue-task"
286
+ | "queue-slice"
287
+ | "pause";
288
+
289
+ export interface PostUnitHookOnBlockConfig {
290
+ /** Routing action for blocking hook findings. */
291
+ action: PostUnitHookOnBlockAction;
292
+ /** Optional artifact used by compatibility retry routing. */
293
+ artifact?: string;
294
+ }
295
+
273
296
  export interface PostUnitHookConfig {
274
297
  /** Unique hook identifier — used in idempotency keys and logging. */
275
298
  name: string;
@@ -283,8 +306,12 @@ export interface PostUnitHookConfig {
283
306
  model?: string;
284
307
  /** Expected output file name (relative to task/slice dir). Used for idempotency — skip if exists. */
285
308
  artifact?: string;
309
+ /** Whether the hook is advisory or blocks unit advancement. Default advisory. */
310
+ criticality?: PostUnitHookCriticality;
286
311
  /** If this file is produced instead of artifact, re-run the trigger unit then re-run hooks. */
287
312
  retry_on?: string;
313
+ /** Optional routing for blocking findings. */
314
+ on_block?: PostUnitHookOnBlockConfig;
288
315
  /** Agent definition file to use. */
289
316
  agent?: string;
290
317
  /** Set false to disable without removing config. Default true. */
@@ -317,6 +344,31 @@ export interface HookDispatchResult {
317
344
  unitId: string;
318
345
  }
319
346
 
347
+ export interface PostUnitGateBlock {
348
+ /** Blocking hook name. */
349
+ hookName: string;
350
+ /** The unit type that triggered the gate. */
351
+ triggerUnitType: string;
352
+ /** The unit ID that triggered the gate. */
353
+ triggerUnitId: string;
354
+ /** Gate artifact name, when configured. */
355
+ artifact?: string;
356
+ /** Absolute path to the gate artifact, when known. */
357
+ artifactPath?: string;
358
+ /** Parsed blocking verdict, when present. */
359
+ verdict?: PostUnitHookOutcomeVerdict | "failed";
360
+ /** Configured routing action that caused the pause. */
361
+ action: PostUnitHookOnBlockAction;
362
+ /** Human-readable pause reason. */
363
+ reason: string;
364
+ /** Current hook cycle count. */
365
+ cycle: number;
366
+ /** Configured max cycle count. */
367
+ maxCycles: number;
368
+ /** Optional compatibility retry artifact. */
369
+ retryArtifact?: string;
370
+ }
371
+
320
372
  // ─── Budget & Notification Types ──────────────────────────────────────────
321
373
 
322
374
  export type BudgetEnforcementMode = "warn" | "pause" | "halt";
@@ -384,10 +436,10 @@ export interface EscalationArtifact {
384
436
  /** Why the executor recommends that option (1-2 sentences). */
385
437
  recommendationRationale: string;
386
438
  /**
387
- * When true, the executor proceeds with the recommendation as the answer
388
- * and the loop continues. User's later choice becomes a carry-forward
389
- * override for the NEXT task. When false, auto-mode pauses until the
390
- * user resolves via `/gsd escalate resolve`.
439
+ * When true, the recommendation is recorded as the default path but the
440
+ * loop still pauses until the user explicitly resolves the escalation.
441
+ * When false, auto-mode also pauses until the user resolves via
442
+ * `/gsd escalate resolve`.
391
443
  */
392
444
  continueWithDefault: boolean;
393
445
  createdAt: string;
@@ -452,6 +504,15 @@ export interface PreDispatchResult {
452
504
  export interface PersistedHookState {
453
505
  /** Cycle counts keyed as "hookName/triggerUnitType/triggerUnitId". */
454
506
  cycleCounts: Record<string, number>;
507
+ /** In-flight hook, persisted so blocking gates cannot be skipped after resume. */
508
+ activeHook?: HookExecutionState | null;
509
+ /** Remaining hook queue by hook name and trigger unit. */
510
+ hookQueue?: Array<{
511
+ hookName: string;
512
+ triggerUnitType: string;
513
+ triggerUnitId: string;
514
+ forceRun?: boolean;
515
+ }>;
455
516
  /** Timestamp of last state save. */
456
517
  savedAt: string;
457
518
  }
@@ -465,6 +526,8 @@ export interface HookStatusEntry {
465
526
  enabled: boolean;
466
527
  /** What unit types it targets. */
467
528
  targets: string[];
529
+ /** Whether this post-unit hook is advisory or blocking. */
530
+ criticality?: PostUnitHookCriticality;
468
531
  /** Current cycle counts for active triggers. */
469
532
  activeCycles: Record<string, number>;
470
533
  }
@@ -644,7 +707,8 @@ export interface CompleteSliceParams {
644
707
  sliceTitle: string;
645
708
  oneLiner: string;
646
709
  narrative: string;
647
- verification: string;
710
+ /** @optional — if omitted, verification section is left blank in summary */
711
+ verification?: string;
648
712
  uatContent: string;
649
713
  /** @optional — defaults to [] when omitted by models with limited tool-calling */
650
714
  keyFiles?: string[];