@opengsd/gsd-pi 1.1.1-dev.616a1a1 → 1.1.1-dev.75048e7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (452) 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 +55 -0
  14. package/dist/resources/extensions/gsd/auto-post-unit.js +134 -10
  15. package/dist/resources/extensions/gsd/auto-prompts.js +72 -22
  16. package/dist/resources/extensions/gsd/auto-recovery.js +7 -8
  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 +18 -65
  21. package/dist/resources/extensions/gsd/auto-worktree.js +18 -5
  22. package/dist/resources/extensions/gsd/auto.js +31 -6
  23. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +89 -4
  24. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +43 -0
  25. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +56 -20
  26. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +33 -38
  27. package/dist/resources/extensions/gsd/browser-evidence.js +29 -2
  28. package/dist/resources/extensions/gsd/closeout-consistency-gate.js +61 -0
  29. package/dist/resources/extensions/gsd/commands/catalog.js +6 -1
  30. package/dist/resources/extensions/gsd/commands/handlers/core.js +6 -2
  31. package/dist/resources/extensions/gsd/commands/handlers/ops.js +9 -5
  32. package/dist/resources/extensions/gsd/commands-handlers.js +76 -11
  33. package/dist/resources/extensions/gsd/commands-maintenance.js +172 -2
  34. package/dist/resources/extensions/gsd/commands-mcp-status.js +109 -60
  35. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +3 -1
  36. package/dist/resources/extensions/gsd/commands-verdict.js +1 -1
  37. package/dist/resources/extensions/gsd/config-overlay.js +2 -1
  38. package/dist/resources/extensions/gsd/dashboard-overlay.js +21 -7
  39. package/dist/resources/extensions/gsd/docs/preferences-reference.md +8 -0
  40. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +2 -2
  41. package/dist/resources/extensions/gsd/error-classifier.js +2 -1
  42. package/dist/resources/extensions/gsd/escalation.js +4 -4
  43. package/dist/resources/extensions/gsd/exec-sandbox.js +2 -0
  44. package/dist/resources/extensions/gsd/forensics.js +74 -2
  45. package/dist/resources/extensions/gsd/gsd-db.js +42 -6
  46. package/dist/resources/extensions/gsd/guided-flow.js +119 -176
  47. package/dist/resources/extensions/gsd/mcp-filter.js +3 -0
  48. package/dist/resources/extensions/gsd/mcp-project-config.js +76 -84
  49. package/dist/resources/extensions/gsd/memory-store.js +4 -1
  50. package/dist/resources/extensions/gsd/migration-auto-check.js +2 -2
  51. package/dist/resources/extensions/gsd/milestone-closeout.js +3 -1
  52. package/dist/resources/extensions/gsd/pending-auto-start.js +0 -1
  53. package/dist/resources/extensions/gsd/post-unit-hooks.js +9 -0
  54. package/dist/resources/extensions/gsd/preferences-validation.js +39 -0
  55. package/dist/resources/extensions/gsd/prompt-loader.js +7 -0
  56. package/dist/resources/extensions/gsd/prompts/forensics.md +61 -1
  57. package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
  58. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
  59. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  60. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
  61. package/dist/resources/extensions/gsd/prompts/run-uat.md +33 -23
  62. package/dist/resources/extensions/gsd/prompts/system.md +3 -1
  63. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
  64. package/dist/resources/extensions/gsd/recovery-classification.js +20 -0
  65. package/dist/resources/extensions/gsd/rule-registry.js +428 -52
  66. package/dist/resources/extensions/gsd/safety/destructive-guard.js +3 -0
  67. package/dist/resources/extensions/gsd/skill-activation.js +20 -3
  68. package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +4 -2
  69. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +1 -1
  70. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +18 -1
  71. package/dist/resources/extensions/gsd/state-reconciliation/index.js +6 -0
  72. package/dist/resources/extensions/gsd/state.js +17 -14
  73. package/dist/resources/extensions/gsd/templates/plan.md +3 -1
  74. package/dist/resources/extensions/gsd/tool-contract.js +5 -0
  75. package/dist/resources/extensions/gsd/tool-presentation-plan.js +143 -0
  76. package/dist/resources/extensions/gsd/tools/complete-slice.js +15 -1
  77. package/dist/resources/extensions/gsd/tools/complete-task.js +11 -1
  78. package/dist/resources/extensions/gsd/tools/exec-tool.js +109 -0
  79. package/dist/resources/extensions/gsd/tools/plan-slice.js +14 -9
  80. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +2 -2
  81. package/dist/resources/extensions/gsd/tools/validate-milestone.js +46 -16
  82. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +483 -6
  83. package/dist/resources/extensions/gsd/unit-context-manifest.js +8 -3
  84. package/dist/resources/extensions/gsd/unit-tool-contracts.js +169 -0
  85. package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
  86. package/dist/resources/extensions/gsd/verdict-parser.js +59 -15
  87. package/dist/resources/extensions/gsd/verification-gate.js +72 -1
  88. package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +3 -1
  89. package/dist/resources/extensions/gsd/workflow-mcp.js +5 -73
  90. package/dist/resources/extensions/gsd/worktree-lifecycle.js +24 -0
  91. package/dist/resources/extensions/mcp-client/manager.js +31 -1
  92. package/dist/resources/extensions/shared/gsd-browser-cli.js +145 -0
  93. package/dist/rtk.d.ts +7 -1
  94. package/dist/rtk.js +27 -11
  95. package/dist/update-check.d.ts +15 -1
  96. package/dist/update-check.js +87 -12
  97. package/dist/update-cmd.d.ts +1 -0
  98. package/dist/update-cmd.js +53 -2
  99. package/dist/web/standalone/.next/BUILD_ID +1 -1
  100. package/dist/web/standalone/.next/app-path-routes-manifest.json +5 -5
  101. package/dist/web/standalone/.next/build-manifest.json +2 -2
  102. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  103. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  104. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  112. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  118. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  120. package/dist/web/standalone/.next/server/app/index.html +1 -1
  121. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  122. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app-paths-manifest.json +5 -5
  128. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  129. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  131. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  132. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  133. package/package.json +5 -3
  134. package/packages/cloud-mcp-gateway/package.json +2 -2
  135. package/packages/contracts/dist/workflow.d.ts +14 -0
  136. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  137. package/packages/contracts/dist/workflow.js +16 -0
  138. package/packages/contracts/dist/workflow.js.map +1 -1
  139. package/packages/contracts/package.json +1 -1
  140. package/packages/daemon/package.json +4 -4
  141. package/packages/gsd-agent-core/dist/agent-session.d.ts +9 -0
  142. package/packages/gsd-agent-core/dist/agent-session.d.ts.map +1 -1
  143. package/packages/gsd-agent-core/dist/agent-session.js +32 -0
  144. package/packages/gsd-agent-core/dist/agent-session.js.map +1 -1
  145. package/packages/gsd-agent-core/dist/index.d.ts +1 -0
  146. package/packages/gsd-agent-core/dist/index.d.ts.map +1 -1
  147. package/packages/gsd-agent-core/dist/index.js +1 -0
  148. package/packages/gsd-agent-core/dist/index.js.map +1 -1
  149. package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts +2 -0
  150. package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts.map +1 -1
  151. package/packages/gsd-agent-core/dist/session/agent-session-compaction.js +8 -2
  152. package/packages/gsd-agent-core/dist/session/agent-session-compaction.js.map +1 -1
  153. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts +7 -0
  154. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts.map +1 -1
  155. package/packages/gsd-agent-core/dist/session/agent-session-host.js.map +1 -1
  156. package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts.map +1 -1
  157. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js +69 -1
  158. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js.map +1 -1
  159. package/packages/gsd-agent-core/dist/turn-latency.d.ts +47 -0
  160. package/packages/gsd-agent-core/dist/turn-latency.d.ts.map +1 -0
  161. package/packages/gsd-agent-core/dist/turn-latency.js +123 -0
  162. package/packages/gsd-agent-core/dist/turn-latency.js.map +1 -0
  163. package/packages/gsd-agent-core/package.json +6 -6
  164. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts +21 -0
  165. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts.map +1 -0
  166. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js +213 -0
  167. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js.map +1 -0
  168. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  169. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  170. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +10 -0
  171. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
  172. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  173. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +5 -0
  174. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  175. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts +1 -0
  176. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  177. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +92 -31
  178. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  179. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  180. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +7 -1
  181. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  182. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.d.ts.map +1 -1
  183. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js +6 -0
  184. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js.map +1 -1
  185. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.d.ts.map +1 -1
  186. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.js +2 -0
  187. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.js.map +1 -1
  188. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts +1 -1
  189. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts.map +1 -1
  190. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js +1 -1
  191. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js.map +1 -1
  192. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  193. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +1 -0
  194. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
  195. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.d.ts.map +1 -1
  196. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js +5 -0
  197. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js.map +1 -1
  198. package/packages/gsd-agent-modes/package.json +7 -7
  199. package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -1
  200. package/packages/mcp-server/dist/remote-questions.js +23 -9
  201. package/packages/mcp-server/dist/remote-questions.js.map +1 -1
  202. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  203. package/packages/mcp-server/dist/workflow-tools.js +84 -2
  204. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  205. package/packages/mcp-server/package.json +3 -3
  206. package/packages/native/package.json +1 -1
  207. package/packages/pi-agent-core/dist/agent-loop.js +42 -3
  208. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  209. package/packages/pi-agent-core/dist/agent.d.ts +5 -1
  210. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  211. package/packages/pi-agent-core/dist/agent.js +2 -0
  212. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  213. package/packages/pi-agent-core/dist/harness/agent-harness.d.ts.map +1 -1
  214. package/packages/pi-agent-core/dist/harness/agent-harness.js +3 -1
  215. package/packages/pi-agent-core/dist/harness/agent-harness.js.map +1 -1
  216. package/packages/pi-agent-core/dist/harness/types.d.ts +1 -0
  217. package/packages/pi-agent-core/dist/harness/types.d.ts.map +1 -1
  218. package/packages/pi-agent-core/dist/harness/types.js.map +1 -1
  219. package/packages/pi-agent-core/dist/types.d.ts +6 -1
  220. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  221. package/packages/pi-agent-core/dist/types.js.map +1 -1
  222. package/packages/pi-agent-core/package.json +1 -1
  223. package/packages/pi-ai/dist/api-registry.d.ts +2 -0
  224. package/packages/pi-ai/dist/api-registry.d.ts.map +1 -1
  225. package/packages/pi-ai/dist/api-registry.js +23 -0
  226. package/packages/pi-ai/dist/api-registry.js.map +1 -1
  227. package/packages/pi-ai/dist/image-models.generated.d.ts +15 -0
  228. package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
  229. package/packages/pi-ai/dist/image-models.generated.js +15 -0
  230. package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
  231. package/packages/pi-ai/dist/models.generated.d.ts +411 -39
  232. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  233. package/packages/pi-ai/dist/models.generated.js +504 -153
  234. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  235. package/packages/pi-ai/dist/stream.js +6 -6
  236. package/packages/pi-ai/dist/stream.js.map +1 -1
  237. package/packages/pi-ai/package.json +1 -1
  238. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts +3 -0
  239. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts.map +1 -1
  240. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.js.map +1 -1
  241. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  242. package/packages/pi-coding-agent/dist/core/model-registry.js +2 -2
  243. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  244. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
  245. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  246. package/packages/pi-coding-agent/dist/core/settings-manager.js +11 -0
  247. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  248. package/packages/pi-coding-agent/dist/core/tools/bash.js +2 -2
  249. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  250. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
  251. package/packages/pi-coding-agent/dist/core/tools/edit.js +3 -2
  252. package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
  253. package/packages/pi-coding-agent/dist/core/tools/render-utils.d.ts +1 -0
  254. package/packages/pi-coding-agent/dist/core/tools/render-utils.d.ts.map +1 -1
  255. package/packages/pi-coding-agent/dist/core/tools/render-utils.js +6 -0
  256. package/packages/pi-coding-agent/dist/core/tools/render-utils.js.map +1 -1
  257. package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
  258. package/packages/pi-coding-agent/dist/core/tools/write.js +3 -2
  259. package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
  260. package/packages/pi-coding-agent/package.json +7 -7
  261. package/packages/pi-tui/dist/terminal.d.ts +1 -0
  262. package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
  263. package/packages/pi-tui/dist/terminal.js +8 -4
  264. package/packages/pi-tui/dist/terminal.js.map +1 -1
  265. package/packages/pi-tui/package.json +1 -1
  266. package/packages/rpc-client/package.json +2 -2
  267. package/pkg/package.json +1 -1
  268. package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +579 -0
  269. package/src/resources/extensions/browser-tools/engine/selection.ts +19 -0
  270. package/src/resources/extensions/browser-tools/extension-manifest.json +2 -2
  271. package/src/resources/extensions/browser-tools/index.ts +60 -9
  272. package/src/resources/extensions/browser-tools/package.json +5 -1
  273. package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +35 -0
  274. package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +33 -0
  275. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +196 -16
  276. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +239 -63
  277. package/src/resources/extensions/gsd/auto/orchestrator.ts +0 -1
  278. package/src/resources/extensions/gsd/auto/phases.ts +5 -3
  279. package/src/resources/extensions/gsd/auto-dashboard.ts +98 -18
  280. package/src/resources/extensions/gsd/auto-dispatch.ts +67 -0
  281. package/src/resources/extensions/gsd/auto-post-unit.ts +166 -9
  282. package/src/resources/extensions/gsd/auto-prompts.ts +106 -15
  283. package/src/resources/extensions/gsd/auto-recovery.ts +7 -7
  284. package/src/resources/extensions/gsd/auto-runtime-state.ts +4 -0
  285. package/src/resources/extensions/gsd/auto-start.ts +112 -17
  286. package/src/resources/extensions/gsd/auto-tool-tracking.ts +1 -1
  287. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +43 -73
  288. package/src/resources/extensions/gsd/auto-worktree.ts +23 -5
  289. package/src/resources/extensions/gsd/auto.ts +47 -5
  290. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +96 -4
  291. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +51 -0
  292. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +81 -25
  293. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +70 -63
  294. package/src/resources/extensions/gsd/browser-evidence.ts +26 -2
  295. package/src/resources/extensions/gsd/closeout-consistency-gate.ts +137 -0
  296. package/src/resources/extensions/gsd/commands/catalog.ts +6 -1
  297. package/src/resources/extensions/gsd/commands/handlers/core.ts +6 -2
  298. package/src/resources/extensions/gsd/commands/handlers/ops.ts +9 -5
  299. package/src/resources/extensions/gsd/commands-handlers.ts +76 -11
  300. package/src/resources/extensions/gsd/commands-maintenance.ts +197 -2
  301. package/src/resources/extensions/gsd/commands-mcp-status.ts +136 -58
  302. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +4 -1
  303. package/src/resources/extensions/gsd/commands-verdict.ts +1 -1
  304. package/src/resources/extensions/gsd/config-overlay.ts +3 -1
  305. package/src/resources/extensions/gsd/dashboard-overlay.ts +28 -7
  306. package/src/resources/extensions/gsd/docs/preferences-reference.md +8 -0
  307. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +2 -2
  308. package/src/resources/extensions/gsd/error-classifier.ts +2 -1
  309. package/src/resources/extensions/gsd/escalation.ts +4 -4
  310. package/src/resources/extensions/gsd/exec-sandbox.ts +4 -0
  311. package/src/resources/extensions/gsd/forensics.ts +99 -5
  312. package/src/resources/extensions/gsd/gsd-db.ts +46 -8
  313. package/src/resources/extensions/gsd/guided-flow.ts +215 -217
  314. package/src/resources/extensions/gsd/mcp-filter.ts +3 -0
  315. package/src/resources/extensions/gsd/mcp-project-config.ts +105 -88
  316. package/src/resources/extensions/gsd/memory-store.ts +4 -1
  317. package/src/resources/extensions/gsd/migration-auto-check.ts +2 -2
  318. package/src/resources/extensions/gsd/milestone-closeout.ts +3 -1
  319. package/src/resources/extensions/gsd/pending-auto-start.ts +0 -2
  320. package/src/resources/extensions/gsd/post-unit-hooks.ts +14 -1
  321. package/src/resources/extensions/gsd/preferences-types.ts +1 -1
  322. package/src/resources/extensions/gsd/preferences-validation.ts +36 -0
  323. package/src/resources/extensions/gsd/prompt-loader.ts +8 -0
  324. package/src/resources/extensions/gsd/prompts/forensics.md +61 -1
  325. package/src/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
  326. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
  327. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  328. package/src/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
  329. package/src/resources/extensions/gsd/prompts/run-uat.md +33 -23
  330. package/src/resources/extensions/gsd/prompts/system.md +3 -1
  331. package/src/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
  332. package/src/resources/extensions/gsd/recovery-classification.ts +20 -0
  333. package/src/resources/extensions/gsd/rule-registry.ts +558 -58
  334. package/src/resources/extensions/gsd/rule-types.ts +2 -0
  335. package/src/resources/extensions/gsd/safety/destructive-guard.ts +3 -0
  336. package/src/resources/extensions/gsd/skill-activation.ts +20 -2
  337. package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +4 -2
  338. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +1 -1
  339. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +20 -0
  340. package/src/resources/extensions/gsd/state-reconciliation/index.ts +6 -0
  341. package/src/resources/extensions/gsd/state-reconciliation/types.ts +1 -0
  342. package/src/resources/extensions/gsd/state.ts +18 -14
  343. package/src/resources/extensions/gsd/templates/plan.md +3 -1
  344. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +156 -4
  345. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +123 -0
  346. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +10 -2
  347. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +4 -1
  348. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +143 -2
  349. package/src/resources/extensions/gsd/tests/auto-start-project-milestone-reconcile.test.ts +24 -2
  350. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +12 -2
  351. package/src/resources/extensions/gsd/tests/browser-evidence.test.ts +142 -0
  352. package/src/resources/extensions/gsd/tests/check-auto-start-pending-gate.test.ts +9 -15
  353. package/src/resources/extensions/gsd/tests/check-auto-start-ready-guard.test.ts +26 -16
  354. package/src/resources/extensions/gsd/tests/commands-dispatcher-unmerged-milestone.test.ts +21 -0
  355. package/src/resources/extensions/gsd/tests/commands-dispatcher-validation-block.test.ts +38 -3
  356. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +6 -2
  357. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +30 -0
  358. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +42 -0
  359. package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +45 -0
  360. package/src/resources/extensions/gsd/tests/deep-planning-mode-dispatch.test.ts +53 -0
  361. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +8 -0
  362. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +50 -13
  363. package/src/resources/extensions/gsd/tests/discuss-milestone-structured-questions.test.ts +31 -0
  364. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +40 -1
  365. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +60 -0
  366. package/src/resources/extensions/gsd/tests/doctor-runtime-checks.test.ts +27 -0
  367. package/src/resources/extensions/gsd/tests/escalation.test.ts +16 -27
  368. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +18 -0
  369. package/src/resources/extensions/gsd/tests/exec-tool.test.ts +69 -0
  370. package/src/resources/extensions/gsd/tests/forensics-issue-routing.test.ts +20 -0
  371. package/src/resources/extensions/gsd/tests/forensics-prompt-rendering.test.ts +3 -0
  372. package/src/resources/extensions/gsd/tests/forensics-tool-scope.test.ts +69 -0
  373. package/src/resources/extensions/gsd/tests/gate-1b-orphan-discrimination.test.ts +31 -79
  374. package/src/resources/extensions/gsd/tests/gsd-rebuild.test.ts +199 -0
  375. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +75 -0
  376. package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +40 -1
  377. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +86 -0
  378. package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +5 -3
  379. package/src/resources/extensions/gsd/tests/guided-flow-state-rebuild.test.ts +40 -4
  380. package/src/resources/extensions/gsd/tests/guided-flow.test.ts +12 -9
  381. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +4 -4
  382. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +8 -0
  383. package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +16 -0
  384. package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +72 -10
  385. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +13 -6
  386. package/src/resources/extensions/gsd/tests/mcp-filter.test.ts +15 -0
  387. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +100 -0
  388. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +179 -0
  389. package/src/resources/extensions/gsd/tests/memory-maintenance.test.ts +39 -8
  390. package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +63 -0
  391. package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +10 -1
  392. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +3 -3
  393. package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +9 -1
  394. package/src/resources/extensions/gsd/tests/new-milestone-discuss-routing.test.ts +3 -3
  395. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +54 -7
  396. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +9 -0
  397. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +39 -1
  398. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +157 -0
  399. package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +179 -0
  400. package/src/resources/extensions/gsd/tests/preferences.test.ts +29 -0
  401. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +83 -1
  402. package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +14 -0
  403. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +18 -1
  404. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +7 -8
  405. package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +36 -0
  406. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +79 -0
  407. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +1 -1
  408. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +75 -0
  409. package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +4 -0
  410. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +36 -0
  411. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +100 -0
  412. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +55 -0
  413. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +6 -2
  414. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +191 -0
  415. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +84 -10
  416. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +19 -0
  417. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +12 -2
  418. package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +7 -1
  419. package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +29 -6
  420. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +29 -6
  421. package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +6 -3
  422. package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +133 -0
  423. package/src/resources/extensions/gsd/tests/validation-block-guard.test.ts +21 -0
  424. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +51 -0
  425. package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +17 -2
  426. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +493 -0
  427. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +40 -0
  428. package/src/resources/extensions/gsd/tool-contract.ts +6 -0
  429. package/src/resources/extensions/gsd/tool-presentation-plan.ts +223 -0
  430. package/src/resources/extensions/gsd/tools/complete-slice.ts +14 -1
  431. package/src/resources/extensions/gsd/tools/complete-task.ts +20 -2
  432. package/src/resources/extensions/gsd/tools/exec-tool.ts +130 -0
  433. package/src/resources/extensions/gsd/tools/plan-slice.ts +14 -9
  434. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +2 -2
  435. package/src/resources/extensions/gsd/tools/validate-milestone.ts +46 -15
  436. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +589 -8
  437. package/src/resources/extensions/gsd/types.ts +69 -5
  438. package/src/resources/extensions/gsd/unit-context-manifest.ts +14 -5
  439. package/src/resources/extensions/gsd/unit-tool-contracts.ts +186 -0
  440. package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
  441. package/src/resources/extensions/gsd/verdict-parser.ts +54 -13
  442. package/src/resources/extensions/gsd/verification-gate.ts +87 -1
  443. package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +2 -1
  444. package/src/resources/extensions/gsd/workflow-mcp.ts +5 -73
  445. package/src/resources/extensions/gsd/worktree-lifecycle.ts +26 -0
  446. package/src/resources/extensions/mcp-client/manager.ts +33 -1
  447. package/src/resources/extensions/mcp-client/tests/manager.test.ts +35 -0
  448. package/src/resources/extensions/shared/gsd-browser-cli.ts +172 -0
  449. package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound-corrections.test.ts +0 -246
  450. package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound.test.ts +0 -218
  451. /package/dist/web/standalone/.next/static/{L9N5SPFi7f-Ne4u2uXzCe → h4TGni4xJzlZjGkxaT6uU}/_buildManifest.js +0 -0
  452. /package/dist/web/standalone/.next/static/{L9N5SPFi7f-Ne4u2uXzCe → h4TGni4xJzlZjGkxaT6uU}/_ssgManifest.js +0 -0
