@opengsd/gsd-pi 1.2.0-dev.e8563f58 → 1.2.0-dev.fbdca60b

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 (432) hide show
  1. package/dist/cli-model-override.d.ts +15 -0
  2. package/dist/cli-model-override.js +21 -0
  3. package/dist/cli.js +1 -18
  4. package/dist/loader.js +6 -4
  5. package/dist/register-agent-bundles.d.ts +11 -2
  6. package/dist/register-agent-bundles.js +18 -4
  7. package/dist/resource-loader.d.ts +10 -5
  8. package/dist/resource-loader.js +121 -6
  9. package/dist/resources/.managed-resources-content-hash +1 -1
  10. package/dist/resources/extensions/ask-user-questions.js +3 -2
  11. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +447 -215
  12. package/dist/resources/extensions/claude-code-cli/turn-assembler.js +33 -1
  13. package/dist/resources/extensions/gsd/auto/closeout.js +215 -0
  14. package/dist/resources/extensions/gsd/auto/dispatch-history.js +21 -6
  15. package/dist/resources/extensions/gsd/auto/dispatch.js +365 -0
  16. package/dist/resources/extensions/gsd/auto/finalize.js +347 -0
  17. package/dist/resources/extensions/gsd/auto/loop.js +4 -1
  18. package/dist/resources/extensions/gsd/auto/milestone-lease-reclaim.js +56 -0
  19. package/dist/resources/extensions/gsd/auto/orchestrator.js +85 -15
  20. package/dist/resources/extensions/gsd/auto/phase-helpers.js +146 -0
  21. package/dist/resources/extensions/gsd/auto/phases.js +17 -2329
  22. package/dist/resources/extensions/gsd/auto/pre-dispatch.js +534 -0
  23. package/dist/resources/extensions/gsd/auto/session.js +3 -0
  24. package/dist/resources/extensions/gsd/auto/unit-phase.js +694 -0
  25. package/dist/resources/extensions/gsd/auto/workflow-unit-dispatch.js +1 -1
  26. package/dist/resources/extensions/gsd/auto/worktree-safety-phase.js +125 -0
  27. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +3 -2
  28. package/dist/resources/extensions/gsd/auto-dispatch.js +11 -2
  29. package/dist/resources/extensions/gsd/auto-post-unit.js +18 -6
  30. package/dist/resources/extensions/gsd/auto-start.js +23 -3
  31. package/dist/resources/extensions/gsd/auto-unit-closeout.js +45 -21
  32. package/dist/resources/extensions/gsd/auto-verification.js +14 -2
  33. package/dist/resources/extensions/gsd/auto-worktree.js +15 -2
  34. package/dist/resources/extensions/gsd/auto.js +45 -2
  35. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +37 -7
  36. package/dist/resources/extensions/gsd/commands/context.js +16 -2
  37. package/dist/resources/extensions/gsd/commands-mcp-status.js +2 -2
  38. package/dist/resources/extensions/gsd/commands-workflow-templates.js +9 -2
  39. package/dist/resources/extensions/gsd/crash-recovery.js +8 -3
  40. package/dist/resources/extensions/gsd/db/engine.js +24 -6
  41. package/dist/resources/extensions/gsd/db/queries.js +30 -0
  42. package/dist/resources/extensions/gsd/db-migration-backup.js +51 -8
  43. package/dist/resources/extensions/gsd/db-transaction.js +27 -23
  44. package/dist/resources/extensions/gsd/db-writer.js +8 -17
  45. package/dist/resources/extensions/gsd/doctor-engine-checks.js +5 -5
  46. package/dist/resources/extensions/gsd/doctor-environment.js +256 -125
  47. package/dist/resources/extensions/gsd/gsd-db.js +15 -20
  48. package/dist/resources/extensions/gsd/guided-flow.js +93 -4
  49. package/dist/resources/extensions/gsd/health-widget.js +87 -28
  50. package/dist/resources/extensions/gsd/mcp-bridge.js +10 -0
  51. package/dist/resources/extensions/gsd/memory-relations.js +1 -1
  52. package/dist/resources/extensions/gsd/milestone-planning-persistence.js +2 -2
  53. package/dist/resources/extensions/gsd/milestone-reopen-events.js +3 -5
  54. package/dist/resources/extensions/gsd/milestone-settlement.js +2 -2
  55. package/dist/resources/extensions/gsd/notifications.js +12 -7
  56. package/dist/resources/extensions/gsd/projection-flush.js +7 -0
  57. package/dist/resources/extensions/gsd/prompts/complete-slice.md +2 -2
  58. package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -2
  59. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  60. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  61. package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -1
  62. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  63. package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  64. package/dist/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  65. package/dist/resources/extensions/gsd/prompts/research-milestone.md +1 -1
  66. package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
  67. package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  68. package/dist/resources/extensions/gsd/prompts/run-uat.md +3 -1
  69. package/dist/resources/extensions/gsd/prompts/triage-captures.md +1 -1
  70. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +1 -1
  71. package/dist/resources/extensions/gsd/prompts/workflow-start.md +2 -1
  72. package/dist/resources/extensions/gsd/roadmap-slices.js +25 -3
  73. package/dist/resources/extensions/gsd/session-lock.js +1 -1
  74. package/dist/resources/extensions/gsd/skill-activation.js +3 -6
  75. package/dist/resources/extensions/gsd/state.js +6 -2
  76. package/dist/resources/extensions/gsd/tool-contract.js +14 -3
  77. package/dist/resources/extensions/gsd/tool-surface-readiness.js +83 -31
  78. package/dist/resources/extensions/gsd/tools/complete-milestone.js +3 -2
  79. package/dist/resources/extensions/gsd/tools/complete-slice.js +2 -2
  80. package/dist/resources/extensions/gsd/tools/complete-task.js +65 -2
  81. package/dist/resources/extensions/gsd/tools/plan-slice.js +2 -2
  82. package/dist/resources/extensions/gsd/tools/plan-task.js +2 -2
  83. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +2 -2
  84. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +2 -2
  85. package/dist/resources/extensions/gsd/tools/reopen-slice.js +2 -2
  86. package/dist/resources/extensions/gsd/tools/reopen-task.js +2 -2
  87. package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -2
  88. package/dist/resources/extensions/gsd/unit-context-composer.js +1 -1
  89. package/dist/resources/extensions/gsd/unit-registry.js +34 -4
  90. package/dist/resources/extensions/gsd/verification-verdict.js +2 -1
  91. package/dist/resources/extensions/gsd/workflow-event-ledger.js +91 -0
  92. package/dist/resources/extensions/gsd/workflow-event-vocabulary.js +46 -0
  93. package/dist/resources/extensions/gsd/workflow-events.js +6 -18
  94. package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +2 -0
  95. package/dist/resources/extensions/gsd/workflow-mcp-readiness-cache.js +105 -0
  96. package/dist/resources/extensions/gsd/workflow-reconcile.js +21 -56
  97. package/dist/resources/extensions/gsd/worktree-manager.js +7 -1
  98. package/dist/resources/extensions/gsd/worktree-safety.js +28 -26
  99. package/dist/resources/extensions/gsd/worktree.js +8 -1
  100. package/dist/resources/extensions/mcp-client/manager.js +6 -1
  101. package/dist/resources/skills/create-skill/SKILL.md +3 -0
  102. package/dist/resources/skills/create-skill/references/skill-structure.md +1 -0
  103. package/dist/runtime-checks.d.ts +10 -0
  104. package/dist/runtime-checks.js +27 -0
  105. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  106. package/dist/web/standalone/.next/BUILD_ID +1 -1
  107. package/dist/web/standalone/.next/app-path-routes-manifest.json +7 -7
  108. package/dist/web/standalone/.next/build-manifest.json +2 -2
  109. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  110. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  111. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  118. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  119. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  122. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  127. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  128. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  129. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  130. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  131. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  132. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  133. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  134. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  135. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  136. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  137. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  138. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  139. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  140. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  141. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  142. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
  143. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  144. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  145. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  146. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  147. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  148. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  149. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  150. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  151. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  152. package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
  153. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  154. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  155. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  156. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  157. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  158. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  159. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  160. package/dist/web/standalone/.next/server/app/index.html +1 -1
  161. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  162. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  163. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  164. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  165. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  166. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  167. package/dist/web/standalone/.next/server/app-paths-manifest.json +7 -7
  168. package/dist/web/standalone/.next/server/chunks/{5942.js → 1128.js} +1 -1
  169. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  170. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  171. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  172. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  173. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  174. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  175. package/package.json +3 -3
  176. package/packages/cloud-mcp-gateway/package.json +2 -2
  177. package/packages/contracts/package.json +1 -1
  178. package/packages/daemon/package.json +4 -4
  179. package/packages/gsd-agent-core/dist/sdk.d.ts.map +1 -1
  180. package/packages/gsd-agent-core/dist/sdk.js +6 -4
  181. package/packages/gsd-agent-core/dist/sdk.js.map +1 -1
  182. package/packages/gsd-agent-core/package.json +5 -5
  183. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  184. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  185. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +10 -0
  186. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
  187. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +8 -0
  188. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  189. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +50 -6
  190. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  191. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts +2 -0
  192. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
  193. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +34 -5
  194. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
  195. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts +1 -0
  196. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  197. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +17 -0
  198. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
  199. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.d.ts.map +1 -1
  200. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js +4 -0
  201. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js.map +1 -1
  202. package/packages/gsd-agent-modes/package.json +7 -7
  203. package/packages/mcp-server/README.md +12 -3
  204. package/packages/mcp-server/dist/cli-runner.d.ts +40 -0
  205. package/packages/mcp-server/dist/cli-runner.d.ts.map +1 -0
  206. package/packages/mcp-server/dist/cli-runner.js +137 -0
  207. package/packages/mcp-server/dist/cli-runner.js.map +1 -0
  208. package/packages/mcp-server/dist/cli.js +2 -53
  209. package/packages/mcp-server/dist/cli.js.map +1 -1
  210. package/packages/mcp-server/dist/pid-registry.d.ts +46 -0
  211. package/packages/mcp-server/dist/pid-registry.d.ts.map +1 -0
  212. package/packages/mcp-server/dist/pid-registry.js +459 -0
  213. package/packages/mcp-server/dist/pid-registry.js.map +1 -0
  214. package/packages/mcp-server/dist/probe-mode.d.ts +4 -0
  215. package/packages/mcp-server/dist/probe-mode.d.ts.map +1 -0
  216. package/packages/mcp-server/dist/probe-mode.js +10 -0
  217. package/packages/mcp-server/dist/probe-mode.js.map +1 -0
  218. package/packages/mcp-server/dist/stdio-watchdog.d.ts +8 -0
  219. package/packages/mcp-server/dist/stdio-watchdog.d.ts.map +1 -0
  220. package/packages/mcp-server/dist/stdio-watchdog.js +40 -0
  221. package/packages/mcp-server/dist/stdio-watchdog.js.map +1 -0
  222. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  223. package/packages/mcp-server/dist/workflow-tools.js +62 -43
  224. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  225. package/packages/mcp-server/package.json +5 -5
  226. package/packages/native/package.json +1 -1
  227. package/packages/pi-agent-core/dist/agent-loop.js +43 -2
  228. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  229. package/packages/pi-agent-core/package.json +1 -1
  230. package/packages/pi-ai/package.json +1 -1
  231. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
  232. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  233. package/packages/pi-coding-agent/dist/core/settings-manager.js +11 -0
  234. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  235. package/packages/pi-coding-agent/dist/theme/theme.d.ts.map +1 -1
  236. package/packages/pi-coding-agent/dist/theme/theme.js +45 -17
  237. package/packages/pi-coding-agent/dist/theme/theme.js.map +1 -1
  238. package/packages/pi-coding-agent/package.json +7 -7
  239. package/packages/pi-tui/README.md +15 -0
  240. package/packages/pi-tui/dist/index.d.ts +2 -2
  241. package/packages/pi-tui/dist/index.d.ts.map +1 -1
  242. package/packages/pi-tui/dist/index.js +2 -2
  243. package/packages/pi-tui/dist/index.js.map +1 -1
  244. package/packages/pi-tui/dist/terminal-image.d.ts +33 -0
  245. package/packages/pi-tui/dist/terminal-image.d.ts.map +1 -1
  246. package/packages/pi-tui/dist/terminal-image.js +54 -2
  247. package/packages/pi-tui/dist/terminal-image.js.map +1 -1
  248. package/packages/pi-tui/dist/terminal.d.ts +12 -0
  249. package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
  250. package/packages/pi-tui/dist/terminal.js +70 -25
  251. package/packages/pi-tui/dist/terminal.js.map +1 -1
  252. package/packages/pi-tui/dist/tui.d.ts +15 -0
  253. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  254. package/packages/pi-tui/dist/tui.js +106 -21
  255. package/packages/pi-tui/dist/tui.js.map +1 -1
  256. package/packages/pi-tui/dist/utils.d.ts.map +1 -1
  257. package/packages/pi-tui/dist/utils.js +110 -36
  258. package/packages/pi-tui/dist/utils.js.map +1 -1
  259. package/packages/pi-tui/package.json +2 -2
  260. package/packages/rpc-client/package.json +2 -2
  261. package/pkg/dist/theme/theme.d.ts.map +1 -1
  262. package/pkg/dist/theme/theme.js +45 -17
  263. package/pkg/dist/theme/theme.js.map +1 -1
  264. package/pkg/package.json +1 -1
  265. package/src/resources/extensions/ask-user-questions.ts +7 -2
  266. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +531 -226
  267. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +672 -7
  268. package/src/resources/extensions/claude-code-cli/turn-assembler.ts +38 -1
  269. package/src/resources/extensions/gsd/auto/closeout.ts +309 -0
  270. package/src/resources/extensions/gsd/auto/dispatch-history.ts +22 -6
  271. package/src/resources/extensions/gsd/auto/dispatch.ts +449 -0
  272. package/src/resources/extensions/gsd/auto/finalize.ts +445 -0
  273. package/src/resources/extensions/gsd/auto/loop.ts +4 -1
  274. package/src/resources/extensions/gsd/auto/milestone-lease-reclaim.ts +74 -0
  275. package/src/resources/extensions/gsd/auto/orchestrator.ts +95 -15
  276. package/src/resources/extensions/gsd/auto/phase-helpers.ts +199 -0
  277. package/src/resources/extensions/gsd/auto/phases.ts +58 -3022
  278. package/src/resources/extensions/gsd/auto/pre-dispatch.ts +704 -0
  279. package/src/resources/extensions/gsd/auto/session.ts +3 -0
  280. package/src/resources/extensions/gsd/auto/unit-phase.ts +910 -0
  281. package/src/resources/extensions/gsd/auto/workflow-unit-dispatch.ts +1 -1
  282. package/src/resources/extensions/gsd/auto/worktree-safety-phase.ts +149 -0
  283. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +10 -16
  284. package/src/resources/extensions/gsd/auto-dispatch.ts +11 -10
  285. package/src/resources/extensions/gsd/auto-post-unit.ts +21 -6
  286. package/src/resources/extensions/gsd/auto-start.ts +24 -4
  287. package/src/resources/extensions/gsd/auto-unit-closeout.ts +83 -28
  288. package/src/resources/extensions/gsd/auto-verification.ts +18 -2
  289. package/src/resources/extensions/gsd/auto-worktree.ts +15 -2
  290. package/src/resources/extensions/gsd/auto.ts +56 -2
  291. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +56 -6
  292. package/src/resources/extensions/gsd/commands/context.ts +16 -2
  293. package/src/resources/extensions/gsd/commands-mcp-status.ts +2 -2
  294. package/src/resources/extensions/gsd/commands-workflow-templates.ts +11 -4
  295. package/src/resources/extensions/gsd/crash-recovery.ts +10 -2
  296. package/src/resources/extensions/gsd/db/engine.ts +26 -6
  297. package/src/resources/extensions/gsd/db/queries.ts +29 -0
  298. package/src/resources/extensions/gsd/db-migration-backup.ts +56 -7
  299. package/src/resources/extensions/gsd/db-transaction.ts +37 -20
  300. package/src/resources/extensions/gsd/db-writer.ts +11 -19
  301. package/src/resources/extensions/gsd/doctor-engine-checks.ts +5 -4
  302. package/src/resources/extensions/gsd/doctor-environment.ts +267 -142
  303. package/src/resources/extensions/gsd/gsd-db.ts +15 -19
  304. package/src/resources/extensions/gsd/guided-flow.ts +145 -24
  305. package/src/resources/extensions/gsd/health-widget.ts +91 -27
  306. package/src/resources/extensions/gsd/mcp-bridge.ts +39 -0
  307. package/src/resources/extensions/gsd/memory-relations.ts +1 -1
  308. package/src/resources/extensions/gsd/milestone-planning-persistence.ts +2 -2
  309. package/src/resources/extensions/gsd/milestone-reopen-events.ts +3 -6
  310. package/src/resources/extensions/gsd/milestone-settlement.ts +2 -2
  311. package/src/resources/extensions/gsd/notifications.ts +13 -6
  312. package/src/resources/extensions/gsd/projection-flush.ts +20 -0
  313. package/src/resources/extensions/gsd/prompts/complete-slice.md +2 -2
  314. package/src/resources/extensions/gsd/prompts/execute-task.md +3 -2
  315. package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  316. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  317. package/src/resources/extensions/gsd/prompts/quick-task.md +1 -1
  318. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  319. package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  320. package/src/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  321. package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
  322. package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
  323. package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  324. package/src/resources/extensions/gsd/prompts/run-uat.md +3 -1
  325. package/src/resources/extensions/gsd/prompts/triage-captures.md +1 -1
  326. package/src/resources/extensions/gsd/prompts/validate-milestone.md +1 -1
  327. package/src/resources/extensions/gsd/prompts/workflow-start.md +2 -1
  328. package/src/resources/extensions/gsd/roadmap-slices.ts +28 -3
  329. package/src/resources/extensions/gsd/session-lock.ts +1 -1
  330. package/src/resources/extensions/gsd/skill-activation.ts +3 -6
  331. package/src/resources/extensions/gsd/state.ts +7 -1
  332. package/src/resources/extensions/gsd/tests/auto-abort-pause-regression.test.ts +1 -1
  333. package/src/resources/extensions/gsd/tests/auto-blocked-remediation-message.test.ts +1 -1
  334. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +206 -22
  335. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +6 -1
  336. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +76 -12
  337. package/src/resources/extensions/gsd/tests/auto-pause-double-entry-guard.test.ts +1 -1
  338. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +77 -1
  339. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +2 -1
  340. package/src/resources/extensions/gsd/tests/auto-remote-session-lock-cleanup.test.ts +65 -3
  341. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +236 -0
  342. package/src/resources/extensions/gsd/tests/auto-unit-closeout.test.ts +169 -1
  343. package/src/resources/extensions/gsd/tests/complete-task.test.ts +141 -5
  344. package/src/resources/extensions/gsd/tests/db-migration-backup.test.ts +68 -19
  345. package/src/resources/extensions/gsd/tests/db-transaction.test.ts +59 -0
  346. package/src/resources/extensions/gsd/tests/db-writer.test.ts +15 -4
  347. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +2 -1
  348. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +62 -0
  349. package/src/resources/extensions/gsd/tests/discuss-routing-fixes.test.ts +12 -2
  350. package/src/resources/extensions/gsd/tests/dispatch-history.test.ts +55 -0
  351. package/src/resources/extensions/gsd/tests/dist-redirect.mjs +8 -0
  352. package/src/resources/extensions/gsd/tests/engine-interfaces-contract.test.ts +117 -91
  353. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +113 -0
  354. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +19 -0
  355. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +18 -6
  356. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +15 -0
  357. package/src/resources/extensions/gsd/tests/integration/doctor-environment-async.test.ts +104 -0
  358. package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +18 -0
  359. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +47 -16
  360. package/src/resources/extensions/gsd/tests/mcp-readiness-preflight.test.ts +205 -0
  361. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +6 -5
  362. package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +1 -1
  363. package/src/resources/extensions/gsd/tests/milestone-report-path.test.ts +1 -1
  364. package/src/resources/extensions/gsd/tests/milestone-settlement.test.ts +92 -0
  365. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +1 -1
  366. package/src/resources/extensions/gsd/tests/notifications.test.ts +64 -9
  367. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +2 -2
  368. package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +5 -0
  369. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +1 -1
  370. package/src/resources/extensions/gsd/tests/phases-terminal-complete-idempotent.test.ts +242 -0
  371. package/src/resources/extensions/gsd/tests/plan-gate-failed-doctor-heal-hint.test.ts +3 -3
  372. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +63 -2
  373. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +10 -2
  374. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +2 -4
  375. package/src/resources/extensions/gsd/tests/remote-notification-from-desktop.test.ts +31 -81
  376. package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +68 -0
  377. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +26 -2
  378. package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +170 -48
  379. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +20 -17
  380. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +7 -3
  381. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +1 -1
  382. package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +17 -0
  383. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +4 -2
  384. package/src/resources/extensions/gsd/tests/tool-surface-readiness.test.ts +184 -10
  385. package/src/resources/extensions/gsd/tests/tool-unavailable-retry.test.ts +33 -0
  386. package/src/resources/extensions/gsd/tests/transport-gate-double-complete.test.ts +139 -0
  387. package/src/resources/extensions/gsd/tests/uok-audit-unified.test.ts +8 -0
  388. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +1 -1
  389. package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +2 -0
  390. package/src/resources/extensions/gsd/tests/workflow-events.test.ts +19 -0
  391. package/src/resources/extensions/gsd/tests/workflow-mcp-readiness-cache.test.ts +119 -0
  392. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +65 -2
  393. package/src/resources/extensions/gsd/tests/workflow-phase-contract-matrix.test.ts +332 -0
  394. package/src/resources/extensions/gsd/tests/workflow-reconcile.test.ts +20 -0
  395. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +92 -0
  396. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +1 -1
  397. package/src/resources/extensions/gsd/tests/worktree-project-root-degrade.test.ts +1 -1
  398. package/src/resources/extensions/gsd/tests/worktree-safety-phase.test.ts +100 -0
  399. package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +72 -0
  400. package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +22 -0
  401. package/src/resources/extensions/gsd/tests/worktree.test.ts +18 -0
  402. package/src/resources/extensions/gsd/tool-contract.ts +38 -3
  403. package/src/resources/extensions/gsd/tool-surface-readiness.ts +126 -19
  404. package/src/resources/extensions/gsd/tools/complete-milestone.ts +3 -2
  405. package/src/resources/extensions/gsd/tools/complete-slice.ts +2 -2
  406. package/src/resources/extensions/gsd/tools/complete-task.ts +90 -2
  407. package/src/resources/extensions/gsd/tools/plan-slice.ts +2 -2
  408. package/src/resources/extensions/gsd/tools/plan-task.ts +2 -2
  409. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +2 -2
  410. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +2 -2
  411. package/src/resources/extensions/gsd/tools/reopen-slice.ts +2 -2
  412. package/src/resources/extensions/gsd/tools/reopen-task.ts +2 -2
  413. package/src/resources/extensions/gsd/tools/replan-slice.ts +2 -2
  414. package/src/resources/extensions/gsd/unit-context-composer.ts +1 -1
  415. package/src/resources/extensions/gsd/unit-registry.ts +34 -4
  416. package/src/resources/extensions/gsd/verification-verdict.ts +4 -2
  417. package/src/resources/extensions/gsd/workflow-event-ledger.ts +131 -0
  418. package/src/resources/extensions/gsd/workflow-event-vocabulary.ts +59 -0
  419. package/src/resources/extensions/gsd/workflow-events.ts +12 -20
  420. package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +2 -0
  421. package/src/resources/extensions/gsd/workflow-mcp-readiness-cache.ts +150 -0
  422. package/src/resources/extensions/gsd/workflow-reconcile.ts +29 -62
  423. package/src/resources/extensions/gsd/worktree-manager.ts +6 -1
  424. package/src/resources/extensions/gsd/worktree-safety.ts +41 -39
  425. package/src/resources/extensions/gsd/worktree.ts +7 -1
  426. package/src/resources/extensions/mcp-client/manager.ts +7 -1
  427. package/src/resources/skills/create-skill/SKILL.md +3 -0
  428. package/src/resources/skills/create-skill/references/skill-structure.md +1 -0
  429. package/dist/resources/skills/gsd-browser/SKILL.md +0 -41
  430. package/src/resources/skills/gsd-browser/SKILL.md +0 -41
  431. /package/dist/web/standalone/.next/static/{LDHRKiRBIVZmiuMjrL1Vy → 2T9IOdiiM3o3gZ4UbPi8E}/_buildManifest.js +0 -0
  432. /package/dist/web/standalone/.next/static/{LDHRKiRBIVZmiuMjrL1Vy → 2T9IOdiiM3o3gZ4UbPi8E}/_ssgManifest.js +0 -0
