@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
@@ -15,7 +15,7 @@ import { tmpdir } from "node:os";
15
15
  import { execSync } from "node:child_process";
16
16
 
17
17
  import { PROJECT_FILES, classifyProject } from "../detection.js";
18
- import { _shouldProceedWithInvalidRepoClassificationForTest } from "../auto/phases.ts";
18
+ import { _shouldProceedWithInvalidRepoClassificationForTest } from "../auto/unit-phase.ts";
19
19
 
20
20
  // ─── Helpers ─────────────────────────────────────────────────────────────────
21
21
 
@@ -3,7 +3,7 @@
3
3
  import { describe, test } from "node:test";
4
4
  import assert from "node:assert/strict";
5
5
 
6
- import { shouldDegradeEmptyWorktreeToProjectRoot } from "../auto/phases.ts";
6
+ import { shouldDegradeEmptyWorktreeToProjectRoot } from "../auto/worktree-safety-phase.ts";
7
7
  import type { ProjectClassification } from "../detection.ts";
8
8
 
9
9
  function classification(kind: ProjectClassification["kind"]): ProjectClassification {
@@ -0,0 +1,100 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Regression tests for source-write worktree safety phase behavior.
3
+
4
+ import test from "node:test";
5
+ import assert from "node:assert/strict";
6
+ import { execFileSync } from "node:child_process";
7
+ import { mkdirSync, mkdtempSync, rmSync } from "node:fs";
8
+ import { tmpdir } from "node:os";
9
+ import { join } from "node:path";
10
+
11
+ import { AutoSession } from "../auto/session.ts";
12
+ import { validateSourceWriteWorktreeSafety } from "../auto/worktree-safety-phase.ts";
13
+ import { closeDatabase, insertMilestone, openDatabase } from "../gsd-db.ts";
14
+ import { registerAutoWorker } from "../db/auto-workers.ts";
15
+ import { claimMilestoneLease, getMilestoneLease, releaseMilestoneLease } from "../db/milestone-leases.ts";
16
+
17
+ function runGit(args: string[], cwd: string): void {
18
+ execFileSync("git", args, {
19
+ cwd,
20
+ stdio: ["ignore", "pipe", "pipe"],
21
+ });
22
+ }
23
+
24
+ test("source-write safety reclaims a released milestone lease for resumed branch sessions", async () => {
25
+ const projectRoot = mkdtempSync(join(tmpdir(), "gsd-wt-safety-reclaim-"));
26
+ const previousCwd = process.cwd();
27
+ const notifications: string[] = [];
28
+ const stopReasons: string[] = [];
29
+
30
+ try {
31
+ mkdirSync(join(projectRoot, ".gsd"), { recursive: true });
32
+ runGit(["init", "-b", "auto/M001"], projectRoot);
33
+ runGit(["config", "user.email", "test@example.com"], projectRoot);
34
+ runGit(["config", "user.name", "Test User"], projectRoot);
35
+ process.chdir(projectRoot);
36
+
37
+ openDatabase(join(projectRoot, ".gsd", "gsd.db"));
38
+ insertMilestone({ id: "M001", title: "Milestone 1", status: "active" });
39
+
40
+ const priorWorkerId = registerAutoWorker({ projectRootRealpath: projectRoot });
41
+ const priorLease = claimMilestoneLease(priorWorkerId, "M001");
42
+ assert.equal(priorLease.ok, true);
43
+ if (!priorLease.ok) return;
44
+ assert.equal(releaseMilestoneLease(priorWorkerId, "M001", priorLease.token), true);
45
+
46
+ const resumedWorkerId = registerAutoWorker({ projectRootRealpath: projectRoot });
47
+ const session = new AutoSession();
48
+ session.basePath = projectRoot;
49
+ session.originalBasePath = projectRoot;
50
+ session.currentMilestoneId = null;
51
+ session.workerId = resumedWorkerId;
52
+ session.milestoneLeaseToken = null;
53
+
54
+ const result = await validateSourceWriteWorktreeSafety(
55
+ {
56
+ ctx: {
57
+ ui: {
58
+ notify(message: string) {
59
+ notifications.push(message);
60
+ },
61
+ },
62
+ },
63
+ pi: {},
64
+ s: session,
65
+ deps: {
66
+ getIsolationMode: () => "branch",
67
+ autoWorktreeBranch: () => "auto/M001",
68
+ stopAuto: async (_ctx: unknown, _pi: unknown, reason?: string) => {
69
+ if (reason) stopReasons.push(reason);
70
+ },
71
+ },
72
+ prefs: undefined,
73
+ iteration: 1,
74
+ flowId: "flow-1",
75
+ nextSeq: () => 1,
76
+ } as any,
77
+ "execute-task",
78
+ "M001/S01/T01",
79
+ "M001",
80
+ "resume-pre-dispatch",
81
+ );
82
+
83
+ assert.equal(result, null);
84
+ assert.equal(session.currentMilestoneId, "M001");
85
+ assert.equal(session.milestoneLeaseToken, priorLease.token + 1);
86
+ const lease = getMilestoneLease("M001");
87
+ assert.equal(lease?.worker_id, resumedWorkerId);
88
+ assert.equal(lease?.status, "held");
89
+ assert.equal(stopReasons.length, 0);
90
+ assert.equal(notifications.length, 0);
91
+ } finally {
92
+ try {
93
+ closeDatabase();
94
+ } catch {
95
+ /* noop */
96
+ }
97
+ process.chdir(previousCwd);
98
+ rmSync(projectRoot, { recursive: true, force: true });
99
+ }
100
+ });
@@ -176,6 +176,54 @@ describe("Worktree Safety module", () => {
176
176
  assert.equal(result.branch, "milestone/M001");
177
177
  });
178
178
 
179
+ test("rejects non-project root for source-writing Unit when isolation mode is branch", () => {
180
+ const safety = createWorktreeSafetyModule({
181
+ existsSync: () => true,
182
+ lstatSync: () => ({ isFile: () => true }),
183
+ listRegisteredWorktrees: () => [{ path: unitRoot, branch: "milestone/M001" }],
184
+ });
185
+
186
+ const result = safety.validateUnitRoot({
187
+ unitType: "execute-task",
188
+ unitId: "M001/S01/T01",
189
+ writeScope: "source-writing",
190
+ projectRoot,
191
+ unitRoot,
192
+ milestoneId: "M001",
193
+ isolationMode: "branch",
194
+ });
195
+
196
+ assert.equal(result.ok, false);
197
+ assert.equal(result.kind, "invalid-root");
198
+ assert.equal(result.details?.expectedRoot, projectRoot);
199
+ assert.equal(result.details?.unitRoot, unitRoot);
200
+ });
201
+
202
+ test("rejects branch mismatch for source-writing Unit when isolation mode is branch", () => {
203
+ const safety = createWorktreeSafetyModule({
204
+ existsSync: () => true,
205
+ lstatSync: () => ({ isFile: () => false }),
206
+ listRegisteredWorktrees: () => [{ path: projectRoot, branch: "main" }],
207
+ getCurrentBranch: () => "main",
208
+ });
209
+
210
+ const result = safety.validateUnitRoot({
211
+ unitType: "execute-task",
212
+ unitId: "M001/S01/T01",
213
+ writeScope: "source-writing",
214
+ projectRoot,
215
+ unitRoot: projectRoot,
216
+ milestoneId: "M001",
217
+ isolationMode: "branch",
218
+ expectedBranch: "milestone/M001",
219
+ });
220
+
221
+ assert.equal(result.ok, false);
222
+ assert.equal(result.kind, "branch-mismatch");
223
+ assert.equal(result.details?.branch, "main");
224
+ assert.equal(result.details?.expectedBranch, "milestone/M001");
225
+ });
226
+
179
227
  test("rejects non-project root for source-writing Unit when isolation mode is none", () => {
180
228
  const safety = createWorktreeSafetyModule({
181
229
  existsSync: () => true,
@@ -420,6 +468,30 @@ describe("Worktree Safety module", () => {
420
468
  assert.equal(result.kind, "empty-worktree-with-project-content");
421
469
  });
422
470
 
471
+ test("rejects a source-writing Unit when the milestone lease is required but not held", () => {
472
+ const safety = createWorktreeSafetyModule({
473
+ existsSync: () => true,
474
+ lstatSync: () => ({ isFile: () => false }),
475
+ listRegisteredWorktrees: () => [{ path: projectRoot, branch: "main" }],
476
+ getCurrentBranch: () => "main",
477
+ });
478
+
479
+ const result = safety.validateUnitRoot({
480
+ unitType: "execute-task",
481
+ unitId: "M001/S01/T01",
482
+ writeScope: "source-writing",
483
+ projectRoot,
484
+ unitRoot: projectRoot,
485
+ milestoneId: "M001",
486
+ isolationMode: "none",
487
+ lease: { required: true, held: false, owner: "worker-1" },
488
+ });
489
+
490
+ assert.equal(result.ok, false);
491
+ assert.equal(result.kind, "lease-lost");
492
+ assert.equal(result.details?.owner, "worker-1");
493
+ });
494
+
423
495
  test("default adapter proves registered worktree and current branch", (t) => {
424
496
  const base = makeBaseRepo();
425
497
  t.after(() => rmSync(base, { recursive: true, force: true }));
@@ -25,6 +25,7 @@ import { join } from "node:path";
25
25
  import { tmpdir } from "node:os";
26
26
  import { execSync } from "node:child_process";
27
27
  import { describe, it, after } from "node:test";
28
+ import assert from "node:assert/strict";
28
29
 
29
30
  import { createWorktree, removeWorktree, worktreePath, isInsideWorktreesDir } from "../worktree-manager.ts";
30
31
  import { createTestContext } from "./test-helpers.ts";
@@ -86,6 +87,27 @@ describe("worktree-teardown-safety", () => {
86
87
  );
87
88
  });
88
89
 
90
+ it("removeWorktree survives when current working directory was deleted", () => {
91
+ const tempDir = createTempRepo();
92
+ dirs.push(tempDir);
93
+
94
+ const wt = createWorktree(tempDir, "deleted-cwd");
95
+ assertTrue(existsSync(wt.path), "worktree created successfully");
96
+
97
+ const safeCwd = process.cwd();
98
+ try {
99
+ process.chdir(wt.path);
100
+ rmSync(wt.path, { recursive: true, force: true });
101
+
102
+ assert.doesNotThrow(
103
+ () => removeWorktree(tempDir, "deleted-cwd"),
104
+ "removeWorktree should not call process.cwd() unguarded from a deleted cwd",
105
+ );
106
+ } finally {
107
+ process.chdir(safeCwd);
108
+ }
109
+ });
110
+
89
111
  it("path validation rejects paths outside .gsd/worktrees/", () => {
90
112
  const tempDir = createTempRepo();
91
113
  dirs.push(tempDir);
@@ -9,6 +9,7 @@ import {
9
9
  detectWorktreeName,
10
10
  getCurrentBranch,
11
11
  getMainBranch,
12
+ nudgeGitBranchCache,
12
13
  getSliceBranchName,
13
14
  parseSliceBranch,
14
15
  resolveProjectRoot,
@@ -95,6 +96,23 @@ describe('worktree', async () => {
95
96
  assert.ok(!SLICE_BRANCH_RE.test("gsd/"), "regex rejects bare gsd/");
96
97
  assert.ok(!SLICE_BRANCH_RE.test("worktree/foo"), "regex rejects worktree/foo");
97
98
 
99
+ console.log("\n=== nudgeGitBranchCache deleted cwd ===");
100
+ {
101
+ const safeCwd = process.cwd();
102
+ const deletedCwd = mkdtempSync(join(tmpdir(), "gsd-deleted-cwd-"));
103
+ try {
104
+ process.chdir(deletedCwd);
105
+ rmSync(deletedCwd, { recursive: true, force: true });
106
+
107
+ assert.doesNotThrow(
108
+ () => nudgeGitBranchCache(safeCwd),
109
+ "nudgeGitBranchCache should not call process.cwd() unguarded from a deleted cwd",
110
+ );
111
+ } finally {
112
+ process.chdir(safeCwd);
113
+ }
114
+ }
115
+
98
116
  console.log("\n=== detectWorktreeName ===");
99
117
  assert.deepStrictEqual(detectWorktreeName("/projects/myapp"), null, "no worktree in plain path");
100
118
  assert.deepStrictEqual(detectWorktreeName("/projects/myapp/.gsd/worktrees/feature-auth"), "feature-auth", "detects worktree name");
@@ -9,8 +9,14 @@ import {
9
9
  type ToolsPolicy,
10
10
  type UnitContextManifest,
11
11
  } from "./unit-context-manifest.js";
12
- import { getRequiredWorkflowToolsForAutoUnit } from "./workflow-mcp.js";
13
- import { getUnitToolSurfaceContract } from "./unit-tool-contracts.js";
12
+ import {
13
+ getWorkflowTransportSupportError,
14
+ type WorkflowCapabilityOptions,
15
+ } from "./workflow-mcp.js";
16
+ import {
17
+ getRequiredWorkflowToolsForUnit,
18
+ getUnitToolSurfaceContract,
19
+ } from "./unit-tool-contracts.js";
14
20
  import {
15
21
  WHOLE_FILE_OBSERVATION_MAX_BYTES,
16
22
  WHOLE_FILE_OBSERVATION_MAX_LINES,
@@ -68,6 +74,17 @@ export type UnitContextContractResult =
68
74
  | { ok: true; contract: UnitPromptContextContract }
69
75
  | { ok: false; reason: "unknown-unit-type"; detail: string };
70
76
 
77
+ export interface UnitWorkflowDispatchReadinessInput {
78
+ provider?: string;
79
+ unitType: string;
80
+ projectRoot?: string;
81
+ env?: NodeJS.ProcessEnv;
82
+ surface?: string;
83
+ authMode?: WorkflowCapabilityOptions["authMode"];
84
+ baseUrl?: string;
85
+ activeTools?: string[];
86
+ }
87
+
71
88
  export function compileUnitContextContract(unitType: string): UnitContextContractResult {
72
89
  const manifest = resolveManifest(unitType);
73
90
  if (!manifest) {
@@ -80,6 +97,24 @@ export function compileUnitContextContract(unitType: string): UnitContextContrac
80
97
  return { ok: true, contract: buildPromptContextContract(unitType, manifest) };
81
98
  }
82
99
 
100
+ export function getUnitWorkflowDispatchReadinessError(
101
+ input: UnitWorkflowDispatchReadinessInput,
102
+ ): string | null {
103
+ return getWorkflowTransportSupportError(
104
+ input.provider,
105
+ getRequiredWorkflowToolsForUnit(input.unitType),
106
+ {
107
+ projectRoot: input.projectRoot,
108
+ env: input.env,
109
+ surface: input.surface,
110
+ unitType: input.unitType,
111
+ authMode: input.authMode,
112
+ baseUrl: input.baseUrl,
113
+ activeTools: input.activeTools,
114
+ },
115
+ );
116
+ }
117
+
83
118
  export function compileUnitToolContract(unitType: string): ToolContractResult {
84
119
  const manifest = resolveManifest(unitType);
85
120
  const surfaceContract = getUnitToolSurfaceContract(unitType);
@@ -91,7 +126,7 @@ export function compileUnitToolContract(unitType: string): ToolContractResult {
91
126
  };
92
127
  }
93
128
 
94
- const requiredWorkflowTools = getRequiredWorkflowToolsForAutoUnit(unitType);
129
+ const requiredWorkflowTools = getRequiredWorkflowToolsForUnit(unitType);
95
130
  const forbiddenWorkflowTools = Object.entries(surfaceContract?.forbiddenGsdTools ?? {})
96
131
  .map(([name, reason]) => ({ name, reason }));
97
132
  const closeoutTools = requiredWorkflowTools.filter((tool) =>
@@ -1,8 +1,14 @@
1
1
  // Project/App: gsd-pi
2
2
  // File Purpose: Tool Contract module's runtime face — verify the live SDK tool surface covers a Unit's required workflow tools.
3
3
 
4
+ import { testMcpServerConnection } from "../mcp-client/manager.js";
4
5
  import { mcpToolMatchesBaseName } from "./mcp-tool-name.js";
5
6
  import { getRequiredWorkflowToolsForUnit } from "./unit-tool-contracts.js";
7
+ import {
8
+ recordWorkflowMcpProbe,
9
+ WORKFLOW_MCP_PROBE_TIMEOUT_MS,
10
+ } from "./workflow-mcp-readiness-cache.js";
11
+ import { resolveWorkflowMcpProjectRoot } from "./workflow-mcp.js";
6
12
  import { isWorkflowToolSurfaceName } from "./workflow-tool-surface.js";
7
13
 
8
14
  /**
@@ -36,10 +42,112 @@ export interface LiveToolSurfaceObservation {
36
42
  * workflow server is part of this session (native tool path), when the Unit
37
43
  * requires no workflow tools, or when the surface is ready.
38
44
  */
45
+ export interface WorkflowMcpToolProbeResult {
46
+ ok: boolean;
47
+ tools: readonly string[];
48
+ }
49
+
50
+ export type WorkflowMcpToolProbe = (
51
+ serverName: string,
52
+ projectRoot: string,
53
+ ) => Promise<WorkflowMcpToolProbeResult>;
54
+
55
+ export const DEFAULT_WORKFLOW_MCP_PREFLIGHT_TIMEOUT_MS = 30_000;
56
+ export const DEFAULT_WORKFLOW_MCP_PREFLIGHT_POLL_MS = 200;
57
+ const RUN_UAT_PREFLIGHT_TIMEOUT_MS = 90_000;
58
+
59
+ function resolveWorkflowMcpPreflightTimeoutMs(unitType: string | undefined): number {
60
+ if (unitType === "run-uat") return RUN_UAT_PREFLIGHT_TIMEOUT_MS;
61
+ return DEFAULT_WORKFLOW_MCP_PREFLIGHT_TIMEOUT_MS;
62
+ }
63
+
64
+ export function probeCoversRequiredWorkflowTools(
65
+ tools: readonly string[],
66
+ required: readonly string[],
67
+ ): boolean {
68
+ return required.every((tool) =>
69
+ tools.some((name) => name === tool || mcpToolMatchesBaseName(name, tool)),
70
+ );
71
+ }
72
+
73
+ export async function awaitWorkflowMcpToolRegistration(input: {
74
+ unitType: string | undefined;
75
+ workflowServerName: string | undefined;
76
+ projectRoot: string;
77
+ timeoutMs?: number;
78
+ pollMs?: number;
79
+ probe?: WorkflowMcpToolProbe;
80
+ signal?: AbortSignal;
81
+ }): Promise<string | null> {
82
+ const { unitType, workflowServerName, projectRoot } = input;
83
+ if (!unitType || !workflowServerName) return null;
84
+
85
+ const required = getRequiredWorkflowToolsForUnit(unitType).filter(isWorkflowToolSurfaceName);
86
+ if (required.length === 0) return null;
87
+
88
+ const probe = input.probe ?? (async (serverName, root) => {
89
+ const result = await testMcpServerConnection(serverName, {
90
+ projectDir: resolveWorkflowMcpProjectRoot(root),
91
+ timeoutMs: WORKFLOW_MCP_PROBE_TIMEOUT_MS,
92
+ });
93
+ return { ok: result.ok, tools: result.tools };
94
+ });
95
+
96
+ const deadline = Date.now() + (input.timeoutMs ?? resolveWorkflowMcpPreflightTimeoutMs(unitType));
97
+ const pollMs = input.pollMs ?? DEFAULT_WORKFLOW_MCP_PREFLIGHT_POLL_MS;
98
+
99
+ while (Date.now() < deadline) {
100
+ throwIfAborted(input.signal);
101
+ const result = await probe(workflowServerName, projectRoot);
102
+ throwIfAborted(input.signal);
103
+ if (result.ok && probeCoversRequiredWorkflowTools(result.tools, required)) {
104
+ recordWorkflowMcpProbe(projectRoot, workflowServerName, result.tools);
105
+ return null;
106
+ }
107
+ await sleep(pollMs, input.signal);
108
+ }
109
+
110
+ return `${TOOL_SURFACE_NOT_READY} for ${unitType}: MCP server "${workflowServerName}" did not register required tools before session start: ${required.join(", ")}`;
111
+ }
112
+
113
+ function makeAbortError(): Error {
114
+ const error = new Error("AbortError: The operation was aborted");
115
+ error.name = "AbortError";
116
+ return error;
117
+ }
118
+
119
+ function throwIfAborted(signal: AbortSignal | undefined): void {
120
+ if (signal?.aborted) throw makeAbortError();
121
+ }
122
+
123
+ function sleep(ms: number, signal: AbortSignal | undefined): Promise<void> {
124
+ throwIfAborted(signal);
125
+
126
+ return new Promise((resolve, reject) => {
127
+ const timeout = setTimeout(() => {
128
+ signal?.removeEventListener("abort", onAbort);
129
+ resolve();
130
+ }, ms);
131
+ const onAbort = (): void => {
132
+ clearTimeout(timeout);
133
+ reject(makeAbortError());
134
+ };
135
+ signal?.addEventListener("abort", onAbort, { once: true });
136
+ });
137
+ }
138
+
139
+ /** Brief pause after a successful preflight before SDK query (race with MCP attach). */
140
+ export const POST_PREFLIGHT_SDK_SETTLE_MS = 750;
141
+
142
+ export const POST_PREFLIGHT_READINESS_RETRY_DELAYS_MS = [
143
+ 1_000, 2_000, 3_000, 5_000, 8_000, 10_000, 15_000, 15_000, 15_000, 15_000,
144
+ ] as const;
145
+
39
146
  export function getToolSurfaceReadinessError(input: {
40
147
  unitType: string | undefined;
41
148
  workflowServerName: string | undefined;
42
149
  observation: LiveToolSurfaceObservation;
150
+ projectRoot?: string | undefined;
43
151
  }): string | null {
44
152
  const { unitType, workflowServerName, observation } = input;
45
153
  if (!unitType || !workflowServerName) return null;
@@ -48,29 +156,28 @@ export function getToolSurfaceReadinessError(input: {
48
156
  if (required.length === 0) return null;
49
157
 
50
158
  const server = observation.mcpServers.find((entry) => entry.name === workflowServerName);
51
- if (!server) {
52
- return `${TOOL_SURFACE_NOT_READY} for ${unitType}: MCP server "${workflowServerName}" is absent from the init surface (not yet connected): ${required.join(", ")}`;
53
- }
54
-
55
- // The SDK does not wait for MCP servers before init — a still-connecting
56
- // server reports "pending" there routinely, then registers within seconds,
57
- // usually well before the Unit's first workflow tool call. Aborting on
58
- // "pending" would fail the common healthy session, so it passes through;
59
- // a genuine miss after pass-through still surfaces in-session as
60
- // "No such tool available" and classifies tool-unavailable → bounded retry.
61
- // Only statuses that cannot self-heal abort here.
62
- if (server.status !== "connected" && !TERMINAL_MCP_SERVER_STATUSES.has(server.status)) {
63
- return null;
159
+ if (server && TERMINAL_MCP_SERVER_STATUSES.has(server.status)) {
160
+ const missing = required.filter(
161
+ (tool) => !observation.tools.some((name) => name === tool || mcpToolMatchesBaseName(name, tool)),
162
+ );
163
+ const tools = missing.length > 0 ? missing : required;
164
+ return `${TOOL_SURFACE_NOT_READY} for ${unitType}: MCP server "${workflowServerName}" status is "${server.status}" (terminal) cannot register: ${tools.join(", ")}`;
64
165
  }
65
166
 
66
167
  const missing = required.filter(
67
168
  (tool) => !observation.tools.some((name) => name === tool || mcpToolMatchesBaseName(name, tool)),
68
169
  );
69
- if (missing.length === 0) return null;
170
+ if (missing.length === 0) {
171
+ return null;
172
+ }
173
+
174
+ if (!server) {
175
+ return `${TOOL_SURFACE_NOT_READY} for ${unitType}: MCP server "${workflowServerName}" is absent from the init surface (not yet connected): ${missing.join(", ")}`;
176
+ }
177
+
178
+ if (server.status !== "connected") {
179
+ return `${TOOL_SURFACE_NOT_READY} for ${unitType}: MCP server "${workflowServerName}" status is "${server.status}" (not yet connected): ${missing.join(", ")}`;
180
+ }
70
181
 
71
- const serverDetail =
72
- server.status === "connected"
73
- ? `MCP server "${workflowServerName}" is connected but has not registered`
74
- : `MCP server "${workflowServerName}" status is "${server.status}" and it has not registered`;
75
- return `${TOOL_SURFACE_NOT_READY} for ${unitType}: ${serverDetail}: ${missing.join(", ")}`;
182
+ return `${TOOL_SURFACE_NOT_READY} for ${unitType}: MCP server "${workflowServerName}" is connected but has not registered: ${missing.join(", ")}`;
76
183
  }
@@ -26,7 +26,8 @@ import { resolveCanonicalMilestoneRoot } from "../worktree-manager.js";
26
26
  import { isClosedStatus } from "../status-guards.js";
27
27
  import { saveFile, clearParseCache } from "../files.js";
28
28
  import { invalidateStateCache } from "../state.js";
29
- import { renderAllProjections, stripIdPrefix } from "../workflow-projections.js";
29
+ import { stripIdPrefix } from "../workflow-projections.js";
30
+ import { flushWorkflowProjections } from "../projection-flush.js";
30
31
  import { writeManifest } from "../workflow-manifest.js";
31
32
  import { appendEvent } from "../workflow-events.js";
32
33
  import { logWarning, logError } from "../workflow-logger.js";
@@ -240,7 +241,7 @@ export async function handleCompleteMilestone(
240
241
  // Separate try/catch per step so a projection failure doesn't prevent
241
242
  // the event log entry (critical for worktree reconciliation).
242
243
  try {
243
- await renderAllProjections(artifactBasePath, params.milestoneId);
244
+ await flushWorkflowProjections(artifactBasePath, { milestoneId: params.milestoneId });
244
245
  } catch (projErr) {
245
246
  logWarning("tool", `complete-milestone projection warning: ${(projErr as Error).message}`);
246
247
  }
@@ -30,7 +30,7 @@ import { classifyUatContent, escalatesArtifactUatToBrowser } from "../uat-policy
30
30
  import { invalidateStateCache } from "../state.js";
31
31
  import { renderRoadmapFromDb, roadmapRenderMarksSliceDone } from "../markdown-renderer.js";
32
32
  import { isStaleWrite } from "../auto/turn-epoch.js";
33
- import { renderAllProjections } from "../workflow-projections.js";
33
+ import { flushWorkflowProjections } from "../projection-flush.js";
34
34
  import { writeManifest } from "../workflow-manifest.js";
35
35
  import { appendEvent } from "../workflow-events.js";
36
36
  import { logWarning, logError } from "../workflow-logger.js";
@@ -537,7 +537,7 @@ export async function handleCompleteSlice(
537
537
  // Separate try/catch per step so a projection failure doesn't prevent
538
538
  // the event log entry (critical for worktree reconciliation).
539
539
  try {
540
- await renderAllProjections(artifactBasePath, params.milestoneId);
540
+ await flushWorkflowProjections(artifactBasePath, { milestoneId: params.milestoneId });
541
541
  } catch (projErr) {
542
542
  logWarning("tool", `complete-slice projection warning for ${params.milestoneId}/${params.sliceId}: ${(projErr as Error).message}`);
543
543
  }