gsd-pi 2.82.0-dev.2841a1e44 → 2.82.0-dev.3a3c6509d

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 (377) hide show
  1. package/README.md +3 -3
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/GSD-WORKFLOW.md +7 -0
  4. package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
  5. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +1 -1
  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 +11 -0
  9. package/dist/resources/extensions/gsd/auto/phases.js +81 -31
  10. package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +12 -0
  11. package/dist/resources/extensions/gsd/auto-dashboard.js +66 -1
  12. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +1 -0
  13. package/dist/resources/extensions/gsd/auto-dispatch.js +20 -19
  14. package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
  15. package/dist/resources/extensions/gsd/auto-post-unit.js +71 -10
  16. package/dist/resources/extensions/gsd/auto-recovery.js +71 -14
  17. package/dist/resources/extensions/gsd/auto-start.js +87 -14
  18. package/dist/resources/extensions/gsd/auto-verification.js +17 -4
  19. package/dist/resources/extensions/gsd/auto-worktree.js +176 -10
  20. package/dist/resources/extensions/gsd/auto.js +37 -5
  21. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +31 -7
  22. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +10 -9
  23. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +4 -2
  24. package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +5 -2
  25. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +14 -2
  26. package/dist/resources/extensions/gsd/commands/handlers/core.js +17 -1
  27. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +7 -2
  28. package/dist/resources/extensions/gsd/crash-recovery.js +43 -5
  29. package/dist/resources/extensions/gsd/db/milestone-leases.js +24 -0
  30. package/dist/resources/extensions/gsd/db/unit-dispatches.js +3 -2
  31. package/dist/resources/extensions/gsd/dispatch-guard.js +2 -2
  32. package/dist/resources/extensions/gsd/doctor-git-checks.js +46 -1
  33. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +28 -11
  34. package/dist/resources/extensions/gsd/doctor.js +2 -28
  35. package/dist/resources/extensions/gsd/export-html.js +27 -425
  36. package/dist/resources/extensions/gsd/forensics.js +3 -3
  37. package/dist/resources/extensions/gsd/git-service.js +45 -3
  38. package/dist/resources/extensions/gsd/gsd-db.js +21 -6
  39. package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -3
  40. package/dist/resources/extensions/gsd/guided-flow.js +101 -116
  41. package/dist/resources/extensions/gsd/guided-unit-context.js +23 -0
  42. package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
  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/pending-auto-start.js +52 -0
  47. package/dist/resources/extensions/gsd/post-execution-checks.js +73 -2
  48. package/dist/resources/extensions/gsd/pre-execution-checks.js +28 -1
  49. package/dist/resources/extensions/gsd/prompt-loader.js +1 -1
  50. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  51. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  52. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
  53. package/dist/resources/extensions/gsd/prompts/discuss.md +9 -9
  54. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
  55. package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
  56. package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -4
  57. package/dist/resources/extensions/gsd/prompts/queue.md +4 -4
  58. package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  59. package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  60. package/dist/resources/extensions/gsd/queue-reorder-ui.js +30 -13
  61. package/dist/resources/extensions/gsd/smart-entry-routing.js +36 -0
  62. package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +6 -1
  63. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +9 -14
  64. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +19 -24
  65. package/dist/resources/extensions/gsd/state.js +1 -1
  66. package/dist/resources/extensions/gsd/status-guards.js +11 -0
  67. package/dist/resources/extensions/gsd/templates/plan.md +8 -5
  68. package/dist/resources/extensions/gsd/templates/task-plan.md +4 -2
  69. package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -8
  70. package/dist/resources/extensions/gsd/tools/complete-slice.js +6 -8
  71. package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -1
  72. package/dist/resources/extensions/gsd/tools/plan-slice.js +89 -14
  73. package/dist/resources/extensions/gsd/unit-context-manifest.js +7 -8
  74. package/dist/resources/extensions/gsd/validation.js +23 -1
  75. package/dist/resources/extensions/gsd/verification-gate.js +68 -7
  76. package/dist/resources/extensions/gsd/workflow-mcp.js +17 -1
  77. package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
  78. package/dist/resources/extensions/gsd/worktree-lifecycle.js +33 -8
  79. package/dist/resources/extensions/gsd/worktree-manager.js +1 -1
  80. package/dist/resources/extensions/shared/html-shell.js +388 -0
  81. package/dist/resources/extensions/visual-brief/page-contract.js +2 -0
  82. package/dist/resources/extensions/visual-brief/prompts.js +29 -0
  83. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  84. package/dist/web/standalone/.next/BUILD_ID +1 -1
  85. package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
  86. package/dist/web/standalone/.next/build-manifest.json +3 -3
  87. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  88. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  89. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  90. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  98. package/dist/web/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -7
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
  103. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -5
  105. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -5
  108. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  110. package/dist/web/standalone/.next/server/app/index.html +1 -1
  111. package/dist/web/standalone/.next/server/app/index.rsc +4 -7
  112. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -7
  114. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -5
  116. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -5
  117. package/dist/web/standalone/.next/server/app/page.js +2 -2
  118. package/dist/web/standalone/.next/server/app/page.js.nft.json +1 -1
  119. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
  121. package/dist/web/standalone/.next/server/chunks/4266.js +2 -0
  122. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  125. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  126. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  127. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  128. package/dist/web/standalone/.next/static/chunks/app/layout-8c10ec293ae0f1d5.js +1 -0
  129. package/dist/web/standalone/.next/static/chunks/{webpack-6a95bc41e0f7ec89.js → webpack-9a4db269f9ed63ad.js} +1 -1
  130. package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
  131. package/package.json +2 -2
  132. package/packages/mcp-server/src/workflow-tools.test.ts +1 -1
  133. package/packages/native/tsconfig.json +2 -1
  134. package/packages/native/tsconfig.tsbuildinfo +1 -1
  135. package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts.map +1 -1
  136. package/packages/pi-ai/dist/providers/google-gemini-cli.js +5 -0
  137. package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
  138. package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts +2 -0
  139. package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts.map +1 -0
  140. package/packages/pi-ai/dist/providers/google-gemini-cli.test.js +41 -0
  141. package/packages/pi-ai/dist/providers/google-gemini-cli.test.js.map +1 -0
  142. package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
  143. package/packages/pi-ai/dist/providers/openai-codex-responses.js +82 -1
  144. package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  145. package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts +2 -0
  146. package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts.map +1 -0
  147. package/packages/pi-ai/dist/providers/openai-codex-responses.test.js +52 -0
  148. package/packages/pi-ai/dist/providers/openai-codex-responses.test.js.map +1 -0
  149. package/packages/pi-ai/dist/providers/simple-options.d.ts +2 -4
  150. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  151. package/packages/pi-ai/dist/providers/simple-options.js +5 -6
  152. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  153. package/packages/pi-ai/dist/providers/simple-options.test.d.ts +2 -0
  154. package/packages/pi-ai/dist/providers/simple-options.test.d.ts.map +1 -0
  155. package/packages/pi-ai/dist/providers/simple-options.test.js +50 -0
  156. package/packages/pi-ai/dist/providers/simple-options.test.js.map +1 -0
  157. package/packages/pi-ai/src/providers/google-gemini-cli.test.ts +49 -0
  158. package/packages/pi-ai/src/providers/google-gemini-cli.ts +7 -0
  159. package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +63 -0
  160. package/packages/pi-ai/src/providers/openai-codex-responses.ts +91 -1
  161. package/packages/pi-ai/src/providers/simple-options.test.ts +60 -0
  162. package/packages/pi-ai/src/providers/simple-options.ts +5 -6
  163. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  164. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts +2 -0
  165. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts.map +1 -0
  166. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js +66 -0
  167. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js.map +1 -0
  168. package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
  169. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  170. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +44 -3
  171. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  172. package/packages/pi-coding-agent/dist/core/sdk.js +1 -1
  173. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  174. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  175. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +24 -6
  176. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  177. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  178. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +71 -97
  179. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  180. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js +12 -0
  181. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js.map +1 -1
  182. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  183. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +19 -8
  184. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  185. package/packages/pi-coding-agent/src/core/agent-session-thinking-level.test.ts +79 -0
  186. package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
  187. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +53 -3
  188. package/packages/pi-coding-agent/src/core/sdk.ts +1 -1
  189. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +23 -7
  190. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +75 -102
  191. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-ordering.test.ts +14 -0
  192. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +23 -8
  193. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  194. package/packages/pi-tui/dist/__tests__/terminal.test.d.ts +2 -0
  195. package/packages/pi-tui/dist/__tests__/terminal.test.d.ts.map +1 -0
  196. package/packages/pi-tui/dist/__tests__/terminal.test.js +103 -0
  197. package/packages/pi-tui/dist/__tests__/terminal.test.js.map +1 -0
  198. package/packages/pi-tui/dist/terminal.d.ts +2 -0
  199. package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
  200. package/packages/pi-tui/dist/terminal.js +12 -0
  201. package/packages/pi-tui/dist/terminal.js.map +1 -1
  202. package/packages/pi-tui/src/__tests__/terminal.test.ts +121 -0
  203. package/packages/pi-tui/src/terminal.ts +11 -0
  204. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  205. package/src/resources/GSD-WORKFLOW.md +7 -0
  206. package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
  207. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +1 -1
  208. package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
  209. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +9 -0
  210. package/src/resources/extensions/gsd/auto/contracts.ts +14 -6
  211. package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
  212. package/src/resources/extensions/gsd/auto/loop.ts +8 -5
  213. package/src/resources/extensions/gsd/auto/orchestrator.ts +11 -0
  214. package/src/resources/extensions/gsd/auto/phases.ts +90 -38
  215. package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +13 -0
  216. package/src/resources/extensions/gsd/auto-dashboard.ts +72 -1
  217. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +1 -0
  218. package/src/resources/extensions/gsd/auto-dispatch.ts +21 -19
  219. package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
  220. package/src/resources/extensions/gsd/auto-post-unit.ts +78 -8
  221. package/src/resources/extensions/gsd/auto-recovery.ts +74 -11
  222. package/src/resources/extensions/gsd/auto-start.ts +94 -12
  223. package/src/resources/extensions/gsd/auto-verification.ts +22 -2
  224. package/src/resources/extensions/gsd/auto-worktree.ts +193 -10
  225. package/src/resources/extensions/gsd/auto.ts +40 -5
  226. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +42 -7
  227. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +10 -9
  228. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +4 -2
  229. package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +3 -1
  230. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +17 -2
  231. package/src/resources/extensions/gsd/commands/handlers/core.ts +17 -1
  232. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +8 -3
  233. package/src/resources/extensions/gsd/crash-recovery.ts +44 -4
  234. package/src/resources/extensions/gsd/db/milestone-leases.ts +26 -0
  235. package/src/resources/extensions/gsd/db/unit-dispatches.ts +4 -3
  236. package/src/resources/extensions/gsd/dispatch-guard.ts +2 -2
  237. package/src/resources/extensions/gsd/doctor-git-checks.ts +45 -1
  238. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
  239. package/src/resources/extensions/gsd/doctor-types.ts +1 -0
  240. package/src/resources/extensions/gsd/doctor.ts +2 -27
  241. package/src/resources/extensions/gsd/export-html.ts +27 -427
  242. package/src/resources/extensions/gsd/forensics.ts +3 -3
  243. package/src/resources/extensions/gsd/git-service.ts +51 -4
  244. package/src/resources/extensions/gsd/gsd-db.ts +21 -6
  245. package/src/resources/extensions/gsd/guided-flow-queue.ts +4 -3
  246. package/src/resources/extensions/gsd/guided-flow.ts +134 -133
  247. package/src/resources/extensions/gsd/guided-unit-context.ts +30 -0
  248. package/src/resources/extensions/gsd/migrate/parsers.ts +11 -0
  249. package/src/resources/extensions/gsd/migration-auto-check.ts +15 -23
  250. package/src/resources/extensions/gsd/milestone-actions.ts +10 -4
  251. package/src/resources/extensions/gsd/native-git-bridge.ts +54 -12
  252. package/src/resources/extensions/gsd/pending-auto-start.ts +79 -0
  253. package/src/resources/extensions/gsd/post-execution-checks.ts +87 -2
  254. package/src/resources/extensions/gsd/pre-execution-checks.ts +32 -1
  255. package/src/resources/extensions/gsd/prompt-loader.ts +1 -1
  256. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  257. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  258. package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
  259. package/src/resources/extensions/gsd/prompts/discuss.md +9 -9
  260. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
  261. package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
  262. package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -4
  263. package/src/resources/extensions/gsd/prompts/queue.md +4 -4
  264. package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  265. package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  266. package/src/resources/extensions/gsd/queue-reorder-ui.ts +31 -13
  267. package/src/resources/extensions/gsd/smart-entry-routing.ts +77 -0
  268. package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +8 -1
  269. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +12 -15
  270. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +17 -25
  271. package/src/resources/extensions/gsd/state.ts +1 -1
  272. package/src/resources/extensions/gsd/status-guards.ts +13 -0
  273. package/src/resources/extensions/gsd/templates/plan.md +8 -5
  274. package/src/resources/extensions/gsd/templates/task-plan.md +4 -2
  275. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +71 -0
  276. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +116 -0
  277. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +56 -0
  278. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +80 -1
  279. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +35 -7
  280. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +53 -2
  281. package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +12 -1
  282. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +91 -6
  283. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +1 -0
  284. package/src/resources/extensions/gsd/tests/auto-stop-notification.test.ts +20 -0
  285. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
  286. package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +87 -0
  287. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +11 -2
  288. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +4 -1
  289. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +5 -9
  290. package/src/resources/extensions/gsd/tests/complete-task.test.ts +3 -1
  291. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +86 -2
  292. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
  293. package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
  294. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +59 -2
  295. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +66 -0
  296. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
  297. package/src/resources/extensions/gsd/tests/doctor-empty-worktree.test.ts +65 -0
  298. package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
  299. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +11 -0
  300. package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +2 -0
  301. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +106 -0
  302. package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +59 -11
  303. package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
  304. package/src/resources/extensions/gsd/tests/guided-tool-contract.test.ts +65 -0
  305. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +7 -7
  306. package/src/resources/extensions/gsd/tests/hook-model-resolution.test.ts +5 -0
  307. package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -2
  308. package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +9 -0
  309. package/src/resources/extensions/gsd/tests/integration/doctor-runtime.test.ts +20 -0
  310. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +112 -1
  311. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
  312. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +46 -0
  313. package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +179 -0
  314. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -1
  315. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +26 -18
  316. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +63 -2
  317. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +121 -1
  318. package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +55 -1
  319. package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +29 -5
  320. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +2 -1
  321. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +26 -0
  322. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
  323. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +225 -1
  324. package/src/resources/extensions/gsd/tests/plan-task.test.ts +17 -0
  325. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +86 -0
  326. package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
  327. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +53 -0
  328. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +59 -0
  329. package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
  330. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +37 -1
  331. package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +54 -0
  332. package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +89 -2
  333. package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +2 -3
  334. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
  335. package/src/resources/extensions/gsd/tests/smart-entry-routing.test.ts +113 -0
  336. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +53 -2
  337. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +119 -23
  338. package/src/resources/extensions/gsd/tests/status-guards.test.ts +13 -1
  339. package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +64 -1
  340. package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +7 -3
  341. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +82 -7
  342. package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +29 -2
  343. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
  344. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +19 -1
  345. package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +21 -1
  346. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +1 -1
  347. package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +39 -0
  348. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +64 -12
  349. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +38 -0
  350. package/src/resources/extensions/gsd/tools/complete-milestone.ts +8 -10
  351. package/src/resources/extensions/gsd/tools/complete-slice.ts +6 -8
  352. package/src/resources/extensions/gsd/tools/plan-milestone.ts +5 -1
  353. package/src/resources/extensions/gsd/tools/plan-slice.ts +98 -12
  354. package/src/resources/extensions/gsd/types.ts +1 -1
  355. package/src/resources/extensions/gsd/unit-context-manifest.ts +12 -9
  356. package/src/resources/extensions/gsd/validation.ts +23 -1
  357. package/src/resources/extensions/gsd/verification-gate.ts +78 -6
  358. package/src/resources/extensions/gsd/workflow-mcp.ts +18 -1
  359. package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
  360. package/src/resources/extensions/gsd/worktree-lifecycle.ts +41 -8
  361. package/src/resources/extensions/gsd/worktree-manager.ts +1 -1
  362. package/src/resources/extensions/shared/html-shell.ts +412 -0
  363. package/src/resources/extensions/visual-brief/page-contract.ts +2 -0
  364. package/src/resources/extensions/visual-brief/prompts.ts +37 -1
  365. package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +40 -0
  366. package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
  367. package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +0 -1
  368. package/dist/web/standalone/.next/static/css/0262768ec1b89d34.css +0 -1
  369. package/dist/web/standalone/.next/static/css/de70bee13400563f.css +0 -1
  370. package/dist/web/standalone/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
  371. package/dist/web/standalone/.next/static/media/747892c23ea88013-s.woff2 +0 -0
  372. package/dist/web/standalone/.next/static/media/8d697b304b401681-s.woff2 +0 -0
  373. package/dist/web/standalone/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  374. package/dist/web/standalone/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
  375. package/dist/web/standalone/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  376. /package/dist/web/standalone/.next/static/{Qgr2B_MRhPxC0z8fwv4vT → O6femb9LLl3nlgsDaYwS-}/_buildManifest.js +0 -0
  377. /package/dist/web/standalone/.next/static/{Qgr2B_MRhPxC0z8fwv4vT → O6femb9LLl3nlgsDaYwS-}/_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,7 +241,7 @@ 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, DispatchAdapter } 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";
