gsd-pi 2.82.0-dev.725028083 → 2.82.0-dev.98ea09b1e

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 (355) hide show
  1. package/README.md +4 -3
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/GSD-WORKFLOW.md +10 -1
  4. package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
  5. package/dist/resources/extensions/cmux/index.js +5 -0
  6. package/dist/resources/extensions/gsd/auto/infra-errors.js +9 -3
  7. package/dist/resources/extensions/gsd/auto/loop.js +5 -5
  8. package/dist/resources/extensions/gsd/auto/orchestrator.js +124 -6
  9. package/dist/resources/extensions/gsd/auto/phases.js +8 -1
  10. package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +12 -0
  11. package/dist/resources/extensions/gsd/auto-dispatch.js +13 -6
  12. package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
  13. package/dist/resources/extensions/gsd/auto-post-unit.js +233 -127
  14. package/dist/resources/extensions/gsd/auto-prompts.js +2 -2
  15. package/dist/resources/extensions/gsd/auto-recovery.js +31 -1
  16. package/dist/resources/extensions/gsd/auto-start.js +85 -12
  17. package/dist/resources/extensions/gsd/auto-verification.js +28 -22
  18. package/dist/resources/extensions/gsd/auto-worktree.js +111 -1
  19. package/dist/resources/extensions/gsd/auto.js +158 -55
  20. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +4 -1
  21. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +9 -8
  22. package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +21 -9
  23. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +16 -2
  24. package/dist/resources/extensions/gsd/clean-root-preflight.js +170 -8
  25. package/dist/resources/extensions/gsd/commands/catalog.js +4 -1
  26. package/dist/resources/extensions/gsd/commands/handlers/core.js +37 -0
  27. package/dist/resources/extensions/gsd/commands-bootstrap.js +5 -0
  28. package/dist/resources/extensions/gsd/crash-recovery.js +31 -5
  29. package/dist/resources/extensions/gsd/db/unit-dispatches.js +3 -2
  30. package/dist/resources/extensions/gsd/dispatch-guard.js +2 -2
  31. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +28 -11
  32. package/dist/resources/extensions/gsd/doctor.js +2 -28
  33. package/dist/resources/extensions/gsd/export-html.js +27 -425
  34. package/dist/resources/extensions/gsd/git-service.js +39 -1
  35. package/dist/resources/extensions/gsd/gsd-db.js +1 -0
  36. package/dist/resources/extensions/gsd/guided-flow.js +13 -6
  37. package/dist/resources/extensions/gsd/md-importer.js +1 -1
  38. package/dist/resources/extensions/gsd/migrate/command.js +5 -0
  39. package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
  40. package/dist/resources/extensions/gsd/migrate/preview.js +9 -0
  41. package/dist/resources/extensions/gsd/migrate/transformer.js +51 -4
  42. package/dist/resources/extensions/gsd/migrate/writer.js +11 -1
  43. package/dist/resources/extensions/gsd/migration-auto-check.js +12 -17
  44. package/dist/resources/extensions/gsd/milestone-actions.js +11 -4
  45. package/dist/resources/extensions/gsd/native-git-bridge.js +48 -12
  46. package/dist/resources/extensions/gsd/post-execution-checks.js +73 -2
  47. package/dist/resources/extensions/gsd/pre-execution-checks.js +28 -1
  48. package/dist/resources/extensions/gsd/prompt-loader.js +1 -1
  49. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  50. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  51. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
  52. package/dist/resources/extensions/gsd/prompts/discuss.md +9 -9
  53. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
  54. package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
  55. package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -4
  56. package/dist/resources/extensions/gsd/prompts/queue.md +4 -4
  57. package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  58. package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  59. package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +6 -1
  60. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +9 -14
  61. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +19 -24
  62. package/dist/resources/extensions/gsd/status-guards.js +4 -0
  63. package/dist/resources/extensions/gsd/templates/plan.md +8 -5
  64. package/dist/resources/extensions/gsd/templates/task-plan.md +4 -2
  65. package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -8
  66. package/dist/resources/extensions/gsd/tools/complete-slice.js +6 -8
  67. package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -1
  68. package/dist/resources/extensions/gsd/tools/plan-slice.js +89 -14
  69. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +119 -0
  70. package/dist/resources/extensions/gsd/unit-context-manifest.js +32 -10
  71. package/dist/resources/extensions/gsd/validation.js +23 -1
  72. package/dist/resources/extensions/gsd/verification-gate.js +68 -7
  73. package/dist/resources/extensions/gsd/verification-verdict.js +26 -0
  74. package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
  75. package/dist/resources/extensions/gsd/worktree-lifecycle.js +54 -10
  76. package/dist/resources/extensions/shared/html-shell.js +388 -0
  77. package/dist/resources/extensions/subagent/index.js +448 -78
  78. package/dist/resources/extensions/subagent/launch.js +77 -0
  79. package/dist/resources/extensions/subagent/run-store.js +148 -0
  80. package/dist/resources/extensions/visual-brief/artifact-policy.js +29 -0
  81. package/dist/resources/extensions/visual-brief/extension-manifest.json +8 -0
  82. package/dist/resources/extensions/visual-brief/index.js +5 -0
  83. package/dist/resources/extensions/visual-brief/page-contract.js +124 -0
  84. package/dist/resources/extensions/visual-brief/prompts.js +140 -0
  85. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  86. package/dist/web/standalone/.next/BUILD_ID +1 -1
  87. package/dist/web/standalone/.next/app-path-routes-manifest.json +14 -14
  88. package/dist/web/standalone/.next/build-manifest.json +3 -3
  89. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  90. package/dist/web/standalone/.next/react-loadable-manifest.json +3 -3
  91. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  101. package/dist/web/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  104. package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -7
  105. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
  106. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -5
  108. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -5
  111. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/index.html +1 -1
  113. package/dist/web/standalone/.next/server/app/index.rsc +4 -7
  114. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -7
  116. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -5
  118. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -5
  119. package/dist/web/standalone/.next/server/app/page.js +2 -2
  120. package/dist/web/standalone/.next/server/app/page.js.nft.json +1 -1
  121. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/app-paths-manifest.json +14 -14
  123. package/dist/web/standalone/.next/server/chunks/4266.js +2 -0
  124. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  126. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  128. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  129. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  130. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  131. package/dist/web/standalone/.next/static/chunks/2973.33f26573894b6153.js +2 -0
  132. package/dist/web/standalone/.next/static/chunks/{8359.e059d86b255fce1c.js → 8359.7eb3bb8f8ecf4c01.js} +2 -2
  133. package/dist/web/standalone/.next/static/chunks/app/layout-8c10ec293ae0f1d5.js +1 -0
  134. package/dist/web/standalone/.next/static/chunks/{webpack-de742b64187e13fe.js → webpack-9a4db269f9ed63ad.js} +1 -1
  135. package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
  136. package/package.json +4 -4
  137. package/packages/contracts/dist/rpc.test.js +7 -0
  138. package/packages/contracts/dist/rpc.test.js.map +1 -1
  139. package/packages/contracts/dist/workflow.d.ts +21 -0
  140. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  141. package/packages/contracts/dist/workflow.js +24 -0
  142. package/packages/contracts/dist/workflow.js.map +1 -1
  143. package/packages/contracts/src/rpc.test.ts +8 -0
  144. package/packages/contracts/src/workflow.ts +24 -0
  145. package/packages/mcp-server/README.md +13 -4
  146. package/packages/mcp-server/dist/workflow-tools.d.ts +0 -3
  147. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  148. package/packages/mcp-server/dist/workflow-tools.js +80 -0
  149. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  150. package/packages/mcp-server/src/workflow-tools.test.ts +23 -1
  151. package/packages/mcp-server/src/workflow-tools.ts +168 -0
  152. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  153. package/packages/native/tsconfig.json +2 -1
  154. package/packages/native/tsconfig.tsbuildinfo +1 -1
  155. package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
  156. package/packages/pi-ai/dist/providers/openai-codex-responses.js +82 -1
  157. package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  158. package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts +2 -0
  159. package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts.map +1 -0
  160. package/packages/pi-ai/dist/providers/openai-codex-responses.test.js +52 -0
  161. package/packages/pi-ai/dist/providers/openai-codex-responses.test.js.map +1 -0
  162. package/packages/pi-ai/dist/providers/simple-options.d.ts +2 -4
  163. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  164. package/packages/pi-ai/dist/providers/simple-options.js +5 -6
  165. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  166. package/packages/pi-ai/dist/providers/simple-options.test.d.ts +2 -0
  167. package/packages/pi-ai/dist/providers/simple-options.test.d.ts.map +1 -0
  168. package/packages/pi-ai/dist/providers/simple-options.test.js +50 -0
  169. package/packages/pi-ai/dist/providers/simple-options.test.js.map +1 -0
  170. package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +63 -0
  171. package/packages/pi-ai/src/providers/openai-codex-responses.ts +91 -1
  172. package/packages/pi-ai/src/providers/simple-options.test.ts +60 -0
  173. package/packages/pi-ai/src/providers/simple-options.ts +5 -6
  174. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  175. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts +2 -0
  176. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts.map +1 -0
  177. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js +66 -0
  178. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js.map +1 -0
  179. package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
  180. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  181. package/packages/pi-coding-agent/src/core/agent-session-thinking-level.test.ts +79 -0
  182. package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
  183. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  184. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  185. package/packages/pi-tui/dist/tui.js +5 -0
  186. package/packages/pi-tui/dist/tui.js.map +1 -1
  187. package/packages/pi-tui/src/tui.ts +6 -0
  188. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  189. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  190. package/src/resources/GSD-WORKFLOW.md +10 -1
  191. package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
  192. package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
  193. package/src/resources/extensions/cmux/index.ts +6 -0
  194. package/src/resources/extensions/gsd/auto/contracts.ts +59 -16
  195. package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
  196. package/src/resources/extensions/gsd/auto/loop.ts +8 -5
  197. package/src/resources/extensions/gsd/auto/orchestrator.ts +129 -6
  198. package/src/resources/extensions/gsd/auto/phases.ts +7 -1
  199. package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +13 -0
  200. package/src/resources/extensions/gsd/auto-dispatch.ts +14 -6
  201. package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
  202. package/src/resources/extensions/gsd/auto-post-unit.ts +266 -139
  203. package/src/resources/extensions/gsd/auto-prompts.ts +2 -2
  204. package/src/resources/extensions/gsd/auto-recovery.ts +29 -0
  205. package/src/resources/extensions/gsd/auto-start.ts +92 -9
  206. package/src/resources/extensions/gsd/auto-verification.ts +36 -34
  207. package/src/resources/extensions/gsd/auto-worktree.ts +119 -1
  208. package/src/resources/extensions/gsd/auto.ts +167 -53
  209. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +6 -1
  210. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +9 -8
  211. package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +19 -7
  212. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +19 -3
  213. package/src/resources/extensions/gsd/clean-root-preflight.ts +174 -8
  214. package/src/resources/extensions/gsd/commands/catalog.ts +4 -1
  215. package/src/resources/extensions/gsd/commands/handlers/core.ts +40 -0
  216. package/src/resources/extensions/gsd/commands-bootstrap.ts +10 -0
  217. package/src/resources/extensions/gsd/crash-recovery.ts +30 -4
  218. package/src/resources/extensions/gsd/db/unit-dispatches.ts +4 -3
  219. package/src/resources/extensions/gsd/dispatch-guard.ts +2 -2
  220. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
  221. package/src/resources/extensions/gsd/doctor.ts +2 -27
  222. package/src/resources/extensions/gsd/export-html.ts +27 -427
  223. package/src/resources/extensions/gsd/git-service.ts +45 -1
  224. package/src/resources/extensions/gsd/gsd-db.ts +3 -0
  225. package/src/resources/extensions/gsd/guided-flow.ts +14 -7
  226. package/src/resources/extensions/gsd/md-importer.ts +1 -1
  227. package/src/resources/extensions/gsd/migrate/command.ts +5 -0
  228. package/src/resources/extensions/gsd/migrate/parsers.ts +11 -0
  229. package/src/resources/extensions/gsd/migrate/preview.ts +10 -0
  230. package/src/resources/extensions/gsd/migrate/transformer.ts +58 -4
  231. package/src/resources/extensions/gsd/migrate/writer.ts +14 -1
  232. package/src/resources/extensions/gsd/migration-auto-check.ts +15 -23
  233. package/src/resources/extensions/gsd/milestone-actions.ts +10 -4
  234. package/src/resources/extensions/gsd/native-git-bridge.ts +54 -12
  235. package/src/resources/extensions/gsd/post-execution-checks.ts +87 -2
  236. package/src/resources/extensions/gsd/pre-execution-checks.ts +32 -1
  237. package/src/resources/extensions/gsd/prompt-loader.ts +1 -1
  238. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  239. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  240. package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
  241. package/src/resources/extensions/gsd/prompts/discuss.md +9 -9
  242. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
  243. package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
  244. package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -4
  245. package/src/resources/extensions/gsd/prompts/queue.md +4 -4
  246. package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  247. package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  248. package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +8 -1
  249. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +12 -15
  250. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +17 -25
  251. package/src/resources/extensions/gsd/status-guards.ts +5 -0
  252. package/src/resources/extensions/gsd/templates/plan.md +8 -5
  253. package/src/resources/extensions/gsd/templates/task-plan.md +4 -2
  254. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +116 -0
  255. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +54 -0
  256. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +487 -4
  257. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +12 -11
  258. package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +12 -1
  259. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +15 -1
  260. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +4 -4
  261. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +1 -0
  262. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
  263. package/src/resources/extensions/gsd/tests/brief-command.test.ts +89 -0
  264. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +107 -2
  265. package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +16 -0
  266. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +4 -1
  267. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +5 -9
  268. package/src/resources/extensions/gsd/tests/complete-task.test.ts +3 -1
  269. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +43 -2
  270. package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
  271. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +59 -2
  272. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +39 -0
  273. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
  274. package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +38 -0
  275. package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
  276. package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +2 -0
  277. package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
  278. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +6 -6
  279. package/src/resources/extensions/gsd/tests/hook-model-resolution.test.ts +5 -0
  280. package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -2
  281. package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +9 -0
  282. package/src/resources/extensions/gsd/tests/integration/doctor-runtime.test.ts +20 -0
  283. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +103 -1
  284. package/src/resources/extensions/gsd/tests/integration/migrate-command.test.ts +48 -3
  285. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
  286. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +5 -1
  287. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -1
  288. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +6 -1
  289. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +26 -18
  290. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +63 -2
  291. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +121 -1
  292. package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +55 -1
  293. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +26 -0
  294. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
  295. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +225 -1
  296. package/src/resources/extensions/gsd/tests/plan-task.test.ts +17 -0
  297. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
  298. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +86 -0
  299. package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
  300. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +53 -0
  301. package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
  302. package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +46 -2
  303. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
  304. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +31 -1
  305. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +6 -0
  306. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +119 -23
  307. package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +64 -1
  308. package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +7 -3
  309. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +86 -7
  310. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
  311. package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +78 -0
  312. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +1 -1
  313. package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +21 -1
  314. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +1 -1
  315. package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +39 -0
  316. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +64 -12
  317. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +25 -0
  318. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +54 -0
  319. package/src/resources/extensions/gsd/tools/complete-milestone.ts +8 -10
  320. package/src/resources/extensions/gsd/tools/complete-slice.ts +6 -8
  321. package/src/resources/extensions/gsd/tools/plan-milestone.ts +5 -1
  322. package/src/resources/extensions/gsd/tools/plan-slice.ts +98 -12
  323. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +135 -0
  324. package/src/resources/extensions/gsd/types.ts +1 -1
  325. package/src/resources/extensions/gsd/unit-context-manifest.ts +47 -11
  326. package/src/resources/extensions/gsd/validation.ts +23 -1
  327. package/src/resources/extensions/gsd/verification-gate.ts +78 -6
  328. package/src/resources/extensions/gsd/verification-verdict.ts +47 -0
  329. package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
  330. package/src/resources/extensions/gsd/worktree-lifecycle.ts +61 -10
  331. package/src/resources/extensions/shared/html-shell.ts +412 -0
  332. package/src/resources/extensions/subagent/index.ts +567 -103
  333. package/src/resources/extensions/subagent/launch.ts +131 -0
  334. package/src/resources/extensions/subagent/run-store.ts +218 -0
  335. package/src/resources/extensions/subagent/tests/launch.test.ts +115 -0
  336. package/src/resources/extensions/subagent/tests/run-store.test.ts +111 -0
  337. package/src/resources/extensions/visual-brief/artifact-policy.ts +41 -0
  338. package/src/resources/extensions/visual-brief/extension-manifest.json +8 -0
  339. package/src/resources/extensions/visual-brief/index.ts +8 -0
  340. package/src/resources/extensions/visual-brief/page-contract.ts +136 -0
  341. package/src/resources/extensions/visual-brief/prompts.ts +183 -0
  342. package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +212 -0
  343. package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
  344. package/dist/web/standalone/.next/static/chunks/2556.0527fea66e123b7f.js +0 -1
  345. package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +0 -1
  346. package/dist/web/standalone/.next/static/css/54ec2745c1da488b.css +0 -1
  347. package/dist/web/standalone/.next/static/css/de70bee13400563f.css +0 -1
  348. package/dist/web/standalone/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
  349. package/dist/web/standalone/.next/static/media/747892c23ea88013-s.woff2 +0 -0
  350. package/dist/web/standalone/.next/static/media/8d697b304b401681-s.woff2 +0 -0
  351. package/dist/web/standalone/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  352. package/dist/web/standalone/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
  353. package/dist/web/standalone/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  354. /package/dist/web/standalone/.next/static/{KDRTXR-22LPCsa80X9dey → euQ0CLP_v8V4e76Tu3odJ}/_buildManifest.js +0 -0
  355. /package/dist/web/standalone/.next/static/{KDRTXR-22LPCsa80X9dey → euQ0CLP_v8V4e76Tu3odJ}/_ssgManifest.js +0 -0