@@ -10,7 +10,7 @@ import type {
10
10
  } from "./types.js";
11
11
  import { ExecutionGraphScheduler } from "../uok/execution-graph.js";
12
12
  import type { UokGraphNode } from "../uok/contracts.js";
13
- import { runUnitPhase } from "./phases.js";
13
+ import { runUnitPhase } from "./unit-phase.js";
14
14
  import { decideDispatchNodeKind } from "./workflow-kernel.js";
15
15
 
16
16
  export type DispatchContract = "legacy-direct" | "uok-scheduler";
@@ -0,0 +1,149 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Worktree-safety helpers shared across auto-loop phase modules.
3
+
4
+ import { classifyProject } from "../detection.js";
5
+ import { resolveEffectiveUnitIsolationMode, getIsolationMode } from "../preferences.js";
6
+ import { createWorktreeSafetyModule, type WorktreeSafetyResult } from "../worktree-safety.js";
7
+ import { resolveWorktreeProjectRoot } from "../worktree-root.js";
8
+ import { resolveManifest } from "../unit-context-manifest.js";
9
+ import { debugLog } from "../debug-logger.js";
10
+ import { isSamePathLocal } from "./phase-helpers.js";
11
+ import { hasHeldMilestoneLease, reclaimMissingMilestoneLease } from "./milestone-lease-reclaim.js";
12
+ import type { IterationContext } from "./types.js";
13
+
14
+ export function shouldDegradeEmptyWorktreeToProjectRoot(
15
+ worktreeClassification: ReturnType<typeof classifyProject>,
16
+ projectRootClassification: ReturnType<typeof classifyProject>,
17
+ ): boolean {
18
+ return (
19
+ worktreeClassification.kind === "greenfield" &&
20
+ projectRootClassification.kind !== "greenfield" &&
21
+ projectRootClassification.kind !== "invalid-repo"
22
+ );
23
+ }
24
+
25
+ export function unitWritesSource(unitType: string): boolean | null {
26
+ if (unitType.startsWith("hook/")) return false;
27
+ // Backward compatibility: sidecar queues from older builds may persist
28
+ // prefixed unit types (e.g. "sidecar/quick-task").
29
+ const normalizedUnitType = unitType.startsWith("sidecar/")
30
+ ? unitType.slice("sidecar/".length)
31
+ : unitType;
32
+ const manifest = resolveManifest(normalizedUnitType);
33
+ if (!manifest) return null;
34
+ return manifest.tools.mode === "all" || manifest.tools.mode === "docs";
35
+ }
36
+
37
+ export function formatWorktreeSafetyFailure(result: Extract<WorktreeSafetyResult, { ok: false }>): string {
38
+ return `Worktree Safety failed (${result.kind}): ${result.reason} ${result.remediation}`;
39
+ }
40
+
41
+ export function formatWorktreeSafetyStopReason(result: Extract<WorktreeSafetyResult, { ok: false }>): string {
42
+ if (result.kind === "empty-worktree-with-project-content") {
43
+ return `Worktree Safety failed (${result.kind}). Run /gsd doctor fix, then /gsd auto.`;
44
+ }
45
+ return `Worktree Safety failed (${result.kind}).`;
46
+ }
47
+
48
+ export function resolveEmptyWorktreeWithProjectContent(
49
+ unitRoot: string,
50
+ projectRoot: string,
51
+ ): boolean {
52
+ if (isSamePathLocal(unitRoot, projectRoot)) return false;
53
+ const worktreeClassification = classifyProject(unitRoot);
54
+ if (worktreeClassification.kind !== "greenfield") return false;
55
+ const projectRootClassification = classifyProject(projectRoot);
56
+ return shouldDegradeEmptyWorktreeToProjectRoot(worktreeClassification, projectRootClassification);
57
+ }
58
+
59
+ export async function validateSourceWriteWorktreeSafety(
60
+ ic: IterationContext,
61
+ unitType: string,
62
+ unitId: string,
63
+ milestoneId: string | undefined,
64
+ phase: string,
65
+ ): Promise<{ action: "break"; reason: string } | null> {
66
+ const { ctx, pi, s, deps } = ic;
67
+ if (!s.basePath) return null;
68
+
69
+ // Custom engine workflows (graph-driven, registered via run dirs) define
70
+ // their own step ids that are not in the GSD UnitContextManifest. Don't
71
+ // fail closed for those — the custom engine owns its own dispatch
72
+ // contract. The fail-closed safety check applies only to built-in GSD
73
+ // units whose Tool Contract is registered in the manifest. Use a truthy
74
+ // check so undefined (test sessions that never set the field) routes
75
+ // through the safety check, matching the regression test contract.
76
+ if (s.activeEngineId) return null;
77
+
78
+ const writesSource = unitWritesSource(unitType);
79
+ if (writesSource === null) {
80
+ const msg = `Worktree Safety failed (missing-tool-contract): missing Tool Contract for ${unitType}. Add a UnitContextManifest entry before dispatching this Unit.`;
81
+ debugLog("worktreeSafety", {
82
+ phase,
83
+ unitType,
84
+ unitId,
85
+ milestoneId,
86
+ result: { ok: false, kind: "missing-tool-contract", reason: msg },
87
+ basePath: s.basePath,
88
+ });
89
+ ctx.ui.notify(msg, "error");
90
+ await deps.stopAuto(ctx, pi, msg);
91
+ return { action: "break", reason: "missing-tool-contract" };
92
+ }
93
+ if (!writesSource) return null;
94
+
95
+ const projectRoot = s.canonicalProjectRoot ?? resolveWorktreeProjectRoot(s.basePath, s.originalBasePath);
96
+ // A degraded session already fell back to the milestone branch in the
97
+ // project root — validating against the canonical worktree root there
98
+ // would fail every dispatch with a false invalid-root. The same applies
99
+ // to a stranded-recovery session that adopted the milestone branch.
100
+ const isolationMode = resolveEffectiveUnitIsolationMode(
101
+ deps.getIsolationMode(projectRoot),
102
+ s.isolationDegraded,
103
+ s.strandedRecoveryIsolationMode,
104
+ );
105
+ reclaimMissingMilestoneLease(s, milestoneId, isolationMode, phase);
106
+ const safety = createWorktreeSafetyModule();
107
+ const result = safety.validateUnitRoot({
108
+ unitType,
109
+ unitId,
110
+ writeScope: "source-writing",
111
+ projectRoot,
112
+ unitRoot: s.basePath,
113
+ milestoneId,
114
+ isolationMode,
115
+ expectedBranch:
116
+ isolationMode !== "none" && milestoneId ? deps.autoWorktreeBranch(milestoneId) : null,
117
+ emptyWorktreeWithProjectContent: resolveEmptyWorktreeWithProjectContent(s.basePath, projectRoot),
118
+ // The milestone lease coordinates concurrent workers on an isolated
119
+ // milestone worktree/branch, which is established by enterMilestone in
120
+ // worktree/branch modes. `none` mode has no per-milestone isolation and
121
+ // does not reliably claim a lease (e.g. a fresh headless resume of an
122
+ // already-active milestone never re-enters it), so requiring a held lease
123
+ // there would falsely fail dispatch. Enforce the lease only in isolated
124
+ // modes; none-mode safety still validates the unit root.
125
+ lease: s.workerId
126
+ ? {
127
+ required: isolationMode !== "none",
128
+ held: hasHeldMilestoneLease(s, milestoneId),
129
+ owner: s.workerId,
130
+ }
131
+ : undefined,
132
+ });
133
+
134
+ if (result.ok) return null;
135
+
136
+ const msg = formatWorktreeSafetyFailure(result);
137
+ debugLog("worktreeSafety", {
138
+ phase,
139
+ unitType,
140
+ unitId,
141
+ milestoneId,
142
+ result,
143
+ basePath: s.basePath,
144
+ projectRoot,
145
+ });
146
+ ctx.ui.notify(msg, "error");
147
+ await deps.stopAuto(ctx, pi, formatWorktreeSafetyStopReason(result));
148
+ return { action: "break", reason: result.kind };
149
+ }
@@ -31,10 +31,7 @@ import { loadEffectiveGSDPreferences } from "./preferences.js";
31
31
  import type { MinimalModelRegistry } from "./context-budget.js";