@@ -316,6 +317,13 @@ import { normalizeRealPath } from "./paths.js";
316
317
  /** Throttle STATE.md rebuilds — at most once per 30 seconds */
317
318
  const STATE_REBUILD_MIN_INTERVAL_MS = 30_000;
318
319
 
320
+ export function formatAutoStopNotification(prefix: string, totals: { cost: number; tokens: { total: number } }, unitCount: number): string {
321
+ return [
322
+ `${prefix}.`,
323
+ `Session: ${formatCost(totals.cost)} · ${formatTokenCount(totals.tokens.total)} tokens · ${unitCount} units`,
324
+ ].join("\n");
325
+ }
326
+
319
327
  /**
320
328
  * Phase B — register this auto-mode process in the workers table so other
321
329
  * workers and janitors can detect liveness via heartbeat. Best-effort: if
@@ -1044,6 +1052,7 @@ export async function cleanupAfterLoopExit(ctx: ExtensionContext): Promise<void>
1044
1052
  // visible so the user still has a resumable auto-mode signal on screen.
1045
1053
  if (!s.paused) {
1046
1054
  ctx.ui.setStatus("gsd-auto", undefined);
1055
+ ctx.ui.setWidget("gsd-progress", undefined);
1047
1056
  if (s.completionStopInProgress) {
1048
1057
  s.completionStopInProgress = false;
1049
1058
  }
@@ -1415,7 +1424,7 @@ export async function stopAuto(
1415
1424
  if (ledger && ledger.units.length > 0) {
1416
1425
  const totals = getProjectTotals(ledger.units);
1417
1426
  ctx?.ui.notify(
1418
- `${notificationPrefix}. Session: ${formatCost(totals.cost)} · ${formatTokenCount(totals.tokens.total)} tokens · ${ledger.units.length} units`,
1427
+ formatAutoStopNotification(notificationPrefix, totals, ledger.units.length),
1419
1428
  "info",
1420
1429
  );
1421
1430
  } else {
@@ -1722,7 +1731,6 @@ export async function pauseAuto(
1722
1731
  restoreProjectRootEnv();
1723
1732
  restoreMilestoneLockEnv();
1724
1733
  s.pendingVerificationRetry = null;
1725
- s.verificationRetryCount.clear();
1726
1734
  ctx?.ui.setStatus("gsd-auto", "paused");
1727
1735
  ctx?.ui.setWidget("gsd-progress", undefined);
1728
1736
  const resumeCmd = s.stepMode ? "/gsd next" : "/gsd auto";
@@ -1839,6 +1847,13 @@ export function createWiredDispatchAdapter(
1839
1847
  modelRegistry,
1840
1848
  });
1841
1849
 
1850
+ if (action.action === "stop") {
1851
+ return {
1852
+ kind: "blocked",
1853
+ reason: action.reason,
1854
+ action: action.level === "warning" ? "pause" : "stop",
1855
+ };
1856
+ }
1842
1857
  if (action.action !== "dispatch") return null;
1843
1858
  return {
1844
1859
  unitType: action.unitType,
@@ -2065,6 +2080,18 @@ export function createWiredAutoOrchestrationModule(
2065
2080
  return createAutoOrchestrator(deps);
2066
2081
  }
2067
2082
 
2083
+ function notifyResumeBlocked(ctx: ExtensionContext, result: Extract<AutoAdvanceResult, { kind: "blocked" }>): void {
2084
+ const resumeCmd = s.stepMode ? "/gsd next" : "/gsd auto";
2085
+ ctx.ui.notify(`Auto-mode blocked: ${result.reason}. Fix and run ${resumeCmd} to resume.`, "warning");
2086
+ setLifecycleOutcome(ctx, {
2087
+ status: "blocked",
2088
+ title: "Auto-mode blocked",
2089
+ detail: result.reason,
2090
+ nextAction: `Fix the blocker, then run ${resumeCmd} to resume.`,
2091
+ commands: ["/gsd status for overview", `${resumeCmd} to resume`, "/gsd doctor to diagnose"],
2092
+ });
2093
+ }
2094
+
2068
2095
  function ensureOrchestrationModule(ctx: ExtensionContext, pi: ExtensionAPI, basePath: string): void {
2069
2096
  s.orchestration = createWiredAutoOrchestrationModule(ctx, pi, basePath, lockBase());
2070
2097
  }
@@ -2402,7 +2429,7 @@ export async function startAuto(
2402
2429
  // This closes the journal gap reported in #3348 where the worker wrote side
2403
2430
  // effects (SUMMARY.md, DB updates) but died before emitting unit-end.
2404
2431
  emitCrashRecoveredUnitEnd(base, freshStartAssessment.lock);
2405
- clearLock(base);
2432
+ clearStaleWorkerLock(base);
2406
2433
  }
2407
2434
 
2408
2435
  if (!s.paused) {
@@ -2473,6 +2500,8 @@ export async function startAuto(
2473
2500
  s.unitLifetimeDispatches.clear();
2474
2501
  if (!getLedger()) initMetrics(base);
2475
2502
  if (s.currentMilestoneId) setActiveMilestoneId(base, s.currentMilestoneId);
2503
+ await openProjectDbIfPresent(base);
2504
+ registerAutoWorkerForSession(s, base);
2476
2505
 
2477
2506
  // Re-register health level notification callback lost across process restart
2478
2507
  setLevelChangeCallback((_from, to, summary) => {
@@ -2580,7 +2609,12 @@ export async function startAuto(
2580
2609
  pi.events.emit(CMUX_CHANNELS.LOG, { preferences: loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences, message: s.stepMode ? "Step-mode resumed." : "Auto-mode resumed.", level: "progress" });
2581
2610
 
2582
2611
  try {
2583
- await s.orchestration?.resume();
2612
+ const resumeResult = await s.orchestration?.resume();
2613
+ if (resumeResult?.kind === "blocked") {
2614
+ notifyResumeBlocked(ctx, resumeResult);
2615
+ await cleanupAfterLoopExit(ctx);
2616
+ return;
2617
+ }
2584
2618
  } catch (err) {
2585
2619
  debugLog("resume-orchestration-resume", { error: err instanceof Error ? err.message : String(err) });
2586
2620
  }
@@ -2601,6 +2635,7 @@ export async function startAuto(
2601
2635
  const bootstrapDeps: BootstrapDeps = {
2602
2636
  shouldUseWorktreeIsolation,
2603
2637
  registerSigtermHandler,
2638
+ registerAutoWorkerForSession: (projectRoot) => registerAutoWorkerForSession(s, projectRoot),
2604
2639
  lockBase,
2605
2640
  buildLifecycle,
2606
2641
  };
@@ -32,6 +32,7 @@ import { shouldIgnoreAgentEndForActiveUnit } from "../auto/unit-runner-events.js
32
32
  import { resolveModelId } from "../auto-model-selection.js";
33
33
  import { resolveProjectRoot } from "../worktree.js";
34
34
  import { clearDiscussionFlowState } from "./write-gate.js";
35
+ import { clearGuidedUnitContext } from "../guided-unit-context.js";
35
36
  import { resumeAutoAfterProviderDelay } from "./provider-error-resume.js";
36
37
  import {
37
38
  classifyError,
@@ -48,6 +49,11 @@ const MAX_NETWORK_RETRIES = 2;
48
49
  function isObjectRecord(value: unknown): value is Record<string, unknown> {
49
50
  return !!value && typeof value === "object";
50
51
  }
52
+
53
+ export function _hasEmptyAgentEndContent(content: unknown): boolean {
54
+ return content == null || (Array.isArray(content) && content.length === 0);
55
+ }
56
+
51
57
  /**
52
58
  * Cap on auto-resume attempts for sustained transient-provider errors.
53
59
  *
@@ -94,6 +100,14 @@ export function isUserInitiatedAbortMessage(message: string | undefined | null):
94
100
  return /\b(?:claude code process aborted by user|request aborted by user|process aborted by user)\b/i.test(message);
95
101
  }
96
102
 
103
+ export function shouldDeferTransientErrorToCoreRetry(
104
+ cls: ErrorClass,
105
+ rawErrorMsg: string,
106
+ ): boolean {
107
+ if (!isTransient(cls) || cls.kind === "rate-limit") return false;
108
+ return !/retry failed after \d+ attempts:/i.test(rawErrorMsg);
109
+ }
110
+
97
111
  function isBareClaudeCodeSessionSwitchAbortMarker(message: string | undefined | null): boolean {
98
112
  if (!message) return false;
99
113
  const normalized = message.trim().replace(/\s+/g, " ").toLowerCase();
@@ -196,6 +210,14 @@ export function resolveAgentEndErrorDisplay(
196
210
  return rawErrorMsg;
197
211
  }
198
212
 
213
+ export function isTerminalDeletedWorktreeProviderError(
214
+ message: string | undefined | null,
215
+ ): boolean {
216
+ if (!message) return false;
217
+ if (!/\bdoes not exist\b/i.test(message)) return false;
218
+ return /[/\\]\.gsd[/\\](?:projects[/\\][^/\\]+[/\\])?worktrees[/\\][^/\\\s"']+/i.test(message);
219
+ }
220
+
199
221
  async function pauseTransientWithBackoff(
200
222
  cls: ErrorClass,
201
223
  pi: ExtensionAPI,
@@ -244,9 +266,11 @@ export async function handleAgentEnd(
244
266
  // falsely report files as missing — producing a spurious "ready signal
245
267
  // rejected" loop even though the files are on disk.
246
268
  clearPathCache();
269
+ const basePath = resolveAgentEndBasePath();
270
+ clearGuidedUnitContext(basePath);
247
271
 
248
272
  try {
249
- if (await checkDeepProjectSetupAfterTurn(event, ctx, resolveAgentEndBasePath())) {
273
+ if (await checkDeepProjectSetupAfterTurn(event, ctx, basePath)) {
250
274
  return;
251
275
  }
252
276
  } catch (err) {
@@ -254,8 +278,8 @@ export async function handleAgentEnd(
254
278
  logWarning("bootstrap", `checkDeepProjectSetupAfterTurn failed: ${message}`);
255
279
  }
256
280
 
257
- if (checkAutoStartAfterDiscuss()) {
258
- clearDiscussionFlowState(resolveAgentEndBasePath() ?? process.cwd());
281
+ if (checkAutoStartAfterDiscuss(basePath)) {
282
+ clearDiscussionFlowState(basePath ?? process.cwd());
259
283
  return;
260
284
  }
261
285
 
@@ -263,14 +287,14 @@ export async function handleAgentEnd(
263
287
  // are missing, `checkAutoStartAfterDiscuss` returns false silently. Surface
264
288
  // that and nudge the LLM to complete the writes before the user hits the
265
289
  // downstream "All milestones complete" warning loop.
266
- if (maybeHandleReadyPhraseWithoutFiles(event)) return;
290
+ if (maybeHandleReadyPhraseWithoutFiles(event, basePath)) return;
267
291
 
268
292
  // #4573 — Empty-turn recovery: if the LLM announced intent in prose but
269
293
  // emitted no tool calls, nudge it to execute. Fires only when auto-mode is
270
294
  // active or a discussion autostart is pending (non-auto interactive discuss
271
295
  // is user-driven). Runs before `isAutoActive` early return so pending
272
296
  // discussions (where isAutoActive may be false) still get recovered.
273
- if (maybeHandleEmptyIntentTurn(event, isAutoActive())) return;
297
+ if (maybeHandleEmptyIntentTurn(event, isAutoActive(), basePath)) return;
274
298
 
275
299
  if (!isAutoActive()) return;
276
300
 
@@ -310,7 +334,7 @@ export async function handleAgentEnd(
310
334
  // that carry error context — e.g. errorMessage field or non-empty content
311
335
  // indicating a mid-stream failure. (#2695)
312
336
  const content = "content" in lastMsg ? lastMsg.content : undefined;
313
- const hasEmptyContent = Array.isArray(content) && content.length === 0;
337
+ const hasEmptyContent = _hasEmptyAgentEndContent(content);
314
338
  const hasErrorMessage = "errorMessage" in lastMsg && !!lastMsg.errorMessage;
315
339
 
316
340
  if (hasEmptyContent && !hasErrorMessage) {
@@ -355,6 +379,17 @@ export async function handleAgentEnd(
355
379
  rawErrorMsg,
356
380
  "content" in lastMsg ? lastMsg.content : undefined,
357
381
  );
382
+ if (
383
+ isAutoCompletionStopInProgress() &&
384
+ isTerminalDeletedWorktreeProviderError(`${rawErrorMsg}\n${displayMsg}`)
385
+ ) {
386
+ resetRetryState(retryState);
387
+ logWarning(
388
+ "bootstrap",
389
+ `Ignoring stale deleted-worktree provider error during terminal completion reroot: ${displayMsg || rawErrorMsg}`,
390
+ );
391
+ return;
392
+ }
358
393
  const errorDetail = displayMsg ? `: ${displayMsg}` : "";
359
394
  const explicitRetryAfterMs = ("retryAfterMs" in lastMsg && typeof lastMsg.retryAfterMs === "number") ? lastMsg.retryAfterMs : undefined;
360
395
 
@@ -461,7 +496,7 @@ export async function handleAgentEnd(
461
496
  // Core retries transient failures in-session after this handler.
462
497
  // Keep that behavior for non-rate-limit classes to avoid pause/retry races,
463
498
  // but let rate-limit continue into model fallback logic below (#4373).
464
- if (isTransient(cls) && cls.kind !== "rate-limit") {
499
+ if (shouldDeferTransientErrorToCoreRetry(cls, rawErrorMsg)) {
465
500
  return;
466
501
  }
467
502
 
@@ -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')" })),
@@ -912,7 +913,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
912
913
  label: "Skip Slice",
913
914
  description:
914
915
  "Mark a slice as skipped so auto-mode advances past it without executing. " +
915
- "Non-closed tasks within the slice are cascaded to skipped so milestone completion is not blocked by leftover pending tasks (#4375). " +
916
+ "Non-closed tasks within the slice are cascaded to skipped so milestone completion is not blocked by leftover pending tasks. " +
916
917
  "The slice data is preserved for reference. The state machine treats skipped slices like completed ones for dependency satisfaction.",
917
918
  promptSnippet: "Skip a GSD slice (mark as skipped, auto-mode will advance past it)",
918
919
  promptGuidelines: [
@@ -31,6 +31,7 @@ import { resolveWorktreeProjectRoot } from "../worktree-root.js";
31
31
  import { extractSubagentAgentClasses } from "./subagent-input.js";
32
32
  import { approvalGateIdForUnit, isExplicitApprovalResponse, shouldPauseForUserApprovalQuestion } from "../user-input-boundary.js";
33
33
  import { resolveSkillManifest } from "../skill-manifest.js";
34
+ import { getGuidedUnitContext } from "../guided-unit-context.js";
34
35
 
35
36
  let approvalQuestionAbortInFlight = false;
36
37
 
@@ -772,7 +773,8 @@ export function registerHooks(
772
773
  // subagent dispatch. Closes the b23 bug class where a discuss-milestone
773
774
  // turn used the host Edit tool to modify user source files.
774
775
  const dash = getAutoRuntimeSnapshot();
775
- const activeUnitType = dash.currentUnit?.type;
776
+ const guidedUnit = getGuidedUnitContext(discussionBasePath);
777
+ const activeUnitType = dash.currentUnit?.type ?? guidedUnit?.unitType;
776
778
  if (activeUnitType) {
777
779
  const manifest = resolveManifest(activeUnitType);
778
780
  if (manifest) {
@@ -791,7 +793,7 @@ export function registerHooks(
791
793
  const planningGuard = shouldBlockPlanningUnit(
792
794
  event.toolName,
793
795
  planningInput,
794
- dash.basePath || discussionBasePath,
796
+ dash.basePath || guidedUnit?.basePath || discussionBasePath,
795
797
  activeUnitType,
796
798
  manifest.tools,
797
799
  agentClasses,
@@ -4,7 +4,9 @@ export function extractSubagentAgentClasses(input: unknown): string[] {
4
4
  const agentClasses: string[] = [];
5
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
11
 
10
12
  const visitItems = (value: unknown): void => {
@@ -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>;
@@ -747,7 +748,7 @@ function matchesAllowedGlob(absPath: string, basePath: string, globs: readonly s
747
748
  function blockReason(unitType: string, mode: string, what: string): string {
748
749
  return [
749
750
  `HARD BLOCK: unit "${unitType}" runs under tools-policy "${mode}" — ${what}.`,
750
- `This is a mechanical gate enforced by manifest.tools (#4934). You MUST NOT proceed,`,
751
+ `This is a mechanical gate enforced by manifest.tools. You MUST NOT proceed,`,
751
752
  `retry the same call, or rationalize past this block. If you need to write user source,`,
752
753
  `the work belongs in execute-task, not in a planning unit.`,
753
754
  ].join(" ");
@@ -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,7 +808,7 @@ 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
 
@@ -862,6 +866,17 @@ export function shouldBlockPlanningUnit(
862
866
  }
863
867
 
864
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
+ }
865
880
  if (BASH_READ_ONLY_RE.test(pathOrCommand)) return { block: false };
866
881
  return {
867
882
  block: true,
@@ -1,6 +1,7 @@
1
1
  import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext } from "@gsd/pi-coding-agent";
2
2
  import type { Model } from "@gsd/pi-ai";
3
3
  import type { GSDState } from "../../types.js";
4
+ import { createRequire } from "node:module";
4
5
 
5
6
  import { computeProgressScore, formatProgressLine } from "../../progress-score.js";
6
7
  import { loadEffectiveGSDPreferences, getGlobalGSDPreferencesPath, getProjectGSDPreferencesPath } from "../../preferences.js";
@@ -220,7 +221,22 @@ export async function handleBrief(args: string, ctx: ExtensionCommandContext, pi
220
221
  }
221
222
 
222
223
  const outputDir = getVisualBriefOutputDir();
223
- pi.sendUserMessage(buildVisualBriefPrompt(request, { outputDir }));
224
+ const version = resolveGsdVersion();
225
+ pi.sendUserMessage(buildVisualBriefPrompt(request, { outputDir, version }));
226
+ }
227
+
228
+ const briefRequire = createRequire(import.meta.url);
229
+
230
+ function resolveGsdVersion(): string | undefined {
231
+ const envVersion = process.env.GSD_VERSION?.trim();
232
+ if (envVersion) return envVersion;
233
+ try {
234
+ const pkg = briefRequire("../../../../../../package.json") as { version?: unknown };
235
+ const fromPkg = typeof pkg.version === "string" ? pkg.version.trim() : "";
236
+ return fromPkg || undefined;
237
+ } catch {
238
+ return undefined;
239
+ }
224
240
  }
225
241
 
226
242
  export async function handleSetup(args: string, ctx: ExtensionCommandContext, pi?: ExtensionAPI): Promise<void> {
@@ -587,10 +587,15 @@ async function configureModels(ctx: ExtensionCommandContext, prefs: Record<strin
587
587
  const models: Record<string, unknown> = (prefs.models as Record<string, unknown>) ?? {};
588
588
 
589
589
  const availableModels = ctx.modelRegistry.getAvailable();
590
- if (availableModels.length > 0) {
590
+ const getAllWithDiscovered = (ctx.modelRegistry as { getAllWithDiscovered?: () => typeof availableModels }).getAllWithDiscovered;
591
+ const availableProviders = new Set(availableModels.map((m) => m.provider));
592
+ const selectableModels = typeof getAllWithDiscovered === "function"
593
+ ? getAllWithDiscovered().filter((m) => availableProviders.has(m.provider))
594
+ : availableModels;
595
+ if (selectableModels.length > 0) {
591
596
  // Group models by provider, sorted alphabetically
592
- const byProvider = new Map<string, typeof availableModels>();
593
- for (const m of availableModels) {
597
+ const byProvider = new Map<string, typeof selectableModels>();
598
+ for (const m of selectableModels) {
594
599
  let group = byProvider.get(m.provider);
595
600
  if (!group) {
596
601
  group = [];
@@ -30,9 +30,12 @@ import { join } from "node:path";
30
30
  import {
31
31
  findStaleWorkerForProject,
32
32
  getAllAutoWorkers,
33
+ markWorkerCrashed,
34
+ markWorkerStopping,
33
35
  type AutoWorkerRow,
34
36
  } from "./db/auto-workers.js";
35
- import { getLatestForUnit, type DispatchStatus } from "./db/unit-dispatches.js";
37
+ import { forceReleaseLeasesForWorker } from "./db/milestone-leases.js";
38
+ import { markLatestActiveForWorkerCanceled, type DispatchStatus } from "./db/unit-dispatches.js";
36
39
  import { getRuntimeKv, setRuntimeKv, deleteRuntimeKv } from "./db/runtime-kv.js";
37
40
  import { _getAdapter, isDbAvailable } from "./gsd-db.js";
38
41
  import { gsdRoot, normalizeRealPath } from "./paths.js";
@@ -56,6 +59,15 @@ function lockPath(basePath: string): string {
56
59
  return join(gsdRoot(basePath), effectiveLockFile());
57
60
  }
58
61
 
62
+ function clearLegacyLockFile(basePath: string): void {
63
+ try {
64
+ const p = lockPath(basePath);
65
+ if (existsSync(p)) unlinkSync(p);
66
+ } catch {
67
+ // Best-effort.
68
+ }
69
+ }
70
+
59
71
  function readLegacyLock(basePath: string): LockData | null {
60
72
  try {
61
73
  const p = lockPath(basePath);
@@ -204,18 +216,46 @@ export function writeLock(
204
216
  * stale session-file pointer.
205
217
  */