@@ -41,6 +41,16 @@ function tokenizeSkillContext(...parts) {
41
41
  }
42
42
  return tokens;
43
43
  }
44
+ function tokenizeUnitType(unitType) {
45
+ const tokens = new Set();
46
+ const value = unitType?.trim().toLowerCase();
47
+ if (!value)
48
+ return tokens;
49
+ tokens.add(value);
50
+ tokens.add(value.replace(/[-_]+/g, " "));
51
+ tokens.add(value.replace(/[-_\s]+/g, ""));
52
+ return tokens;
53
+ }
44
54
  function skillMatchesContext(skill, contextTokens) {
45
55
  const haystacks = [
46
56
  skill.name.toLowerCase(),
@@ -63,13 +73,20 @@ function ruleMatchesContext(when, contextTokens) {
63
73
  const whenTokens = tokenizeSkillContext(when);
64
74
  return [...whenTokens].some(token => contextTokens.has(token) || [...contextTokens].some(ctx => ctx.includes(token) || token.includes(ctx)));
65
75
  }
66
- function resolveSkillRuleMatches(prefs, contextTokens, base) {
76
+ function ruleMatchesUnitType(when, unitType) {
77
+ if (!unitType)
78
+ return false;
79
+ const whenTokens = tokenizeSkillContext(when);
80
+ const unitTokens = tokenizeUnitType(unitType);
81
+ return [...unitTokens].some(token => whenTokens.has(token));
82
+ }
83
+ function resolveSkillRuleMatches(prefs, contextTokens, base, unitType) {
67
84
  if (!prefs?.skill_rules?.length)
68
85
  return { include: [], avoid: [] };
69
86
  const include = [];
70
87
  const avoid = [];
71
88
  for (const rule of prefs.skill_rules) {
72
- if (!ruleMatchesContext(rule.when, contextTokens))
89
+ if (!ruleMatchesContext(rule.when, contextTokens) && !ruleMatchesUnitType(rule.when, unitType))
73
90
  continue;
74
91
  include.push(...resolvePreferenceSkillNames([...(rule.use ?? []), ...(rule.prefer ?? [])], base));
75
92
  avoid.push(...resolvePreferenceSkillNames(rule.avoid ?? [], base));
@@ -141,7 +158,7 @@ export function buildSkillActivationBlock(params) {
141
158
  for (const name of resolvePreferenceSkillNames(prefs?.always_use_skills ?? [], params.base)) {
142
159
  matched.add(name);
143
160
  }
144
- const ruleMatches = resolveSkillRuleMatches(prefs, contextTokens, params.base);
161
+ const ruleMatches = resolveSkillRuleMatches(prefs, contextTokens, params.base, params.unitType);
145
162
  for (const name of ruleMatches.include)
146
163
  matched.add(name);
147
164
  for (const name of ruleMatches.avoid)
@@ -313,7 +313,8 @@ export function repairArtifactDbDrift(record, ctx) {
313
313
  throw new Error(`Artifact/DB status drift in ${record.milestoneId}` +
314
314
  `${record.sliceId ? `/${record.sliceId}` : ""}` +
315
315
  `${record.taskId ? `/${record.taskId}` : ""}: ${record.reason}. ` +
316
- "Runtime will not silently import completion artifacts into DB state; run explicit recovery/repair after review.");
316
+ "Runtime will not silently import completion artifacts into DB state. " +
317
+ "Run `/gsd rebuild markdown` after review to quarantine stale projections and re-render from the DB; use `/gsd recover --confirm` only when markdown should repopulate a lost or corrupt DB.");
317
318
  }
318
319
  export function describeArtifactDbDriftBlocker(record) {
319
320
  if (record.kind === "disk-slice-id-divergence") {
@@ -329,7 +330,8 @@ export function describeArtifactDbDriftBlocker(record) {
329
330
  return (`Artifact/DB status drift in ${record.milestoneId}` +
330
331
  `${record.sliceId ? `/${record.sliceId}` : ""}` +
331
332
  `${record.taskId ? `/${record.taskId}` : ""}: ${record.reason}. ` +
332
- "Runtime will not silently import completion artifacts into DB state; run explicit recovery/repair after review.");
333
+ "Runtime will not silently import completion artifacts into DB state. " +
334
+ "Run `/gsd rebuild markdown` after review to quarantine stale projections and re-render from the DB; use `/gsd recover --confirm` only when markdown should repopulate a lost or corrupt DB.");
333
335
  }
334
336
  export const diskSliceIdDivergenceHandler = {
335
337
  kind: "disk-slice-id-divergence",
@@ -36,7 +36,7 @@ export function detectUnregisteredMilestoneDrift(_state, ctx) {
36
36
  */
37
37
  export function repairUnregisteredMilestone(record, _ctx) {
38
38
  throw new Error(`Milestone ${record.milestoneId} exists only as markdown projection. ` +
39
- "Runtime reconciliation will not import markdown into the authoritative DB; run `/gsd recover` if this markdown should repopulate the database.");
39
+ "Runtime reconciliation will not import markdown into the authoritative DB; run `/gsd recover --confirm` if this markdown should repopulate the database.");
40
40
  }
41
41
  export const unregisteredMilestoneHandler = {
42
42
  kind: "unregistered-milestone",
@@ -4,7 +4,7 @@
4
4
  // checkboxes) and the DB slice rows for that milestone, then re-renders the
5
5
  // ROADMAP projection from the authoritative DB rows.
6
6
  import { existsSync, readFileSync } from "node:fs";
7
- import { getMilestone, getMilestoneSlices, isDbAvailable, } from "../../gsd-db.js";
7
+ import { getMilestone, getMilestoneSlices, getSliceTasks, isDbAvailable, } from "../../gsd-db.js";
8
8
  import { renderRoadmapFromDb } from "../../markdown-renderer.js";
9
9
  import { findMilestoneIds } from "../../milestone-ids.js";
10
10
  import { parseRoadmap } from "../../parsers-legacy.js";
@@ -18,6 +18,15 @@ function arraysEqual(a, b) {
18
18
  return false;
19
19
  return true;
20
20
  }
21
+ function getSlicesReadyForDivergenceCheck(milestoneId, dbSlices) {
22
+ const ready = new Set();
23
+ for (const slice of dbSlices) {
24
+ if (isClosedStatus(slice.status) || getSliceTasks(milestoneId, slice.id).length > 0) {
25
+ ready.add(slice.id);
26
+ }
27
+ }
28
+ return ready;
29
+ }
21
30
  function milestoneHasDivergence(basePath, milestoneId) {
22
31
  const roadmapPath = resolveMilestoneFile(basePath, milestoneId, "ROADMAP");
23
32
  if (!roadmapPath || !existsSync(roadmapPath))
@@ -31,6 +40,10 @@ function milestoneHasDivergence(basePath, milestoneId) {
31
40
  }
32
41
  const dbSlices = getMilestoneSlices(milestoneId);
33
42
  const dbSliceMap = new Map(dbSlices.map((s) => [s.id, s]));
43
+ const readySliceIds = getSlicesReadyForDivergenceCheck(milestoneId, dbSlices);
44
+ if (dbSlices.length > 0 && readySliceIds.size === 0) {
45
+ return false;
46
+ }
34
47
  const roadmapSliceIds = new Set();
35
48
  for (let i = 0; i < roadmap.slices.length; i++) {
36
49
  const roadmapSlice = roadmap.slices[i];
@@ -39,6 +52,8 @@ function milestoneHasDivergence(basePath, milestoneId) {
39
52
  const dbSlice = dbSliceMap.get(roadmapSlice.id);
40
53
  if (!dbSlice)
41
54
  return true; // Roadmap has a slice the DB doesn't.
55
+ if (!readySliceIds.has(dbSlice.id))
56
+ continue;
42
57
  if (dbSlice.sequence !== expectedSequence)
43
58
  return true;
44
59
  if (!arraysEqual(dbSlice.depends, roadmapSlice.depends))
@@ -47,6 +62,8 @@ function milestoneHasDivergence(basePath, milestoneId) {
47
62
  return true;
48
63
  }
49
64
  for (const dbSlice of dbSlices) {
65
+ if (!readySliceIds.has(dbSlice.id))
66
+ continue;
50
67
  if (!roadmapSliceIds.has(dbSlice.id))
51
68
  return true;
52
69
  }
@@ -2,6 +2,7 @@
2
2
  // File Purpose: ADR-017 drift-driven State Reconciliation Module entry point.
3
3
  // reconcileBeforeDispatch runs before every Dispatch decision and worker spawn.
4
4
  import { deriveState as defaultDeriveState, invalidateStateCache as defaultInvalidate, } from "../state.js";
5
+ import { clearParseCache as defaultClearParseCache } from "../files.js";
5
6
  import { ReconciliationFailedError, } from "./errors.js";
6
7
  import { DRIFT_REGISTRY } from "./registry.js";
7
8
  export { ReconciliationFailedError } from "./errors.js";
@@ -10,6 +11,7 @@ const MAX_PASSES = 2;
10
11
  const defaultDeps = {
11
12
  invalidateStateCache: defaultInvalidate,
12
13
  deriveState: defaultDeriveState,
14
+ clearParseCache: defaultClearParseCache,
13
15
  };
14
16
  /**
15
17
  * Drift-driven pre-dispatch reconciliation per ADR-017.
@@ -27,6 +29,7 @@ const defaultDeps = {
27
29
  */
28
30
  export async function reconcileBeforeDispatch(basePath, deps = defaultDeps) {
29
31
  const registry = deps.registry ?? DRIFT_REGISTRY;
32
+ const clearParseCache = deps.clearParseCache ?? defaultClearParseCache;
30
33
  const repaired = [];
31
34
  for (let pass = 0; pass < MAX_PASSES; pass++) {
32
35
  deps.invalidateStateCache();
@@ -67,6 +70,9 @@ export async function reconcileBeforeDispatch(basePath, deps = defaultDeps) {
67
70
  failures.push({ drift: record, cause });
68
71
  }
69
72
  }
73
+ if (repairedThisPass) {
74
+ clearParseCache();
75
+ }
70
76
  if (blockers.length > 0) {
71
77
  let blockerState = stateSnapshot;
72
78
  if (repairedThisPass) {
@@ -35,7 +35,7 @@ function formatNeedsRemediationBlocker(milestoneId) {
35
35
  return [
36
36
  `Milestone ${milestoneId} is blocked because milestone validation returned needs-remediation, but all slices are complete.`,
37
37
  `Fix options:`,
38
- `1. Add remediation slices with \`gsd_reassess_roadmap\`, then run \`/gsd auto\``,
38
+ `1. Run \`/gsd dispatch reassess\` to add remediation slices, then run \`/gsd auto\``,
39
39
  `2. If the finding is acceptable, override it: \`/gsd verdict pass --rationale "why this is okay"\``,
40
40
  `3. If this should wait, defer it explicitly: \`/gsd park ${milestoneId}\``,
41
41
  ].join("\n");
@@ -204,10 +204,16 @@ export function invalidateStateCache() {
204
204
  /**
205
205
  * Returns the ID of the first incomplete milestone, or null if all are complete.
206
206
  */
207
+ function getRequestedMilestoneLock() {
208
+ const lock = process.env.GSD_MILESTONE_LOCK?.trim();
209
+ return lock || undefined;
210
+ }
207
211
  export async function getActiveMilestoneId(basePath) {
208
- // Parallel worker isolation. Normal DB state derivation remains DB-only;
209
- // lock env vars are execution routing for explicit worker processes.
210
- const milestoneLock = process.env.GSD_PARALLEL_WORKER ? process.env.GSD_MILESTONE_LOCK : undefined;
212
+ // Milestone-scoped execution. Parallel workers and explicit solo commands
213
+ // such as `/gsd auto M002` both set GSD_MILESTONE_LOCK; state derivation must
214
+ // honor it so recovery/adoption sees the requested milestone, not the first
215
+ // open milestone in queue order.
216
+ const milestoneLock = getRequestedMilestoneLock();
211
217
  if (milestoneLock) {
212
218
  if (isDbAvailable()) {
213
219
  const locked = getAllMilestones().find(m => m.id === milestoneLock);
@@ -573,7 +579,7 @@ function checkReplanTrigger(basePath, milestoneId, sliceId) {
573
579
  export async function deriveStateFromDb(basePath, artifactReadRoot = basePath) {
574
580
  const requirements = getRequirementCounts();
575
581
  const allMilestones = getAllMilestones();
576
- const milestoneLock = process.env.GSD_PARALLEL_WORKER ? process.env.GSD_MILESTONE_LOCK : undefined;
582
+ const milestoneLock = getRequestedMilestoneLock();
577
583
  const milestones = milestoneLock
578
584
  ? allMilestones.filter(m => m.id === milestoneLock)
579
585
  : allMilestones;
@@ -718,8 +724,8 @@ export async function deriveStateFromDb(basePath, artifactReadRoot = basePath) {
718
724
  }
719
725
  }
720
726
  // ADR-011 Phase 2: pause-on-escalation takes precedence over dispatching the
721
- // next task. `awaiting_review` tasks (continueWithDefault=true) are NOT
722
- // surfaced here they let the loop continue.
727
+ // next task. `awaiting_review` tasks (continueWithDefault=true) still pause
728
+ // here so silence is never treated as consent.
723
729
  //
724
730
  // We do NOT gate this on `phases.mid_execution_escalation` — creation of
725
731
  // new escalations is gated at the write site (tools/complete-task.ts:315),
@@ -779,13 +785,10 @@ export async function _deriveStateImpl(basePath, opts) {
779
785
  const diskIds = findMilestoneIds(basePath);
780
786
  const customOrder = loadQueueOrder(basePath);
781
787
  const milestoneIds = sortByQueueOrder(diskIds, customOrder);
782
- // ── Parallel worker isolation ──────────────────────────────────────────
783
- // When GSD_PARALLEL_WORKER and GSD_MILESTONE_LOCK are set, this process is a parallel worker
784
- // scoped to a single milestone. Filter the milestone list so this worker
785
- // only sees its assigned milestone (all others are treated as if they
786
- // don't exist). This gives each worker complete isolation without
787
- // modifying any other state derivation logic.
788
- const milestoneLock = process.env.GSD_PARALLEL_WORKER ? process.env.GSD_MILESTONE_LOCK : undefined;
788
+ // ── Milestone-scoped execution ─────────────────────────────────────────
789
+ // Parallel workers and explicit solo recovery both scope auto-mode to one
790
+ // milestone through GSD_MILESTONE_LOCK.
791
+ const milestoneLock = getRequestedMilestoneLock();
789
792
  if (milestoneLock && milestoneIds.includes(milestoneLock)) {
790
793
  milestoneIds.length = 0;
791
794
  milestoneIds.push(milestoneLock);
@@ -132,14 +132,16 @@
132
132
  Verify field rules:
133
133
  - MUST be a mechanically executable command: `npm test`, `grep -q "pattern" file`, `test -f path`
134
134
  - MUST NOT use shell pipes, redirects, semicolons, backticks, command substitution, output trimming, or grep regex alternation with `|`
135
+ - For absence checks, use `! grep -q "pattern" file` or `! rg -q "pattern" file`; do not use `grep -c` or `rg -c` to assert zero matches because count commands exit 1 when they find zero matches
135
136
  - MUST NOT use inline `node -e` assertions for verification; put assertions in a real test file and run it with `node --test` or a package test script
136
137
  - For content/document tasks: verify file existence, section count, YAML validity, or word count
137
138
  NOT exact phrasing, specific formulas, or "zero TBD" aspirational criteria
138
139
  - If no command can verify the output, write: "Manual review — file exists and is non-empty"
139
140
  - BAD: `python3 -m pytest tests/ -q --tb=short 2>&1 | tail -5`
141
+ - BAD: `grep -c "old_api" src/index.ts`
140
142
  - BAD: "Sections 3.1 and 3.2 exist with exact formulas. Zero TBD/TODO."
141
143
  - GOOD: `python3 -m pytest tests/ -q --tb=short`
142
- - GOOD: `node --test tests/verify-doc.test.js`, `grep -q "Required heading" doc.md`, `test -s doc.md`
144
+ - GOOD: `node --test tests/verify-doc.test.js`, `grep -q "Required heading" doc.md`, `! grep -q "old_api" src/index.ts`, `test -s doc.md`
143
145
 
144
146
  Integration closure rule:
145
147
  - At least one slice in any multi-boundary milestone should perform real composition/wiring, not just contract hardening
@@ -2,8 +2,10 @@
2
2
  // File Purpose: ADR-015 Tool Contract module for Unit prompt, policy, and tool parity.
3
3
  import { resolveManifest, } from "./unit-context-manifest.js";
4
4
  import { getRequiredWorkflowToolsForAutoUnit } from "./workflow-mcp.js";
5
+ import { getUnitToolSurfaceContract } from "./unit-tool-contracts.js";
5
6
  export function compileUnitToolContract(unitType) {
6
7
  const manifest = resolveManifest(unitType);
8
+ const surfaceContract = getUnitToolSurfaceContract(unitType);
7
9
  if (!manifest) {
8
10
  return {
9
11
  ok: false,
@@ -12,6 +14,8 @@ export function compileUnitToolContract(unitType) {
12
14
  };
13
15
  }
14
16
  const requiredWorkflowTools = getRequiredWorkflowToolsForAutoUnit(unitType);
17
+ const forbiddenWorkflowTools = Object.entries(surfaceContract?.forbiddenGsdTools ?? {})
18
+ .map(([name, reason]) => ({ name, reason }));
15
19
  const closeoutTools = requiredWorkflowTools.filter((tool) => /^gsd_(?:task|slice|milestone|complete|validate|save|summary)/.test(tool));
16
20
  if (requiresCloseoutTool(unitType) && closeoutTools.length === 0) {
17
21
  return {
@@ -27,6 +31,7 @@ export function compileUnitToolContract(unitType) {
27
31
  contextMode: manifest.contextMode,
28
32
  toolsPolicy: manifest.tools,
29
33
  requiredWorkflowTools,
34
+ forbiddenWorkflowTools,
30
35
  promptObligations: [
31
36
  `context-mode:${manifest.contextMode}`,
32
37
  `tools-policy:${manifest.tools.mode}`,
@@ -0,0 +1,143 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Resolve phase-aware tool surfaces for GSD model presentations.
3
+ import { RUN_UAT_BROWSER_TOOL_NAMES, RUN_UAT_READ_ONLY_TOOL_NAMES, RUN_UAT_TOOL_PRESENTATION_PLAN_ID, RUN_UAT_WORKFLOW_TOOL_NAMES, } from "./unit-tool-contracts.js";
4
+ export { RUN_UAT_BROWSER_TOOL_NAMES, RUN_UAT_READ_ONLY_TOOL_NAMES, RUN_UAT_TOOL_PRESENTATION_PLAN_ID, RUN_UAT_WORKFLOW_TOOL_NAMES, } from "./unit-tool-contracts.js";
5
+ export const RUN_UAT_FORBIDDEN_TOOL_NAMES = [
6
+ "edit",
7
+ "write",
8
+ "gsd_exec",
9
+ "gsd_summary_save",
10
+ "gsd_save_gate_result",
11
+ "search-the-web",
12
+ "WebSearch",
13
+ "Bash",
14
+ "Write",
15
+ "Edit",
16
+ "mcp__gsd-workflow__*",
17
+ ];
18
+ export const RUN_UAT_CLAUDE_NATIVE_TOOL_NAMES = [
19
+ "Read",
20
+ "Glob",
21
+ "Grep",
22
+ ];
23
+ const WORKFLOW_ALIAS_TO_CANONICAL = {
24
+ gsd_save_decision: "gsd_decision_save",
25
+ gsd_update_requirement: "gsd_requirement_update",
26
+ gsd_save_requirement: "gsd_requirement_save",
27
+ gsd_save_summary: "gsd_summary_save",
28
+ gsd_generate_milestone_id: "gsd_milestone_generate_id",
29
+ gsd_milestone_plan: "gsd_plan_milestone",
30
+ gsd_slice_plan: "gsd_plan_slice",
31
+ gsd_task_plan: "gsd_plan_task",
32
+ gsd_slice_replan: "gsd_replan_slice",
33
+ gsd_complete_slice: "gsd_slice_complete",
34
+ gsd_milestone_complete: "gsd_complete_milestone",
35
+ gsd_milestone_validate: "gsd_validate_milestone",
36
+ gsd_roadmap_reassess: "gsd_reassess_roadmap",
37
+ gsd_complete_task: "gsd_task_complete",
38
+ gsd_reopen_task: "gsd_task_reopen",
39
+ gsd_reopen_slice: "gsd_slice_reopen",
40
+ gsd_reopen_milestone: "gsd_milestone_reopen",
41
+ };
42
+ export function canonicalWorkflowToolName(toolName) {
43
+ const mcp = parseMcpToolName(toolName);
44
+ const baseName = mcp?.tool ?? toolName;
45
+ return WORKFLOW_ALIAS_TO_CANONICAL[baseName] ?? baseName;
46
+ }
47
+ export function parseMcpToolName(toolName) {
48
+ if (!toolName.startsWith("mcp__"))
49
+ return null;
50
+ const toolSeparator = toolName.indexOf("__", "mcp__".length);
51
+ if (toolSeparator < 0)
52
+ return null;
53
+ return {
54
+ server: toolName.slice("mcp__".length, toolSeparator),
55
+ tool: toolName.slice(toolSeparator + 2),
56
+ };
57
+ }
58
+ export function toWorkflowMcpToolName(serverName, toolName) {
59
+ return `mcp__${serverName}__${canonicalWorkflowToolName(toolName)}`;
60
+ }
61
+ function dedupe(values) {
62
+ return [...new Set(values)];
63
+ }
64
+ function addBlockedTool(blocked, name, reason) {
65
+ if (!blocked.some((entry) => entry.name === name)) {
66
+ blocked.push({ name, reason });
67
+ }
68
+ }
69
+ export function buildRunUatCanonicalToolNames(options = {}) {
70
+ return dedupe([
71
+ ...RUN_UAT_WORKFLOW_TOOL_NAMES,
72
+ ...RUN_UAT_READ_ONLY_TOOL_NAMES,
73
+ ...(options.includeBrowserTools ?? []),
74
+ ]);
75
+ }
76
+ export function runUatBrowserToolsForType(uatType) {
77
+ return uatType === "browser-executable" ? RUN_UAT_BROWSER_TOOL_NAMES : [];
78
+ }
79
+ export function runUatPresentationSurfaceForType(uatType) {
80
+ return uatType === "browser-executable" ? "hybrid" : "mcp";
81
+ }
82
+ export function buildRunUatPresentationForType(uatType, options = {}) {
83
+ return buildRunUatResultPresentation({
84
+ ...options,
85
+ surface: options.surface ?? runUatPresentationSurfaceForType(uatType),
86
+ includeBrowserTools: runUatBrowserToolsForType(uatType),
87
+ });
88
+ }
89
+ export function buildRunUatResultPresentation(options = {}) {
90
+ const presentedTools = options.presentedTools
91
+ ? dedupe(options.presentedTools)
92
+ : buildRunUatCanonicalToolNames({ includeBrowserTools: options.includeBrowserTools });
93
+ const blockedTools = RUN_UAT_FORBIDDEN_TOOL_NAMES
94
+ .filter((toolName) => !toolName.includes("*"))
95
+ .map((name) => ({ name, reason: "forbidden during run-uat" }));
96
+ return {
97
+ surface: options.surface ?? "mcp",
98
+ presentedTools,
99
+ blockedTools,
100
+ toolPresentationPlanId: RUN_UAT_TOOL_PRESENTATION_PLAN_ID,
101
+ };
102
+ }
103
+ export function resolveToolPresentationPlan(options) {
104
+ const requested = options.requestedToolNames ?? (options.phase === "run-uat"
105
+ ? buildRunUatCanonicalToolNames({ includeBrowserTools: options.includeBrowserTools })
106
+ : []);
107
+ const available = new Set(options.availableToolNames ?? requested);
108
+ const aliases = [];
109
+ const blockedToolNames = [];
110
+ const allowed = [];
111
+ for (const name of requested) {
112
+ const canonical = canonicalWorkflowToolName(name);
113
+ if (canonical !== name)
114
+ aliases.push({ requested: name, canonical });
115
+ if (!available.has(name) && !available.has(canonical)) {
116
+ addBlockedTool(blockedToolNames, canonical, "not registered or provider-incompatible");
117
+ continue;
118
+ }
119
+ allowed.push(canonical);
120
+ }
121
+ const allowedToolNames = dedupe(allowed);
122
+ const workflowServerName = options.workflowMcpServerName || "gsd-workflow";
123
+ const presentedToolNames = options.surface === "claude-code-sdk" || options.surface === "mcp"
124
+ ? allowedToolNames.map((name) => name.startsWith("gsd_") || name === "ask_user_questions"
125
+ ? toWorkflowMcpToolName(workflowServerName, name)
126
+ : name)
127
+ : allowedToolNames;
128
+ if (options.phase === "run-uat") {
129
+ for (const forbidden of RUN_UAT_FORBIDDEN_TOOL_NAMES) {
130
+ addBlockedTool(blockedToolNames, forbidden, "forbidden during run-uat");
131
+ }
132
+ }
133
+ return {
134
+ phase: options.phase,
135
+ surface: options.surface,
136
+ model: options.model,
137
+ allowedToolNames,
138
+ presentedToolNames,
139
+ blockedToolNames,
140
+ aliases,
141
+ diagnostics: [],
142
+ };
143
+ }
@@ -158,7 +158,7 @@ ${params.narrative}
158
158
 
159
159
  ## Verification
160
160
 
161
- ${params.verification}
161
+ ${params.verification ?? ""}
162
162
 
163
163
  ## Requirements Advanced
164
164
 
@@ -351,6 +351,20 @@ export async function handleCompleteSlice(params, basePath) {
351
351
  if (parsed.length > 0)
352
352
  effectiveParams.requirementsInvalidated = parsed;
353
353
  }
354
+ if (effectiveParams.verification === undefined) {
355
+ const headingLine = "## Verification\n\n";
356
+ const start = existingSummaryMd.indexOf(headingLine);
357
+ if (start !== -1) {
358
+ const contentStart = start + headingLine.length;
359
+ const nextHeading = existingSummaryMd.indexOf("\n\n## ", contentStart);
360
+ const prior = nextHeading === -1
361
+ ? existingSummaryMd.slice(contentStart)
362
+ : existingSummaryMd.slice(contentStart, nextHeading);
363
+ const trimmed = prior.trim();
364
+ if (trimmed)
365
+ effectiveParams.verification = trimmed;
366
+ }
367
+ }
354
368
  }
355
369
  // Render summary markdown
356
370
  const summaryMd = renderSliceSummaryMarkdown(effectiveParams);
@@ -314,9 +314,18 @@ export async function handleCompleteTask(params, basePath) {
314
314
  // overwrite it; gate rows are UPSERT-keyed per task and will also be
315
315
  // overwritten. This restores the invariant that deriveState() sees a
316
316
  // consistent "task not done" view so the loop re-dispatches the task.
317
+ let escalationMetadata;
317
318
  if (validatedEscalationArtifact) {
318
319
  try {
319
- writeEscalationArtifact(artifactBasePath, validatedEscalationArtifact);
320
+ const escalationPath = writeEscalationArtifact(artifactBasePath, validatedEscalationArtifact);
321
+ escalationMetadata = {
322
+ artifactPath: escalationPath,
323
+ question: validatedEscalationArtifact.question,
324
+ options: validatedEscalationArtifact.options,
325
+ recommendation: validatedEscalationArtifact.recommendation,
326
+ recommendationRationale: validatedEscalationArtifact.recommendationRationale,
327
+ continueWithDefault: validatedEscalationArtifact.continueWithDefault,
328
+ };
320
329
  }
321
330
  catch (escalationErr) {
322
331
  const msg = `complete-task escalation write failed for ${params.milestoneId}/${params.sliceId}/${params.taskId}: ${escalationErr.message}`;
@@ -378,6 +387,7 @@ export async function handleCompleteTask(params, basePath) {
378
387
  sliceId: params.sliceId,
379
388
  milestoneId: params.milestoneId,
380
389
  summaryPath,
390
+ ...(escalationMetadata ? { escalation: escalationMetadata } : {}),
381
391
  ...(projectionStale ? { stale: true } : {}),
382
392
  };
383
393
  }
@@ -5,6 +5,27 @@ import { realpathSync } from "node:fs";
5
5
  import path from "node:path";
6
6
  import { isContextModeEnabled } from "../preferences-types.js";
7
7
  import { contextModeDisabledResult } from "./context-mode-tool-result.js";
8
+ const UAT_EXEC_INTENTS = [
9
+ "uat-artifact-check",
10
+ "uat-runtime-check",
11
+ "uat-browser-check",
12
+ "uat-service-start",
13
+ "uat-log-inspection",
14
+ ];
15
+ const UAT_EXEC_INTENT_ALIASES = {
16
+ artifact: "uat-artifact-check",
17
+ "artifact-driven": "uat-artifact-check",
18
+ runtime: "uat-runtime-check",
19
+ "runtime-executable": "uat-runtime-check",
20
+ "live-runtime": "uat-runtime-check",
21
+ browser: "uat-browser-check",
22
+ "browser-executable": "uat-browser-check",
23
+ service: "uat-service-start",
24
+ "service-start": "uat-service-start",
25
+ log: "uat-log-inspection",
26
+ logs: "uat-log-inspection",
27
+ "log-inspection": "uat-log-inspection",
28
+ };
8
29
  export function buildExecOptions(baseDir, cfg, extras) {
9
30
  const allowlist = Array.isArray(cfg?.exec_env_allowlist) ? cfg.exec_env_allowlist : EXEC_DEFAULTS.envAllowlist;
10
31
  const stdoutCap = clampNumber(cfg?.exec_stdout_cap_bytes, EXEC_DEFAULTS.stdoutCapBytes, 4_096, 16_777_216);
@@ -73,6 +94,39 @@ function normalizeScript(params) {
73
94
  }
74
95
  return paramError("script is required and must be a non-empty string");
75
96
  }
97
+ function normalizeRequiredString(value, field) {
98
+ if (typeof value !== "string" || value.trim().length === 0) {
99
+ return paramError(`${field} is required and must be a non-empty string`);
100
+ }
101
+ return value.trim();
102
+ }
103
+ function normalizeUatIntent(value) {
104
+ if (typeof value !== "string") {
105
+ return paramError(`intent is required and must be one of: ${UAT_EXEC_INTENTS.join(", ")}`);
106
+ }
107
+ const normalized = value.trim().toLowerCase();
108
+ if (UAT_EXEC_INTENTS.includes(normalized))
109
+ return normalized;
110
+ const alias = UAT_EXEC_INTENT_ALIASES[normalized];
111
+ if (alias)
112
+ return alias;
113
+ return paramError(`invalid intent "${value}" — must be one of: ${UAT_EXEC_INTENTS.join(", ")}`);
114
+ }
115
+ function rejectUatScript(script) {
116
+ const patterns = [
117
+ { re: /\b(?:npm|pnpm|yarn|bun)\s+(?:i|install|add|remove|update|upgrade)\b/i, reason: "package dependency mutation is not allowed during UAT" },
118
+ { re: /\b(?:pip|pip3|python\s+-m\s+pip)\s+install\b/i, reason: "package dependency mutation is not allowed during UAT" },
119
+ { re: /\bgit\s+(?:add|commit|push|reset|checkout|switch|merge|rebase|clean|rm|mv|tag|branch)\b/i, reason: "git mutations are not allowed during UAT" },
120
+ { re: /\brm\s+-[^\n\r;|&]*r[^\n\r;|&]*f\b/i, reason: "destructive filesystem cleanup is not allowed during UAT" },
121
+ { re: /\b(?:env|printenv)\b(?:\s|$)/i, reason: "dumping environment variables is not allowed during UAT" },
122
+ { re: /\bcat\s+\.env(?:\b|\.|$)/i, reason: "reading credential files is not allowed during UAT" },
123
+ ];
124
+ for (const pattern of patterns) {
125
+ if (pattern.re.test(script))
126
+ return pattern.reason;
127
+ }
128
+ return null;
129
+ }
76
130
  function isToolExecutionResult(value) {
77
131
  return typeof value === "object" && value !== null && Array.isArray(value.content);
78
132
  }
@@ -207,6 +261,7 @@ export async function executeGsdExec(params, deps) {
207
261
  runtime,
208
262
  script,
209
263
  ...(typeof params.purpose === "string" ? { purpose: params.purpose } : {}),
264
+ ...(params.metadata && typeof params.metadata === "object" ? { metadata: params.metadata } : {}),
210
265
  ...(typeof params.timeout_ms === "number" ? { timeout_ms: params.timeout_ms } : {}),
211
266
  }, opts);
212
267
  return formatResult(result);
@@ -220,6 +275,60 @@ export async function executeGsdExec(params, deps) {
220
275
  };
221
276
  }
222
277
  }
278
+ export async function executeUatExec(params, deps) {
279
+ const milestoneId = normalizeRequiredString(params.milestoneId, "milestoneId");
280
+ if (isToolExecutionResult(milestoneId))
281
+ return milestoneId;
282
+ const sliceId = normalizeRequiredString(params.sliceId, "sliceId");
283
+ if (isToolExecutionResult(sliceId))
284
+ return sliceId;
285
+ const checkId = normalizeRequiredString(params.checkId, "checkId");
286
+ if (isToolExecutionResult(checkId))
287
+ return checkId;
288
+ const intent = normalizeUatIntent(params.intent);
289
+ if (isToolExecutionResult(intent))
290
+ return intent;
291
+ const script = normalizeScript(params);
292
+ if (isToolExecutionResult(script))
293
+ return script;
294
+ const rejected = rejectUatScript(script);
295
+ if (rejected) {
296
+ return {
297
+ content: [{ type: "text", text: `Error: gsd_uat_exec blocked command — ${rejected}` }],
298
+ details: { operation: "gsd_uat_exec", error: "uat_exec_policy_block", reason: rejected },
299
+ isError: true,
300
+ };
301
+ }
302
+ const result = await executeGsdExec({
303
+ ...params,
304
+ script,
305
+ purpose: typeof params.purpose === "string" && params.purpose.trim().length > 0
306
+ ? params.purpose
307
+ : `UAT ${milestoneId}/${sliceId}/${checkId} (${intent})`,
308
+ metadata: {
309
+ kind: "uat_exec",
310
+ milestoneId,
311
+ sliceId,
312
+ checkId,
313
+ intent,
314
+ ...(typeof params.expected === "string" && params.expected.trim().length > 0
315
+ ? { expected: params.expected.trim() }
316
+ : {}),
317
+ },
318
+ }, deps);
319
+ const details = result.details ?? {};
320
+ return {
321
+ ...result,
322
+ details: {
323
+ ...details,
324
+ operation: "gsd_uat_exec",
325
+ milestoneId,
326
+ sliceId,
327
+ checkId,
328
+ intent,
329
+ },
330
+ };
331
+ }
223
332
  function formatResult(result) {
224
333
  const headerLines = [
225
334
  `gsd_exec[${result.id}] runtime=${result.runtime} exit=${formatExit(result)} duration=${result.duration_ms}ms`,
@@ -268,15 +268,9 @@ export async function handlePlanSlice(rawParams, basePath) {
268
268
  for (const taskId of omittedTaskIds) {
269
269
  deleteTask(params.milestoneId, params.sliceId, taskId);
270
270
  }
271
+ const existingTaskById = new Map(existingTasks.map((task) => [task.id, task]));
271
272
  for (const task of params.tasks) {
272
- insertTask({
273
- id: task.taskId,
274
- sliceId: params.sliceId,
275
- milestoneId: params.milestoneId,
276
- title: task.title,
277
- status: "pending",
278
- });
279
- upsertTaskPlanning(params.milestoneId, params.sliceId, task.taskId, {
273
+ const planning = {
280
274
  title: task.title,
281
275
  description: task.description,
282
276
  estimate: task.estimate,
@@ -287,7 +281,18 @@ export async function handlePlanSlice(rawParams, basePath) {
287
281
  observabilityImpact: task.observabilityImpact ?? "",
288
282
  fullPlanMd: task.fullPlanMd,
289
283
  targetRepositories: task.targetRepositories ?? params.targetRepositories ?? defaultTargets,
290
- });
284
+ };
285
+ const existingTask = existingTaskById.get(task.taskId);
286
+ if (!existingTask || !isClosedStatus(existingTask.status)) {
287
+ insertTask({
288
+ id: task.taskId,
289
+ sliceId: params.sliceId,
290
+ milestoneId: params.milestoneId,
291
+ title: task.title,
292
+ status: "pending",
293
+ });
294
+ }
295
+ upsertTaskPlanning(params.milestoneId, params.sliceId, task.taskId, planning);
291
296
  }
292
297
  // Seed quality gate rows inside the transaction — all-or-nothing with
293
298
  // the plan data so a crash can't leave orphaned gates without tasks.