@@ -58,6 +58,7 @@ import {
58
58
  import {
59
59
  writeLock,
60
60
  clearLock,
61
+ clearStaleWorkerLock,
61
62
  readCrashLock,
62
63
  isLockProcessAlive,
63
64
  formatCrashInfo,
@@ -240,12 +241,14 @@ import { runAutoLoopWithUok } from "./uok/kernel.js";
240
241
  import { resolveUokFlags } from "./uok/flags.js";
241
242
  import { validateDirectory } from "./validate-directory.js";
242
243
  import { createAutoOrchestrator } from "./auto/orchestrator.js";
243
- import type { AutoOrchestrationModule, AutoOrchestratorDeps } from "./auto/contracts.js";
244
+ import type { AutoAdvanceResult, AutoOrchestrationModule, AutoOrchestratorDeps, DispatchAdapter } from "./auto/contracts.js";
244
245
  import { reconcileBeforeDispatch } from "./state-reconciliation.js";
245
246
  import { compileUnitToolContract } from "./tool-contract.js";
246
247
  import { createWorktreeSafetyModule } from "./worktree-safety.js";
247
248
  import { resolveManifest } from "./unit-context-manifest.js";
248
249
  import { classifyFailure } from "./recovery-classification.js";
250
+ import { supportsStructuredQuestions } from "./workflow-mcp.js";
251
+ import type { MinimalModelRegistry } from "./context-budget.js";
249
252
  // Slice-level parallelism (#2340)
250
253
  import { getEligibleSlices } from "./slice-parallel-eligibility.js";
251
254
  import { startSliceParallel } from "./slice-parallel-orchestrator.js";
@@ -1042,19 +1045,18 @@ export async function cleanupAfterLoopExit(ctx: ExtensionContext): Promise<void>
1042
1045
  // visible so the user still has a resumable auto-mode signal on screen.
1043
1046
  if (!s.paused) {
1044
1047
  ctx.ui.setStatus("gsd-auto", undefined);
1048
+ ctx.ui.setWidget("gsd-progress", undefined);
1045
1049
  if (s.completionStopInProgress) {
1046
1050
  s.completionStopInProgress = false;
1047
1051
  }
1048
1052
  initHealthWidget(ctx);
1049
1053
  }
1050
1054
 
1051
- // ADR-016 phase 3 (#5693): the stop-path basePath restore routes through
1052
- // `Lifecycle.restoreToProjectRoot()`, the sole owner of `s.basePath`
1053
- // mutation. The verb assigns `s.basePath` before any throwable work
1054
- // (rebuildGitService, cache invalidation), so a thrown error still leaves
1055
- // basePath restored no fallback assignment needed at the call site.
1056
- // The chdir stays here because `restoreToProjectRoot` is a pure
1057
- // session-state mutation.
1055
+ // ADR-016 phase 3 (#5693): the stop-path basePath restore + chdir routes
1056
+ // through `Lifecycle.restoreToProjectRoot()`, the sole owner of both
1057
+ // `s.basePath` mutation and the paired `process.chdir` for auto-loop
1058
+ // transitions. The verb assigns `s.basePath` before any throwable work, so
1059
+ // a thrown error still leaves basePath restored.
1058
1060
  if (s.originalBasePath) {
1059
1061
  try {
1060
1062
  buildLifecycle().restoreToProjectRoot();
@@ -1065,11 +1067,6 @@ export async function cleanupAfterLoopExit(ctx: ExtensionContext): Promise<void>
1065
1067
  { file: "auto.ts" },
1066
1068
  );
1067
1069
  }
1068
- try {
1069
- process.chdir(s.originalBasePath);
1070
- } catch (err) {
1071
- logWarning("engine", `basePath restore/chdir failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
1072
- }
1073
1070
  }
1074
1071
 
1075
1072
  if (s.originalBasePath && s.cmdCtx) {
@@ -1384,20 +1381,14 @@ export async function stopAuto(
1384
1381
  }
1385
1382
 
1386
1383
  // ── Step 7: Restore basePath and chdir (ADR-016 phase 3, #5693) ──
1387
- // `restoreToProjectRoot` assigns s.basePath before any throwable work;
1388
- // no fallback assignment is needed at the call site.
1384
+ // `restoreToProjectRoot` owns both s.basePath restore and process.chdir;
1385
+ // no paired chdir is needed at the call site.
1389
1386
  if (s.originalBasePath) {
1390
1387
  try {
1391
1388
  buildLifecycle().restoreToProjectRoot();
1392
1389
  } catch (e) {
1393
1390
  debugLog("stop-cleanup-basepath", { error: e instanceof Error ? e.message : String(e) });
1394
1391
  }
1395
- try {
1396
- process.chdir(s.basePath);
1397
- } catch (err) {
1398
- /* best-effort */
1399
- logWarning("engine", `chdir failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
1400
- }
1401
1392
  }
1402
1393
 
1403
1394
  // Re-root the active command session/tool runtime after worktree teardown.
@@ -1792,6 +1783,82 @@ function buildLifecycle(): WorktreeLifecycle {
1792
1783
  return new WorktreeLifecycle(s, buildWorktreeLifecycleDeps());
1793
1784
  }
1794
1785
 
1786
+ /**
1787
+ * Build the production `DispatchAdapter` used by `createWiredAutoOrchestrationModule`.
1788
+ *
1789
+ * Exported so tests can verify parity with `runDispatch`'s `resolveDispatch` call —
1790
+ * the wired adapter must derive `structuredQuestionsAvailable`, `sessionContextWindow`,
1791
+ * `sessionProvider`, and `modelRegistry` the same way phases.ts:runDispatch does.
1792
+ */
1793
+ export function createWiredDispatchAdapter(
1794
+ ctx: ExtensionContext,
1795
+ pi: ExtensionAPI,
1796
+ dispatchBasePath: string,
1797
+ ): DispatchAdapter {
1798
+ return {
1799
+ async decideNextUnit(input) {
1800
+ const state = input.stateSnapshot;
1801
+ const active = state.activeMilestone;
1802
+ if (!active) return null;
1803
+
1804
+ const prefs = loadEffectiveGSDPreferences(dispatchBasePath)?.preferences;
1805
+
1806
+ // Derive session-derived dispatch inputs the same way phases.ts:runDispatch does
1807
+ // (#5789). Prefer caller-supplied values when present so test harnesses and
1808
+ // alternative wirings can inject deterministic snapshots; otherwise pull from
1809
+ // the captured pi/ctx references.
1810
+ const sessionProvider = input.sessionProvider ?? ctx.model?.provider;
1811
+ const sessionContextWindow = input.sessionContextWindow ?? ctx.model?.contextWindow;
1812
+ const modelRegistry = input.modelRegistry ?? (ctx.modelRegistry as MinimalModelRegistry | undefined);
1813
+ const authMode =
1814
+ sessionProvider && typeof ctx.modelRegistry?.getProviderAuthMode === "function"
1815
+ ? ctx.modelRegistry.getProviderAuthMode(sessionProvider)
1816
+ : undefined;
1817
+ const activeTools = typeof pi.getActiveTools === "function" ? pi.getActiveTools() : [];
1818
+ // Mirrors runDispatch: deep-planning keeps approval gates in plain chat
1819
+ // because structured questions can be cancelled outside the chat turn on
1820
+ // some transports.
1821
+ const structuredQuestionsAvailable =
1822
+ input.structuredQuestionsAvailable ??
1823
+ (prefs?.planning_depth === "deep"
1824
+ ? "false"
1825
+ : supportsStructuredQuestions(activeTools, {
1826
+ authMode,
1827
+ baseUrl: ctx.model?.baseUrl,
1828
+ })
1829
+ ? "true"
1830
+ : "false");
1831
+
1832
+ const action = await resolveDispatch({
1833
+ basePath: dispatchBasePath,
1834
+ mid: active.id,
1835
+ midTitle: active.title,
1836
+ state,
1837
+ prefs,
1838
+ structuredQuestionsAvailable,
1839
+ sessionContextWindow,
1840
+ sessionProvider,
1841
+ modelRegistry,
1842
+ });
1843
+
1844
+ if (action.action === "stop") {
1845
+ return {
1846
+ kind: "blocked",
1847
+ reason: action.reason,
1848
+ action: action.level === "warning" ? "pause" : "stop",
1849
+ };
1850
+ }
1851
+ if (action.action !== "dispatch") return null;
1852
+ return {
1853
+ unitType: action.unitType,
1854
+ unitId: action.unitId,
1855
+ reason: action.matchedRule ?? "dispatch",
1856
+ preconditions: [],
1857
+ };
1858
+ },
1859
+ };
1860
+ }
1861
+
1795
1862
  /**
1796
1863
  * Thin entry glue for the new Auto Orchestration module.
1797
1864
  *
@@ -1801,7 +1868,7 @@ function buildLifecycle(): WorktreeLifecycle {
1801
1868
  */
1802
1869
  export function createWiredAutoOrchestrationModule(
1803
1870
  ctx: ExtensionContext,
1804
- _pi: ExtensionAPI,
1871
+ pi: ExtensionAPI,
1805
1872
  dispatchBasePath: string,
1806
1873
  runtimeBasePath = resolveProjectRoot(dispatchBasePath),
1807
1874
  ): AutoOrchestrationModule {
@@ -1830,30 +1897,7 @@ export function createWiredAutoOrchestrationModule(
1830
1897
  };
1831
1898
  },
1832
1899
  },
1833
- dispatch: {
1834
- async decideNextUnit(input) {
1835
- const state = input.stateSnapshot;
1836
- const active = state.activeMilestone;
1837
- if (!active) return null;
1838
-
1839
- const prefs = loadEffectiveGSDPreferences(dispatchBasePath)?.preferences;
1840
- const action = await resolveDispatch({
1841
- basePath: dispatchBasePath,
1842
- mid: active.id,
1843
- midTitle: active.title,
1844
- state,
1845
- prefs,
1846
- });
1847
-
1848
- if (action.action !== "dispatch") return null;
1849
- return {
1850
- unitType: action.unitType,
1851
- unitId: action.unitId,
1852
- reason: action.matchedRule ?? "dispatch",
1853
- preconditions: [],
1854
- };
1855
- },
1856
- },
1900
+ dispatch: createWiredDispatchAdapter(ctx, pi, dispatchBasePath),
1857
1901
  recovery: {
1858
1902
  async classifyAndRecover(input) {
1859
1903
  const recovery = classifyFailure(input);
@@ -1902,12 +1946,25 @@ export function createWiredAutoOrchestrationModule(
1902
1946
  async cleanupOnStop() {},
1903
1947
  },
1904
1948
  health: {
1949
+ checkResourcesStale() {
1950
+ return checkResourcesStale(s.resourceVersionOnStart);
1951
+ },
1905
1952
  async preAdvanceGate() {
1906
- const gate = await preDispatchHealthGate(dispatchBasePath);
1907
- return {
1908
- allow: gate.proceed,
1909
- reason: gate.reason,
1910
- };
1953
+ try {
1954
+ const gate = await preDispatchHealthGate(dispatchBasePath);
1955
+ if (gate.proceed) {
1956
+ return {
1957
+ kind: "pass",
1958
+ fixesApplied: gate.fixesApplied,
1959
+ };
1960
+ }
1961
+ return {
1962
+ kind: "fail",
1963
+ reason: gate.reason ?? "Pre-dispatch health check failed — run /gsd doctor for details.",
1964
+ };
1965
+ } catch (error) {
1966
+ return { kind: "threw", error };
1967
+ }
1911
1968
  },
1912
1969
  async postAdvanceRecord(result) {
1913
1970
  if (result.kind === "error") {
@@ -1975,11 +2032,60 @@ export function createWiredAutoOrchestrationModule(
1975
2032
  }
1976
2033
  },
1977
2034
  },
2035
+ uokGate: {
2036
+ async emit(input) {
2037
+ const prefs = loadEffectiveGSDPreferences(dispatchBasePath)?.preferences;
2038
+ const uokFlags = resolveUokFlags(prefs);
2039
+ if (!uokFlags.gates) return;
2040
+ const milestoneId = input.milestoneId ?? s.currentMilestoneId ?? undefined;
2041
+ try {
2042
+ const { UokGateRunner } = await import("./uok/gate-runner.js");
2043
+ const runner = new UokGateRunner();
2044
+ runner.register({
2045
+ id: input.gateId,
2046
+ type: input.gateType,
2047
+ execute: async () => ({
2048
+ outcome: input.outcome,
2049
+ failureClass: input.failureClass,
2050
+ rationale: input.rationale,
2051
+ findings: input.findings ?? "",
2052
+ }),
2053
+ });
2054
+ await runner.run(input.gateId, {
2055
+ basePath: dispatchBasePath,
2056
+ traceId: `pre-dispatch:${flowId}`,
2057
+ turnId: `orch-${seq}`,
2058
+ milestoneId,
2059
+ unitType: "pre-dispatch",
2060
+ unitId: `orch-${seq}`,
2061
+ });
2062
+ } catch (err) {
2063
+ logWarning("engine", `uok gate emit failed: ${getErrorMessage(err)}`, {
2064
+ file: "auto.ts",
2065
+ gateId: input.gateId,
2066
+ gateType: input.gateType,
2067
+ ...(milestoneId ? { milestoneId } : {}),
2068
+ });
2069
+ }
2070
+ },
2071
+ },
1978
2072
  };
1979
2073
 
1980
2074
  return createAutoOrchestrator(deps);
1981
2075
  }
1982
2076
 
2077
+ function notifyResumeBlocked(ctx: ExtensionContext, result: Extract<AutoAdvanceResult, { kind: "blocked" }>): void {
2078
+ const resumeCmd = s.stepMode ? "/gsd next" : "/gsd auto";
2079
+ ctx.ui.notify(`Auto-mode blocked: ${result.reason}. Fix and run ${resumeCmd} to resume.`, "warning");
2080
+ setLifecycleOutcome(ctx, {
2081
+ status: "blocked",
2082
+ title: "Auto-mode blocked",
2083
+ detail: result.reason,
2084
+ nextAction: `Fix the blocker, then run ${resumeCmd} to resume.`,
2085
+ commands: ["/gsd status for overview", `${resumeCmd} to resume`, "/gsd doctor to diagnose"],
2086
+ });
2087
+ }
2088
+
1983
2089
  function ensureOrchestrationModule(ctx: ExtensionContext, pi: ExtensionAPI, basePath: string): void {
1984
2090
  s.orchestration = createWiredAutoOrchestrationModule(ctx, pi, basePath, lockBase());
1985
2091
  }
@@ -2317,7 +2423,7 @@ export async function startAuto(
2317
2423
  // This closes the journal gap reported in #3348 where the worker wrote side
2318
2424
  // effects (SUMMARY.md, DB updates) but died before emitting unit-end.
2319
2425
  emitCrashRecoveredUnitEnd(base, freshStartAssessment.lock);
2320
- clearLock(base);
2426
+ clearStaleWorkerLock(base);
2321
2427
  }
2322
2428
 
2323
2429
  if (!s.paused) {
@@ -2388,6 +2494,8 @@ export async function startAuto(
2388
2494
  s.unitLifetimeDispatches.clear();
2389
2495
  if (!getLedger()) initMetrics(base);
2390
2496
  if (s.currentMilestoneId) setActiveMilestoneId(base, s.currentMilestoneId);
2497
+ await openProjectDbIfPresent(base);
2498
+ registerAutoWorkerForSession(s, base);
2391
2499
 
2392
2500
  // Re-register health level notification callback lost across process restart
2393
2501
  setLevelChangeCallback((_from, to, summary) => {
@@ -2495,7 +2603,12 @@ export async function startAuto(
2495
2603
  pi.events.emit(CMUX_CHANNELS.LOG, { preferences: loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences, message: s.stepMode ? "Step-mode resumed." : "Auto-mode resumed.", level: "progress" });
2496
2604
 
2497
2605
  try {
2498
- await s.orchestration?.resume();
2606
+ const resumeResult = await s.orchestration?.resume();
2607
+ if (resumeResult?.kind === "blocked") {
2608
+ notifyResumeBlocked(ctx, resumeResult);
2609
+ await cleanupAfterLoopExit(ctx);
2610
+ return;
2611
+ }
2499
2612
  } catch (err) {
2500
2613
  debugLog("resume-orchestration-resume", { error: err instanceof Error ? err.message : String(err) });
2501
2614
  }
@@ -2516,6 +2629,7 @@ export async function startAuto(
2516
2629
  const bootstrapDeps: BootstrapDeps = {
2517
2630
  shouldUseWorktreeIsolation,
2518
2631
  registerSigtermHandler,
2632
+ registerAutoWorkerForSession: (projectRoot) => registerAutoWorkerForSession(s, projectRoot),
2519
2633
  lockBase,
2520
2634
  buildLifecycle,
2521
2635
  };
@@ -48,6 +48,11 @@ const MAX_NETWORK_RETRIES = 2;
48
48
  function isObjectRecord(value: unknown): value is Record<string, unknown> {
49
49
  return !!value && typeof value === "object";
50
50
  }
51
+
52
+ export function _hasEmptyAgentEndContent(content: unknown): boolean {
53
+ return content == null || (Array.isArray(content) && content.length === 0);
54
+ }
55
+
51
56
  /**
52
57
  * Cap on auto-resume attempts for sustained transient-provider errors.
53
58
  *
@@ -310,7 +315,7 @@ export async function handleAgentEnd(
310
315
  // that carry error context — e.g. errorMessage field or non-empty content
311
316
  // indicating a mid-stream failure. (#2695)
312
317
  const content = "content" in lastMsg ? lastMsg.content : undefined;
313
- const hasEmptyContent = Array.isArray(content) && content.length === 0;
318
+ const hasEmptyContent = _hasEmptyAgentEndContent(content);
314
319
  const hasErrorMessage = "errorMessage" in lastMsg && !!lastMsg.errorMessage;
315
320
 
316
321
  if (hasEmptyContent && !hasErrorMessage) {
@@ -487,17 +487,18 @@ export function registerDbTools(pi: ExtensionAPI): void {
487
487
  promptGuidelines: [
488
488
  "Use gsd_plan_milestone for milestone planning instead of writing ROADMAP.md directly.",
489
489
  "Keep parameters flat and provide the full milestone planning payload, including slices.",
490
+ "Milestone and slice titles must not contain forward slash (/), en dash, or em dash characters.",
490
491
  "The tool validates input, writes milestone and slice planning data transactionally, renders ROADMAP.md from DB, and clears both state and parse caches after success.",
491
492
  "Use the canonical name gsd_plan_milestone; gsd_milestone_plan is only an alias.",
492
493
  ],
493
494
  parameters: Type.Object({
494
495
  // ── Core identification + content (required) ──────────────────────
495
496
  milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
496
- title: Type.String({ description: "Milestone title" }),
497
+ title: Type.String({ description: "Milestone title; must not contain forward slash (/), en dash, or em dash characters" }),
497
498
  vision: Type.String({ description: "Milestone vision" }),
498
499
  slices: Type.Array(Type.Object({
499
500
  sliceId: Type.String({ description: "Slice ID (e.g. S01)" }),
500
- title: Type.String({ description: "Slice title" }),
501
+ title: Type.String({ description: "Slice title; must not contain forward slash (/), en dash, or em dash characters" }),
501
502
  risk: Type.String({ description: "Slice risk" }),
502
503
  depends: Type.Array(Type.String(), { description: "Slice dependency IDs" }),
503
504
  demo: Type.String({ description: "Roadmap demo text / After this" }),
@@ -570,10 +571,10 @@ export function registerDbTools(pi: ExtensionAPI): void {
570
571
  title: Type.String({ description: "Task title" }),
571
572
  description: Type.String({ description: "Task description / steps block" }),
572
573
  estimate: Type.String({ description: "Task estimate string" }),
573
- files: Type.Array(Type.String(), { description: "Files likely touched" }),
574
+ files: Type.Array(Type.String(), { description: "Array<string> of files likely touched; pass [\"path\"] or [], never a single string" }),
574
575
  verify: Type.String({ description: "Verification command or block" }),
575
- inputs: Type.Array(Type.String(), { description: "Input files or references" }),
576
- expectedOutput: Type.Array(Type.String(), { description: "Expected output files or artifacts" }),
576
+ inputs: Type.Array(Type.String(), { description: "Array<string> of input files or references; pass [\"path\"] or [], never a single string" }),
577
+ expectedOutput: Type.Array(Type.String(), { description: "Array<string> of expected output files or artifacts; pass [\"path\"] or [], never a single string" }),
577
578
  observabilityImpact: Type.Optional(Type.String({ description: "Task observability impact" })),
578
579
  }), { description: "Planned tasks for the slice" }),
579
580
  // ── Enrichment metadata (optional — defaults to empty) ────────────
@@ -650,10 +651,10 @@ export function registerDbTools(pi: ExtensionAPI): void {
650
651
  title: Type.String({ description: "Task title" }),
651
652
  description: Type.String({ description: "Task description / steps block" }),
652
653
  estimate: Type.String({ description: "Task estimate string" }),
653
- files: Type.Array(Type.String(), { description: "Files likely touched" }),
654
+ files: Type.Array(Type.String(), { description: "Array<string> of files likely touched; pass [\"path\"] or [], never a single string" }),
654
655
  verify: Type.String({ description: "Verification command or block" }),
655
- inputs: Type.Array(Type.String(), { description: "Input files or references" }),
656
- expectedOutput: Type.Array(Type.String(), { description: "Expected output files or artifacts" }),
656
+ inputs: Type.Array(Type.String(), { description: "Array<string> of input files or references; pass [\"path\"] or [], never a single string" }),
657
+ expectedOutput: Type.Array(Type.String(), { description: "Array<string> of expected output files or artifacts; pass [\"path\"] or [], never a single string" }),
657
658
  observabilityImpact: Type.Optional(Type.String({ description: "Task observability impact" })),
658
659
  // Single-writer v3 audit trail (Stream 2): caller-provided actor identity + causation.
659
660
  actorName: Type.Optional(Type.String({ description: "Caller-provided actor identity for the audit trail (e.g. 'executor-01', 'gsd-orchestrator')" })),
@@ -1,20 +1,32 @@
1
1
  export function extractSubagentAgentClasses(input: unknown): string[] {
2
2
  if (!input || typeof input !== "object") return [];
3
3
 
4
- const record = input as Record<string, unknown>;
5
4
  const agentClasses: string[] = [];
5
+ const visited = new WeakSet<object>();
6
6
  const addAgentClass = (value: unknown): void => {
7
- if (typeof value === "string" && value.trim().length > 0) agentClasses.push(value.trim());
7
+ if (typeof value !== "string") return;
8
+ const normalized = value.trim().replace(/\.md$/i, "");
9
+ if (normalized.length > 0) agentClasses.push(normalized);
8
10
  };
9
- const addFromItems = (value: unknown): void => {
11
+
12
+ const visitItems = (value: unknown): void => {
10
13
  if (!Array.isArray(value)) return;
11
14
  for (const item of value) {
12
- if (item && typeof item === "object") addAgentClass((item as Record<string, unknown>).agent);
15
+ visit(item);
13
16
  }
14
17
  };
15
18
 
16
- addAgentClass(record.agent);
17
- addFromItems(record.tasks);
18
- addFromItems(record.chain);
19
+ const visit = (value: unknown): void => {
20
+ if (!value || typeof value !== "object") return;
21
+ if (visited.has(value)) return;
22
+ visited.add(value);
23
+ const record = value as Record<string, unknown>;
24
+ addAgentClass(record.agent);
25
+ visitItems(record.tasks);
26
+ visitItems(record.chain);
27
+ visitItems(record.parallel);
28
+ };
29
+
30
+ visit(input);
19
31
  return agentClasses;
20
32
  }
@@ -5,7 +5,7 @@ import { isAbsolute, join, relative, resolve, sep } from "node:path";
5
5
  import { minimatch } from "minimatch";
6
6
 
7
7
  import { getIsolationMode } from "../preferences.js";
8
- import type { ToolsPolicy } from "../unit-context-manifest.js";
8
+ import { compileSubagentPermissionContract, type ToolsPolicy } from "../unit-context-manifest.js";
9
9
  import { logWarning } from "../workflow-logger.js";
10
10
  import { isGsdWorktreePath, resolveWorktreeProjectRoot } from "../worktree-root.js";
11
11
 
@@ -65,6 +65,7 @@ const QUEUE_SAFE_TOOLS = new Set([
65
65
  * true / false — shell no-ops / test exit codes
66
66
  */
67
67
  const BASH_READ_ONLY_RE = /^\s*(cat|head|tail|less|more|wc|file|stat|du|df|which|type|echo|printf|ls|find|grep|rg|awk|sed\b(?!.*-i)|sort|uniq|diff|comm|tr|cut|tee\s+-a\s+\/dev\/null|git\s+(log|show|diff|status|branch|tag|remote|rev-parse|ls-files|blame|shortlog|describe|stash\s+list|config\s+--get|cat-file)|gh\s+(issue|pr|api|repo|release)\s+(view|list|diff|status|checks)|mkdir\s+-p\s+\.gsd|rtk\s|npm\s+run\s+(test|test:\w+|lint|lint:\w+|typecheck|type-check|type-check:\w+|check|verify|audit|outdated|format:check|ci|validate)\b|npm\s+(ls|list|info|view|show|outdated|audit|explain|doctor|ping|--version|-v)\b|npx\s|tsx\s|node\s+(--print|--version|-v\b)|python[23]?\s+(-c\s+'[^']*'|--version|-V\b|-m\s+(pip\s+show|pip\s+list|site))|pip[23]?\s+(show|list|freeze|check|index\s+versions)\b|jq\s|yq\s|curl\s+(-s\b|--silent\b)(?!\s+[^|>]*\s-[oO]\b)(?!\s+[^|>]*\s--output\b)[^|>]*$|openssl\s+(version|x509|s_client)|env\b|printenv\b|true\b|false\b)/;
68
+ const BASH_VERIFICATION_RE = /^\s*(npm\s+(run\s+(build|test|test:\w+|lint|lint:\w+|typecheck|type-check|verify|ci|validate)\b|test\b)|pnpm\s+(build|test|lint|typecheck|verify)\b|yarn\s+(build|test|lint|typecheck|verify)\b|vitest\b|jest\b|go\s+test\b)/;
68
69
 
69
70
  interface InMemoryWriteGateState {
70
71
  verifiedDepthMilestones: Set<string>;
@@ -767,6 +768,9 @@ function blockReason(unitType: string, mode: string, what: string): string {
767
768
  * and listed in the policy's allowedSubagents.
768
769
  * - "docs" → like "planning" but also allows writes to paths
769
770
  * matching `allowedPathGlobs` relative to basePath.
771
+ * - "verification"
772
+ * → allows Bash for project verification commands, but keeps
773
+ * writes restricted to .gsd/ and blocks subagent dispatch.
770
774
  *
771
775
  * `pathOrCommand` is the file path for write/edit-shaped tools and the
772
776
  * shell command for bash. Other tools ignore this argument.
@@ -804,14 +808,15 @@ export function shouldBlockPlanningUnit(
804
808
  return { block: true, reason: blockReason(unitType, policy.mode, `tool "${tool}" is not on the read-only allowlist`) };
805
809
  }
806
810
 
807
- // planning / planning-dispatch / docs modes share the same surface for safe tools, bash, and subagent.
811
+ // planning / planning-dispatch / docs / verification modes share the same surface for safe tools, bash, and subagent.
808
812
  if (PLANNING_SAFE_TOOLS.has(tool)) return { block: false };
809
813
  if (tool.startsWith("gsd_")) return { block: false };
810
814
 
811
815
  if (PLANNING_SUBAGENT_TOOLS.has(tool)) {
812
816
  if (policy.mode === "planning-dispatch") {
813
817
  const requested = (agentClasses ?? []).map(a => a.trim()).filter(Boolean);
814
- const allowedSubagents = Array.isArray(policy.allowedSubagents) ? policy.allowedSubagents : [];
818
+ const dispatchContract = compileSubagentPermissionContract(policy);
819
+ const allowedSubagents = dispatchContract.allowedSubagents;
815
820
  const allowed = new Set(allowedSubagents);
816
821
  // When agentClasses is undefined, the caller has not been updated to extract
817
822
  // agent identities yet. Block and warn so stale callers surface in telemetry
@@ -861,6 +866,17 @@ export function shouldBlockPlanningUnit(
861
866
  }
862
867
 
863
868
  if (tool === "bash") {
869
+ if (policy.mode === "verification") {
870
+ if (BASH_VERIFICATION_RE.test(pathOrCommand) || BASH_READ_ONLY_RE.test(pathOrCommand)) return { block: false };
871
+ return {
872
+ block: true,
873
+ reason: blockReason(
874
+ unitType,
875
+ policy.mode,
876
+ `bash is restricted to build/test verification commands (npm run build, npm test, etc.); cannot run "${pathOrCommand.slice(0, 80)}${pathOrCommand.length > 80 ? "…" : ""}"`,
877
+ ),
878
+ };
879
+ }
864
880
  if (BASH_READ_ONLY_RE.test(pathOrCommand)) return { block: false };
865
881
  return {
866
882
  block: true,