206
218
  export function clearLock(basePath: string): void {
219
+ clearLegacyLockFile(basePath);
220
+
221
+ if (!isDbAvailable()) return;
207
222
  try {
208
- const p = lockPath(basePath);
209
- if (existsSync(p)) unlinkSync(p);
223
+ const projectRoot = normalizeRealPath(basePath);
224
+ const staleWorker = findStaleWorkerForProject(projectRoot);
225
+ if (staleWorker) {
226
+ markWorkerCrashed(staleWorker.worker_id);
227
+ forceReleaseLeasesForWorker(staleWorker.worker_id);
228
+ deleteRuntimeKv("worker", staleWorker.worker_id, SESSION_FILE_KV_KEY);
229
+ return;
230
+ }
231
+ const worker = findActiveWorkerForCurrentProcess(projectRoot);
232
+ if (worker) deleteRuntimeKv("worker", worker.worker_id, SESSION_FILE_KV_KEY);
233
+
234
+ const stale = findStaleWorkerForProject(projectRoot);
235
+ if (stale) {
236
+ markWorkerStopping(stale.worker_id);
237
+ deleteRuntimeKv("worker", stale.worker_id, SESSION_FILE_KV_KEY);
238
+ }
210
239
  } catch {
211
240
  // Best-effort.
212
241
  }
242
+ }
243
+
244
+ /**
245
+ * Clear a stale DB-backed worker lock after readCrashLock/findStaleWorkerForProject
246
+ * has identified a dead worker. Unlike clearLock(), this targets the stale
247
+ * worker row instead of the current process's active worker.
248
+ */
249
+ export function clearStaleWorkerLock(basePath: string): void {
250
+ clearLegacyLockFile(basePath);
213
251
 
214
252
  if (!isDbAvailable()) return;
215
253
  try {
216
254
  const projectRoot = normalizeRealPath(basePath);
217
- const worker = findActiveWorkerForCurrentProcess(projectRoot);
255
+ const worker = findStaleWorkerForProject(projectRoot);
218
256
  if (!worker) return;
257
+ markLatestActiveForWorkerCanceled(worker.worker_id, "crash-recovered");
258
+ markWorkerCrashed(worker.worker_id);
219
259
  deleteRuntimeKv("worker", worker.worker_id, SESSION_FILE_KV_KEY);
220
260
  } catch {
221
261
  // Best-effort.
@@ -255,6 +255,32 @@ export function releaseMilestoneLease(
255
255
  });
256
256
  }
