@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
@@ -42,9 +42,15 @@ export { nextMilestoneIdReserved } from "./milestone-id-reservation.js";
42
42
  import { parkMilestone, discardMilestone } from "./milestone-actions.js";
43
43
  import { buildCloseoutMenuActions, buildIdleMenuSummary, getPrimaryCloseoutRecommendation, handleCloseoutChoice, loadCloseoutContext, } from "./closeout-wizard.js";
44
44
  import { buildRequirementsBacklogDiscussContext, countUnmappedActiveRequirements, showRequirementsBacklogReview, } from "./requirements-backlog.js";
45
- import { selectAndApplyModel } from "./auto-model-selection.js";
45
+ import { selectAndApplyModel, getRegisteredToolSnapshot } from "./auto-model-selection.js";
46
46
  import { DISCUSS_TOOLS_ALLOWLIST } from "./constants.js";
47
- import { getWorkflowTransportSupportError, getRequiredWorkflowToolsForGuidedUnit, supportsStructuredQuestions, } from "./workflow-mcp.js";
47
+ import { detectWorkflowMcpLaunchConfig, resolveWorkflowMcpProjectRoot, supportsStructuredQuestions, } from "./workflow-mcp.js";
48
+ import { usesWorkflowMcpTransport } from "./question-transport.js";
49
+ import { getCachedWorkflowMcpProbe, probeAndCacheWorkflowMcp, warmWorkflowMcpProbeInBackground, workflowMcpProbeAdvertisesSurface, WORKFLOW_MCP_PROBE_TIMEOUT_MS, } from "./workflow-mcp-readiness-cache.js";
50
+ import { probeCoversRequiredWorkflowTools } from "./tool-surface-readiness.js";
51
+ import { getRequiredWorkflowToolsForUnit } from "./unit-tool-contracts.js";
52
+ import { isWorkflowToolSurfaceName } from "./workflow-tool-surface.js";
53
+ import { getUnitWorkflowDispatchReadinessError } from "./tool-contract.js";
48
54
  import { runPreparation, formatCodebaseBrief, formatPriorContextBrief, } from "./preparation.js";
49
55
  import { verifyExpectedArtifact } from "./auto-recovery.js";
50
56
  import { clearPendingGate, extractDepthVerificationMilestoneId, getPendingGate } from "./bootstrap/write-gate.js";
