@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
@@ -1,7 +1,7 @@
1
1
  // Project/App: gsd-pi
2
2
  // File Purpose: Unit dispatch contract adapter for auto-mode loop.
3
3
  import { ExecutionGraphScheduler } from "../uok/execution-graph.js";
4
- import { runUnitPhase } from "./phases.js";
4
+ import { runUnitPhase } from "./unit-phase.js";
5
5
  import { decideDispatchNodeKind } from "./workflow-kernel.js";
6
6
  export async function runUnitPhaseViaContract(dispatchContract, ic, iterData, loopState, sidecarItem, deps) {
7
7
  if (dispatchContract === "legacy-direct") {
@@ -0,0 +1,125 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Worktree-safety helpers shared across auto-loop phase modules.
3
+ import { classifyProject } from "../detection.js";
4
+ import { resolveEffectiveUnitIsolationMode } from "../preferences.js";
5
+ import { createWorktreeSafetyModule } from "../worktree-safety.js";
6
+ import { resolveWorktreeProjectRoot } from "../worktree-root.js";
7
+ import { resolveManifest } from "../unit-context-manifest.js";
8
+ import { debugLog } from "../debug-logger.js";
9
+ import { isSamePathLocal } from "./phase-helpers.js";
10
+ import { hasHeldMilestoneLease, reclaimMissingMilestoneLease } from "./milestone-lease-reclaim.js";
11
+ export function shouldDegradeEmptyWorktreeToProjectRoot(worktreeClassification, projectRootClassification) {
12
+ return (worktreeClassification.kind === "greenfield" &&
13
+ projectRootClassification.kind !== "greenfield" &&
14
+ projectRootClassification.kind !== "invalid-repo");
15
+ }
16
+ export function unitWritesSource(unitType) {
17
+ if (unitType.startsWith("hook/"))
18
+ return false;
19
+ // Backward compatibility: sidecar queues from older builds may persist
20
+ // prefixed unit types (e.g. "sidecar/quick-task").
21
+ const normalizedUnitType = unitType.startsWith("sidecar/")
22
+ ? unitType.slice("sidecar/".length)
23
+ : unitType;
24
+ const manifest = resolveManifest(normalizedUnitType);
25
+ if (!manifest)
26
+ return null;
27
+ return manifest.tools.mode === "all" || manifest.tools.mode === "docs";
28
+ }
29
+ export function formatWorktreeSafetyFailure(result) {
30
+ return `Worktree Safety failed (${result.kind}): ${result.reason} ${result.remediation}`;
31
+ }
32
+ export function formatWorktreeSafetyStopReason(result) {
33
+ if (result.kind === "empty-worktree-with-project-content") {
34
+ return `Worktree Safety failed (${result.kind}). Run /gsd doctor fix, then /gsd auto.`;
35
+ }
36
+ return `Worktree Safety failed (${result.kind}).`;
37
+ }
38
+ export function resolveEmptyWorktreeWithProjectContent(unitRoot, projectRoot) {
39
+ if (isSamePathLocal(unitRoot, projectRoot))
40
+ return false;
41
+ const worktreeClassification = classifyProject(unitRoot);
42
+ if (worktreeClassification.kind !== "greenfield")
43
+ return false;
44
+ const projectRootClassification = classifyProject(projectRoot);
45
+ return shouldDegradeEmptyWorktreeToProjectRoot(worktreeClassification, projectRootClassification);
46
+ }
47
+ export async function validateSourceWriteWorktreeSafety(ic, unitType, unitId, milestoneId, phase) {
48
+ const { ctx, pi, s, deps } = ic;
49
+ if (!s.basePath)
50
+ return null;
51
+ // Custom engine workflows (graph-driven, registered via run dirs) define
52
+ // their own step ids that are not in the GSD UnitContextManifest. Don't
53
+ // fail closed for those — the custom engine owns its own dispatch
54
+ // contract. The fail-closed safety check applies only to built-in GSD
55
+ // units whose Tool Contract is registered in the manifest. Use a truthy
56
+ // check so undefined (test sessions that never set the field) routes
57
+ // through the safety check, matching the regression test contract.
58
+ if (s.activeEngineId)
59
+ return null;
60
+ const writesSource = unitWritesSource(unitType);
61
+ if (writesSource === null) {
62
+ const msg = `Worktree Safety failed (missing-tool-contract): missing Tool Contract for ${unitType}. Add a UnitContextManifest entry before dispatching this Unit.`;
63
+ debugLog("worktreeSafety", {
64
+ phase,
65
+ unitType,
66
+ unitId,
67
+ milestoneId,
68
+ result: { ok: false, kind: "missing-tool-contract", reason: msg },
69
+ basePath: s.basePath,
70
+ });
71
+ ctx.ui.notify(msg, "error");
72
+ await deps.stopAuto(ctx, pi, msg);
73
+ return { action: "break", reason: "missing-tool-contract" };
74
+ }
75
+ if (!writesSource)
76
+ return null;
77
+ const projectRoot = s.canonicalProjectRoot ?? resolveWorktreeProjectRoot(s.basePath, s.originalBasePath);
78
+ // A degraded session already fell back to the milestone branch in the
79
+ // project root — validating against the canonical worktree root there
80
+ // would fail every dispatch with a false invalid-root. The same applies
81
+ // to a stranded-recovery session that adopted the milestone branch.
82
+ const isolationMode = resolveEffectiveUnitIsolationMode(deps.getIsolationMode(projectRoot), s.isolationDegraded, s.strandedRecoveryIsolationMode);
83
+ reclaimMissingMilestoneLease(s, milestoneId, isolationMode, phase);
84
+ const safety = createWorktreeSafetyModule();
85
+ const result = safety.validateUnitRoot({
86
+ unitType,
87
+ unitId,
88
+ writeScope: "source-writing",
89
+ projectRoot,
90
+ unitRoot: s.basePath,
91
+ milestoneId,
92
+ isolationMode,
93
+ expectedBranch: isolationMode !== "none" && milestoneId ? deps.autoWorktreeBranch(milestoneId) : null,
94
+ emptyWorktreeWithProjectContent: resolveEmptyWorktreeWithProjectContent(s.basePath, projectRoot),
95
+ // The milestone lease coordinates concurrent workers on an isolated
96
+ // milestone worktree/branch, which is established by enterMilestone in
97
+ // worktree/branch modes. `none` mode has no per-milestone isolation and
98
+ // does not reliably claim a lease (e.g. a fresh headless resume of an
99
+ // already-active milestone never re-enters it), so requiring a held lease
100
+ // there would falsely fail dispatch. Enforce the lease only in isolated
101
+ // modes; none-mode safety still validates the unit root.
102
+ lease: s.workerId
103
+ ? {
104
+ required: isolationMode !== "none",
105
+ held: hasHeldMilestoneLease(s, milestoneId),
106
+ owner: s.workerId,
107
+ }
108
+ : undefined,
109
+ });
110
+ if (result.ok)
111
+ return null;
112
+ const msg = formatWorktreeSafetyFailure(result);
113
+ debugLog("worktreeSafety", {
114
+ phase,
115
+ unitType,
116
+ unitId,
117
+ milestoneId,
118
+ result,
119
+ basePath: s.basePath,
120
+ projectRoot,
121
+ });
122
+ ctx.ui.notify(msg, "error");
123
+ await deps.stopAuto(ctx, pi, formatWorktreeSafetyStopReason(result));
124
+ return { action: "break", reason: result.kind };
125
+ }
@@ -10,7 +10,7 @@ import { buildResearchSlicePrompt, buildResearchMilestonePrompt, buildPlanSliceP
10
10
  import { loadEffectiveGSDPreferences } from "./preferences.js";
11
11
  import { pauseAuto } from "./auto.js";
12
12
  import { resolveCanonicalMilestoneRoot } from "./worktree-manager.js";
13
- import { getWorkflowTransportSupportError, getRequiredWorkflowToolsForAutoUnit, } from "./workflow-mcp.js";
13
+ import { getUnitWorkflowDispatchReadinessError } from "./tool-contract.js";
14
14
  export async function dispatchDirectPhase(ctx, pi, phase, base) {
15
15
  const state = await deriveState(base);
16
16
  const mid = state.activeMilestone?.id;
@@ -201,7 +201,8 @@ export async function dispatchDirectPhase(ctx, pi, phase, base) {
201
201
  ctx.ui.notify(`Unknown phase "${phase}". Valid phases: research, plan, execute, complete, validate, reassess, uat, replan.`, "warning");
202
202
  return;
203
203
  }
204
- const compatibilityError = getWorkflowTransportSupportError(ctx.model?.provider, getRequiredWorkflowToolsForAutoUnit(unitType), {
204
+ const compatibilityError = getUnitWorkflowDispatchReadinessError({
205
+ provider: ctx.model?.provider,
205
206
  projectRoot,
206
207
  surface: "direct phase dispatch",
207
208
  unitType,
@@ -24,7 +24,8 @@ import { isAutoActive } from "./auto.js";
24
24
  import { hostWriteGateAdapter } from "./bootstrap/write-gate.js";
25
25
  import { ensureWorkflowPreferencesCaptured } from "./planning-depth.js";
26
26
  import { MILESTONE_ID_RE } from "./milestone-ids.js";
27
- import { getWorkflowTransportSupportError, getRequiredWorkflowToolsForAutoUnit, resolveWorkflowMcpProjectRoot, } from "./workflow-mcp.js";
27
+ import { resolveWorkflowMcpProjectRoot } from "./workflow-mcp.js";
28
+ import { getUnitWorkflowDispatchReadinessError } from "./tool-contract.js";
28
29
  import { prepareBrowserDaemonForUat } from "./browser-daemon-auto-prep.js";
29
30
  import { PROJECT_RESEARCH_INFLIGHT_MARKER, } from "./project-research-policy.js";
30
31
  import { isWorkflowPrefsCaptured, resolveDeepProjectSetupState, } from "./deep-project-setup-policy.js";
@@ -512,7 +513,15 @@ export const DISPATCH_RULES = [
512
513
  // Transport preflight: verify required MCP tools are actually connected
513
514
  // before consuming a retry attempt. Fixes tool-starved sessions burning
514
515
  // all MAX_UAT_ATTEMPTS before stopping (#477).
515
- const transportError = getWorkflowTransportSupportError(sessionProvider, getRequiredWorkflowToolsForAutoUnit("run-uat"), { projectRoot: basePath, surface: "auto-mode", unitType: "run-uat", authMode: sessionAuthMode, baseUrl: sessionBaseUrl, activeTools });
516
+ const transportError = getUnitWorkflowDispatchReadinessError({
517
+ provider: sessionProvider,
518
+ projectRoot: basePath,
519
+ surface: "auto-mode",
520
+ unitType: "run-uat",
521
+ authMode: sessionAuthMode,
522
+ baseUrl: sessionBaseUrl,
523
+ activeTools,
524
+ });
516
525
  if (transportError) {
517
526
  return { action: "stop", reason: transportError, level: "warning" };
518
527
  }
@@ -1704,13 +1704,24 @@ export async function postUnitPreVerification(pctx, opts) {
1704
1704
  }
1705
1705
  else if (!triggerArtifactVerified) {
1706
1706
  if (s.lastToolInvocationError && isToolUnavailableError(s.lastToolInvocationError)) {
1707
- // Tool-unavailable is the one transient invocation error: the
1708
- // workflow MCP server registers its surface asynchronously, so a
1709
- // Unit's first call can race the registration. Fall through to the
1710
- // bounded verification retry instead of pausing.
1711
- debugLog("postUnit", { phase: "tool-unavailable-retry", unitType: s.currentUnit.type, unitId: s.currentUnit.id, error: s.lastToolInvocationError });
1712
- ctx.ui.notify(`Tool unavailable for ${s.currentUnit.type}: ${s.lastToolInvocationError}. The tool surface may still be registering — retrying.`, "warning");
1707
+ // Tool-unavailable is transient: the workflow MCP server registers
1708
+ // its surface asynchronously, so a Unit's first call can race the
1709
+ // registration. Retry with escalating delay, bounded at 3 attempts.
1710
+ // ponytail: MAX constant so the guard, log, and display all agree
1711
+ const MAX_TOOL_UNAVAIL_RETRIES = 3;
1712
+ if (s.toolUnavailableRetries >= MAX_TOOL_UNAVAIL_RETRIES) {
1713
+ debugLog("postUnit", { phase: "tool-unavailable-exhausted", unitType: s.currentUnit.type, unitId: s.currentUnit.id, retries: s.toolUnavailableRetries });
1714
+ ctx.ui.notify(`Tool unavailable for ${s.currentUnit.type} after ${MAX_TOOL_UNAVAIL_RETRIES} retries: ${s.lastToolInvocationError}. MCP server may not be starting — pausing auto-mode.`, "error");
1715
+ s.lastToolInvocationError = null;
1716
+ await pauseAuto(ctx, pi);
1717
+ return "dispatched";
1718
+ }
1719
+ s.toolUnavailableRetries++;
1720
+ const delayMs = s.toolUnavailableRetries * 1000;
1721
+ debugLog("postUnit", { phase: "tool-unavailable-retry", unitType: s.currentUnit.type, unitId: s.currentUnit.id, error: s.lastToolInvocationError, attempt: s.toolUnavailableRetries, delayMs });
1722
+ ctx.ui.notify(`Tool unavailable for ${s.currentUnit.type}: ${s.lastToolInvocationError}. Waiting ${delayMs}ms for MCP server — retry ${s.toolUnavailableRetries}/${MAX_TOOL_UNAVAIL_RETRIES}.`, "warning");
1713
1723
  s.lastToolInvocationError = null;
1724
+ await new Promise(r => setTimeout(r, delayMs));
1714
1725
  }
1715
1726
  else if (s.lastToolInvocationError) {
1716
1727
  const isUserSkip = /queued user message/i.test(s.lastToolInvocationError);
@@ -1825,6 +1836,7 @@ export async function postUnitPreVerification(pctx, opts) {
1825
1836
  if (s.pendingVerificationRetry?.unitId === s.currentUnit.id) {
1826
1837
  s.pendingVerificationRetry = null;
1827
1838
  }
1839
+ s.toolUnavailableRetries = 0;
1828
1840
  s.verificationRetryCount.delete(retryKey);
1829
1841
  s.verificationRetryFailureHashes.delete(retryKey);
1830
1842
  s.exhaustedVerificationUnits.delete(retryKey);
@@ -976,9 +976,26 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
976
976
  state = await deriveState(wtPath);
977
977
  }
978
978
  }
979
- const blockingStrandedRecoveryAction = state.activeMilestone
980
- ? strandedRecoveryActions.find((action) => action.milestoneId !== state.activeMilestone?.id) ?? strandedRecoveryAction
981
- : strandedRecoveryAction;
979
+ const requestedMilestoneLock = process.env.GSD_MILESTONE_LOCK?.trim() || null;
980
+ const lockedActiveMilestone = requestedMilestoneLock && state.activeMilestone?.id === requestedMilestoneLock;
981
+ let blockingStrandedRecoveryAction;
982
+ if (lockedActiveMilestone) {
983
+ // Parallel worker or explicit `/gsd auto Mxxx`: sibling milestones'
984
+ // stranded work must not block this milestone's resumption, and the
985
+ // downstream `strandedRecoveryAction` (used for currentMilestoneId,
986
+ // setActiveMilestoneId, and adoptStrandedMilestone) must be scoped to
987
+ // the locked milestone only. Falling back to the first sibling action
988
+ // would mis-target adoption (#742).
989
+ const lockMatch = strandedRecoveryActions.find((action) => action.milestoneId === requestedMilestoneLock) ?? null;
990
+ blockingStrandedRecoveryAction = lockMatch;
991
+ strandedRecoveryAction = lockMatch;
992
+ }
993
+ else if (state.activeMilestone) {
994
+ blockingStrandedRecoveryAction = strandedRecoveryActions.find((action) => action.milestoneId !== state.activeMilestone?.id) ?? strandedRecoveryAction;
995
+ }
996
+ else {
997
+ blockingStrandedRecoveryAction = strandedRecoveryAction;
998
+ }
982
999
  if (blockingStrandedRecoveryAction) {
983
1000
  if (!state.activeMilestone) {
984
1001
  ctx.ui.notify(formatStrandedWorkBlockerMessage(blockingStrandedRecoveryAction, null), "error");
@@ -991,6 +1008,9 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
991
1008
  strandedRecoveryAction = blockingStrandedRecoveryAction;
992
1009
  ctx.ui.notify(formatStrandedWorkRecoveryMessage(strandedRecoveryAction), "info");
993
1010
  }
1011
+ else if (lockedActiveMilestone) {
1012
+ strandedRecoveryAction = null;
1013
+ }
994
1014
  if (process.env.GSD_HEADLESS === "1" &&
995
1015
  orphanAuditRecovered &&
996
1016
  !state.activeMilestone &&
@@ -36,17 +36,17 @@ export function isSuspiciousGhostCompletion(ctx, startedAt, maxElapsedMs = GHOST
36
36
  activity.assistantMessages === 0);
37
37
  }
38
38
  /**
39
- * Snapshot metrics, save activity log, and fire-and-forget memory extraction
40
- * for a completed unit. Returns the activity log file path (if any).
39
+ * Snapshot metrics, save activity log, extract memories, and record the git
40
+ * transaction for a completed auto-mode unit.
41
41
  */
42
- export async function closeoutUnit(ctx, basePath, unitType, unitId, startedAt, opts) {
43
- const modelId = ctx.model?.id ?? "unknown";
44
- snapshotUnitMetrics(ctx, unitType, unitId, startedAt, modelId, opts);
45
- const activityFile = saveActivityLog(ctx, basePath, unitType, unitId);
42
+ export async function closeoutAutoUnit(request) {
43
+ const modelId = request.ctx.model?.id ?? "unknown";
44
+ snapshotUnitMetrics(request.ctx, request.unitType, request.unitId, request.startedAt, modelId, request.opts);
45
+ const activityFile = saveActivityLog(request.ctx, request.basePath, request.unitType, request.unitId);
46
46
  if (activityFile) {
47
47
  try {
48
- const { buildMemoryLLMCall, extractMemoriesFromUnit } = await import('./memory-extractor.js');
49
- const llmCallFn = buildMemoryLLMCall(ctx);
48
+ const { buildMemoryLLMCall, extractMemoriesFromUnit } = await import("./memory-extractor.js");
49
+ const llmCallFn = buildMemoryLLMCall(request.ctx);
50
50
  if (llmCallFn) {
51
51
  // Awaited: a fire-and-forget here lets memory-extractor writes land in
52
52
  // .gsd/ after closeoutUnit returns but before the milestone merge
@@ -55,10 +55,10 @@ export async function closeoutUnit(ctx, basePath, unitType, unitId, startedAt, o
55
55
  // bounded by the extractor's LLM call, which is the acceptable price
56
56
  // for not racing the merge boundary.
57
57
  try {
58
- await extractMemoriesFromUnit(activityFile, unitType, unitId, llmCallFn);
58
+ await extractMemoriesFromUnit(activityFile, request.unitType, request.unitId, llmCallFn);
59
59
  }
60
60
  catch (err) {
61
- logWarning("engine", `memory extraction failed for ${unitType}/${unitId}: ${err.message}`);
61
+ logWarning("engine", `memory extraction failed for ${request.unitType}/${request.unitId}: ${err.message}`);
62
62
  }
63
63
  }
64
64
  }
@@ -66,22 +66,46 @@ export async function closeoutUnit(ctx, basePath, unitType, unitId, startedAt, o
66
66
  logWarning("engine", `operation failed: ${err instanceof Error ? err.message : String(err)}`);
67
67
  }
68
68
  }
69
- if (opts?.traceId && opts.turnId && opts.gitAction && opts.gitStatus) {
69
+ const gitTransaction = resolveGitTransactionOptions(request.opts);
70
+ if (gitTransaction) {
70
71
  writeTurnGitTransaction({
71
- basePath,
72
- traceId: opts.traceId,
73
- turnId: opts.turnId,
74
- unitType,
75
- unitId,
72
+ basePath: request.basePath,
73
+ traceId: gitTransaction.traceId,
74
+ turnId: gitTransaction.turnId,
75
+ unitType: request.unitType,
76
+ unitId: request.unitId,
76
77
  stage: "record",
77
- action: opts.gitAction,
78
- push: opts.gitPush === true,
79
- status: opts.gitStatus,
80
- error: opts.gitError,
78
+ action: gitTransaction.gitAction,
79
+ push: gitTransaction.gitPush === true,
80
+ status: gitTransaction.gitStatus,
81
+ error: gitTransaction.gitError,
81
82
  metadata: {
82
83
  activityFile,
83
84
  },
84
85
  });
85
86
  }
86
- return activityFile ?? undefined;
87
+ return {
88
+ ...(activityFile ? { activityFile } : {}),
89
+ gitTransactionRecorded: Boolean(gitTransaction),
90
+ };
91
+ }
92
+ function resolveGitTransactionOptions(opts) {
93
+ if (!opts?.traceId || !opts.turnId || !opts.gitAction || !opts.gitStatus)
94
+ return null;
95
+ return {
96
+ traceId: opts.traceId,
97
+ turnId: opts.turnId,
98
+ gitAction: opts.gitAction,
99
+ gitStatus: opts.gitStatus,
100
+ gitPush: opts.gitPush,
101
+ gitError: opts.gitError,
102
+ };
103
+ }
104
+ /**
105
+ * Compatibility wrapper for existing auto-loop callers. New code should prefer
106
+ * closeoutAutoUnit so the closeout request and result stay explicit.
107
+ */
108
+ export async function closeoutUnit(ctx, basePath, unitType, unitId, startedAt, opts) {
109
+ const result = await closeoutAutoUnit({ ctx, basePath, unitType, unitId, startedAt, opts });
110
+ return result.activityFile;
87
111
  }
@@ -23,6 +23,7 @@ import { getSlice } from "./gsd-db.js";
23
23
  import { getLedger } from "./metrics.js";
24
24
  import { getUnitCostSpikeAction, resolveUnitCostSpikeMultiplier } from "./auto-budget.js";
25
25
  import { formatPostUnitStatusCard } from "./auto-status-message.js";
26
+ import { detectWebApp } from "./web-app-uat.js";
26
27
  function getCurrentUnitCostStats(unitId) {
27
28
  const ledger = getLedger();
28
29
  if (!ledger || !Array.isArray(ledger.units) || ledger.units.length === 0) {
@@ -617,14 +618,25 @@ export async function runPostUnitVerification(vctx, pauseAuto) {
617
618
  s.pendingVerificationRetry = null;
618
619
  return "continue";
619
620
  }
621
+ else if (verdict.reason === "no-host-checks" &&
622
+ taskAlreadyComplete &&
623
+ detectWebApp(s.basePath) &&
624
+ !result.runtimeErrors?.some((e) => e.blocking)) {
625
+ s.verificationRetryCount.delete(retryKey);
626
+ s.verificationRetryFailureHashes.delete(retryKey);
627
+ s.pendingVerificationRetry = null;
628
+ ctx.ui.notify("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.", "warning");
629
+ return "continue";
630
+ }
620
631
  else if (verdict.reason === "no-host-checks") {
621
632
  s.verificationRetryCount.delete(retryKey);
622
633
  s.verificationRetryFailureHashes.delete(retryKey);
623
634
  s.pendingVerificationRetry = null;
624
- ctx.ui.notify("Verification gate FAILED no runnable host-owned verification checks were discovered. Pausing for human review.", "error");
635
+ const pauseMessage = `Verification failed: ${verdict.failureContext}`;
636
+ ctx.ui.notify(`Verification gate FAILED — ${verdict.failureContext}`, "error");
625
637
  process.stderr.write(`verification-gate: ${verdict.failureContext}\n`);
626
638
  await pauseAuto(ctx, pi, {
627
- message: "Verification failed: no runnable host-owned verification checks were discovered.",
639
+ message: pauseMessage,
628
640
  category: "unknown",
629
641
  });
630
642
  return "pause";
@@ -800,6 +800,14 @@ function _resolveIntegrationBranchForReuse(basePath, milestoneId) {
800
800
  return null;
801
801
  }
802
802
  }
803
+ function safeCwd(fallback) {
804
+ try {
805
+ return process.cwd();
806
+ }
807
+ catch {
808
+ return fallback;
809
+ }
810
+ }
803
811
  /**
804
812
  * When reusing an existing milestone branch, fast-forward it onto the
805
813
  * integration branch when that's safe (branch is a strict ancestor of
@@ -949,7 +957,7 @@ export function teardownAutoWorktree(originalBasePath, milestoneId, opts = {}) {
949
957
  originalBasePath = resolveWorktreeProjectRoot(originalBasePath);
950
958
  const branch = autoWorktreeBranch(milestoneId);
951
959
  const { preserveBranch = false, preserveWorktree = false } = opts;
952
- const previousCwd = process.cwd();
960
+ const previousCwd = safeCwd(originalBasePath);
953
961
  // Wrap the entire teardown body in a single try/finally so activeWorkspace
954
962
  // is ALWAYS cleared — even if process.chdir throws (e.g. originalBasePath
955
963
  // was deleted before teardown ran). Previously the finally only covered
@@ -1033,7 +1041,7 @@ export function teardownAutoWorktree(originalBasePath, milestoneId, opts = {}) {
1033
1041
  * still works after process restart when module state has been reset.
1034
1042
  */
1035
1043
  export function isInAutoWorktree(basePath) {
1036
- const targetPath = isGsdWorktreePath(basePath) ? basePath : process.cwd();
1044
+ const targetPath = isGsdWorktreePath(basePath) ? basePath : safeCwd("");
1037
1045
  if (!isGsdWorktreePath(targetPath))
1038
1046
  return false;
1039
1047
  const storedBase = getAutoWorktreeOriginalBase();
@@ -1901,6 +1909,11 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
1901
1909
  }
1902
1910
  catch (err) {
1903
1911
  logWarning("worktree", `chdir to project root after merge failed: ${err instanceof Error ? err.message : String(err)}`);
1912
+ debugLog("mergeMilestoneToMain", {
1913
+ phase: "post-merge-chdir-failed",
1914
+ target: originalBasePath_,
1915
+ error: err instanceof Error ? err.message : String(err),
1916
+ });
1904
1917
  }
1905
1918
  };
1906
1919
  let shouldCleanup = false;
@@ -512,6 +512,16 @@ export function _warnIfWorktreeMissingForTest(worktreePath, milestoneId) {
512
512
  }
513
513
  return false;
514
514
  }
515
+ export function anchorProcessCwdForAutoResume(basePath) {
516
+ try {
517
+ process.chdir(basePath);
518
+ return true;
519
+ }
520
+ catch (err) {
521
+ logWarning("session", `resume cwd anchor failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts", basePath });
522
+ return false;
523
+ }
524
+ }
515
525
  export function isAutoPaused() {
516
526
  return s.paused;
517
527
  }
@@ -630,6 +640,35 @@ export function stopAutoRemote(projectRoot) {
630
640
  return { found: false, error: err.message };
631
641
  }
632
642
  }
643
+ /**
644
+ * Force-stop a remote auto-mode session before stealing its lock.
645
+ * The normal stop path stays SIGTERM-only so cooperative sessions can clean up;
646
+ * this path is only for the explicit "Force start" action.
647
+ */
648
+ export function forceStopAutoRemote(projectRoot) {
649
+ const lock = readCrashLock(projectRoot);
650
+ if (!lock)
651
+ return { found: false };
652
+ if (lock.pid === process.pid) {
653
+ clearLock(projectRoot);
654
+ return { found: false };
655
+ }
656
+ if (!isLockProcessAlive(lock)) {
657
+ clearLock(projectRoot);
658
+ return { found: false };
659
+ }
660
+ try {
661
+ process.kill(lock.pid, "SIGTERM");
662
+ if (isLockProcessAlive(lock)) {
663
+ process.kill(lock.pid, "SIGKILL");
664
+ }
665
+ clearLock(projectRoot);
666
+ return { found: true, pid: lock.pid };
667
+ }
668
+ catch (err) {
669
+ return { found: false, error: err.message };
670
+ }
671
+ }
633
672
  /**
634
673
  * Check if a remote auto-mode session is running (from a different process).
635
674
  * Reads the crash lock, checks PID liveness, and returns session details.
@@ -722,6 +761,9 @@ function pauseAutoUnitIdentityMatches(expected) {
722
761
  s.currentUnit.id === expected.id &&
723
762
  s.currentUnit.startedAt === expected.startedAt;
724
763
  }
764
+ function shouldPreserveCoordinationForPause(errorContext) {
765
+ return errorContext?.category === "provider" && errorContext.isTransient === true;
766
+ }
725
767
  function setLifecycleOutcome(ctx, input) {
726
768
  if (!ctx?.hasUI)
727
769
  return;
@@ -1556,7 +1598,7 @@ export async function pauseAuto(ctx, _pi, _errorContext, options = {}) {
1556
1598
  releaseSessionLock(lockBase());
1557
1599
  clearLock(lockBase());
1558
1600
  }
1559
- if (s.workerId) {
1601
+ if (s.workerId && !shouldPreserveCoordinationForPause(_errorContext)) {
1560
1602
  try {
1561
1603
  if (s.currentMilestoneId && s.milestoneLeaseToken) {
1562
1604
  releaseMilestoneLease(s.workerId, s.currentMilestoneId, s.milestoneLeaseToken);
@@ -1831,7 +1873,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
1831
1873
  if (freshStartAssessment.classification === "running") {
1832
1874
  const pid = freshStartAssessment.lock?.pid;
1833
1875
  ctx.ui.notify(pid
1834
- ? `Another auto-mode session (PID ${pid}) appears to be running.\nStop it with \`kill ${pid}\` before starting a new session.`
1876
+ ? `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.`
1835
1877
  : "Another auto-mode session appears to be running.", "error");
1836
1878
  return;
1837
1879
  }
@@ -2001,6 +2043,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
2001
2043
  }
2002
2044
  // ADR-016 phase 2 / B3 (#5621): paused-resume worktree-path adoption.
2003
2045
  buildLifecycle().resumeFromPausedSession(base, resumeWorktreePath);
2046
+ anchorProcessCwdForAutoResume(s.basePath || base);
2004
2047
  // Rebuild scope now that s.basePath reflects the actual worktree (or project root).
2005
2048
  rebuildScope(s.basePath, s.currentMilestoneId);
2006
2049
  // Ensure the workflow-logger audit log is pinned to the project root
@@ -5,7 +5,7 @@ import { homedir } from "node:os";
5
5
  import { join } from "node:path";
6
6
  import { createBashTool, createEditTool, createReadTool, createWriteTool } from "@gsd/pi-coding-agent";
7
7
  import { logWarning } from "../workflow-logger.js";
8
- import { openWorkflowDatabase } from "../db-workspace.js";
8
+ import { getWorkflowDatabaseStatus, openWorkflowDatabase, } from "../db-workspace.js";
9
9
  import { getAutoWorktreePath } from "../auto-worktree.js";
10
10
  import { resolveWorktreeProjectRoot } from "../worktree-root.js";
11
11
  import { worktreesDirs } from "../worktree-placement.js";
@@ -61,16 +61,46 @@ export function resolveWorkflowToolBasePath(ctx, scope) {
61
61
  return cwd;
62
62
  }
63
63
  export { resolveProjectRootDbPath } from "../db-workspace.js";
64
+ function sqliteProviderHint(status, nodeVersion) {
65
+ if (status.provider)
66
+ return `Provider: ${status.provider}.`;
67
+ const major = Number.parseInt(nodeVersion.split(".")[0] ?? "", 10);
68
+ if (Number.isFinite(major) && major < 22) {
69
+ return (`No SQLite provider available. Upgrade Node to >= 22.0.0 (current: v${nodeVersion}), ` +
70
+ "use the packaged GSD runtime, or install/restore better-sqlite3 in this runtime.");
71
+ }
72
+ return ("No SQLite provider available. Use a Node build with node:sqlite enabled, " +
73
+ "run the packaged GSD runtime, or install/restore better-sqlite3 in this runtime.");
74
+ }
75
+ function dbOpenPhaseHint(status) {
76
+ if (status.lastPhase === "open")
77
+ return "The database file could not be opened";
78
+ if (status.lastPhase === "initSchema")
79
+ return "The database schema could not be initialized";
80
+ if (status.lastPhase === "vacuum-recovery")
81
+ return "Corruption recovery (VACUUM) failed";
82
+ if (status.attempted)
83
+ return "The database could not be opened";
84
+ return "The database provider could not be loaded";
85
+ }
86
+ export function formatWorkflowDatabaseOpenFailure(result, status, nodeVersion = process.versions.node) {
87
+ if (result.reason === "missing-gsd-dir") {
88
+ return `ensureDbOpen failed — no .gsd directory found at ${result.location.projectGsd}`;
89
+ }
90
+ if (result.reason === "missing-database") {
91
+ return `ensureDbOpen failed — no GSD database found at ${result.location.projectDb}`;
92
+ }
93
+ const resolvedStatus = status ?? getWorkflowDatabaseStatus();
94
+ const detail = result.error?.message ?? resolvedStatus.lastError?.message ?? "";
95
+ const detailSuffix = detail ? ` (${detail})` : "";
96
+ return (`ensureDbOpen failed for ${result.location.projectDb}: ` +
97
+ `${dbOpenPhaseHint(resolvedStatus)}${detailSuffix}. ${sqliteProviderHint(resolvedStatus, nodeVersion)}`);
98
+ }
64
99
  export async function ensureDbOpen(basePath = safeWorkspaceCwd()) {
65
100
  const result = openWorkflowDatabase(basePath);
66
101
  if (result.ok)
67
102
  return true;
68
- if (result.reason === "missing-gsd-dir") {
69
- logWarning("bootstrap", "ensureDbOpen failed — no .gsd directory found");
70
- }
71
- else {
72
- logWarning("bootstrap", `ensureDbOpen failed: ${result.error?.message ?? "open failed"}`);
73
- }
103
+ logWarning("bootstrap", formatWorkflowDatabaseOpenFailure(result));
74
104
  return false;
75
105
  }
76
106
  export function registerDynamicTools(pi) {
@@ -1,4 +1,4 @@
1
- import { checkRemoteAutoSession, isAutoActive, isAutoPaused, stopAutoRemote } from "../auto.js";
1
+ import { checkRemoteAutoSession, forceStopAutoRemote, isAutoActive, isAutoPaused, stopAutoRemote } from "../auto.js";
2
2
  import { validateDirectory } from "../validate-directory.js";
3
3
  import { resolveProjectRoot } from "../worktree.js";
4
4
  import { showNextAction } from "../../shared/tui.js";
@@ -135,5 +135,19 @@ export async function guardRemoteSession(ctx, pi) {
135
135
  }
136
136
  return false;
137
137
  }
138
- return choice === "force";
138
+ if (choice === "force") {
139
+ const result = forceStopAutoRemote(projectRoot());
140
+ if (result.error) {
141
+ ctx.ui.notify(`Failed to force-stop remote auto-mode: ${result.error}`, "error");
142
+ return false;
143
+ }
144
+ if (result.found) {
145
+ ctx.ui.notify(`Force-stopped auto-mode session (PID ${result.pid}). Starting a new session.`, "warning");
146
+ }
147
+ else {
148
+ ctx.ui.notify("Remote session is no longer running. Starting a new session.", "info");
149
+ }
150
+ return true;
151
+ }
152
+ return false;
139
153
  }
@@ -59,7 +59,7 @@ export function formatMcpStatusReport(servers) {
59
59
  : s.connected
60
60
  ? `connected — ${s.toolCount} tools`
61
61
  : s.available
62
- ? `available — ${s.toolCount} tools`
62
+ ? `probe available — ${s.toolCount} tools`
63
63
  : "disconnected";
64
64
  const warningText = s.envWarnings?.length ? ` — ${s.envWarnings.length} warning(s)` : "";
65
65
  lines.push(` ${icon} ${s.name} (${s.transport}) — ${status}${warningText}`);
@@ -83,7 +83,7 @@ export function formatMcpServerDetail(server) {
83
83
  lines.push(` Error: ${server.error}`);
84
84
  }
85
85
  else if (server.connected || server.available) {
86
- lines.push(` Status: ${server.connected ? "connected" : "available"}`);
86
+ lines.push(` Status: ${server.connected ? "connected" : "probe available"}`);
87
87
  lines.push(` Tools: ${server.toolCount}`);
88
88
  if (server.tools.length > 0) {
89
89
  lines.push("");