@opengsd/gsd-pi 1.2.0-dev.5457a158 → 1.2.0-dev.822c9439

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 (489) hide show
  1. package/dist/headless-events.js +7 -5
  2. package/dist/mcp-server.js +2 -1
  3. package/dist/resource-loader.d.ts +9 -5
  4. package/dist/resource-loader.js +114 -6
  5. package/dist/resources/.managed-resources-content-hash +1 -1
  6. package/dist/resources/GSD-WORKFLOW.md +5 -4
  7. package/dist/resources/extensions/async-jobs/async-bash-tool.js +30 -64
  8. package/dist/resources/extensions/async-jobs/await-tool.js +80 -12
  9. package/dist/resources/extensions/async-jobs/index.js +65 -0
  10. package/dist/resources/extensions/async-jobs/job-manager.js +12 -1
  11. package/dist/resources/extensions/bg-shell/bg-shell-command.js +6 -6
  12. package/dist/resources/extensions/bg-shell/bg-shell-tool.js +10 -7
  13. package/dist/resources/extensions/bg-shell/overlay.js +9 -6
  14. package/dist/resources/extensions/bg-shell/process-manager.js +54 -25
  15. package/dist/resources/extensions/bg-shell/readiness-detector.js +11 -0
  16. package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +209 -88
  17. package/dist/resources/extensions/browser-tools/engine/selection.js +73 -5
  18. package/dist/resources/extensions/browser-tools/index.js +69 -12
  19. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +3 -2
  20. package/dist/resources/extensions/gsd/auto/custom-verify-retry-store.js +17 -2
  21. package/dist/resources/extensions/gsd/auto/detect-stuck.js +33 -13
  22. package/dist/resources/extensions/gsd/auto/dispatch-history.js +105 -0
  23. package/dist/resources/extensions/gsd/auto/dispatch-key.js +37 -0
  24. package/dist/resources/extensions/gsd/auto/loop.js +4 -1
  25. package/dist/resources/extensions/gsd/auto/orchestrator.js +89 -54
  26. package/dist/resources/extensions/gsd/auto/phases.js +49 -6
  27. package/dist/resources/extensions/gsd/auto/session.js +3 -0
  28. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +11 -34
  29. package/dist/resources/extensions/gsd/auto-dispatch.js +50 -58
  30. package/dist/resources/extensions/gsd/auto-model-selection.js +36 -13
  31. package/dist/resources/extensions/gsd/auto-post-unit.js +30 -12
  32. package/dist/resources/extensions/gsd/auto-prompts.js +78 -19
  33. package/dist/resources/extensions/gsd/auto-start.js +12 -12
  34. package/dist/resources/extensions/gsd/auto-unit-closeout.js +45 -21
  35. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +5 -4
  36. package/dist/resources/extensions/gsd/auto-verification.js +23 -30
  37. package/dist/resources/extensions/gsd/auto-worktree.js +14 -1
  38. package/dist/resources/extensions/gsd/auto.js +37 -1
  39. package/dist/resources/extensions/gsd/blocked-models.js +28 -0
  40. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +26 -6
  41. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +23 -6
  42. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +2 -2
  43. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +19 -0
  44. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +172 -59
  45. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +302 -80
  46. package/dist/resources/extensions/gsd/browser-daemon-auto-prep.js +83 -0
  47. package/dist/resources/extensions/gsd/browser-evidence.js +8 -2
  48. package/dist/resources/extensions/gsd/closeout-wizard.js +92 -0
  49. package/dist/resources/extensions/gsd/commands/context.js +16 -2
  50. package/dist/resources/extensions/gsd/commands-handlers.js +46 -3
  51. package/dist/resources/extensions/gsd/consent-question.js +353 -0
  52. package/dist/resources/extensions/gsd/consent-verdict.js +63 -0
  53. package/dist/resources/extensions/gsd/constants.js +0 -2
  54. package/dist/resources/extensions/gsd/crash-recovery.js +8 -3
  55. package/dist/resources/extensions/gsd/db/queries.js +26 -0
  56. package/dist/resources/extensions/gsd/dispatch-guard.js +10 -35
  57. package/dist/resources/extensions/gsd/doctor-engine-checks.js +5 -5
  58. package/dist/resources/extensions/gsd/doctor-git-checks.js +2 -18
  59. package/dist/resources/extensions/gsd/engine-hook-contract.js +70 -0
  60. package/dist/resources/extensions/gsd/exec-sandbox.js +30 -10
  61. package/dist/resources/extensions/gsd/files.js +33 -19
  62. package/dist/resources/extensions/gsd/gsd-command-home.js +22 -12
  63. package/dist/resources/extensions/gsd/gsd-db.js +2 -1
  64. package/dist/resources/extensions/gsd/guidance.js +60 -0
  65. package/dist/resources/extensions/gsd/guided-flow.js +6 -3
  66. package/dist/resources/extensions/gsd/markdown-renderer.js +10 -0
  67. package/dist/resources/extensions/gsd/mcp-filter.js +2 -19
  68. package/dist/resources/extensions/gsd/milestone-closeout.js +85 -24
  69. package/dist/resources/extensions/gsd/milestone-planning-persistence.js +2 -2
  70. package/dist/resources/extensions/gsd/milestone-reopen-events.js +3 -5
  71. package/dist/resources/extensions/gsd/parsers-legacy.js +16 -4
  72. package/dist/resources/extensions/gsd/preferences-models.js +2 -2
  73. package/dist/resources/extensions/gsd/projection-flush.js +7 -0
  74. package/dist/resources/extensions/gsd/prompts/complete-slice.md +3 -3
  75. package/dist/resources/extensions/gsd/prompts/execute-task.md +1 -1
  76. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  77. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  78. package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -1
  79. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  80. package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  81. package/dist/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  82. package/dist/resources/extensions/gsd/prompts/research-milestone.md +1 -1
  83. package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
  84. package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  85. package/dist/resources/extensions/gsd/prompts/run-uat.md +7 -5
  86. package/dist/resources/extensions/gsd/prompts/system.md +5 -2
  87. package/dist/resources/extensions/gsd/prompts/triage-captures.md +1 -1
  88. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +1 -1
  89. package/dist/resources/extensions/gsd/reactive-graph.js +8 -1
  90. package/dist/resources/extensions/gsd/roadmap-slices.js +25 -3
  91. package/dist/resources/extensions/gsd/safety/destructive-confirmation.js +108 -0
  92. package/dist/resources/extensions/gsd/session-lock.js +1 -1
  93. package/dist/resources/extensions/gsd/state.js +5 -0
  94. package/dist/resources/extensions/gsd/tool-contract.js +14 -3
  95. package/dist/resources/extensions/gsd/tool-presentation-plan.js +4 -4
  96. package/dist/resources/extensions/gsd/tools/complete-milestone.js +3 -2
  97. package/dist/resources/extensions/gsd/tools/complete-slice.js +22 -12
  98. package/dist/resources/extensions/gsd/tools/complete-task.js +3 -2
  99. package/dist/resources/extensions/gsd/tools/exec-tool.js +5 -0
  100. package/dist/resources/extensions/gsd/tools/plan-slice.js +2 -2
  101. package/dist/resources/extensions/gsd/tools/plan-task.js +2 -2
  102. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +2 -2
  103. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +2 -2
  104. package/dist/resources/extensions/gsd/tools/reopen-slice.js +2 -2
  105. package/dist/resources/extensions/gsd/tools/reopen-task.js +2 -2
  106. package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -2
  107. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +67 -2
  108. package/dist/resources/extensions/gsd/uat-policy.js +42 -16
  109. package/dist/resources/extensions/gsd/unit-context-composer.js +65 -0
  110. package/dist/resources/extensions/gsd/unit-registry.js +7 -20
  111. package/dist/resources/extensions/gsd/verdict-parser.js +1 -1
  112. package/dist/resources/extensions/gsd/verification-verdict.js +2 -1
  113. package/dist/resources/extensions/gsd/web-app-uat.js +45 -8
  114. package/dist/resources/extensions/gsd/workflow-event-ledger.js +91 -0
  115. package/dist/resources/extensions/gsd/workflow-event-vocabulary.js +46 -0
  116. package/dist/resources/extensions/gsd/workflow-events.js +6 -18
  117. package/dist/resources/extensions/gsd/workflow-reconcile.js +21 -56
  118. package/dist/resources/extensions/gsd/worktree-lifecycle.js +3 -2
  119. package/dist/resources/extensions/gsd/worktree-manager.js +7 -1
  120. package/dist/resources/extensions/gsd/worktree.js +8 -1
  121. package/dist/resources/extensions/search-the-web/native-search.js +5 -3
  122. package/dist/resources/extensions/shared/browser-contract.js +59 -0
  123. package/dist/resources/extensions/shared/gsd-browser-cli.js +116 -6
  124. package/dist/resources/shared/gsd-browser-path-sync.js +214 -0
  125. package/dist/resources/shared/package-manager-detection.js +1 -1
  126. package/dist/resources/shared/package.json +3 -0
  127. package/dist/resources/skills/create-skill/SKILL.md +3 -0
  128. package/dist/resources/skills/create-skill/references/executable-code.md +1 -1
  129. package/dist/resources/skills/create-skill/references/skill-structure.md +1 -0
  130. package/dist/resources/skills/create-skill/workflows/add-reference.md +8 -3
  131. package/dist/resources/skills/create-skill/workflows/add-script.md +4 -2
  132. package/dist/resources/skills/create-skill/workflows/add-template.md +3 -1
  133. package/dist/resources/skills/create-skill/workflows/add-workflow.md +8 -3
  134. package/dist/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
  135. package/dist/resources/skills/create-skill/workflows/verify-skill.md +9 -4
  136. package/dist/resources/skills/spike-wrap-up/SKILL.md +9 -9
  137. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  138. package/dist/update-check.d.ts +2 -0
  139. package/dist/update-check.js +24 -1
  140. package/dist/update-cmd.js +20 -3
  141. package/dist/web/standalone/.next/BUILD_ID +1 -1
  142. package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
  143. package/dist/web/standalone/.next/build-manifest.json +3 -3
  144. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  145. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  146. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  147. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  148. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  149. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  150. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  151. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  152. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  153. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  154. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  155. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  156. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  157. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  158. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  159. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  160. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  161. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  162. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
  164. package/dist/web/standalone/.next/server/app/index.html +1 -1
  165. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  166. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  167. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  168. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  169. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  170. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  171. package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
  172. package/dist/web/standalone/.next/server/chunks/8357.js +2 -2
  173. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  174. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  175. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  176. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  177. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  178. package/dist/web/standalone/.next/static/chunks/{796.cf859a427a2cb2ac.js → 796.e0bdc932325d7e03.js} +1 -1
  179. package/dist/web/standalone/.next/static/chunks/{webpack-fbea77b5f9953368.js → webpack-f0285ce91d4ec9ef.js} +1 -1
  180. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  181. package/dist/web/standalone/package.json +1 -1
  182. package/package.json +1 -1
  183. package/packages/cloud-mcp-gateway/package.json +2 -2
  184. package/packages/contracts/dist/rpc.d.ts +1 -0
  185. package/packages/contracts/dist/rpc.d.ts.map +1 -1
  186. package/packages/contracts/dist/rpc.js.map +1 -1
  187. package/packages/contracts/package.json +1 -1
  188. package/packages/daemon/package.json +4 -4
  189. package/packages/gsd-agent-core/package.json +5 -5
  190. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +5 -0
  191. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  192. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +5 -0
  193. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  194. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  195. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +7 -0
  196. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  197. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  198. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +8 -1
  199. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  200. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
  201. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +11 -1
  202. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
  203. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts.map +1 -1
  204. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js +4 -4
  205. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js.map +1 -1
  206. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  207. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js +3 -1
  208. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js.map +1 -1
  209. package/packages/gsd-agent-modes/package.json +7 -7
  210. package/packages/mcp-server/dist/cli.js +10 -5
  211. package/packages/mcp-server/dist/cli.js.map +1 -1
  212. package/packages/mcp-server/dist/moonshot-tool-schema.d.ts +29 -0
  213. package/packages/mcp-server/dist/moonshot-tool-schema.d.ts.map +1 -0
  214. package/packages/mcp-server/dist/moonshot-tool-schema.js +50 -0
  215. package/packages/mcp-server/dist/moonshot-tool-schema.js.map +1 -0
  216. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  217. package/packages/mcp-server/dist/server.js +4 -0
  218. package/packages/mcp-server/dist/server.js.map +1 -1
  219. package/packages/mcp-server/dist/workflow-tools.d.ts +18 -18
  220. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  221. package/packages/mcp-server/dist/workflow-tools.js +99 -38
  222. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  223. package/packages/mcp-server/package.json +5 -4
  224. package/packages/native/package.json +1 -1
  225. package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts +1 -0
  226. package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts.map +1 -1
  227. package/packages/pi-agent-core/dist/harness/env/nodejs.js +34 -3
  228. package/packages/pi-agent-core/dist/harness/env/nodejs.js.map +1 -1
  229. package/packages/pi-agent-core/dist/index.d.ts +1 -0
  230. package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
  231. package/packages/pi-agent-core/dist/index.js +3 -0
  232. package/packages/pi-agent-core/dist/index.js.map +1 -1
  233. package/packages/pi-agent-core/package.json +1 -1
  234. package/packages/pi-ai/README.md +1 -0
  235. package/packages/pi-ai/dist/image-models.generated.d.ts +2 -2
  236. package/packages/pi-ai/dist/image-models.generated.js +6 -6
  237. package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
  238. package/packages/pi-ai/dist/index.d.ts +2 -0
  239. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  240. package/packages/pi-ai/dist/index.js +2 -0
  241. package/packages/pi-ai/dist/index.js.map +1 -1
  242. package/packages/pi-ai/dist/models.generated.d.ts +239 -153
  243. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  244. package/packages/pi-ai/dist/models.generated.js +256 -145
  245. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  246. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  247. package/packages/pi-ai/dist/providers/anthropic.js +12 -7
  248. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  249. package/packages/pi-ai/dist/providers/google-shared.d.ts +5 -0
  250. package/packages/pi-ai/dist/providers/google-shared.d.ts.map +1 -1
  251. package/packages/pi-ai/dist/providers/google-shared.js +12 -3
  252. package/packages/pi-ai/dist/providers/google-shared.js.map +1 -1
  253. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  254. package/packages/pi-ai/dist/providers/openai-completions.js +7 -3
  255. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  256. package/packages/pi-ai/dist/utils/moonshot-tool-schema.d.ts +9 -0
  257. package/packages/pi-ai/dist/utils/moonshot-tool-schema.d.ts.map +1 -0
  258. package/packages/pi-ai/dist/utils/moonshot-tool-schema.js +34 -0
  259. package/packages/pi-ai/dist/utils/moonshot-tool-schema.js.map +1 -0
  260. package/packages/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
  261. package/packages/pi-ai/dist/utils/oauth/github-copilot.js +6 -2
  262. package/packages/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
  263. package/packages/pi-ai/package.json +3 -2
  264. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +2 -2
  265. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  266. package/packages/pi-coding-agent/dist/core/auth-storage.js +19 -13
  267. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  268. package/packages/pi-coding-agent/dist/core/provider-readiness.d.ts.map +1 -1
  269. package/packages/pi-coding-agent/dist/core/provider-readiness.js +13 -6
  270. package/packages/pi-coding-agent/dist/core/provider-readiness.js.map +1 -1
  271. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +11 -0
  272. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
  273. package/packages/pi-coding-agent/dist/core/tools/bash.js +53 -11
  274. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  275. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  276. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  277. package/packages/pi-coding-agent/dist/index.js +1 -1
  278. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  279. package/packages/pi-coding-agent/dist/utils/shell.d.ts +28 -2
  280. package/packages/pi-coding-agent/dist/utils/shell.d.ts.map +1 -1
  281. package/packages/pi-coding-agent/dist/utils/shell.js +56 -10
  282. package/packages/pi-coding-agent/dist/utils/shell.js.map +1 -1
  283. package/packages/pi-coding-agent/package.json +7 -7
  284. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  285. package/packages/pi-tui/dist/tui.js +9 -0
  286. package/packages/pi-tui/dist/tui.js.map +1 -1
  287. package/packages/pi-tui/package.json +2 -2
  288. package/packages/rpc-client/package.json +2 -2
  289. package/pkg/package.json +1 -1
  290. package/src/resources/GSD-WORKFLOW.md +5 -4
  291. package/src/resources/extensions/async-jobs/async-bash-cancel.test.ts +360 -0
  292. package/src/resources/extensions/async-jobs/async-bash-tool.ts +33 -56
  293. package/src/resources/extensions/async-jobs/await-tool.test.ts +139 -0
  294. package/src/resources/extensions/async-jobs/await-tool.ts +82 -12
  295. package/src/resources/extensions/async-jobs/index.ts +79 -0
  296. package/src/resources/extensions/async-jobs/job-manager.ts +21 -1
  297. package/src/resources/extensions/bg-shell/bg-shell-command.ts +6 -6
  298. package/src/resources/extensions/bg-shell/bg-shell-tool.ts +10 -6
  299. package/src/resources/extensions/bg-shell/overlay.ts +9 -5
  300. package/src/resources/extensions/bg-shell/process-manager.ts +50 -25
  301. package/src/resources/extensions/bg-shell/readiness-detector.ts +12 -0
  302. package/src/resources/extensions/bg-shell/tests/lifecycle-and-utilities.test.ts +48 -1
  303. package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +265 -98
  304. package/src/resources/extensions/browser-tools/engine/selection.ts +90 -4
  305. package/src/resources/extensions/browser-tools/index.ts +71 -13
  306. package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +83 -13
  307. package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +40 -1
  308. package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +136 -0
  309. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +3 -2
  310. package/src/resources/extensions/gsd/auto/custom-verify-retry-store.ts +21 -3
  311. package/src/resources/extensions/gsd/auto/detect-stuck.ts +32 -9
  312. package/src/resources/extensions/gsd/auto/dispatch-history.ts +152 -0
  313. package/src/resources/extensions/gsd/auto/dispatch-key.ts +39 -0
  314. package/src/resources/extensions/gsd/auto/loop.ts +4 -1
  315. package/src/resources/extensions/gsd/auto/orchestrator.ts +98 -56
  316. package/src/resources/extensions/gsd/auto/phases.ts +65 -26
  317. package/src/resources/extensions/gsd/auto/session.ts +3 -0
  318. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +18 -48
  319. package/src/resources/extensions/gsd/auto-dispatch.ts +48 -61
  320. package/src/resources/extensions/gsd/auto-model-selection.ts +41 -12
  321. package/src/resources/extensions/gsd/auto-post-unit.ts +33 -12
  322. package/src/resources/extensions/gsd/auto-prompts.ts +115 -35
  323. package/src/resources/extensions/gsd/auto-start.ts +12 -14
  324. package/src/resources/extensions/gsd/auto-unit-closeout.ts +83 -28
  325. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +4 -4
  326. package/src/resources/extensions/gsd/auto-verification.ts +26 -28
  327. package/src/resources/extensions/gsd/auto-worktree.ts +14 -1
  328. package/src/resources/extensions/gsd/auto.ts +44 -1
  329. package/src/resources/extensions/gsd/blocked-models.ts +49 -0
  330. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +34 -5
  331. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +23 -6
  332. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +2 -2
  333. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +24 -0
  334. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +211 -59
  335. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +350 -86
  336. package/src/resources/extensions/gsd/browser-daemon-auto-prep.ts +108 -0
  337. package/src/resources/extensions/gsd/browser-evidence.ts +18 -2
  338. package/src/resources/extensions/gsd/closeout-wizard.ts +102 -0
  339. package/src/resources/extensions/gsd/commands/context.ts +16 -2
  340. package/src/resources/extensions/gsd/commands-handlers.ts +46 -3
  341. package/src/resources/extensions/gsd/consent-question.ts +431 -0
  342. package/src/resources/extensions/gsd/consent-verdict.ts +86 -0
  343. package/src/resources/extensions/gsd/constants.ts +0 -3
  344. package/src/resources/extensions/gsd/crash-recovery.ts +10 -2
  345. package/src/resources/extensions/gsd/db/queries.ts +37 -0
  346. package/src/resources/extensions/gsd/dispatch-guard.ts +8 -31
  347. package/src/resources/extensions/gsd/doctor-engine-checks.ts +5 -4
  348. package/src/resources/extensions/gsd/doctor-git-checks.ts +2 -19
  349. package/src/resources/extensions/gsd/engine-hook-contract.ts +79 -0
  350. package/src/resources/extensions/gsd/exec-sandbox.ts +49 -9
  351. package/src/resources/extensions/gsd/files.ts +33 -12
  352. package/src/resources/extensions/gsd/gsd-command-home.ts +13 -3
  353. package/src/resources/extensions/gsd/gsd-db.ts +4 -3
  354. package/src/resources/extensions/gsd/guidance.ts +78 -0
  355. package/src/resources/extensions/gsd/guided-flow.ts +21 -26
  356. package/src/resources/extensions/gsd/markdown-renderer.ts +11 -0
  357. package/src/resources/extensions/gsd/mcp-filter.ts +2 -23
  358. package/src/resources/extensions/gsd/milestone-closeout.ts +109 -24
  359. package/src/resources/extensions/gsd/milestone-planning-persistence.ts +2 -2
  360. package/src/resources/extensions/gsd/milestone-reopen-events.ts +3 -6
  361. package/src/resources/extensions/gsd/parsers-legacy.ts +16 -4
  362. package/src/resources/extensions/gsd/preferences-models.ts +2 -1
  363. package/src/resources/extensions/gsd/projection-flush.ts +20 -0
  364. package/src/resources/extensions/gsd/prompts/complete-slice.md +3 -3
  365. package/src/resources/extensions/gsd/prompts/execute-task.md +1 -1
  366. package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  367. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  368. package/src/resources/extensions/gsd/prompts/quick-task.md +1 -1
  369. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  370. package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  371. package/src/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  372. package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
  373. package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
  374. package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  375. package/src/resources/extensions/gsd/prompts/run-uat.md +7 -5
  376. package/src/resources/extensions/gsd/prompts/system.md +5 -2
  377. package/src/resources/extensions/gsd/prompts/triage-captures.md +1 -1
  378. package/src/resources/extensions/gsd/prompts/validate-milestone.md +1 -1
  379. package/src/resources/extensions/gsd/reactive-graph.ts +11 -1
  380. package/src/resources/extensions/gsd/roadmap-slices.ts +28 -3
  381. package/src/resources/extensions/gsd/safety/destructive-confirmation.ts +134 -0
  382. package/src/resources/extensions/gsd/session-lock.ts +1 -1
  383. package/src/resources/extensions/gsd/state.ts +5 -0
  384. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +97 -1
  385. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +198 -26
  386. package/src/resources/extensions/gsd/tests/auto-remote-session-lock-cleanup.test.ts +65 -3
  387. package/src/resources/extensions/gsd/tests/blocked-models.test.ts +19 -0
  388. package/src/resources/extensions/gsd/tests/browser-automation-contract-fixture.ts +39 -0
  389. package/src/resources/extensions/gsd/tests/browser-contract.test.ts +44 -0
  390. package/src/resources/extensions/gsd/tests/browser-daemon-auto-prep.test.ts +144 -0
  391. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +42 -0
  392. package/src/resources/extensions/gsd/tests/consent-question.test.ts +351 -0
  393. package/src/resources/extensions/gsd/tests/custom-verify-retry-store.test.ts +67 -0
  394. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +10 -10
  395. package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +303 -0
  396. package/src/resources/extensions/gsd/tests/discuss-routing-fixes.test.ts +12 -2
  397. package/src/resources/extensions/gsd/tests/dispatch-history.test.ts +273 -0
  398. package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +2 -1
  399. package/src/resources/extensions/gsd/tests/doctor-git-checks-terminal.test.ts +73 -0
  400. package/src/resources/extensions/gsd/tests/dynamic-bash-no-cap.test.ts +132 -0
  401. package/src/resources/extensions/gsd/tests/engine-hook-contract.test.ts +148 -0
  402. package/src/resources/extensions/gsd/tests/exec-graceful-kill.test.ts +193 -0
  403. package/src/resources/extensions/gsd/tests/exec-tool.test.ts +29 -1
  404. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +35 -1
  405. package/src/resources/extensions/gsd/tests/gsd-command-home.test.ts +120 -0
  406. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +27 -0
  407. package/src/resources/extensions/gsd/tests/guidance.test.ts +23 -0
  408. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +2 -6
  409. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +7 -11
  410. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +20 -58
  411. package/src/resources/extensions/gsd/tests/integration/gsd-integration-fixture.ts +80 -0
  412. package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +199 -0
  413. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +3 -1
  414. package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +95 -4
  415. package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +32 -1
  416. package/src/resources/extensions/gsd/tests/oauth-api-model-routing.test.ts +167 -0
  417. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +18 -0
  418. package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +138 -0
  419. package/src/resources/extensions/gsd/tests/phases-terminal-complete-idempotent.test.ts +242 -0
  420. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +63 -2
  421. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +124 -6
  422. package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +68 -0
  423. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +19 -1
  424. package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +17 -0
  425. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +76 -0
  426. package/src/resources/extensions/gsd/tests/tool-unavailable-retry.test.ts +33 -0
  427. package/src/resources/extensions/gsd/tests/transport-gate-double-complete.test.ts +139 -0
  428. package/src/resources/extensions/gsd/tests/uat-policy.test.ts +112 -29
  429. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +44 -0
  430. package/src/resources/extensions/gsd/tests/uok-audit-unified.test.ts +8 -0
  431. package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +2 -0
  432. package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +44 -1
  433. package/src/resources/extensions/gsd/tests/workflow-events.test.ts +19 -0
  434. package/src/resources/extensions/gsd/tests/workflow-reconcile.test.ts +20 -0
  435. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +273 -38
  436. package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +22 -0
  437. package/src/resources/extensions/gsd/tests/worktree.test.ts +18 -0
  438. package/src/resources/extensions/gsd/tests/write-gate-seam.test.ts +358 -0
  439. package/src/resources/extensions/gsd/tests/write-gate.test.ts +67 -1
  440. package/src/resources/extensions/gsd/tool-contract.ts +38 -3
  441. package/src/resources/extensions/gsd/tool-presentation-plan.ts +4 -4
  442. package/src/resources/extensions/gsd/tools/complete-milestone.ts +3 -2
  443. package/src/resources/extensions/gsd/tools/complete-slice.ts +22 -12
  444. package/src/resources/extensions/gsd/tools/complete-task.ts +3 -2
  445. package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -0
  446. package/src/resources/extensions/gsd/tools/plan-slice.ts +2 -2
  447. package/src/resources/extensions/gsd/tools/plan-task.ts +2 -2
  448. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +2 -2
  449. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +2 -2
  450. package/src/resources/extensions/gsd/tools/reopen-slice.ts +2 -2
  451. package/src/resources/extensions/gsd/tools/reopen-task.ts +2 -2
  452. package/src/resources/extensions/gsd/tools/replan-slice.ts +2 -2
  453. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +81 -2
  454. package/src/resources/extensions/gsd/uat-policy.ts +62 -16
  455. package/src/resources/extensions/gsd/unit-context-composer.ts +99 -0
  456. package/src/resources/extensions/gsd/unit-registry.ts +7 -20
  457. package/src/resources/extensions/gsd/verdict-parser.ts +1 -1
  458. package/src/resources/extensions/gsd/verification-verdict.ts +4 -2
  459. package/src/resources/extensions/gsd/web-app-uat.ts +51 -8
  460. package/src/resources/extensions/gsd/workflow-event-ledger.ts +131 -0
  461. package/src/resources/extensions/gsd/workflow-event-vocabulary.ts +59 -0
  462. package/src/resources/extensions/gsd/workflow-events.ts +12 -20
  463. package/src/resources/extensions/gsd/workflow-reconcile.ts +29 -62
  464. package/src/resources/extensions/gsd/worktree-lifecycle.ts +3 -8
  465. package/src/resources/extensions/gsd/worktree-manager.ts +6 -1
  466. package/src/resources/extensions/gsd/worktree.ts +7 -1
  467. package/src/resources/extensions/search-the-web/native-search.ts +5 -3
  468. package/src/resources/extensions/shared/browser-contract.ts +66 -0
  469. package/src/resources/extensions/shared/gsd-browser-cli.ts +141 -6
  470. package/src/resources/shared/gsd-browser-path-sync.ts +273 -0
  471. package/src/resources/shared/package-manager-detection.ts +1 -1
  472. package/src/resources/shared/package.json +3 -0
  473. package/src/resources/skills/create-skill/SKILL.md +3 -0
  474. package/src/resources/skills/create-skill/references/executable-code.md +1 -1
  475. package/src/resources/skills/create-skill/references/skill-structure.md +1 -0
  476. package/src/resources/skills/create-skill/workflows/add-reference.md +8 -3
  477. package/src/resources/skills/create-skill/workflows/add-script.md +4 -2
  478. package/src/resources/skills/create-skill/workflows/add-template.md +3 -1
  479. package/src/resources/skills/create-skill/workflows/add-workflow.md +8 -3
  480. package/src/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
  481. package/src/resources/skills/create-skill/workflows/verify-skill.md +9 -4
  482. package/src/resources/skills/spike-wrap-up/SKILL.md +9 -9
  483. package/dist/resources/extensions/gsd/user-input-boundary.js +0 -218
  484. package/dist/resources/skills/gsd-browser/SKILL.md +0 -41
  485. package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +0 -173
  486. package/src/resources/extensions/gsd/user-input-boundary.ts +0 -216
  487. package/src/resources/skills/gsd-browser/SKILL.md +0 -41
  488. /package/dist/web/standalone/.next/static/{2p9Rv9pQflAxCBbGVI2vb → yWwBo-w09Y_W-nmeeWFRp}/_buildManifest.js +0 -0
  489. /package/dist/web/standalone/.next/static/{2p9Rv9pQflAxCBbGVI2vb → yWwBo-w09Y_W-nmeeWFRp}/_ssgManifest.js +0 -0