257
257
 
258
+ /**
259
+ * Force-release all held leases for a worker.
260
+ *
261
+ * Used by crash recovery once PID liveness has confirmed the worker is dead.
262
+ * No fencing token is required because this path is cleanup-only for a
263
+ * non-running process.
264
+ */
265
+ export function forceReleaseLeasesForWorker(workerId: string): number {
266
+ if (!isDbAvailable()) return 0;
267
+ const db = _getAdapter()!;
268
+ let changes = 0;
269
+ transaction(() => {
270
+ const result = db.prepare(
271
+ `UPDATE milestone_leases
272
+ SET status = 'released'
273
+ WHERE worker_id = :worker_id
274
+ AND status = 'held'`,
275
+ ).run({ ":worker_id": workerId });
276
+ changes =
277
+ typeof (result as { changes?: unknown }).changes === "number"
278
+ ? (result as { changes: number }).changes
279
+ : 0;
280
+ });
281
+ return changes;
282
+ }
283
+
258
284
  /**
259
285
  * Read current lease row for diagnostics. Returns null if no row exists.
260
286
  */
@@ -524,17 +524,18 @@ export function getRecentUnitKeysForProjectRoot(
524
524
  if (!isDbAvailable()) return [];
525
525
  const db = _getAdapter()!;
526
526
  const rows = db.prepare(
527
- `SELECT ud.unit_id
527
+ `SELECT ud.unit_type, ud.unit_id
528
528
  FROM unit_dispatches ud
529
529
  INNER JOIN workers w ON w.worker_id = ud.worker_id
530
530
  WHERE w.project_root_realpath = :project_root_realpath
531
+ AND w.status != 'crashed'
531
532
  ORDER BY ud.started_at DESC, ud.id DESC
532
533
  LIMIT :limit`,
533
534
  ).all({
534
535
  ":project_root_realpath": projectRootRealpath,
535
536
  ":limit": limit,
536
- }) as Array<{ unit_id: string }>;
537
- return rows.reverse().map((r) => ({ key: r.unit_id }));
537
+ }) as Array<{ unit_type: string; unit_id: string }>;
538
+ return rows.reverse().map((r) => ({ key: `${r.unit_type}/${r.unit_id}` }));
538
539
  }
539
540
 
540
541
  /**
@@ -5,7 +5,7 @@ import { findMilestoneIds } from "./guided-flow.js";
5
5
  import { parseUnitId } from "./unit-id.js";
6
6
  import { isDbAvailable, getMilestoneSlices, getMilestone } from "./gsd-db.js";
7
7
  import { parseRoadmap } from "./parsers-legacy.js";
8
- import { isClosedStatus } from "./status-guards.js";
8
+ import { isClosedStatus, isSkippedForDispatch } from "./status-guards.js";
9
9
  import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.js";
10
10
  import { readFileSync } from "node:fs";
11
11
 
@@ -58,7 +58,7 @@ export function getPriorSliceCompletionBlocker(
58
58
  // DB-backed projects must not treat SUMMARY.md as authoritative.
59
59
  if (isDbAvailable()) {
60
60
  const milestoneRow = getMilestone(mid);
61
- if (milestoneRow && isClosedStatus(milestoneRow.status)) continue;
61
+ if (milestoneRow && isSkippedForDispatch(milestoneRow.status)) continue;
62
62
  } else {
63
63
  const summaryPath = resolveMilestoneFile(base, mid, "SUMMARY");
64
64
  let summaryContent: string | null = null;