32
32
  import { pauseAuto } from "./auto.js";
33
33
  import { resolveCanonicalMilestoneRoot } from "./worktree-manager.js";
34
- import {
35
- getWorkflowTransportSupportError,
36
- getRequiredWorkflowToolsForAutoUnit,
37
- } from "./workflow-mcp.js";
34
+ import { getUnitWorkflowDispatchReadinessError } from "./tool-contract.js";
38
35
 
39
36
  export async function dispatchDirectPhase(
40
37
  ctx: ExtensionCommandContext,
@@ -256,18 +253,15 @@ export async function dispatchDirectPhase(
256
253
  return;
257
254
  }
258
255
 
259
- const compatibilityError = getWorkflowTransportSupportError(
260
- ctx.model?.provider,
261
- getRequiredWorkflowToolsForAutoUnit(unitType),
262
- {
263
- projectRoot,
264
- surface: "direct phase dispatch",
265
- unitType,
266
- authMode: ctx.model?.provider ? ctx.modelRegistry.getProviderAuthMode(ctx.model.provider) : undefined,
267
- baseUrl: ctx.model?.baseUrl,
268
- activeTools: typeof pi.getActiveTools === "function" ? pi.getActiveTools() : [],
269
- },
270
- );
256
+ const compatibilityError = getUnitWorkflowDispatchReadinessError({
257
+ provider: ctx.model?.provider,
258
+ projectRoot,
259
+ surface: "direct phase dispatch",
260
+ unitType,
261
+ authMode: ctx.model?.provider ? ctx.modelRegistry.getProviderAuthMode(ctx.model.provider) : undefined,
262
+ baseUrl: ctx.model?.baseUrl,
263
+ activeTools: typeof pi.getActiveTools === "function" ? pi.getActiveTools() : [],
264
+ });
271
265
  if (compatibilityError) {
272
266
  ctx.ui.notify(compatibilityError, "error");
273
267
  return;
@@ -91,11 +91,8 @@ import { isAutoActive } from "./auto.js";
91
91
  import { hostWriteGateAdapter } from "./bootstrap/write-gate.js";
92
92
  import { ensureWorkflowPreferencesCaptured } from "./planning-depth.js";
93
93
  import { MILESTONE_ID_RE } from "./milestone-ids.js";
94
- import {
95
- getWorkflowTransportSupportError,
96
- getRequiredWorkflowToolsForAutoUnit,
97
- resolveWorkflowMcpProjectRoot,
98
- } from "./workflow-mcp.js";
94
+ import { resolveWorkflowMcpProjectRoot } from "./workflow-mcp.js";
95
+ import { getUnitWorkflowDispatchReadinessError } from "./tool-contract.js";
99
96
  import { prepareBrowserDaemonForUat } from "./browser-daemon-auto-prep.js";
100
97
  import {
101
98
  PROJECT_RESEARCH_INFLIGHT_MARKER,
@@ -745,11 +742,15 @@ export const DISPATCH_RULES: DispatchRule[] = [
745
742
  // Transport preflight: verify required MCP tools are actually connected
746
743
  // before consuming a retry attempt. Fixes tool-starved sessions burning
747
744
  // all MAX_UAT_ATTEMPTS before stopping (#477).
748
- const transportError = getWorkflowTransportSupportError(
749
- sessionProvider,
750
- getRequiredWorkflowToolsForAutoUnit("run-uat"),
751
- { projectRoot: basePath, surface: "auto-mode", unitType: "run-uat", authMode: sessionAuthMode, baseUrl: sessionBaseUrl, activeTools },
752
- );
745
+ const transportError = getUnitWorkflowDispatchReadinessError({
746
+ provider: sessionProvider,
747
+ projectRoot: basePath,
748
+ surface: "auto-mode",
749
+ unitType: "run-uat",
750
+ authMode: sessionAuthMode,
751
+ baseUrl: sessionBaseUrl,
752
+ activeTools,
753
+ });
753
754
  if (transportError) {
754
755
  return { action: "stop" as const, reason: transportError, level: "warning" as const };
755
756
  }
@@ -2025,16 +2025,30 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
2025
2025
  );
2026
2026
  } else if (!triggerArtifactVerified) {
2027
2027
  if (s.lastToolInvocationError && isToolUnavailableError(s.lastToolInvocationError)) {
2028
- // Tool-unavailable is the one transient invocation error: the
2029
- // workflow MCP server registers its surface asynchronously, so a
2030
- // Unit's first call can race the registration. Fall through to the
2031
- // bounded verification retry instead of pausing.
2032
- debugLog("postUnit", { phase: "tool-unavailable-retry", unitType: s.currentUnit.type, unitId: s.currentUnit.id, error: s.lastToolInvocationError });
2028
+ // Tool-unavailable is transient: the workflow MCP server registers
2029
+ // its surface asynchronously, so a Unit's first call can race the
2030
+ // registration. Retry with escalating delay, bounded at 3 attempts.
2031
+ // ponytail: MAX constant so the guard, log, and display all agree
2032
+ const MAX_TOOL_UNAVAIL_RETRIES = 3;
2033
+ if (s.toolUnavailableRetries >= MAX_TOOL_UNAVAIL_RETRIES) {
2034
+ debugLog("postUnit", { phase: "tool-unavailable-exhausted", unitType: s.currentUnit.type, unitId: s.currentUnit.id, retries: s.toolUnavailableRetries });
2035
+ ctx.ui.notify(
2036
+ `Tool unavailable for ${s.currentUnit.type} after ${MAX_TOOL_UNAVAIL_RETRIES} retries: ${s.lastToolInvocationError}. MCP server may not be starting — pausing auto-mode.`,
2037
+ "error",
2038
+ );
2039
+ s.lastToolInvocationError = null;
2040
+ await pauseAuto(ctx, pi);
2041
+ return "dispatched";
2042
+ }
2043
+ s.toolUnavailableRetries++;
2044
+ const delayMs = s.toolUnavailableRetries * 1000;
2045
+ debugLog("postUnit", { phase: "tool-unavailable-retry", unitType: s.currentUnit.type, unitId: s.currentUnit.id, error: s.lastToolInvocationError, attempt: s.toolUnavailableRetries, delayMs });
2033
2046
  ctx.ui.notify(
2034
- `Tool unavailable for ${s.currentUnit.type}: ${s.lastToolInvocationError}. The tool surface may still be registering — retrying.`,
2047
+ `Tool unavailable for ${s.currentUnit.type}: ${s.lastToolInvocationError}. Waiting ${delayMs}ms for MCP server retry ${s.toolUnavailableRetries}/${MAX_TOOL_UNAVAIL_RETRIES}.`,
2035
2048
  "warning",
2036
2049
  );
2037
2050
  s.lastToolInvocationError = null;
2051
+ await new Promise(r => setTimeout(r, delayMs));
2038
2052
  } else if (s.lastToolInvocationError) {
2039
2053
  const isUserSkip = /queued user message/i.test(s.lastToolInvocationError);
2040
2054
  const errMsg = isUserSkip
@@ -2193,6 +2207,7 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
2193
2207
  if (s.pendingVerificationRetry?.unitId === s.currentUnit.id) {
2194
2208
  s.pendingVerificationRetry = null;
2195
2209
  }
2210
+ s.toolUnavailableRetries = 0;
2196
2211
  s.verificationRetryCount.delete(retryKey);
2197
2212
  s.verificationRetryFailureHashes.delete(retryKey);
2198
2213
  s.exhaustedVerificationUnits.delete(retryKey);
@@ -1271,11 +1271,29 @@ export async function bootstrapAutoSession(
1271
1271
  }
1272
1272
  }
1273
1273
 
1274
- const blockingStrandedRecoveryAction = state.activeMilestone
1275
- ? strandedRecoveryActions.find(
1274
+ const requestedMilestoneLock = process.env.GSD_MILESTONE_LOCK?.trim() || null;
1275
+ const lockedActiveMilestone =
1276
+ requestedMilestoneLock && state.activeMilestone?.id === requestedMilestoneLock;
1277
+ let blockingStrandedRecoveryAction: OrphanAuditAction | null;
1278
+ if (lockedActiveMilestone) {
1279
+ // Parallel worker or explicit `/gsd auto Mxxx`: sibling milestones'
1280
+ // stranded work must not block this milestone's resumption, and the
1281
+ // downstream `strandedRecoveryAction` (used for currentMilestoneId,
1282
+ // setActiveMilestoneId, and adoptStrandedMilestone) must be scoped to
1283
+ // the locked milestone only. Falling back to the first sibling action
1284
+ // would mis-target adoption (#742).
1285
+ const lockMatch = strandedRecoveryActions.find(
1286
+ (action) => action.milestoneId === requestedMilestoneLock,
1287
+ ) ?? null;
1288
+ blockingStrandedRecoveryAction = lockMatch;
1289
+ strandedRecoveryAction = lockMatch;
1290
+ } else if (state.activeMilestone) {
1291
+ blockingStrandedRecoveryAction = strandedRecoveryActions.find(
1276
1292
  (action) => action.milestoneId !== state.activeMilestone?.id,
1277
- ) ?? strandedRecoveryAction
1278
- : strandedRecoveryAction;
1293
+ ) ?? strandedRecoveryAction;
1294
+ } else {
1295
+ blockingStrandedRecoveryAction = strandedRecoveryAction;
1296
+ }
1279
1297
 
1280
1298
  if (blockingStrandedRecoveryAction) {
1281
1299
  if (!state.activeMilestone) {
@@ -1297,6 +1315,8 @@ export async function bootstrapAutoSession(
1297
1315
  formatStrandedWorkRecoveryMessage(strandedRecoveryAction),
1298
1316
  "info",
1299
1317
  );
1318
+ } else if (lockedActiveMilestone) {
1319
+ strandedRecoveryAction = null;
1300
1320
  }
1301
1321
 
1302
1322
  if (
@@ -33,6 +33,24 @@ export interface UnitActivitySnapshot {
33
33
  assistantMessages: number;
34
34
  }
35
35
 
36
+ export interface AutoUnitCloseoutRequest {
37
+ ctx: ExtensionContext;
38
+ basePath: string;
39
+ unitType: string;
40
+ unitId: string;
41
+ startedAt: number;
42
+ opts?: CloseoutOptions;
43
+ }
44
+
45
+ export interface AutoUnitCloseoutResult {
46
+ activityFile?: string;
47
+ gitTransactionRecorded: boolean;
48
+ }
49
+
50
+ type GitTransactionCloseoutOptions =
51
+ Required<Pick<CloseoutOptions, "traceId" | "turnId" | "gitAction" | "gitStatus">>
52
+ & Pick<CloseoutOptions, "gitPush" | "gitError">;
53
+
36
54
  export const GHOST_COMPLETION_MAX_ELAPSED_MS = 500;
37
55
 
38
56
  export function snapshotUnitActivity(
@@ -76,25 +94,27 @@ export function isSuspiciousGhostCompletion(
76
94
  }
77
95
 
78
96
  /**
79
- * Snapshot metrics, save activity log, and fire-and-forget memory extraction
80
- * for a completed unit. Returns the activity log file path (if any).
97
+ * Snapshot metrics, save activity log, extract memories, and record the git
98
+ * transaction for a completed auto-mode unit.
81
99
  */
82
- export async function closeoutUnit(
83
- ctx: ExtensionContext,
84
- basePath: string,
85
- unitType: string,
86
- unitId: string,
87
- startedAt: number,
88
- opts?: CloseoutOptions,
89
- ): Promise<string | undefined> {
90
- const modelId = ctx.model?.id ?? "unknown";
91
- snapshotUnitMetrics(ctx, unitType, unitId, startedAt, modelId, opts);
92
- const activityFile = saveActivityLog(ctx, basePath, unitType, unitId);
100
+ export async function closeoutAutoUnit(
101
+ request: AutoUnitCloseoutRequest,
102
+ ): Promise<AutoUnitCloseoutResult> {
103
+ const modelId = request.ctx.model?.id ?? "unknown";
104
+ snapshotUnitMetrics(
105
+ request.ctx,
106
+ request.unitType,
107
+ request.unitId,
108
+ request.startedAt,
109
+ modelId,
110
+ request.opts,
111
+ );
112
+ const activityFile = saveActivityLog(request.ctx, request.basePath, request.unitType, request.unitId);
93
113
 
94
114
  if (activityFile) {
95
115
  try {
96
- const { buildMemoryLLMCall, extractMemoriesFromUnit } = await import('./memory-extractor.js');
97
- const llmCallFn = buildMemoryLLMCall(ctx);
116
+ const { buildMemoryLLMCall, extractMemoriesFromUnit } = await import("./memory-extractor.js");
117
+ const llmCallFn = buildMemoryLLMCall(request.ctx);
98
118
  if (llmCallFn) {
99
119
  // Awaited: a fire-and-forget here lets memory-extractor writes land in
100
120
  // .gsd/ after closeoutUnit returns but before the milestone merge
@@ -103,11 +123,11 @@ export async function closeoutUnit(
103
123
  // bounded by the extractor's LLM call, which is the acceptable price
104
124
  // for not racing the merge boundary.
105
125
  try {
106
- await extractMemoriesFromUnit(activityFile, unitType, unitId, llmCallFn);
126
+ await extractMemoriesFromUnit(activityFile, request.unitType, request.unitId, llmCallFn);
107
127
  } catch (err) {
108
128
  logWarning(
109
129
  "engine",
110
- `memory extraction failed for ${unitType}/${unitId}: ${(err as Error).message}`,
130
+ `memory extraction failed for ${request.unitType}/${request.unitId}: ${(err as Error).message}`,
111
131
  );
112
132
  }
113
133
  }
@@ -116,23 +136,58 @@ export async function closeoutUnit(
116
136
  }
117
137
  }
118
138
 
119
- if (opts?.traceId && opts.turnId && opts.gitAction && opts.gitStatus) {
139
+ const gitTransaction = resolveGitTransactionOptions(request.opts);
140
+
141
+ if (gitTransaction) {
120
142
  writeTurnGitTransaction({
121
- basePath,
122
- traceId: opts.traceId,
123
- turnId: opts.turnId,
124
- unitType,
125
- unitId,
143
+ basePath: request.basePath,
144
+ traceId: gitTransaction.traceId,
145
+ turnId: gitTransaction.turnId,
146
+ unitType: request.unitType,
147
+ unitId: request.unitId,
126
148
  stage: "record",
127
- action: opts.gitAction,
128
- push: opts.gitPush === true,
129
- status: opts.gitStatus,
130
- error: opts.gitError,
149
+ action: gitTransaction.gitAction,
150
+ push: gitTransaction.gitPush === true,
151
+ status: gitTransaction.gitStatus,
152
+ error: gitTransaction.gitError,
131
153
  metadata: {
132
154
  activityFile,
133
155
  },
134
156
  });
135
157
  }
136
158
 
137
- return activityFile ?? undefined;
159
+ return {
160
+ ...(activityFile ? { activityFile } : {}),
161
+ gitTransactionRecorded: Boolean(gitTransaction),
162
+ };
163
+ }
164
+
165
+ function resolveGitTransactionOptions(
166
+ opts: CloseoutOptions | undefined,
167
+ ): GitTransactionCloseoutOptions | null {
168
+ if (!opts?.traceId || !opts.turnId || !opts.gitAction || !opts.gitStatus) return null;
169
+ return {
170
+ traceId: opts.traceId,
171
+ turnId: opts.turnId,
172
+ gitAction: opts.gitAction,
173
+ gitStatus: opts.gitStatus,
174
+ gitPush: opts.gitPush,
175
+ gitError: opts.gitError,
176
+ };
177
+ }
178
+
179
+ /**
180
+ * Compatibility wrapper for existing auto-loop callers. New code should prefer
181
+ * closeoutAutoUnit so the closeout request and result stay explicit.
182
+ */
183
+ export async function closeoutUnit(
184
+ ctx: ExtensionContext,
185
+ basePath: string,
186
+ unitType: string,
187
+ unitId: string,
188
+ startedAt: number,
189
+ opts?: CloseoutOptions,
190
+ ): Promise<string | undefined> {
191
+ const result = await closeoutAutoUnit({ ctx, basePath, unitType, unitId, startedAt, opts });
192
+ return result.activityFile;
138
193
  }
@@ -50,6 +50,7 @@ import { getSlice } from "./gsd-db.js";
50
50
  import { getLedger } from "./metrics.js";
51
51
  import { getUnitCostSpikeAction, resolveUnitCostSpikeMultiplier } from "./auto-budget.js";
52
52
  import { formatPostUnitStatusCard } from "./auto-status-message.js";
53
+ import { detectWebApp } from "./web-app-uat.js";
53
54
 
54
55
  export interface VerificationContext {
55
56
  s: AutoSession;
@@ -787,17 +788,32 @@ export async function runPostUnitVerification(
787
788
  s.verificationRetryFailureHashes.delete(retryKey);
788
789
  s.pendingVerificationRetry = null;
789
790
  return "continue";
791
+ } else if (
792
+ verdict.reason === "no-host-checks" &&
793
+ taskAlreadyComplete &&
794
+ detectWebApp(s.basePath) &&
795
+ !result.runtimeErrors?.some((e) => e.blocking)
796
+ ) {
797
+ s.verificationRetryCount.delete(retryKey);
798
+ s.verificationRetryFailureHashes.delete(retryKey);
799
+ s.pendingVerificationRetry = null;
800
+ ctx.ui.notify(
801
+ "No task-level host verification command was found for a completed browser-facing task; continuing so slice UAT can verify the UI with browser tools.",
802
+ "warning",
803
+ );
804
+ return "continue";
790
805
  } else if (verdict.reason === "no-host-checks") {
791
806
  s.verificationRetryCount.delete(retryKey);
792
807
  s.verificationRetryFailureHashes.delete(retryKey);
793
808
  s.pendingVerificationRetry = null;
809
+ const pauseMessage = `Verification failed: ${verdict.failureContext}`;
794
810
  ctx.ui.notify(
795
- "Verification gate FAILED — no runnable host-owned verification checks were discovered. Pausing for human review.",
811
+ `Verification gate FAILED — ${verdict.failureContext}`,
796
812
  "error",
797
813
  );
798
814
  process.stderr.write(`verification-gate: ${verdict.failureContext}\n`);
799
815
  await pauseAuto(ctx, pi, {
800
- message: "Verification failed: no runnable host-owned verification checks were discovered.",
816
+ message: pauseMessage,
801
817
  category: "unknown",
802
818
  });
803
819
  return "pause";
@@ -972,6 +972,14 @@ function _resolveIntegrationBranchForReuse(
972
972
  }
973
973
  }
974
974
 
975
+ function safeCwd(fallback: string): string {
976
+ try {
977
+ return process.cwd();
978
+ } catch {
979
+ return fallback;
980
+ }
981
+ }
982
+
975
983
  /**
976
984
  * When reusing an existing milestone branch, fast-forward it onto the
977
985
  * integration branch when that's safe (branch is a strict ancestor of
@@ -1155,7 +1163,7 @@ export function teardownAutoWorktree(
1155
1163
 
1156
1164
  const branch = autoWorktreeBranch(milestoneId);
1157
1165
  const { preserveBranch = false, preserveWorktree = false } = opts;
1158
- const previousCwd = process.cwd();
1166
+ const previousCwd = safeCwd(originalBasePath);
1159
1167
 
1160
1168
  // Wrap the entire teardown body in a single try/finally so activeWorkspace
1161
1169
  // is ALWAYS cleared — even if process.chdir throws (e.g. originalBasePath
@@ -1250,7 +1258,7 @@ export function teardownAutoWorktree(
1250
1258
  * still works after process restart when module state has been reset.
1251
1259
  */
1252
1260
  export function isInAutoWorktree(basePath: string): boolean {
1253
- const targetPath = isGsdWorktreePath(basePath) ? basePath : process.cwd();
1261
+ const targetPath = isGsdWorktreePath(basePath) ? basePath : safeCwd("");
1254
1262
  if (!isGsdWorktreePath(targetPath)) return false;
1255
1263
 
1256
1264
  const storedBase = getAutoWorktreeOriginalBase();
@@ -2229,6 +2237,11 @@ export function mergeMilestoneToMain(
2229
2237
  process.chdir(originalBasePath_);
2230
2238
  } catch (err) {
2231
2239
  logWarning("worktree", `chdir to project root after merge failed: ${err instanceof Error ? err.message : String(err)}`);
2240
+ debugLog("mergeMilestoneToMain", {
2241
+ phase: "post-merge-chdir-failed",
2242
+ target: originalBasePath_,
2243
+ error: err instanceof Error ? err.message : String(err),
2244
+ });
2232
2245
  }
2233
2246
  };
2234
2247
 
@@ -859,6 +859,20 @@ export function _warnIfWorktreeMissingForTest(
859
859
  return false;
860
860
  }
861
861
 
862
+ export function anchorProcessCwdForAutoResume(basePath: string): boolean {
863
+ try {
864
+ process.chdir(basePath);
865
+ return true;
866
+ } catch (err) {
867
+ logWarning(
868
+ "session",
869
+ `resume cwd anchor failed: ${err instanceof Error ? err.message : String(err)}`,
870
+ { file: "auto.ts", basePath },
871
+ );
872
+ return false;
873
+ }
874
+ }
875
+
862
876
  export function isAutoPaused(): boolean {
863
877
  return s.paused;
864
878
  }
@@ -1008,6 +1022,41 @@ export function stopAutoRemote(projectRoot: string): {
1008
1022
  }
1009
1023
  }
1010
1024
 
1025
+ /**
1026
+ * Force-stop a remote auto-mode session before stealing its lock.
1027
+ * The normal stop path stays SIGTERM-only so cooperative sessions can clean up;
1028
+ * this path is only for the explicit "Force start" action.
1029
+ */
1030
+ export function forceStopAutoRemote(projectRoot: string): {
1031
+ found: boolean;
1032
+ pid?: number;
1033
+ error?: string;
1034
+ } {
1035
+ const lock = readCrashLock(projectRoot);
1036
+ if (!lock) return { found: false };
1037
+
1038
+ if (lock.pid === process.pid) {
1039
+ clearLock(projectRoot);
1040
+ return { found: false };
1041
+ }
1042
+
1043
+ if (!isLockProcessAlive(lock)) {
1044
+ clearLock(projectRoot);
1045
+ return { found: false };
1046
+ }
1047
+
1048
+ try {
1049
+ process.kill(lock.pid, "SIGTERM");
1050
+ if (isLockProcessAlive(lock)) {
1051
+ process.kill(lock.pid, "SIGKILL");
1052
+ }
1053
+ clearLock(projectRoot);
1054
+ return { found: true, pid: lock.pid };
1055
+ } catch (err) {
1056
+ return { found: false, error: (err as Error).message };
1057
+ }
1058
+ }
1059
+
1011
1060
  /**
1012
1061
  * Check if a remote auto-mode session is running (from a different process).
1013
1062
  * Reads the crash lock, checks PID liveness, and returns session details.
@@ -1125,6 +1174,10 @@ function pauseAutoUnitIdentityMatches(expected: PauseAutoUnitIdentity | null): b
1125
1174
  s.currentUnit.startedAt === expected.startedAt;
1126
1175
  }
1127
1176
 
1177
+ function shouldPreserveCoordinationForPause(errorContext?: ErrorContext): boolean {
1178
+ return errorContext?.category === "provider" && errorContext.isTransient === true;
1179
+ }
1180
+
1128
1181
  function setLifecycleOutcome(
1129
1182
  ctx: ExtensionContext | undefined,
1130
1183
  input: {
@@ -2085,7 +2138,7 @@ export async function pauseAuto(
2085
2138
  clearLock(lockBase());
2086
2139
  }
2087
2140
 
2088
- if (s.workerId) {
2141
+ if (s.workerId && !shouldPreserveCoordinationForPause(_errorContext)) {
2089
2142
  try {
2090
2143
  if (s.currentMilestoneId && s.milestoneLeaseToken) {
2091
2144
  releaseMilestoneLease(s.workerId, s.currentMilestoneId, s.milestoneLeaseToken);
@@ -2408,7 +2461,7 @@ export async function startAuto(
2408
2461
  const pid = freshStartAssessment.lock?.pid;
2409
2462
  ctx.ui.notify(
2410
2463
  pid
2411
- ? `Another auto-mode session (PID ${pid}) appears to be running.\nStop it with \`kill ${pid}\` before starting a new session.`
2464
+ ? `Another auto-mode session (PID ${pid}) appears to be running.\nRun \`/gsd stop\` for graceful shutdown, or choose "Force start" from \`/gsd auto\` to terminate it.`
2412
2465
  : "Another auto-mode session appears to be running.",
2413
2466
  "error",
2414
2467
  );
@@ -2603,6 +2656,7 @@ export async function startAuto(
2603
2656
  }
2604
2657
  // ADR-016 phase 2 / B3 (#5621): paused-resume worktree-path adoption.
2605
2658
  buildLifecycle().resumeFromPausedSession(base, resumeWorktreePath);
2659
+ anchorProcessCwdForAutoResume(s.basePath || base);
2606
2660
  // Rebuild scope now that s.basePath reflects the actual worktree (or project root).
2607
2661
  rebuildScope(s.basePath, s.currentMilestoneId);
2608
2662
  // Ensure the workflow-logger audit log is pinned to the project root