@@ -3,6 +3,11 @@
3
3
  // GSD Extension — State Derivation
4
4
  // DB-authoritative runtime derivation with explicit legacy filesystem fallback.
5
5
  // Pure TypeScript, zero Pi dependencies.
6
+ // Pre-migration fallback ONLY (ADR-017): deriveState must work on projects
7
+ // whose DB does not exist yet (before md-importer runs), so it parses markdown
8
+ // projections when `isDbAvailable()` is false or the DB has no rows. Once the
9
+ // DB is populated, decision reads go through gsd-db queries — these parsers
10
+ // must never be consulted when DB data is present.
6
11
  import { parseRoadmap, parsePlan, } from './parsers-legacy.js';
7
12
  import { parseSummary, loadFile, parseRequirementCounts, parseContextDependsOn, } from './files.js';
8
13
  import { resolveMilestoneFile, resolveSlicePath, resolveSliceFile, resolveTaskFile, resolveTasksDir, resolveGsdRootFile, gsdRoot, } from './paths.js';
@@ -1,8 +1,8 @@
1
1
  // Project/App: gsd-pi
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
- import { getRequiredWorkflowToolsForAutoUnit } from "./workflow-mcp.js";
5
- import { getUnitToolSurfaceContract } from "./unit-tool-contracts.js";
4
+ import { getWorkflowTransportSupportError, } from "./workflow-mcp.js";
5
+ import { getRequiredWorkflowToolsForUnit, getUnitToolSurfaceContract, } from "./unit-tool-contracts.js";
6
6
  import { WHOLE_FILE_OBSERVATION_MAX_BYTES, WHOLE_FILE_OBSERVATION_MAX_LINES, } from "./source-observations.js";