@@ -368,6 +374,67 @@ async function dispatchNextDeepProjectSetupStage(entry) {
368
374
  export function resolveGuidedDispatchProjectRoot(basePath) {
369
375
  return basePath ?? process.cwd();
370
376
  }
377
+ /**
378
+ * Wait until the workflow MCP server is reachable and advertising its tool
379
+ * surface. Returns failure details when timed out, or null when ready (or MCP
380
+ * is not the transport). Called inside dispatchWorkflow() so every guided-flow
381
+ * dispatch path is gated automatically.
382
+ */
383
+ const MCP_READINESS_TIMEOUT_MS = 15_000;
384
+ const MCP_READINESS_POLL_MS = 200;
385
+ async function awaitWorkflowMcpReadiness(pi, ctx, basePath, options = {}) {
386
+ const provider = ctx.model?.provider;
387
+ const authMode = provider ? ctx.modelRegistry.getProviderAuthMode(provider) : undefined;
388
+ if (!usesWorkflowMcpTransport(authMode, ctx.model?.baseUrl))
389
+ return null;
390
+ const projectRoot = resolveWorkflowMcpProjectRoot(basePath);
391
+ const launch = detectWorkflowMcpLaunchConfig(projectRoot);
392
+ if (!launch)
393
+ return null;
394
+ const requiredTools = options.unitType
395
+ ? getRequiredWorkflowToolsForUnit(options.unitType).filter(isWorkflowToolSurfaceName)
396
+ : [];
397
+ const coversExpectedSurface = (tools) => requiredTools.length > 0
398
+ ? probeCoversRequiredWorkflowTools(tools, requiredTools)
399
+ : workflowMcpProbeAdvertisesSurface(tools);
400
+ const serverPrefix = `mcp__${launch.name}__`;
401
+ const systemPrompt = () => typeof ctx.getSystemPrompt === "function" ? ctx.getSystemPrompt() : "";
402
+ const systemPromptCoversExpectedSurface = () => {
403
+ const prompt = systemPrompt();
404
+ return requiredTools.length > 0
405
+ ? requiredTools.every((tool) => prompt.includes(`${serverPrefix}${tool}`))
406
+ : prompt.includes(serverPrefix);
407
+ };
408
+ const sessionAlreadyReady = () => coversExpectedSurface(getRegisteredToolSnapshot(pi)) ||
409
+ systemPromptCoversExpectedSurface();
410
+ if (sessionAlreadyReady())
411
+ return null;
412
+ if (coversExpectedSurface(getCachedWorkflowMcpProbe(projectRoot)?.tools ?? [])) {
413
+ return null;
414
+ }
415
+ const probe = options.probe ?? probeAndCacheWorkflowMcp;
416
+ const probeTimeoutMs = options.probeTimeoutMs ?? WORKFLOW_MCP_PROBE_TIMEOUT_MS;
417
+ ctx.ui.setStatus("gsd-step", `Waiting for ${launch.name} MCP server…`);
418
+ let lastError;
419
+ const deadline = Date.now() + (options.timeoutMs ?? MCP_READINESS_TIMEOUT_MS);
420
+ const pollMs = options.pollMs ?? MCP_READINESS_POLL_MS;
421
+ while (Date.now() < deadline) {
422
+ if (sessionAlreadyReady()) {
423
+ ctx.ui.setStatus("gsd-step", "");
424
+ return null;
425
+ }
426
+ const result = await probe(projectRoot, { timeoutMs: probeTimeoutMs });
427
+ if (result.ok && coversExpectedSurface(result.tools)) {
428
+ ctx.ui.setStatus("gsd-step", "");
429
+ return null;
430
+ }
431
+ lastError = result.error;
432
+ await new Promise((r) => setTimeout(r, pollMs));
433
+ }
434
+ ctx.ui.setStatus("gsd-step", "");
435
+ return lastError ? { server: launch.name, error: lastError } : { server: launch.name };
436
+ }
437
+ export const _awaitWorkflowMcpReadinessForTest = awaitWorkflowMcpReadiness;
371
438
  /**
372
439
  * Read GSD-WORKFLOW.md and dispatch it to the LLM with a contextual note.
373
440
  * This is the only way the wizard triggers work — everything else is the LLM's job.
@@ -382,7 +449,8 @@ async function dispatchWorkflow(pi, note, customType = "gsd-run", ctx, unitType,
382
449
  const projectRoot = resolveGuidedDispatchProjectRoot(resolvedOptions.basePath);
383
450
  const loadPreferences = resolvedOptions.deps?.loadPreferences ?? loadEffectiveGSDPreferences;
384
451
  const selectModel = resolvedOptions.deps?.selectModel ?? selectAndApplyModel;
385
- const getTransportSupportError = resolvedOptions.deps?.getTransportSupportError ?? getWorkflowTransportSupportError;
452
+ const getDispatchReadinessError = resolvedOptions.deps?.getDispatchReadinessError
453
+ ?? getUnitWorkflowDispatchReadinessError;
386
454
  // Route through the dynamic routing pipeline (complexity classification,
387
455
  // tier downgrade, fallback chains) — same path as auto-mode dispatches (#2958).
388
456
  if (ctx && unitType) {
@@ -396,7 +464,8 @@ async function dispatchWorkflow(pi, note, customType = "gsd-run", ctx, unitType,
396
464
  routing: result.routing,
397
465
  });
398
466
  }
399
- const compatibilityError = getTransportSupportError(result.appliedModel?.provider ?? ctx.model?.provider, getRequiredWorkflowToolsForGuidedUnit(unitType), {
467
+ const compatibilityError = getDispatchReadinessError({
468
+ provider: result.appliedModel?.provider ?? ctx.model?.provider,
400
469
  projectRoot,
401
470
  surface: "guided flow",
402
471
  unitType,
@@ -415,6 +484,25 @@ async function dispatchWorkflow(pi, note, customType = "gsd-run", ctx, unitType,
415
484
  ctx.ui.notify(compatibilityError, "error");
416
485
  return;
417
486
  }
487
+ // ── Live MCP readiness gate ────────────────────────────────────────
488
+ // Units with required workflow tools must not dispatch until the MCP
489
+ // surface covers that exact contract; otherwise the model can race into
490
+ // "No such tool available" before recovery sees a clean readiness error.
491
+ warmWorkflowMcpProbeInBackground(projectRoot);
492
+ const requiredWorkflowTools = getRequiredWorkflowToolsForUnit(unitType).filter(isWorkflowToolSurfaceName);
493
+ const strictBlocking = requiredWorkflowTools.length > 0
494
+ && (process.env.GSD_GUIDED_MCP_BLOCKING ?? "").trim() !== "0";
495
+ if (strictBlocking) {
496
+ // If the workflow MCP server is configured but still connecting, wait
497
+ // for it instead of dispatching into a child session that will abort.
498
+ const readinessFailure = await awaitWorkflowMcpReadiness(pi, ctx, projectRoot, { unitType });
499
+ if (readinessFailure) {
500
+ const detail = readinessFailure.error ? ` ${readinessFailure.error}` : "";
501
+ ctx.ui.notify(`GSD workflow server "${readinessFailure.server}" did not connect in time.${detail} ` +
502
+ `Run \`/gsd mcp check ${readinessFailure.server}\` for details.`, "warning");
503
+ return;
504
+ }
505
+ }
418
506
  }
419
507
  // Scope tools for guided workflow turns (#2949, token-consumption savings).
420
508
  // Providers with grammar-based constrained decoding (xAI/Grok) return
@@ -1297,6 +1385,7 @@ async function handleMilestoneActions(ctx, pi, basePath, milestoneId, milestoneT
1297
1385
  }
1298
1386
  export async function showSmartEntry(ctx, pi, basePath, options) {
1299
1387
  const stepMode = options?.step ?? true;
1388
+ warmWorkflowMcpProbeInBackground(basePath);
1300
1389
  // ── Clear stale milestone ID reservations from previous cancelled sessions ──
1301
1390
  // Reservations only need to survive within a single /gsd interaction.
1302
1391
  // Without this, each cancelled session permanently bumps the next ID. (#2488)
@@ -1,7 +1,7 @@
1
1
  // Project/App: gsd-pi
2
2
  // File Purpose: Always-on ambient health signal rendered below the editor.
3
3
  import { runProviderChecks, summariseProviderIssues } from "./doctor-providers.js";
4
- import { runEnvironmentChecks } from "./doctor-environment.js";
4
+ import { runEnvironmentChecks, runEnvironmentChecksAsync } from "./doctor-environment.js";
5
5
  import { loadEffectiveGSDPreferences } from "./preferences.js";
6
6
  import { nativeIsRepo, nativeLastCommitEpoch, nativeGetCurrentBranch, nativeCommitSubject } from "./native-git-bridge.js";
7
7
  import { loadLedgerFromDisk, getProjectTotals } from "./metrics.js";
@@ -9,7 +9,28 @@ import { projectRoot } from "./commands/context.js";
9
9
  import { buildHealthLines, detectHealthWidgetProjectState, } from "./health-widget-core.js";
10
10
  export const HEALTH_WIDGET_ACTIVE_HINTS = " /gsd auto to run · /gsd status to inspect · /gsd report for snapshots · /gsd notifications for history · /gsd help";
11
11
  // ── Data loader ────────────────────────────────────────────────────────────────
12
- function loadHealthWidgetData(basePath) {
12
+ // Last-commit lookup is subprocess-backed (native-git-bridge → git spawns),
13
+ // so it is treated like the other expensive checks: skipped on first paint,
14
+ // run only by the background refresh.
15
+ function loadLastCommitInfo(basePath) {
16
+ try {
17
+ if (nativeIsRepo(basePath)) {
18
+ const branch = nativeGetCurrentBranch(basePath);
19
+ const epoch = nativeLastCommitEpoch(basePath, branch || "HEAD");
20
+ if (epoch > 0) {
21
+ return { epoch, message: nativeCommitSubject(basePath, branch || "HEAD") || null };
22
+ }
23
+ }
24
+ }
25
+ catch { /* non-fatal */ }
26
+ return { epoch: null, message: null };
27
+ }
28
+ function loadHealthWidgetData(basePath, options) {
29
+ // `includeChecks` gates the expensive subprocess-backed checks (provider +
30
+ // environment doctor: `lsof`, `docker`, `node --version`, ...). The initial
31
+ // synchronous render passes `false` so first paint is never blocked on them;
32
+ // the async refresh (off the first-paint path) runs the full suite.
33
+ const includeChecks = options?.includeChecks ?? true;
13
34
  let budgetCeiling;
14
35
  let budgetSpent = 0;
15
36
  let providerIssue = null;
@@ -28,13 +49,57 @@ function loadHealthWidgetData(basePath) {
28
49
  }
29
50
  }
30
51
  catch { /* non-fatal */ }
52
+ if (includeChecks) {
53
+ try {
54
+ const providerResults = runProviderChecks();
55
+ providerIssue = summariseProviderIssues(providerResults);
56
+ }
57
+ catch { /* non-fatal */ }
58
+ try {
59
+ const envResults = runEnvironmentChecks(basePath);
60
+ for (const r of envResults) {
61
+ if (r.status === "error")
62
+ environmentErrorCount++;
63
+ else if (r.status === "warning")
64
+ environmentWarningCount++;
65
+ }
66
+ }
67
+ catch { /* non-fatal */ }
68
+ }
69
+ // ── Last commit info ── (git spawns — gated like the other expensive checks)
70
+ if (includeChecks) {
71
+ const commit = loadLastCommitInfo(basePath);
72
+ lastCommitEpoch = commit.epoch;
73
+ lastCommitMessage = commit.message;
74
+ }
75
+ return {
76
+ projectState,
77
+ budgetCeiling,
78
+ budgetSpent,
79
+ providerIssue,
80
+ environmentErrorCount,
81
+ environmentWarningCount,
82
+ lastCommitEpoch,
83
+ lastCommitMessage,
84
+ lastRefreshed: Date.now(),
85
+ };
86
+ }
87
+ // Non-blocking variant used by the widget's background refresh: the cheap fields
88
+ // come from the synchronous snapshot, then provider + environment checks are
89
+ // layered in off the event-loop critical path (env checks run concurrently via
90
+ // runEnvironmentChecksAsync). Keeps the always-on widget from stalling the UI on
91
+ // its initial enrichment or its 60s refresh.
92
+ async function loadHealthWidgetDataAsync(basePath) {
93
+ const data = loadHealthWidgetData(basePath, { includeChecks: false });
94
+ let providerIssue = data.providerIssue;
95
+ let environmentErrorCount = 0;
96
+ let environmentWarningCount = 0;
31
97
  try {
32
- const providerResults = runProviderChecks();
33
- providerIssue = summariseProviderIssues(providerResults);
98
+ providerIssue = summariseProviderIssues(runProviderChecks());
34
99
  }
35
100
  catch { /* non-fatal */ }
36
101
  try {
37
- const envResults = runEnvironmentChecks(basePath);
102
+ const envResults = await runEnvironmentChecksAsync(basePath);
38
103
  for (const r of envResults) {
39
104
  if (r.status === "error")
40
105
  environmentErrorCount++;
@@ -43,27 +108,14 @@ function loadHealthWidgetData(basePath) {
43
108
  }
44
109
  }
45
110
  catch { /* non-fatal */ }
46
- // ── Last commit info ──
47
- try {
48
- if (nativeIsRepo(basePath)) {
49
- const branch = nativeGetCurrentBranch(basePath);
50
- const epoch = nativeLastCommitEpoch(basePath, branch || "HEAD");
51
- if (epoch > 0) {
52
- lastCommitEpoch = epoch;
53
- lastCommitMessage = nativeCommitSubject(basePath, branch || "HEAD") || null;
54
- }
55
- }
56
- }
57
- catch { /* non-fatal */ }
111
+ const commit = loadLastCommitInfo(basePath);
58
112
  return {
59
- projectState,
60
- budgetCeiling,
61
- budgetSpent,
113
+ ...data,
62
114
  providerIssue,
63
115
  environmentErrorCount,
64
116
  environmentWarningCount,
65
- lastCommitEpoch,
66
- lastCommitMessage,
117
+ lastCommitEpoch: commit.epoch,
118
+ lastCommitMessage: commit.message,
67
119
  lastRefreshed: Date.now(),
68
120
  };
69
121
  }
@@ -77,8 +129,13 @@ export function initHealthWidget(ctx) {
77
129
  if (!ctx.hasUI)
78
130
  return;
79
131
  const basePath = projectRoot();
80
- // String-array fallback — used in RPC mode (factory is a no-op there)
81
- const initialData = loadHealthWidgetData(basePath);
132
+ // String-array fallback — used in RPC mode (factory is a no-op there).
133
+ // Skip the expensive provider/environment doctor checks here: this runs
134
+ // synchronously on the interactive-startup path, where running them would
135
+ // block first paint by ~0.9s (lsof/docker probes, otherwise run again
136
+ // immediately by the factory below). The factory's async refresh fills in
137
+ // real health once the screen is up.
138
+ const initialData = loadHealthWidgetData(basePath, { includeChecks: false });
82
139
  ctx.ui.setWidget("gsd-health", buildHealthLines(initialData), { placement: "belowEditor" });
83
140
  // Factory-based widget for TUI mode — replaces the string-array above
84
141
  ctx.ui.setWidget("gsd-health", (_tui, _theme) => {
@@ -91,7 +148,7 @@ export function initHealthWidget(ctx) {
91
148
  return;
92
149
  refreshInFlight = true;
93
150
  try {
94
- data = loadHealthWidgetData(basePath);
151
+ data = await loadHealthWidgetDataAsync(basePath);
95
152
  cachedLines = undefined;
96
153
  if (!isDisposed)
97
154
  _tui.requestRender();
@@ -101,9 +158,11 @@ export function initHealthWidget(ctx) {
101
158
  refreshInFlight = false;
102
159
  }
103
160
  };
104
- // Fire first enrichment immediately. requestRender() inside is a no-op
105
- // if the widget has not yet rendered, so this is safe before factory return.
106
- void refresh();
161
+ // Fire the first full enrichment off the first-paint path. setTimeout(0)
162
+ // yields to the initial render + input loop, so the expensive doctor checks
163
+ // (provider + environment) never delay the moment the user sees the UI.
164
+ // requestRender() inside refresh repaints the widget once data is ready.
165
+ setTimeout(() => { void refresh(); }, 0);
107
166
  const refreshTimer = setInterval(() => {
108
167
  void refresh();
109
168
  }, REFRESH_INTERVAL_MS);
@@ -0,0 +1,10 @@
1
+ // mcp-bridge.ts — stable runtime seam for MCP server consumption (phase 1).
2
+ export { loadWriteGateSnapshot, shouldBlockPendingGateInSnapshot, shouldBlockQueueExecutionInSnapshot, } from "./bootstrap/write-gate.js";
3
+ export { ensureDbOpen } from "./bootstrap/dynamic-tools.js";
4
+ export { _getAdapter, checkpointDatabase, closeDatabase, getAllMilestones, getDb, getGateResults, getMilestoneSlices, getPendingGates, getSliceTasks, insertDecision, insertMilestone, insertSlice, openDatabase, upsertMilestonePlanning, } from "./gsd-db.js";
5
+ export { invalidateStateCache, isReusableGhostMilestone } from "./state.js";
6
+ export { loadEffectiveGSDPreferences } from "./preferences.js";
7
+ export { saveDecisionToDb, saveRequirementToDb, updateRequirementInDb, } from "./db-writer.js";
8
+ export { rebuildState } from "./doctor.js";
9
+ export { queryJournal } from "./journal.js";
10
+ export { claimReservedId, findMilestoneIds, getReservedMilestoneIds, milestoneIdSort, nextMilestoneId, } from "./milestone-ids.js";
@@ -3,7 +3,7 @@
3
3
  // Phase 4 companion to memory-store.ts. Edges live in the `memory_relations`
4
4
  // table and are created by (a) explicit LINK actions emitted by the memory
5
5
  // extractor, or (b) future `/gsd memory link` CLI commands. All writes go
6
- // through the single-writer gate in `gsd-db.ts`.
6
+ // through typed writer wrappers re-exported by `gsd-db.ts`.
7
7
  import { _getAdapter, deleteMemoryRelationsFor, insertMemoryRelationRow, isDbAvailable, } from "./gsd-db.js";
8
8
  export const VALID_RELATIONS = [
9
9
  "related_to",
@@ -5,7 +5,7 @@ import { isClosedStatus } from "./status-guards.js";
5
5
  import { transaction, getMilestone, getMilestoneSlices, getSlice, insertMilestone, insertSlice, upsertMilestonePlanning, upsertSlicePlanning, } from "./gsd-db.js";
6
6
  import { invalidateStateCache } from "./state.js";
7
7
  import { renderRoadmapFromDb } from "./markdown-renderer.js";
8
- import { renderAllProjections } from "./workflow-projections.js";
8
+ import { flushWorkflowProjections } from "./projection-flush.js";
9
9
  import { writeManifest } from "./workflow-manifest.js";
10
10
  import { appendEvent } from "./workflow-events.js";
11
11
  import { logWarning } from "./workflow-logger.js";
@@ -109,7 +109,7 @@ async function renderPlanArtifacts(basePath, params) {
109
109
  }
110
110
  async function runPostPlanHooks(basePath, params) {
111
111
  try {
112
- await renderAllProjections(basePath, params.milestoneId);
112
+ await flushWorkflowProjections(basePath, { milestoneId: params.milestoneId });
113
113
  writeManifest(basePath);
114
114
  appendEvent(basePath, {
115
115
  cmd: "plan-milestone",
@@ -1,11 +1,9 @@
1
- import { join } from "node:path";
2
- import { gsdRoot } from "./paths.js";
1
+ import { workflowEventArchivePath, workflowEventLogPath } from "./workflow-event-ledger.js";
3
2
  import { readEvents } from "./workflow-events.js";
4
3
  export function latestExplicitReopenAt(basePath, milestoneId) {
5
- const root = gsdRoot(basePath);
6
4
  const candidates = [
7
- join(root, "event-log.jsonl"),
8
- join(root, `event-log-${milestoneId}.jsonl.archived`),
5
+ workflowEventLogPath(basePath),
6
+ workflowEventArchivePath(basePath, milestoneId),
9
7
  ];
10
8
  let latest = null;
11
9
  for (const file of candidates) {
@@ -43,8 +43,8 @@ export function evaluateAllCompleteSettlement(input) {
43
43
  reason: "merge-pending",
44
44
  action: "pause",
45
45
  message: `Milestone ${milestoneId} is complete, but its worktree branch has not been merged to main. ` +
46
- `Retry with \`/gsd dispatch complete-milestone ${milestoneId}\` or merge manually.`,
47
- nextAction: `Retry \`/gsd dispatch complete-milestone ${milestoneId}\` or merge manually.`,
46
+ `Retry with \`/gsd dispatch complete-milestone ${milestoneId}\` to finish the system-owned merge.`,
47
+ nextAction: `Retry \`/gsd dispatch complete-milestone ${milestoneId}\`.`,
48
48
  milestoneId,
49
49
  };
50
50
  }
@@ -2,31 +2,36 @@
2
2
  // Cross-platform desktop notifications for auto-mode events.
3
3
  import { execFileSync } from "node:child_process";
4
4
  import { loadEffectiveGSDPreferences } from "./preferences.js";
5
- import { sendRemoteNotification } from "../remote-questions/notify.js";
5
+ import { sendRemoteNotification as _sendRemoteNotification } from "../remote-questions/notify.js";
6
+ /** Swappable dispatcher for remote notifications — exported so tests can mock it. */
7
+ export const remoteNotificationDispatcher = {
8
+ send: _sendRemoteNotification,
9
+ };
6
10
  /**
7
11
  * Send a native desktop notification. Non-blocking, non-fatal.
8
12
  * macOS: osascript, Linux: notify-send, Windows: skipped.
9
13
  */
10
- export function sendDesktopNotification(title, message, level = "info", kind = "complete", projectName) {
14
+ export function sendDesktopNotification(title, message, level = "info", kind = "complete", projectName, deps = {}) {
11
15
  // When a projectName is provided and the title is the default "GSD",
12
16
  // replace it with a project-qualified title for multi-project clarity.
13
17
  if (projectName && title === "GSD") {
14
18
  title = formatNotificationTitle(projectName);
15
19
  }
16
- const loaded = loadEffectiveGSDPreferences()?.preferences;
20
+ const loadedPreferences = loadEffectiveGSDPreferences()?.preferences;
21
+ const notifications = deps.notifications ?? loadedPreferences?.notifications;
17
22
  // Remote notifications fire independently of desktop preferences.
18
23
  // sendRemoteNotification handles "not configured" gracefully (early return).
19
- void sendRemoteNotification(title, message).catch(() => { });
20
- if (!shouldSendDesktopNotification(kind, loaded?.notifications))
24
+ void remoteNotificationDispatcher.send(title, message).catch(() => { });
25
+ if (!shouldSendDesktopNotification(kind, notifications))
21
26
  return;
22
27
  // cmux delivery and desktop delivery are independent — if cmux import or
23
28
  // delivery fails, we must still attempt the native desktop notification.
24
29
  const runCmux = async () => {
25
30
  try {
26
31
  const { CmuxClient, emitOsc777Notification, resolveCmuxConfig } = await import("../cmux/index.js");
27
- const cmux = resolveCmuxConfig(loaded);
32
+ const cmux = resolveCmuxConfig(loadedPreferences);
28
33
  if (cmux.notifications) {
29
- const delivered = CmuxClient.fromPreferences(loaded).notify(title, message);
34
+ const delivered = CmuxClient.fromPreferences(loadedPreferences).notify(title, message);
30
35
  if (delivered)
31
36
  return true;
32
37
  emitOsc777Notification(title, message);
@@ -0,0 +1,7 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Single workflow projection flush seam for mutation exits.
3
+ import { renderAllProjections } from "./workflow-projections.js";
4
+ export async function flushWorkflowProjections(basePath, scope) {
5
+ await renderAllProjections(basePath, scope.milestoneId);
6
+ return { milestoneId: scope.milestoneId };
7
+ }
@@ -38,7 +38,7 @@ Use `subagent` only when useful: reviewer, security, or tester. Apply findings b
38
38
  10. Prepare `gsd_slice_complete` content with camelCase fields `milestoneId`, `sliceId`, `sliceTitle`, `oneLiner`, `narrative`, `verification`, and `uatContent`.
39
39
  11. Draft concrete UAT with preconditions, steps, expected outcomes, edge cases, and UAT Type. Declare the type as a bullet under a `## UAT Type` heading, exactly like `- UAT mode: browser-executable`.
40
40
  **Web apps:** when inlined Web App UAT guidance is present, declare `browser-executable` or `runtime-executable` (not `artifact-driven`) for localhost/browser/screenshot steps; include dev-server preconditions and name Playwright specs when they exist.
41
- 12. Review the inlined task-summary excerpts for DECISIONS.md/KNOWLEDGE.md-worthy decisions and gotchas. Read full `*-SUMMARY.md` only if needed. Capture with `capture_thought`; do not append knowledge files.
41
+ 12. Review the inlined task-summary excerpts for DECISIONS.md/KNOWLEDGE.md-worthy decisions and gotchas. Read full `*-SUMMARY.md` only if needed. Capture with `gsd_capture_thought` (MCP-scoped `mcp__...__gsd_capture_thought`), not bare `capture_thought`; do not append knowledge files.
42
42
  13. When verification passes, call `gsd_slice_complete`. The DB-backed tool is the canonical write path. Do **not** manually write `{{sliceSummaryPath}}`. Do **not** manually write `{{sliceUatPath}}`. Do not edit roadmap checkboxes.
43
43
  14. Do not run git commands.
44
44
  15. If the current project state needs refresh, call `gsd_summary_save` with `artifact_type: "PROJECT"` and the full updated project markdown as `content`; omit `milestone_id`. Do not write or edit `.gsd/PROJECT.md` directly.
@@ -49,4 +49,4 @@ Use `subagent` only when useful: reviewer, security, or tester. Apply findings b
49
49
 
50
50
  **You MUST call `gsd_slice_complete` with summary and UAT content only after verification passes.**
51
51
 
52
- When done, say: "Slice {{sliceId}} complete."
52
+ When done, say: "Slice {{sliceId}} complete." Say this exactly once — if you already said it in a prior message, do not repeat it.
@@ -52,6 +52,7 @@ You execute. The inlined task plan is authoritative. Verify referenced files and
52
52
 
53
53
  - If task sections exist for Failure Modes (Q5), Load Profile (Q6), Negative Tests (Q7), or Observability Impact, implement and verify them.
54
54
  - Verify must-haves with concrete commands or observable behavior.
55
+ - Run verification commands through `gsd_exec` / Context Mode evidence when workflow MCP tools are presented. Use `gsd_exec_search` before rerunning noisy checks, and `gsd_resume` after compaction or resume. Do not call direct `bash` for final verification evidence in this unit.
55
56
  - Run slice-level verification from the slice plan. Final tasks need all checks passing; intermediate tasks should record partial passes.
56
57
  - Populate `## Verification Evidence` with `formatEvidenceTable` rows: command, exit code, verdict, duration. If no checks were found, say so.
57
58
  - For UI/browser/DOM/user-visible web changes, exercise the real flow and record explicit checks.
@@ -64,7 +65,7 @@ Keep about **{{verificationBudget}}** for verification and summary. If context i
64
65
 
65
66
  - If the plan is fundamentally invalid, set `blocker_discovered: true` in the summary and explain.
66
67
  - For downstream-impacting ambiguity that cannot be resolved from code, plans, or decisions, include an `escalation` object with question, options, recommendation, rationale, and `continueWithDefault`.
67
- - Capture meaningful architecture/pattern/observability decisions with `capture_thought`; capture non-obvious gotchas or conventions only when they save future investigation.
68
+ - Capture meaningful architecture/pattern/observability decisions with `gsd_capture_thought` (or MCP-scoped `mcp__...__gsd_capture_thought`) when workflow MCP tools are presented; capture non-obvious gotchas or conventions only when they save future investigation.
68
69
  - Use the inlined Task Summary template below. Read `{{taskSummaryTemplatePath}}` only if the inlined template is absent or visibly truncated.
69
70
  - Call `gsd_task_complete` with camelCase fields `milestoneId`, `sliceId`, `taskId`, `oneLiner`, `narrative`, `verification`, and `verificationEvidence`. Include `blockerDiscovered: true` when a stale-path safety failure or other plan-invalidating blocker prevents execution.
70
71
  - The DB-backed tool is the canonical write path. Do **not** manually write `{{taskSummaryPath}}` or edit PLAN.md checkboxes; the tool renders the summary and updates state.
@@ -76,4 +77,4 @@ Keep about **{{verificationBudget}}** for verification and summary. If context i
76
77
 
77
78
  **You MUST call `gsd_task_complete` before finishing, including when the stale-path safety rule stops execution.**
78
79
 
79
- When done, say: "Task {{taskId}} complete."
80
+ When done, say: "Task {{taskId}} complete." Say this exactly once — if you already said it in a prior message, do not repeat it.
@@ -118,4 +118,4 @@ If external API keys or secrets are required, use the inlined **Secrets Manifest
118
118
 
119
119
  If no external API keys or secrets are required, skip this step; do not create an empty manifest.
120
120
 
121
- When done, say: "Milestone {{milestoneId}} planned."
121
+ When done, say: "Milestone {{milestoneId}} planned." Say this exactly once — if you already said it in a prior message, do not repeat it.
@@ -57,4 +57,4 @@ The slice directory already exists. Do not mkdir.
57
57
 
58
58
  **You MUST call `gsd_plan_slice` to persist planning state before finishing, unless the stale-path safety rule above stops the unit before safe planning can occur.**
59
59
 
60
- When done, say: "Slice {{sliceId}} planned."
60
+ When done, say: "Slice {{sliceId}} planned." Say this exactly once — if you already said it in a prior message, do not repeat it.
@@ -37,4 +37,4 @@ You are executing a GSD quick task — a lightweight, focused unit of work outsi
37
37
  - <what was tested/verified>
38
38
  ```
39
39
 
40
- When done, say: "Quick task {{taskNum}} complete."
40
+ When done, say: "Quick task {{taskNum}} complete." Say this exactly once — if you already said it in a prior message, do not repeat it.
@@ -67,4 +67,4 @@ If `.gsd/REQUIREMENTS.md` exists and requirement ownership or status changed, up
67
67
 
68
68
  **DB access safety:** Do NOT query `.gsd/gsd.db` directly via `sqlite3` or `node -e require('better-sqlite3')`. Use `gsd_milestone_status` to read current milestone and slice state. All roadmap mutations go through `gsd_reassess_roadmap` — the tool writes to the DB and re-renders ROADMAP.md atomically.
69
69
 
70
- When done, say: "Roadmap reassessed."
70
+ When done, say: "Roadmap reassessed." Say this exactly once — if you already said it in a prior message, do not repeat it.
@@ -77,4 +77,4 @@ The slice directory and tasks/ subdirectory already exist. Do NOT mkdir.
77
77
 
78
78
  **You MUST call `gsd_plan_slice` to persist planning state before finishing.** After success, the pipeline clears the sketch flag on next state derivation; the on-disk PLAN file is the signal.
79
79
 
80
- When done, say: "Slice {{sliceId}} refined."
80
+ When done, say: "Slice {{sliceId}} refined." Say this exactly once — if you already said it in a prior message, do not repeat it.
@@ -38,4 +38,4 @@ Consider these captures when rewriting the remaining tasks — they represent th
38
38
  4. If any incomplete task had a `T0x-PLAN.md`, remove or rewrite it to match the new task description.
39
39
  5. Do not commit manually — the system auto-commits your changes after this unit completes.
40
40
 
41
- When done, say: "Slice {{sliceId}} replanned."
41
+ When done, say: "Slice {{sliceId}} replanned." Say this exactly once — if you already said it in a prior message, do not repeat it.
@@ -46,4 +46,4 @@ Then research the codebase and relevant technologies. Narrate key findings and s
46
46
 
47
47
  **You MUST call `gsd_summary_save` with the research content before finishing.**
48
48
 
49
- When done, say: "Milestone {{milestoneId}} researched."
49
+ When done, say: "Milestone {{milestoneId}} researched." Say this exactly once — if you already said it in a prior message, do not repeat it.
@@ -55,4 +55,4 @@ The slice directory already exists at `{{slicePath}}/`. Do NOT mkdir.
55
55
 
56
56
  **You MUST call `gsd_summary_save` with the research content before finishing.**
57
57
 
58
- When done, say: "Slice {{sliceId}} researched."
58
+ When done, say: "Slice {{sliceId}} researched." Say this exactly once — if you already said it in a prior message, do not repeat it.
@@ -30,4 +30,4 @@ An override was issued by the user that changes a fundamental decision or approa
30
30
 
31
31
  **You MUST update the relevant documents AND mark overrides as resolved in `{{overridesPath}}` before finishing.**
32
32
 
33
- When done, say: "Override applied across all documents."
33
+ When done, say: "Override applied across all documents." Say this exactly once — if you already said it in a prior message, do not repeat it.
@@ -10,6 +10,8 @@ If any inlined plan, summary, verification command, or prior artifact names an a
10
10
 
11
11
  All relevant context has been preloaded below. Start working immediately without re-reading these files.
12
12
 
13
+ If a `.gsd/**` or `.gsd/**/*` glob returns no matches, treat that as a possible symlink-backed traversal limitation; do not infer that the GSD harness is missing. Use the preloaded UAT context and direct `.gsd/...` file paths named in this prompt instead.
14
+
13
15
  {{inlinedContext}}
14
16
 
15
17
  {{skillActivation}}
@@ -100,4 +102,4 @@ checks: [{
100
102
 
101
103
  **You MUST call `gsd_uat_result_save` before finishing. Do not write the assessment file directly, and do not call `gsd_summary_save` as a substitute.**
102
104
 
103
- When done, say: "UAT {{sliceId}} complete."
105
+ When done, say: "UAT {{sliceId}} complete." Say this exactly once — if you already said it in a prior message, do not repeat it.
@@ -65,4 +65,4 @@ Classify each capture as one of:
65
65
 
66
66
  **Important:** Do NOT execute any resolutions. Only classify and update CAPTURES.md. Resolution execution happens separately (in auto-mode dispatch or manually by the user).
67
67
 
68
- When done, say: "Triage complete."
68
+ When done, say: "Triage complete." Say this exactly once — if you already said it in a prior message, do not repeat it.
@@ -87,4 +87,4 @@ If verdict is `needs-remediation`:
87
87
 
88
88
  **File system safety:** When scanning milestone directories, use `ls` or `find` first. Never pass a directory path such as `tasks/` or `slices/` directly to `read`; it only accepts files.
89
89
 
90
- When done, say: "Milestone {{milestoneId}} validation complete — verdict: <verdict>."
90
+ When done, say: "Milestone {{milestoneId}} validation complete — verdict: <verdict>." Say this exactly once — if you already said it in a prior message, do not repeat it.
@@ -25,4 +25,5 @@ Follow the workflow defined below. Execute each phase in order, completing one b
25
25
  3. **Atomic commits.** Commit working code after each meaningful change. Use conventional commit format: `<type>(<scope>): <description>`.
26
26
  4. **Verify before shipping.** Run the project's test suite and build before marking the workflow complete.
27
27
  5. **Decision gates, not ceremony.** After each phase, summarize what changed. For low/medium complexity, ask for confirmation only when the next phase depends on a real user choice or external approval. For high complexity, confirm before proceeding to each new phase.
28
- 6. **Stay focused.** This is a {{complexity}}-complexity workflow. Match your ceremony level to the task don't over-engineer or under-deliver.
28
+ 6. **Persist workflow state.** If the artifact directory contains `STATE.json`, update it after each phase: mark the finished phase `completed`, mark the next phase `active`, set `currentPhase` to the active phase index, and refresh `updatedAt`. When every phase is completed, set `completedAt` to the completion timestamp.
29
+ 7. **Stay focused.** This is a {{complexity}}-complexity workflow. Match your ceremony level to the task — don't over-engineer or under-deliver.
@@ -161,6 +161,26 @@ function parseTableSlices(section) {
161
161
  }
162
162
  return slices;
163
163
  }
164
+ function looksLikeTable(section) {
165
+ const lines = section.split("\n");
166
+ // Checkbox format takes precedence — embedded demo tables must not switch mode (#721).
167
+ if (lines.some(line => /^\s*-\s+\[[ xX]\]/.test(line))) {
168
+ return false;
169
+ }
170
+ const pipeLines = lines.filter(line => /^\s*\|/.test(line));
171
+ if (pipeLines.length < 2)
172
+ return false;
173
+ const hasSeparatorRow = pipeLines.some((line, index) => {
174
+ if (index === 0)
175
+ return false;
176
+ const cells = line.split("|").map(c => c.trim()).filter(Boolean);
177
+ return /^\s*\|[\s:-]+\|/.test(line) && cells.length >= 2 && cells.every(c => /^[\s:-]+$/.test(c));
178
+ });
179
+ if (hasSeparatorRow)
180
+ return true;
181
+ // Tables without a separator row still expose slice IDs in data rows.
182
+ return pipeLines.some(line => /\bS\d+\b/.test(line));
183
+ }
164
184
  export function parseRoadmapSlices(content) {
165
185
  const slicesSection = extractSlicesSection(content);
166
186
  if (!slicesSection) {
@@ -171,9 +191,11 @@ export function parseRoadmapSlices(content) {
171
191
  }
172
192
  // Try table format first — if the section contains pipe-delimited rows with
173
193
  // slice IDs, parse them as a table (#1736).
174
- const tableSlices = parseTableSlices(slicesSection);
175
- if (tableSlices.length > 0) {
176
- return tableSlices;
194
+ if (looksLikeTable(slicesSection)) {
195
+ const tableSlices = parseTableSlices(slicesSection);
196
+ if (tableSlices.length > 0) {
197
+ return tableSlices;
198
+ }
177
199
  }
178
200
  // Standard checkbox format
179
201
  const slices = [];