7
7
  export function compileUnitContextContract(unitType) {
8
8
  const manifest = resolveManifest(unitType);
@@ -15,6 +15,17 @@ export function compileUnitContextContract(unitType) {
15
15
  }
16
16
  return { ok: true, contract: buildPromptContextContract(unitType, manifest) };
17
17
  }
18
+ export function getUnitWorkflowDispatchReadinessError(input) {
19
+ return getWorkflowTransportSupportError(input.provider, getRequiredWorkflowToolsForUnit(input.unitType), {
20
+ projectRoot: input.projectRoot,
21
+ env: input.env,
22
+ surface: input.surface,
23
+ unitType: input.unitType,
24
+ authMode: input.authMode,
25
+ baseUrl: input.baseUrl,
26
+ activeTools: input.activeTools,
27
+ });
28
+ }
18
29
  export function compileUnitToolContract(unitType) {
19
30
  const manifest = resolveManifest(unitType);
20
31
  const surfaceContract = getUnitToolSurfaceContract(unitType);
@@ -25,7 +36,7 @@ export function compileUnitToolContract(unitType) {
25
36
  detail: `No Unit manifest is registered for ${unitType}`,
26
37
  };
27
38
  }
28
- const requiredWorkflowTools = getRequiredWorkflowToolsForAutoUnit(unitType);
39
+ const requiredWorkflowTools = getRequiredWorkflowToolsForUnit(unitType);
29
40
  const forbiddenWorkflowTools = Object.entries(surfaceContract?.forbiddenGsdTools ?? {})
30
41
  .map(([name, reason]) => ({ name, reason }));
31
42
  const closeoutTools = requiredWorkflowTools.filter((tool) => /^gsd_(?:task|slice|milestone|complete|validate|save|summary|uat)/.test(tool));
@@ -4,7 +4,7 @@ import { RUN_UAT_BROWSER_TOOL_NAMES, RUN_UAT_READ_ONLY_TOOL_NAMES, RUN_UAT_TOOL_
4
4
  import { toMcpToolName } from "./mcp-tool-name.js";
5
5
  import { createToolSurfaceSnapshot } from "./tool-surface-snapshot.js";
6
6
  import { uatTypeIncludesBrowser } from "./uat-policy.js";
7
- import { canonicalWorkflowSurfaceToolName } from "./workflow-tool-surface.js";
7
+ import { canonicalWorkflowToolName } from "./engine-hook-contract.js";
8
8
  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";
9
9
  export const RUN_UAT_FORBIDDEN_TOOL_NAMES = [
10
10
  "edit",
@@ -24,9 +24,9 @@ export const RUN_UAT_CLAUDE_NATIVE_TOOL_NAMES = [
24
24
  "Glob",
25
25
  "Grep",
26
26
  ];
27
- export function canonicalWorkflowToolName(toolName) {
28
- return canonicalWorkflowSurfaceToolName(toolName);
29
- }
27
+ // Normalizer seam lives in engine-hook-contract.ts; re-exported here for
28
+ // existing presentation importers (uat-run.ts).
29
+ export { canonicalWorkflowToolName };
30
30
  export { parseMcpToolName } from "./mcp-tool-name.js";
31
31
  export function toWorkflowMcpToolName(serverName, toolName) {
32
32
  return toMcpToolName(serverName, canonicalWorkflowToolName(toolName));
@@ -16,7 +16,8 @@ import { resolveCanonicalMilestoneRoot } from "../worktree-manager.js";
16
16
  import { isClosedStatus } from "../status-guards.js";
17
17
  import { saveFile, clearParseCache } from "../files.js";
18
18
  import { invalidateStateCache } from "../state.js";
19
- import { renderAllProjections, stripIdPrefix } from "../workflow-projections.js";
19
+ import { stripIdPrefix } from "../workflow-projections.js";
20
+ import { flushWorkflowProjections } from "../projection-flush.js";
20
21
  import { writeManifest } from "../workflow-manifest.js";
21
22
  import { appendEvent } from "../workflow-events.js";
22
23
  import { logWarning, logError } from "../workflow-logger.js";
@@ -166,7 +167,7 @@ export async function handleCompleteMilestone(params, basePath) {
166
167
  // Separate try/catch per step so a projection failure doesn't prevent
167
168
  // the event log entry (critical for worktree reconciliation).
168
169
  try {
169
- await renderAllProjections(artifactBasePath, params.milestoneId);
170
+ await flushWorkflowProjections(artifactBasePath, { milestoneId: params.milestoneId });
170
171
  }
171
172
  catch (projErr) {
172
173
  logWarning("tool", `complete-milestone projection warning: ${projErr.message}`);
@@ -17,12 +17,11 @@ import { gsdProjectionRoot, clearPathCache, resolveMilestoneFile } from "../path
17
17
  import { resolveCanonicalMilestoneRoot } from "../worktree-manager.js";
18
18
  import { checkOwnership, sliceUnitKey } from "../unit-ownership.js";
19
19
  import { saveFile, clearParseCache } from "../files.js";
20
- import { getDeclaredUatType, shouldEscalateArtifactUatToBrowser } from "../uat-policy.js";
20
+ import { classifyUatContent, escalatesArtifactUatToBrowser } from "../uat-policy.js";
21
21
  import { invalidateStateCache } from "../state.js";
22
- import { renderRoadmapFromDb } from "../markdown-renderer.js";
23
- import { parseRoadmap } from "../parsers-legacy.js";
22
+ import { renderRoadmapFromDb, roadmapRenderMarksSliceDone } from "../markdown-renderer.js";
24
23
  import { isStaleWrite } from "../auto/turn-epoch.js";
25
- import { renderAllProjections } from "../workflow-projections.js";
24
+ import { flushWorkflowProjections } from "../projection-flush.js";
26
25
  import { writeManifest } from "../workflow-manifest.js";
27
26
  import { appendEvent } from "../workflow-events.js";
28
27
  import { logWarning, logError } from "../workflow-logger.js";
@@ -55,9 +54,11 @@ function hasCompleteSliceArtifactContract(basePath, milestoneId, sliceId) {
55
54
  join(gsdProjectionRoot(basePath), "milestones", milestoneId, `${milestoneId}-ROADMAP.md`);
56
55
  if (!existsSync(roadmapPath))
57
56
  return false;
57
+ // Projection-completeness check (ADR-017): the DB has already recorded the
58
+ // duplicate completion; this only verifies the rendered markdown artifacts
59
+ // exist and reflect it, deciding whether re-rendering is needed.
58
60
  try {
59
- const roadmap = parseRoadmap(readFileSync(roadmapPath, "utf-8"));
60
- return roadmap.slices.some((slice) => slice.id === sliceId && slice.done);
61
+ return roadmapRenderMarksSliceDone(readFileSync(roadmapPath, "utf-8"), sliceId);
61
62
  }
62
63
  catch {
63
64
  return false;
@@ -288,10 +289,18 @@ export async function handleCompleteSlice(params, basePath) {
288
289
  // `npx playwright test` via gsd_uat_exec, and live-runtime/mixed/
289
290
  // browser-executable receive browser tools (UAT_MODE_POLICIES).
290
291
  const uatContent = params.uatContent || "";
291
- const declaredUatMode = getDeclaredUatType(uatContent);
292
- if (shouldEscalateArtifactUatToBrowser(uatContent)) {
292
+ const uatPolicy = classifyUatContent(uatContent);
293
+ if (escalatesArtifactUatToBrowser(uatPolicy)) {
294
+ // Distinguish an explicit artifact-driven declaration from a missing or
295
+ // unparseable one that merely *defaulted* to artifact-driven — telling an
296
+ // agent it "declared artifact-driven" when its declaration simply failed
297
+ // to parse sends it into a rewrite loop with the same unparseable format.
298
+ const staticOnlyClause = `which only runs static/file checks and would defer the browser work to a human`;
299
+ const modeClause = uatPolicy.modeDeclared
300
+ ? `declares "UAT mode: artifact-driven", ${staticOnlyClause}`
301
+ : `has no parseable UAT mode declaration in its "## UAT Type" section (the declaration must be a bullet exactly like "- UAT mode: browser-executable"), so it defaults to "artifact-driven", ${staticOnlyClause}`;
293
302
  return {
294
- error: `UAT requires browser verification (opening a page in a browser, navigating to a page or localhost, screenshots) but declares "UAT mode: artifact-driven", which only runs static/file checks and would defer the browser work to a human. Use a mode that actually verifies the UI: "browser-executable" (interactive browser tools), "runtime-executable" (a browser test command such as playwright), or a browser-inclusive "mixed"/"live-runtime". Re-author the UAT Type section and complete the slice again.`,
303
+ error: `UAT requires browser verification (opening a page in a browser, navigating to a page or localhost, screenshots) but ${modeClause}. Use a mode that actually verifies the UI: "browser-executable" (interactive browser tools), "runtime-executable" (a browser test command such as playwright), or a browser-inclusive "mixed"/"live-runtime". Re-author the UAT Type section and complete the slice again.`,
295
304
  };
296
305
  }
297
306
  // ── Atomic completion cascade (guards + writes in one transaction) ───────
@@ -388,8 +397,9 @@ export async function handleCompleteSlice(params, basePath) {
388
397
  await saveFile(uatPath, uatMd);
389
398
  const roadmap = await renderRoadmapFromDb(artifactBasePath, params.milestoneId);
390
399
  clearParseCache();
391
- const roadmapSlice = parseRoadmap(roadmap.content).slices.find((slice) => slice.id === params.sliceId);
392
- if (!roadmapSlice?.done) {
400
+ // Render verification (ADR-017): confirms the just-written projection
401
+ // reflects the DB completion; the DB row is already committed.
402
+ if (!roadmapRenderMarksSliceDone(roadmap.content, params.sliceId)) {
393
403
  throw new Error(`roadmap render did not mark ${params.milestoneId}/${params.sliceId} complete`);
394
404
  }
395
405
  }
@@ -438,7 +448,7 @@ export async function handleCompleteSlice(params, basePath) {
438
448
  // Separate try/catch per step so a projection failure doesn't prevent
439
449
  // the event log entry (critical for worktree reconciliation).
440
450
  try {
441
- await renderAllProjections(artifactBasePath, params.milestoneId);
451
+ await flushWorkflowProjections(artifactBasePath, { milestoneId: params.milestoneId });
442
452
  }
443
453
  catch (projErr) {
444
454
  logWarning("tool", `complete-slice projection warning for ${params.milestoneId}/${params.sliceId}: ${projErr.message}`);
@@ -18,7 +18,8 @@ import { checkOwnership, taskUnitKey } from "../unit-ownership.js";
18
18
  import { saveFile, clearParseCache } from "../files.js";
19
19
  import { invalidateStateCache } from "../state.js";
20
20
  import { renderPlanCheckboxes } from "../markdown-renderer.js";
21
- import { renderAllProjections, renderSummaryContent } from "../workflow-projections.js";
21
+ import { renderSummaryContent } from "../workflow-projections.js";
22
+ import { flushWorkflowProjections } from "../projection-flush.js";
22
23
  import { writeManifest } from "../workflow-manifest.js";
23
24
  import { appendEvent } from "../workflow-events.js";
24
25
  import { logWarning, logError } from "../workflow-logger.js";
@@ -358,7 +359,7 @@ export async function handleCompleteTask(params, basePath) {
358
359
  // Separate try/catch per step so a projection failure doesn't prevent
359
360
  // the event log entry (critical for worktree reconciliation).
360
361
  try {
361
- await renderAllProjections(artifactBasePath, params.milestoneId);
362
+ await flushWorkflowProjections(artifactBasePath, { milestoneId: params.milestoneId });
362
363
  }
363
364
  catch (projErr) {
364
365
  logWarning("tool", `complete-task projection warning: ${projErr.message}`);
@@ -342,6 +342,7 @@ function formatResult(result) {
342
342
  exit_code: result.exit_code,
343
343
  signal: result.signal,
344
344
  timed_out: result.timed_out,
345
+ force_resolved: result.force_resolved,
345
346
  duration_ms: result.duration_ms,
346
347
  stdout_bytes: result.stdout_bytes,
347
348
  stderr_bytes: result.stderr_bytes,
@@ -355,6 +356,10 @@ function formatResult(result) {
355
356
  };
356
357
  }
357
358
  function formatExit(result) {
359
+ // force_resolved means a non-closing (D-state) child was force-resolved past its
360
+ // hard deadline rather than observed exiting; distinguish it from a clean timeout.
361
+ if (result.force_resolved)
362
+ return "timeout(force-killed)";
358
363
  if (result.timed_out)
359
364
  return "timeout";
360
365
  if (result.signal)
@@ -7,7 +7,7 @@ import { getGateIdsForTurn } from "../gate-registry.js";
7
7
  import { transaction, getMilestone, getSlice, getSliceTasks, insertTask, upsertSlicePlanning, upsertTaskPlanning, insertGateRow, updateSliceStatus, setSliceSketchFlag, deleteTask, deleteArtifactByPath, } from "../gsd-db.js";
8
8
  import { invalidateStateCache } from "../state.js";
9
9
  import { renderPlanFromDb } from "../markdown-renderer.js";
10
- import { renderAllProjections } from "../workflow-projections.js";
10
+ import { flushWorkflowProjections } from "../projection-flush.js";
11
11
  import { writeManifest } from "../workflow-manifest.js";
12
12
  import { appendEvent } from "../workflow-events.js";
13
13
  import { logWarning } from "../workflow-logger.js";
@@ -367,7 +367,7 @@ export async function handlePlanSlice(rawParams, basePath) {
367
367
  clearParseCache();
368
368
  // ── Post-mutation hook: projections, manifest, event log ─────────────
369
369
  try {
370
- await renderAllProjections(basePath, params.milestoneId);
370
+ await flushWorkflowProjections(basePath, { milestoneId: params.milestoneId });
371
371
  writeManifest(basePath);
372
372
  appendEvent(basePath, {
373
373
  cmd: "plan-slice",
@@ -4,7 +4,7 @@ import { isNonEmptyString, validateStringArray } from "../validation.js";
4
4
  import { transaction, getSlice, getTask, insertTask, upsertTaskPlanning } from "../gsd-db.js";
5
5
  import { invalidateStateCache } from "../state.js";
6
6
  import { renderTaskPlanFromDb } from "../markdown-renderer.js";
7
- import { renderAllProjections } from "../workflow-projections.js";
7
+ import { flushWorkflowProjections } from "../projection-flush.js";
8
8
  import { writeManifest } from "../workflow-manifest.js";
9
9
  import { appendEvent } from "../workflow-events.js";
10
10
  import { logWarning } from "../workflow-logger.js";
@@ -110,7 +110,7 @@ export async function handlePlanTask(rawParams, basePath) {
110
110
  clearParseCache();
111
111
  // ── Post-mutation hook: projections, manifest, event log ─────────────
112
112
  try {
113
- await renderAllProjections(basePath, params.milestoneId);
113
+ await flushWorkflowProjections(basePath, { milestoneId: params.milestoneId });
114
114
  writeManifest(basePath);
115
115
  appendEvent(basePath, {
116
116
  cmd: "plan-task",
@@ -6,7 +6,7 @@ import { isNonEmptyString } from "../validation.js";
6
6
  import { transaction, getMilestone, getMilestoneSlices, getSlice, insertSlice, updateSliceFields, insertAssessment, deleteAssessmentByScope, deleteSlice, } from "../gsd-db.js";
7
7
  import { invalidateStateCache } from "../state.js";
8
8
  import { renderRoadmapFromDb, renderAssessmentFromDb } from "../markdown-renderer.js";
9
- import { renderAllProjections } from "../workflow-projections.js";
9
+ import { flushWorkflowProjections } from "../projection-flush.js";
10
10
  import { writeManifest } from "../workflow-manifest.js";
11
11
  import { appendEvent } from "../workflow-events.js";
12
12
  import { logWarning } from "../workflow-logger.js";
@@ -234,7 +234,7 @@ export async function handleReassessRoadmap(rawParams, basePath) {
234
234
  clearParseCache();
235
235
  // ── Post-mutation hook: projections, manifest, event log ─────
236
236
  try {
237
- await renderAllProjections(basePath, params.milestoneId);
237
+ await flushWorkflowProjections(basePath, { milestoneId: params.milestoneId });
238
238
  writeManifest(basePath);
239
239
  appendEvent(basePath, {
240
240
  cmd: "reassess-roadmap",
@@ -9,7 +9,7 @@
9
9
  */
10
10
  import { getMilestoneSlices, getSliceTasks, reopenMilestoneCascade, } from "../gsd-db.js";
11
11
  import { invalidateStateCache } from "../state.js";
12
- import { renderAllProjections } from "../workflow-projections.js";
12
+ import { flushWorkflowProjections } from "../projection-flush.js";
13
13
  import { writeManifest } from "../workflow-manifest.js";
14
14
  import { appendEvent } from "../workflow-events.js";
15
15
  import { logWarning } from "../workflow-logger.js";
@@ -74,7 +74,7 @@ export async function handleReopenMilestone(params, basePath) {
74
74
  clearPathCache();
75
75
  // ── Post-mutation hook ───────────────────────────────────────────────────
76
76
  try {
77
- await renderAllProjections(basePath, params.milestoneId);
77
+ await flushWorkflowProjections(basePath, { milestoneId: params.milestoneId });
78
78
  writeManifest(basePath);
79
79
  appendEvent(basePath, {
80
80
  cmd: "reopen-milestone",
@@ -11,7 +11,7 @@
11
11
  // Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
12
12
  import { getSliceTasks, reopenSliceCascade, } from "../gsd-db.js";
13
13
  import { invalidateStateCache } from "../state.js";
14
- import { renderAllProjections } from "../workflow-projections.js";
14
+ import { flushWorkflowProjections } from "../projection-flush.js";
15
15
  import { writeManifest } from "../workflow-manifest.js";
16
16
  import { appendEvent } from "../workflow-events.js";
17
17
  import { logWarning } from "../workflow-logger.js";
@@ -72,7 +72,7 @@ export async function handleReopenSlice(params, basePath) {
72
72
  clearPathCache();
73
73
  // ── Post-mutation hook ───────────────────────────────────────────────────
74
74
  try {
75
- await renderAllProjections(basePath, params.milestoneId);
75
+ await flushWorkflowProjections(basePath, { milestoneId: params.milestoneId });
76
76
  writeManifest(basePath);
77
77
  appendEvent(basePath, {
78
78
  cmd: "reopen-slice",
@@ -11,7 +11,7 @@
11
11
  import { getMilestone, getSlice, getTask, updateTaskStatus, transaction, } from "../gsd-db.js";
12
12
  import { invalidateStateCache } from "../state.js";
13
13
  import { isClosedStatus } from "../status-guards.js";
14
- import { renderAllProjections } from "../workflow-projections.js";
14
+ import { flushWorkflowProjections } from "../projection-flush.js";
15
15
  import { writeManifest } from "../workflow-manifest.js";
16
16
  import { appendEvent } from "../workflow-events.js";
17
17
  import { logWarning } from "../workflow-logger.js";
@@ -83,7 +83,7 @@ export async function handleReopenTask(params, basePath) {
83
83
  clearPathCache();
84
84
  // ── Post-mutation hook ───────────────────────────────────────────────────
85
85
  try {
86
- await renderAllProjections(basePath, params.milestoneId);
86
+ await flushWorkflowProjections(basePath, { milestoneId: params.milestoneId });
87
87
  writeManifest(basePath);
88
88
  appendEvent(basePath, {
89
89
  cmd: "reopen-task",
@@ -4,7 +4,7 @@ import { invalidateStateCache } from "../state.js";
4
4
  import { isClosedStatus } from "../status-guards.js";
5
5
  import { isNonEmptyString } from "../validation.js";
6
6
  import { renderPlanFromDb, renderReplanFromDb } from "../markdown-renderer.js";
7
- import { renderAllProjections } from "../workflow-projections.js";
7
+ import { flushWorkflowProjections } from "../projection-flush.js";
8
8
  import { writeManifest } from "../workflow-manifest.js";
9
9
  import { appendEvent } from "../workflow-events.js";
10
10
  import { logWarning } from "../workflow-logger.js";
@@ -162,7 +162,7 @@ export async function handleReplanSlice(rawParams, basePath) {
162
162
  clearParseCache();
163
163
  // ── Post-mutation hook: projections, manifest, event log ─────
164
164
  try {
165
- await renderAllProjections(basePath, params.milestoneId);
165
+ await flushWorkflowProjections(basePath, { milestoneId: params.milestoneId });
166
166
  writeManifest(basePath);
167
167
  appendEvent(basePath, {
168
168
  cmd: "replan-slice",
@@ -6,9 +6,10 @@ import { loadWriteGateSnapshot, shouldBlockContextArtifactSaveInSnapshot, should
6
6
  import { getActiveRequirements, getAllMilestones, getMilestone, getSliceStatusSummary, getSliceTaskCounts, insertMilestone, insertAssessment, insertGateRun, readTransaction, saveGateResult, upsertQualityGate, } from "../gsd-db.js";
7
7
  import { GATE_REGISTRY } from "../gate-registry.js";
8
8
  import { generateRequirementsMd, saveArtifactToDb } from "../db-writer.js";
9
- import { clearPathCache, relSliceFile, resolveGsdPathContract, resolveMilestoneFile, resolveSliceFile } from "../paths.js";
9
+ import { clearPathCache, normalizeRealPath, relSliceFile, resolveGsdPathContract, resolveMilestoneFile, resolveSliceFile } from "../paths.js";
10
10
  import { saveFile, clearParseCache } from "../files.js";
11
11
  import { unlinkSync } from "node:fs";
12
+ import { hostname } from "node:os";
12
13
  import { join } from "node:path";
13
14
  import { handleCompleteMilestone } from "./complete-milestone.js";
14
15
  import { handleCompleteTask } from "./complete-task.js";
@@ -25,9 +26,11 @@ import { logError, logWarning } from "../workflow-logger.js";
25
26
  import { invalidateStateCache } from "../state.js";
26
27
  import { loadEffectiveGSDPreferences } from "../preferences.js";
27
28
  import { parseProject } from "../schemas/parsers.js";
28
- import { getAutoRuntimeSnapshot } from "../auto-runtime-state.js";
29
+ import { autoSession, getAutoRuntimeSnapshot, isAutoActive } from "../auto-runtime-state.js";
29
30
  import { renderPlanFromDb } from "../markdown-renderer.js";
30
31
  import { prepareUatRun, saveUatAttemptArtifact, } from "../uat-run.js";
32
+ import { registerAutoWorker, markWorkerStopping, getAutoWorker } from "../db/auto-workers.js";
33
+ import { claimMilestoneLease, releaseMilestoneLease, getMilestoneLease, refreshMilestoneLease, milestoneLeaseTtlSeconds, } from "../db/milestone-leases.js";
31
34
  export const SUPPORTED_SUMMARY_ARTIFACT_TYPES = [
32
35
  "SUMMARY",
33
36
  "RESEARCH",
@@ -61,6 +64,19 @@ function blockIfWrongAutoUnit(requiredUnitType, operation) {
61
64
  isError: true,
62
65
  };
63
66
  }
67
+ function milestoneLeaseConflictResult(milestoneId, byWorker, expiresAt) {
68
+ return {
69
+ content: [{ type: "text", text: `Milestone ${milestoneId} is currently leased by ${byWorker}. Retry after ${expiresAt}.` }],
70
+ details: {
71
+ operation: "plan_milestone",
72
+ error: "milestone_lease_conflict",
73
+ milestoneId,
74
+ byWorker,
75
+ expiresAt,
76
+ },
77
+ isError: true,
78
+ };
79
+ }
64
80
  function registerProjectMilestoneSequence(content) {
65
81
  const parsed = parseProject(content);
66
82
  const registered = [];
@@ -1066,7 +1082,45 @@ export async function executePlanMilestone(params, basePath = process.cwd()) {
1066
1082
  isError: true,
1067
1083
  };
1068
1084
  }
1085
+ let workerId = null;
1086
+ let acquiredToken = null;
1087
+ let leaseRefreshTimer;
1069
1088
  try {
1089
+ // Re-read at the gate so a peer-created milestone is not treated as fresh.
1090
+ const milestoneExists = getMilestone(params.milestoneId) !== null;
1091
+ if (milestoneExists) {
1092
+ const heldLease = getMilestoneLease(params.milestoneId);
1093
+ if (heldLease?.status === "held" && Date.parse(heldLease.expires_at) > Date.now()) {
1094
+ const holder = getAutoWorker(heldLease.worker_id);
1095
+ // Let the one-shot claim path recover stale same-process worker rows.
1096
+ const projectRoot = normalizeRealPath(basePath);
1097
+ const isOurAutoLease = isAutoActive() && heldLease.worker_id === autoSession.workerId;
1098
+ const holderIsOneShotReentrantPeer = !isAutoActive()
1099
+ && !!holder
1100
+ && holder.host === hostname()
1101
+ && holder.pid === process.pid
1102
+ && holder.project_root_realpath === projectRoot;
1103
+ if (holder?.status === "active" && !isOurAutoLease && !holderIsOneShotReentrantPeer) {
1104
+ return milestoneLeaseConflictResult(params.milestoneId, heldLease.worker_id, heldLease.expires_at);
1105
+ }
1106
+ }
1107
+ }
1108
+ // Fresh creation cannot claim a lease because the FK row does not exist.
1109
+ // In-process auto already owns its lease; re-claiming would bump its token.
1110
+ if (!isAutoActive() && milestoneExists) {
1111
+ workerId = registerAutoWorker({ projectRootRealpath: normalizeRealPath(basePath) });
1112
+ const lease = claimMilestoneLease(workerId, params.milestoneId);
1113
+ if (!lease.ok) {
1114
+ return milestoneLeaseConflictResult(params.milestoneId, lease.byWorker, lease.expiresAt);
1115
+ }
1116
+ acquiredToken = lease.token;
1117
+ const leaseRefreshMs = (milestoneLeaseTtlSeconds() / 2) * 1000;
1118
+ leaseRefreshTimer = setInterval(() => {
1119
+ if (acquiredToken !== null && workerId !== null) {
1120
+ refreshMilestoneLease(workerId, params.milestoneId, acquiredToken);
1121
+ }
1122
+ }, leaseRefreshMs);
1123
+ }
1070
1124
  const result = await handlePlanMilestone(params, basePath);
1071
1125
  if ("error" in result) {
1072
1126
  return {
@@ -1093,6 +1147,17 @@ export async function executePlanMilestone(params, basePath = process.cwd()) {
1093
1147
  isError: true,
1094
1148
  };
1095
1149
  }
1150
+ finally {
1151
+ if (leaseRefreshTimer !== undefined) {
1152
+ clearInterval(leaseRefreshTimer);
1153
+ }
1154
+ if (workerId !== null && acquiredToken !== null) {
1155
+ releaseMilestoneLease(workerId, params.milestoneId, acquiredToken);
1156
+ }
1157
+ if (workerId !== null) {
1158
+ markWorkerStopping(workerId);
1159
+ }
1160
+ }
1096
1161
  }
1097
1162
  export async function executePlanSlice(params, basePath = process.cwd()) {
1098
1163
  const dbAvailable = await ensureDbOpen(basePath);
@@ -1,16 +1,10 @@
1
1
  // Project/App: gsd-pi
2
2
  // File Purpose: Central UAT mode policy for dispatch, tool presentation, and result validation.
3
- import { extractUatType } from "./files.js";
3
+ import { hasBrowserContractPrefix } from "../shared/browser-contract.js";
4
+ import { extractUatType, UAT_TYPE_KEYWORDS } from "./files.js";
4
5
  import { hasBrowserRequiredText } from "./browser-evidence.js";
5
6
  import { parseMcpToolName } from "./mcp-tool-name.js";
6
- export const UAT_TYPES = [
7
- "artifact-driven",
8
- "browser-executable",
9
- "runtime-executable",
10
- "live-runtime",
11
- "mixed",
12
- "human-experience",
13
- ];
7
+ export const UAT_TYPES = UAT_TYPE_KEYWORDS;
14
8
  export const UAT_MODE_POLICIES = {
15
9
  "artifact-driven": {
16
10
  browserTools: false,
@@ -55,23 +49,55 @@ export function isUatType(value) {
55
49
  export function getDeclaredUatType(content) {
56
50
  return extractUatType(content) ?? "artifact-driven";
57
51
  }
58
- export function classifyUatContent(content) {
59
- const declaredType = getDeclaredUatType(content);
60
- const browserRequired = hasBrowserRequiredText(content);
61
- const effectiveType = declaredType === "artifact-driven" && browserRequired
52
+ /** Self-contained browser UAT harnesses that manage server lifecycle internally. */
53
+ const SELF_CONTAINED_RUNTIME_UAT_COMMAND_RE = /\b(?:npm run test:uat|node\s+(?:--check\s+\S+\s+&&\s+)*tests\/browser\/search-uat\.mjs|npx playwright test(?:\s+\S+)?)\b/i;
54
+ export function hasSelfContainedRuntimeUatCommand(content) {
55
+ return SELF_CONTAINED_RUNTIME_UAT_COMMAND_RE.test(content);
56
+ }
57
+ function resolveEffectiveUatTypeFromPolicy(declaredType, browserRequired, content) {
58
+ let effectiveType = declaredType === "artifact-driven" && browserRequired
62
59
  ? "browser-executable"
63
60
  : declaredType;
61
+ // M006/S01 regression: specs often declare browser-executable with localhost
62
+ // preconditions while the Evidence section names a runtime harness such as
63
+ // `npm run test:uat`. Interactive browser_* checks then race a fixed port
64
+ // against the script's own ephemeral server — run the harness instead.
65
+ if (effectiveType === "browser-executable" &&
66
+ hasSelfContainedRuntimeUatCommand(content)) {
67
+ effectiveType = "runtime-executable";
68
+ }
69
+ return effectiveType;
70
+ }
71
+ export function classifyUatContent(content) {
72
+ return classifyUatContentForRun(content);
73
+ }
74
+ /**
75
+ * Classify UAT mode for run-uat dispatch. Supplemental context (slice summary,
76
+ * verification excerpts) can name a self-contained harness even when the UAT
77
+ * file only documents a separate server command such as `npm run test:server`.
78
+ */
79
+ export function classifyUatContentForRun(content, supplementalContext = "") {
80
+ const parsedType = extractUatType(content);
81
+ const declaredType = parsedType ?? "artifact-driven";
82
+ const browserRequired = hasBrowserRequiredText(content);
83
+ const combinedForHarness = supplementalContext.trim()
84
+ ? `${content}\n\n${supplementalContext}`
85
+ : content;
86
+ const effectiveType = resolveEffectiveUatTypeFromPolicy(declaredType, browserRequired, combinedForHarness);
64
87
  return {
65
88
  declaredType,
89
+ modeDeclared: parsedType !== undefined,
66
90
  effectiveType,
67
91
  browserRequired,
68
92
  shouldDispatchByDefault: effectiveType !== "artifact-driven" || browserRequired,
69
93
  };
70
94
  }
71
- export function shouldEscalateArtifactUatToBrowser(content) {
72
- const policy = classifyUatContent(content);
95
+ export function escalatesArtifactUatToBrowser(policy) {
73
96
  return policy.declaredType === "artifact-driven" && policy.browserRequired;
74
97
  }
98
+ export function shouldEscalateArtifactUatToBrowser(content) {
99
+ return escalatesArtifactUatToBrowser(classifyUatContent(content));
100
+ }
75
101
  export function resolveEffectiveUatType(content) {
76
102
  return classifyUatContent(content).effectiveType;
77
103
  }
@@ -84,7 +110,7 @@ export function uatTypeIncludesBrowser(uatType) {
84
110
  export function isUatBrowserToolName(toolName) {
85
111
  const parsed = parseMcpToolName(toolName);
86
112
  const canonicalName = parsed?.toolName ?? toolName;
87
- if (canonicalName.startsWith("browser_"))
113
+ if (hasBrowserContractPrefix(canonicalName))
88
114
  return true;
89
115
  return parsed?.toolName === "*" && parsed.serverName.toLowerCase().includes("browser");
90
116
  }
@@ -36,6 +36,7 @@
36
36
  // owned by the unit, not in the composer. Reviews must enforce this — it
37
37
  // is the difference between an orchestrator and a runaway DSL.
38
38
  import { resolveManifest, } from "./unit-context-manifest.js";
39
+ import { getUnitToolSurfaceContract } from "./unit-tool-contracts.js";
39
40
  /**
40
41
  * Produce the inlined-context portion of a unit's system prompt by
41
42
  * walking the manifest's `artifacts.inline` list in order and calling
@@ -122,6 +123,70 @@ export function composeContextModeInstructions(unitType, opts) {
122
123
  guidance,
123
124
  ].join("\n");
124
125
  }
126
+ const TOOL_SURFACE_GUIDANCE_BY_UNIT = {
127
+ "run-uat": "Do not call `gsd_exec`, `Bash`, `Write`, or `Edit` — they are unavailable in this unit. Run every automated check through `gsd_uat_exec` with the appropriate `intent`. For browser UAT modes, use `browser_*` tools when presented; if browser automation fails, record the failure honestly and use `gsd_uat_exec` for the best objective substitute.",
128
+ "complete-slice": "Run slice-level verification through `gsd_exec` (or MCP-scoped `mcp__…__gsd_exec`), not direct `bash`. Do not call `gsd_uat_result_save` — run-uat owns persisted UAT assessment. On verification failure, do not edit user source files in this unit.",
129
+ "gate-evaluate": "Dispatch only **tester** subagents via `subagent`. Persist each gate with `gsd_save_gate_result`. Do not use `ToolSearch` — it is not available.",
130
+ "reactive-execute": "Dispatch only **worker** subagents via `subagent`. Do not call `gsd_task_complete` from this parent batch — each worker owns its task completion. If a failed task left no summary, call `gsd_summary_save` with `blocker_discovered: true`.",
131
+ "execute-task": "Complete only this task via `gsd_task_complete`. Do not call `gsd_slice_complete`, `gsd_validate_milestone`, or `gsd_complete_milestone` — the orchestrator owns phase transitions.",
132
+ "validate-milestone": "Dispatch reviewer subagents in parallel, then persist the verdict via `gsd_validate_milestone`. Do not query `.gsd/gsd.db` directly — use `gsd_milestone_status` and inlined context.",
133
+ "complete-milestone": "Persist completion only through `gsd_complete_milestone` after verification passes. Do not query `.gsd/gsd.db` directly. Do not write `.gsd/PROJECT.md` or `.gsd/REQUIREMENTS.md` by hand — use `gsd_summary_save` and `gsd_requirement_update`.",
134
+ "replan-slice": "Persist replans through `gsd_replan_slice` only. Do not edit `PLAN.md` or task plans directly.",
135
+ "plan-slice": "Persist planning through `gsd_plan_slice` only. Dispatch subagents only to **scout** or **planner** for reconnaissance — not implementation agents. Do not edit user source files outside `.gsd/**`.",
136
+ "refine-slice": "Persist refinements through `gsd_plan_slice` only. Dispatch subagents only to **scout** or **planner**. Do not edit user source files outside `.gsd/**`.",
137
+ "plan-milestone": "Persist milestone planning through `gsd_plan_milestone` / `gsd_plan_slice`. Do not edit user source files outside `.gsd/**`.",
138
+ "research-slice": "Dispatch subagents only to **scout** or **planner** for reconnaissance. Do not edit user source files outside `.gsd/**`.",
139
+ };
140
+ function guidanceForToolsPolicy(policy) {
141
+ switch (policy.mode) {
142
+ case "planning":
143
+ return "Writes are restricted to `.gsd/**` under the working directory — do not edit user source files. `bash` is limited to read-only investigation commands. Do not dispatch subagents. For human elicitation, use workflow MCP `ask_user_questions` when available — not native `AskUserQuestion`.";
144
+ case "planning-dispatch": {
145
+ const agents = policy.allowedSubagents.map((agent) => `**${agent}**`).join(", ");
146
+ return `Writes are restricted to \`.gsd/**\`. Dispatch subagents only to: ${agents}. Do not edit user source files.`;
147
+ }
148
+ case "docs":
149
+ return "Writes are restricted to `.gsd/**` and project documentation paths (`docs/`, `README*`, `CHANGELOG.md`, root `*.md`). Do not edit application source.";
150
+ case "verification": {
151
+ const subagentLine = policy.allowedSubagents?.length
152
+ ? ` Dispatch subagents only to: ${policy.allowedSubagents.map((agent) => `**${agent}**`).join(", ")}.`
153
+ : " Do not dispatch subagents.";
154
+ return `\`bash\` is limited to build/test verification commands. Writes restricted to \`.gsd/**\`.${subagentLine}`;
155
+ }
156
+ default:
157
+ return null;
158
+ }
159
+ }
160
+ function formatForbiddenWorkflowToolsLine(unitType, unitGuidance) {
161
+ const forbidden = getUnitToolSurfaceContract(unitType)?.forbiddenGsdTools;
162
+ if (!forbidden)
163
+ return null;
164
+ const names = Object.keys(forbidden).filter((name) => !unitGuidance?.includes(`\`${name}\``));
165
+ if (names.length === 0)
166
+ return null;
167
+ return `Do not call ${names.map((name) => `\`${name}\``).join(", ")} in this unit.`;
168
+ }
169
+ /**
170
+ * Render upfront tool-surface guidance for a unit type. Unknown units and
171
+ * unrestricted (`tools.mode: "all"`) units omit the block unless they have
172
+ * unit-specific closeout guidance registered above.
173
+ */
174
+ export function composeToolSurfaceInstructions(unitType, opts) {
175
+ const manifest = resolveManifest(unitType);
176
+ if (!manifest)
177
+ return "";
178
+ const unitGuidance = TOOL_SURFACE_GUIDANCE_BY_UNIT[unitType];
179
+ const policyGuidance = unitGuidance ? null : guidanceForToolsPolicy(manifest.tools);
180
+ const forbiddenLine = formatForbiddenWorkflowToolsLine(unitType, unitGuidance);
181
+ const parts = [unitGuidance, policyGuidance, forbiddenLine].filter((part) => typeof part === "string" && part.length > 0);
182
+ if (parts.length === 0)
183
+ return "";
184
+ const body = parts.join(" ");
185
+ if (opts.renderMode === "nested") {
186
+ return `Tool surface: ${body}`;
187
+ }
188
+ return ["## Tool Surface", "", body].join("\n");
189
+ }
125
190
  const SECTION_SEPARATOR = "\n\n---\n\n";
126
191
  /**
127
192
  * Compose all manifest-declared context for a unit type using the v2