@opengsd/gsd-pi 1.2.0-dev.844675c9 → 1.2.0-dev.955e4da0

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 (530) hide show
  1. package/dist/cli-web-branch.d.ts +2 -0
  2. package/dist/cli-web-branch.js +9 -2
  3. package/dist/help-text.js +5 -0
  4. package/dist/resources/.managed-resources-content-hash +1 -1
  5. package/dist/resources/extensions/ask-user-questions.js +78 -23
  6. package/dist/resources/extensions/bg-shell/utilities.js +2 -2
  7. package/dist/resources/extensions/claude-code-cli/models.js +9 -0
  8. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +92 -230
  9. package/dist/resources/extensions/claude-code-cli/turn-assembler.js +224 -0
  10. package/dist/resources/extensions/github-sync/templates.js +3 -3
  11. package/dist/resources/extensions/gsd/artifact-projection.js +14 -0
  12. package/dist/resources/extensions/gsd/auto/loop.js +74 -56
  13. package/dist/resources/extensions/gsd/auto/orchestrator.js +142 -15
  14. package/dist/resources/extensions/gsd/auto/phases.js +34 -4
  15. package/dist/resources/extensions/gsd/auto/run-unit.js +2 -1
  16. package/dist/resources/extensions/gsd/auto/session.js +3 -0
  17. package/dist/resources/extensions/gsd/auto-dashboard.js +16 -4
  18. package/dist/resources/extensions/gsd/auto-dispatch.js +6 -5
  19. package/dist/resources/extensions/gsd/auto-model-selection.js +8 -0
  20. package/dist/resources/extensions/gsd/auto-post-unit.js +12 -9
  21. package/dist/resources/extensions/gsd/auto-prompts.js +81 -8
  22. package/dist/resources/extensions/gsd/auto-recovery.js +48 -49
  23. package/dist/resources/extensions/gsd/auto-runtime-state.js +14 -0
  24. package/dist/resources/extensions/gsd/auto-start.js +20 -36
  25. package/dist/resources/extensions/gsd/auto-timers.js +16 -2
  26. package/dist/resources/extensions/gsd/auto-tool-tracking.js +32 -0
  27. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +4 -29
  28. package/dist/resources/extensions/gsd/auto-verification.js +7 -7
  29. package/dist/resources/extensions/gsd/auto-worktree-repair.js +10 -2
  30. package/dist/resources/extensions/gsd/auto-worktree.js +34 -289
  31. package/dist/resources/extensions/gsd/auto.js +15 -14
  32. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +28 -37
  33. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +20 -43
  34. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +2 -2
  35. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +131 -140
  36. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +89 -8
  37. package/dist/resources/extensions/gsd/captures.js +5 -13
  38. package/dist/resources/extensions/gsd/closeout-consistency-gate.js +21 -4
  39. package/dist/resources/extensions/gsd/closeout-recovery.js +3 -2
  40. package/dist/resources/extensions/gsd/codebase-generator.js +8 -4
  41. package/dist/resources/extensions/gsd/commands/catalog.js +6 -62
  42. package/dist/resources/extensions/gsd/commands/handlers/auto.js +3 -0
  43. package/dist/resources/extensions/gsd/commands-handlers.js +20 -0
  44. package/dist/resources/extensions/gsd/commands-inspect.js +4 -8
  45. package/dist/resources/extensions/gsd/commands-maintenance.js +61 -41
  46. package/dist/resources/extensions/gsd/commands-ship.js +2 -2
  47. package/dist/resources/extensions/gsd/commands-verdict.js +12 -2
  48. package/dist/resources/extensions/gsd/db/engine.js +755 -0
  49. package/dist/resources/extensions/gsd/db/queries.js +372 -0
  50. package/dist/resources/extensions/gsd/db/sql-constants.js +11 -0
  51. package/dist/resources/extensions/gsd/db/writers/cascades.js +194 -0
  52. package/dist/resources/extensions/gsd/db/writers/import-restore.js +182 -0
  53. package/dist/resources/extensions/gsd/db/writers/memory.js +149 -0
  54. package/dist/resources/extensions/gsd/db/writers/reconcile.js +458 -0
  55. package/dist/resources/extensions/gsd/db/writers/status.js +70 -0
  56. package/dist/resources/extensions/gsd/db-workspace.js +103 -0
  57. package/dist/resources/extensions/gsd/delegation-policy.js +2 -10
  58. package/dist/resources/extensions/gsd/discussion-handoff.js +218 -0
  59. package/dist/resources/extensions/gsd/docs/preferences-reference.md +9 -0
  60. package/dist/resources/extensions/gsd/doctor-environment.js +8 -10
  61. package/dist/resources/extensions/gsd/doctor-git-checks.js +4 -3
  62. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +9 -2
  63. package/dist/resources/extensions/gsd/doctor.js +16 -9
  64. package/dist/resources/extensions/gsd/error-classifier.js +1 -1
  65. package/dist/resources/extensions/gsd/git-conflict-state.js +16 -1
  66. package/dist/resources/extensions/gsd/git-service.js +1 -0
  67. package/dist/resources/extensions/gsd/gitignore.js +3 -0
  68. package/dist/resources/extensions/gsd/gsd-db.js +183 -2048
  69. package/dist/resources/extensions/gsd/guided-flow.js +68 -471
  70. package/dist/resources/extensions/gsd/guided-unit-completion.js +225 -0
  71. package/dist/resources/extensions/gsd/markdown-renderer.js +2 -1
  72. package/dist/resources/extensions/gsd/mcp-filter.js +2 -1
  73. package/dist/resources/extensions/gsd/mcp-tool-name.js +26 -0
  74. package/dist/resources/extensions/gsd/md-importer.js +4 -3
  75. package/dist/resources/extensions/gsd/migrate/safety.js +19 -11
  76. package/dist/resources/extensions/gsd/migration-auto-check.js +27 -5
  77. package/dist/resources/extensions/gsd/milestone-closeout-proof.js +72 -0
  78. package/dist/resources/extensions/gsd/milestone-closeout.js +12 -4
  79. package/dist/resources/extensions/gsd/milestone-merge-transaction.js +10 -0
  80. package/dist/resources/extensions/gsd/milestone-planning-persistence.js +156 -0
  81. package/dist/resources/extensions/gsd/milestone-readiness.js +77 -0
  82. package/dist/resources/extensions/gsd/milestone-settlement.js +50 -0
  83. package/dist/resources/extensions/gsd/milestone-validation-evidence.js +73 -0
  84. package/dist/resources/extensions/gsd/milestone-validation-verdict.js +57 -0
  85. package/dist/resources/extensions/gsd/model-cost-table.js +1 -0
  86. package/dist/resources/extensions/gsd/model-router.js +3 -0
  87. package/dist/resources/extensions/gsd/parallel-eligibility.js +3 -6
  88. package/dist/resources/extensions/gsd/parallel-merge.js +14 -11
  89. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +7 -5
  90. package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -2
  91. package/dist/resources/extensions/gsd/paths.js +10 -24
  92. package/dist/resources/extensions/gsd/preferences-diagnostics.js +67 -0
  93. package/dist/resources/extensions/gsd/preferences.js +161 -29
  94. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -0
  95. package/dist/resources/extensions/gsd/prompts/execute-task.md +2 -0
  96. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +3 -1
  97. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
  98. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -0
  99. package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -0
  100. package/dist/resources/extensions/gsd/prompts/system.md +1 -1
  101. package/dist/resources/extensions/gsd/provider-payload-policy.js +83 -0
  102. package/dist/resources/extensions/gsd/pull-request-process.js +13 -0
  103. package/dist/resources/extensions/gsd/quality-gate-closure.js +109 -0
  104. package/dist/resources/extensions/gsd/question-transport.js +86 -0
  105. package/dist/resources/extensions/gsd/recovery-classification.js +12 -1
  106. package/dist/resources/extensions/gsd/roadmap-slices.js +8 -2
  107. package/dist/resources/extensions/gsd/safety/evidence-collector.js +37 -4
  108. package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +7 -2
  109. package/dist/resources/extensions/gsd/safety/file-change-validator.js +10 -0
  110. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +3 -2
  111. package/dist/resources/extensions/gsd/state-transition-matrix.js +38 -0
  112. package/dist/resources/extensions/gsd/state.js +13 -5
  113. package/dist/resources/extensions/gsd/status-guards.js +56 -8
  114. package/dist/resources/extensions/gsd/templates/plan.md +7 -0
  115. package/dist/resources/extensions/gsd/templates/project.md +1 -0
  116. package/dist/resources/extensions/gsd/templates/roadmap.md +1 -1
  117. package/dist/resources/extensions/gsd/templates/uat.md +5 -1
  118. package/dist/resources/extensions/gsd/tool-contract.js +52 -8
  119. package/dist/resources/extensions/gsd/tool-presentation-plan.js +15 -34
  120. package/dist/resources/extensions/gsd/tool-surface-snapshot.js +17 -0
  121. package/dist/resources/extensions/gsd/tools/complete-slice.js +24 -43
  122. package/dist/resources/extensions/gsd/tools/exec-tool.js +5 -5
  123. package/dist/resources/extensions/gsd/tools/plan-milestone.js +15 -143
  124. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +39 -0
  125. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +11 -29
  126. package/dist/resources/extensions/gsd/tools/reopen-slice.js +14 -33
  127. package/dist/resources/extensions/gsd/tools/skip-slice.js +18 -36
  128. package/dist/resources/extensions/gsd/tools/validate-milestone.js +15 -78
  129. package/dist/resources/extensions/gsd/uat-policy.js +16 -10
  130. package/dist/resources/extensions/gsd/uat-run.js +9 -14
  131. package/dist/resources/extensions/gsd/undo.js +8 -7
  132. package/dist/resources/extensions/gsd/unit-context-composer.js +40 -20
  133. package/dist/resources/extensions/gsd/unit-runtime.js +3 -2
  134. package/dist/resources/extensions/gsd/unit-tool-contracts.js +2 -1
  135. package/dist/resources/extensions/gsd/user-input-boundary.js +23 -0
  136. package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
  137. package/dist/resources/extensions/gsd/web-app-uat.js +80 -0
  138. package/dist/resources/extensions/gsd/workflow-mcp.js +15 -102
  139. package/dist/resources/extensions/gsd/workflow-reconcile.js +4 -3
  140. package/dist/resources/extensions/gsd/workflow-tool-surface.js +46 -0
  141. package/dist/resources/extensions/gsd/workspace-git-guard.js +2 -0
  142. package/dist/resources/extensions/gsd/worktree-git-recovery.js +287 -0
  143. package/dist/resources/extensions/gsd/worktree-lifecycle.js +9 -1
  144. package/dist/resources/extensions/gsd/worktree-manager.js +45 -28
  145. package/dist/resources/extensions/gsd/worktree-placement.js +59 -0
  146. package/dist/resources/extensions/gsd/worktree-reentry.js +12 -8
  147. package/dist/resources/extensions/gsd/worktree-root.js +17 -6
  148. package/dist/resources/extensions/gsd/worktree-safety.js +8 -5
  149. package/dist/resources/extensions/gsd/worktree-session-state.js +12 -10
  150. package/dist/resources/extensions/gsd/worktree-state-projection.js +33 -4
  151. package/dist/resources/extensions/gsd/worktree-telemetry.js +12 -0
  152. package/dist/resources/extensions/shared/interview-ui.js +2 -2
  153. package/dist/resources/shared/claude-runtime-floor.js +182 -0
  154. package/dist/resources/skills/gsd-browser/SKILL.md +1 -1
  155. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  156. package/dist/update-cmd.js +20 -0
  157. package/dist/web/standalone/.next/BUILD_ID +1 -1
  158. package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
  159. package/dist/web/standalone/.next/build-manifest.json +3 -3
  160. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  161. package/dist/web/standalone/.next/react-loadable-manifest.json +8 -8
  162. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  163. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  164. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  165. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  166. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  167. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  168. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  169. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  170. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  171. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  172. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  173. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  174. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  175. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  176. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  177. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  178. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  179. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  180. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  181. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  182. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  183. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  184. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  185. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  186. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  187. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  188. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  189. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  190. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  191. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  192. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  193. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  194. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
  195. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  196. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  197. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  198. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  199. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  200. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  201. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  202. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  203. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  204. package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
  205. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  206. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  207. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  208. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  209. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  210. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  211. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  212. package/dist/web/standalone/.next/server/app/index.html +1 -1
  213. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  214. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  215. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  216. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  217. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  218. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  219. package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
  220. package/dist/web/standalone/.next/server/chunks/{5047.js → 5942.js} +2 -2
  221. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  222. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  223. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  224. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  225. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  226. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  227. package/dist/web/standalone/.next/static/chunks/2659.b7b129ee6a769448.js +1 -0
  228. package/dist/web/standalone/.next/static/chunks/2772.bfa657f49f955239.js +1 -0
  229. package/dist/web/standalone/.next/static/chunks/{3616.4113d484a994e411.js → 3616.3c60753b8ffcbd2e.js} +1 -1
  230. package/dist/web/standalone/.next/static/chunks/4283.e4873b058df143a1.js +2 -0
  231. package/dist/web/standalone/.next/static/chunks/5826.a46ecdd1cfe8dabc.js +1 -0
  232. package/dist/web/standalone/.next/static/chunks/796.cf859a427a2cb2ac.js +10 -0
  233. package/dist/web/standalone/.next/static/chunks/8785.2e5a118797fb2dd2.js +1 -0
  234. package/dist/web/standalone/.next/static/chunks/{webpack-dda80a1ef5587410.js → webpack-fbea77b5f9953368.js} +1 -1
  235. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  236. package/dist/web-mode.d.ts +2 -0
  237. package/dist/web-mode.js +20 -8
  238. package/dist/worktree-status-banner.js +7 -3
  239. package/package.json +2 -1
  240. package/packages/cloud-mcp-gateway/package.json +2 -2
  241. package/packages/contracts/package.json +1 -1
  242. package/packages/daemon/package.json +4 -4
  243. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts +2 -0
  244. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts.map +1 -1
  245. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js +14 -0
  246. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js.map +1 -1
  247. package/packages/gsd-agent-core/package.json +5 -5
  248. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  249. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +3 -0
  250. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  251. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  252. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +106 -40
  253. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  254. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.d.ts.map +1 -1
  255. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js +6 -0
  256. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js.map +1 -1
  257. package/packages/gsd-agent-modes/package.json +7 -7
  258. package/packages/mcp-server/dist/server.d.ts +10 -0
  259. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  260. package/packages/mcp-server/dist/server.js +8 -0
  261. package/packages/mcp-server/dist/server.js.map +1 -1
  262. package/packages/mcp-server/dist/workflow-tools.d.ts +41 -0
  263. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  264. package/packages/mcp-server/dist/workflow-tools.js +32 -22
  265. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  266. package/packages/mcp-server/package.json +3 -3
  267. package/packages/native/package.json +1 -1
  268. package/packages/pi-agent-core/package.json +1 -1
  269. package/packages/pi-ai/dist/image-models.generated.d.ts +2 -2
  270. package/packages/pi-ai/dist/image-models.generated.js +6 -6
  271. package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
  272. package/packages/pi-ai/dist/models.generated.d.ts +295 -98
  273. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  274. package/packages/pi-ai/dist/models.generated.js +309 -154
  275. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  276. package/packages/pi-ai/package.json +1 -1
  277. package/packages/pi-coding-agent/dist/core/capability-patches.d.ts.map +1 -1
  278. package/packages/pi-coding-agent/dist/core/capability-patches.js +3 -1
  279. package/packages/pi-coding-agent/dist/core/capability-patches.js.map +1 -1
  280. package/packages/pi-coding-agent/package.json +7 -7
  281. package/packages/pi-tui/dist/components/input.js +1 -1
  282. package/packages/pi-tui/dist/components/input.js.map +1 -1
  283. package/packages/pi-tui/dist/keys.d.ts.map +1 -1
  284. package/packages/pi-tui/dist/keys.js +39 -30
  285. package/packages/pi-tui/dist/keys.js.map +1 -1
  286. package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
  287. package/packages/pi-tui/dist/stdin-buffer.js +22 -0
  288. package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
  289. package/packages/pi-tui/package.json +2 -2
  290. package/packages/rpc-client/package.json +2 -2
  291. package/pkg/package.json +1 -1
  292. package/src/resources/extensions/ask-user-questions.ts +87 -24
  293. package/src/resources/extensions/bg-shell/utilities.ts +2 -2
  294. package/src/resources/extensions/claude-code-cli/models.ts +9 -0
  295. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +114 -281
  296. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +268 -0
  297. package/src/resources/extensions/claude-code-cli/turn-assembler.ts +287 -0
  298. package/src/resources/extensions/github-sync/templates.ts +3 -3
  299. package/src/resources/extensions/github-sync/tests/templates.test.ts +2 -2
  300. package/src/resources/extensions/gsd/artifact-projection.ts +31 -0
  301. package/src/resources/extensions/gsd/auto/contracts.ts +32 -2
  302. package/src/resources/extensions/gsd/auto/loop-deps.ts +3 -1
  303. package/src/resources/extensions/gsd/auto/loop.ts +83 -61
  304. package/src/resources/extensions/gsd/auto/orchestrator.ts +164 -17
  305. package/src/resources/extensions/gsd/auto/phases.ts +45 -4
  306. package/src/resources/extensions/gsd/auto/run-unit.ts +2 -1
  307. package/src/resources/extensions/gsd/auto/session.ts +4 -0
  308. package/src/resources/extensions/gsd/auto-dashboard.ts +18 -4
  309. package/src/resources/extensions/gsd/auto-dispatch.ts +20 -7
  310. package/src/resources/extensions/gsd/auto-model-selection.ts +8 -0
  311. package/src/resources/extensions/gsd/auto-post-unit.ts +16 -8
  312. package/src/resources/extensions/gsd/auto-prompts.ts +107 -9
  313. package/src/resources/extensions/gsd/auto-recovery.ts +50 -50
  314. package/src/resources/extensions/gsd/auto-runtime-state.ts +26 -0
  315. package/src/resources/extensions/gsd/auto-start.ts +25 -34
  316. package/src/resources/extensions/gsd/auto-timers.ts +16 -2
  317. package/src/resources/extensions/gsd/auto-tool-tracking.ts +35 -0
  318. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +9 -30
  319. package/src/resources/extensions/gsd/auto-verification.ts +7 -8
  320. package/src/resources/extensions/gsd/auto-worktree-repair.ts +13 -2
  321. package/src/resources/extensions/gsd/auto-worktree.ts +53 -306
  322. package/src/resources/extensions/gsd/auto.ts +27 -17
  323. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +29 -37
  324. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +20 -43
  325. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +2 -2
  326. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +147 -153
  327. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +132 -6
  328. package/src/resources/extensions/gsd/captures.ts +5 -14
  329. package/src/resources/extensions/gsd/closeout-consistency-gate.ts +27 -5
  330. package/src/resources/extensions/gsd/closeout-recovery.ts +2 -1
  331. package/src/resources/extensions/gsd/codebase-generator.ts +9 -5
  332. package/src/resources/extensions/gsd/commands/catalog.ts +6 -68
  333. package/src/resources/extensions/gsd/commands/handlers/auto.ts +3 -0
  334. package/src/resources/extensions/gsd/commands-handlers.ts +18 -0
  335. package/src/resources/extensions/gsd/commands-inspect.ts +7 -8
  336. package/src/resources/extensions/gsd/commands-maintenance.ts +74 -40
  337. package/src/resources/extensions/gsd/commands-ship.ts +2 -2
  338. package/src/resources/extensions/gsd/commands-verdict.ts +19 -2
  339. package/src/resources/extensions/gsd/db/engine.ts +809 -0
  340. package/src/resources/extensions/gsd/db/queries.ts +453 -0
  341. package/src/resources/extensions/gsd/db/sql-constants.ts +12 -0
  342. package/src/resources/extensions/gsd/db/writers/cascades.ts +237 -0
  343. package/src/resources/extensions/gsd/db/writers/import-restore.ts +310 -0
  344. package/src/resources/extensions/gsd/db/writers/memory.ts +220 -0
  345. package/src/resources/extensions/gsd/db/writers/reconcile.ts +500 -0
  346. package/src/resources/extensions/gsd/db/writers/status.ts +88 -0
  347. package/src/resources/extensions/gsd/db-workspace.ts +170 -0
  348. package/src/resources/extensions/gsd/delegation-policy.ts +3 -11
  349. package/src/resources/extensions/gsd/discussion-handoff.ts +276 -0
  350. package/src/resources/extensions/gsd/docs/preferences-reference.md +9 -0
  351. package/src/resources/extensions/gsd/doctor-environment.ts +8 -11
  352. package/src/resources/extensions/gsd/doctor-git-checks.ts +3 -3
  353. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +10 -3
  354. package/src/resources/extensions/gsd/doctor.ts +15 -5
  355. package/src/resources/extensions/gsd/error-classifier.ts +1 -1
  356. package/src/resources/extensions/gsd/git-conflict-state.ts +17 -1
  357. package/src/resources/extensions/gsd/git-service.ts +1 -0
  358. package/src/resources/extensions/gsd/gitignore.ts +3 -0
  359. package/src/resources/extensions/gsd/gsd-db.ts +185 -2373
  360. package/src/resources/extensions/gsd/guided-flow.ts +81 -561
  361. package/src/resources/extensions/gsd/guided-unit-completion.ts +275 -0
  362. package/src/resources/extensions/gsd/markdown-renderer.ts +2 -1
  363. package/src/resources/extensions/gsd/mcp-filter.ts +2 -1
  364. package/src/resources/extensions/gsd/mcp-tool-name.ts +35 -0
  365. package/src/resources/extensions/gsd/md-importer.ts +3 -3
  366. package/src/resources/extensions/gsd/migrate/safety.ts +17 -9
  367. package/src/resources/extensions/gsd/migration-auto-check.ts +30 -5
  368. package/src/resources/extensions/gsd/milestone-closeout-proof.ts +131 -0
  369. package/src/resources/extensions/gsd/milestone-closeout.ts +12 -4
  370. package/src/resources/extensions/gsd/milestone-merge-transaction.ts +47 -0
  371. package/src/resources/extensions/gsd/milestone-planning-persistence.ts +224 -0
  372. package/src/resources/extensions/gsd/milestone-readiness.ts +125 -0
  373. package/src/resources/extensions/gsd/milestone-settlement.ts +81 -0
  374. package/src/resources/extensions/gsd/milestone-validation-evidence.ts +95 -0
  375. package/src/resources/extensions/gsd/milestone-validation-verdict.ts +80 -0
  376. package/src/resources/extensions/gsd/model-cost-table.ts +1 -0
  377. package/src/resources/extensions/gsd/model-router.ts +3 -0
  378. package/src/resources/extensions/gsd/parallel-eligibility.ts +4 -5
  379. package/src/resources/extensions/gsd/parallel-merge.ts +12 -9
  380. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +6 -5
  381. package/src/resources/extensions/gsd/parallel-orchestrator.ts +6 -2
  382. package/src/resources/extensions/gsd/paths.ts +9 -22
  383. package/src/resources/extensions/gsd/preferences-diagnostics.ts +98 -0
  384. package/src/resources/extensions/gsd/preferences-types.ts +16 -0
  385. package/src/resources/extensions/gsd/preferences.ts +191 -28
  386. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -0
  387. package/src/resources/extensions/gsd/prompts/execute-task.md +2 -0
  388. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +3 -1
  389. package/src/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
  390. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -0
  391. package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -0
  392. package/src/resources/extensions/gsd/prompts/system.md +1 -1
  393. package/src/resources/extensions/gsd/provider-payload-policy.ts +140 -0
  394. package/src/resources/extensions/gsd/pull-request-process.ts +41 -0
  395. package/src/resources/extensions/gsd/quality-gate-closure.ts +140 -0
  396. package/src/resources/extensions/gsd/question-transport.ts +138 -0
  397. package/src/resources/extensions/gsd/recovery-classification.ts +14 -1
  398. package/src/resources/extensions/gsd/roadmap-slices.ts +8 -2
  399. package/src/resources/extensions/gsd/safety/evidence-collector.ts +36 -4
  400. package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +7 -2
  401. package/src/resources/extensions/gsd/safety/file-change-validator.ts +14 -0
  402. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +6 -2
  403. package/src/resources/extensions/gsd/state-transition-matrix.ts +42 -0
  404. package/src/resources/extensions/gsd/state.ts +15 -5
  405. package/src/resources/extensions/gsd/status-guards.ts +59 -8
  406. package/src/resources/extensions/gsd/templates/plan.md +7 -0
  407. package/src/resources/extensions/gsd/templates/project.md +1 -0
  408. package/src/resources/extensions/gsd/templates/roadmap.md +1 -1
  409. package/src/resources/extensions/gsd/templates/uat.md +5 -1
  410. package/src/resources/extensions/gsd/tests/ask-user-questions-render.test.ts +92 -0
  411. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +29 -1
  412. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +444 -5
  413. package/src/resources/extensions/gsd/tests/auto-milestone-target.test.ts +23 -0
  414. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +18 -0
  415. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +133 -4
  416. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +3 -1
  417. package/src/resources/extensions/gsd/tests/auto-post-unit-evidence-crossref-4909.test.ts +46 -0
  418. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +34 -0
  419. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +2 -2
  420. package/src/resources/extensions/gsd/tests/auto-worktree-repair.test.ts +4 -2
  421. package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +20 -0
  422. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +22 -0
  423. package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
  424. package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +11 -0
  425. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +38 -1
  426. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +34 -3
  427. package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +88 -0
  428. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +18 -0
  429. package/src/resources/extensions/gsd/tests/evidence-xref-gsd-exec.test.ts +157 -0
  430. package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +1 -0
  431. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +33 -1
  432. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +1 -5
  433. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +1 -5
  434. package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +48 -1
  435. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +5 -4
  436. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +1 -1
  437. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +3 -2
  438. package/src/resources/extensions/gsd/tests/mcp-tool-name.test.ts +34 -0
  439. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +143 -1
  440. package/src/resources/extensions/gsd/tests/milestone-closeout-proof.test.ts +99 -0
  441. package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +25 -0
  442. package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +46 -0
  443. package/src/resources/extensions/gsd/tests/milestone-readiness.test.ts +65 -0
  444. package/src/resources/extensions/gsd/tests/milestone-validation-evidence.test.ts +41 -0
  445. package/src/resources/extensions/gsd/tests/milestone-validation-verdict.test.ts +55 -0
  446. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +45 -0
  447. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
  448. package/src/resources/extensions/gsd/tests/planning-crossval.test.ts +45 -0
  449. package/src/resources/extensions/gsd/tests/preferences-diagnostics.test.ts +67 -0
  450. package/src/resources/extensions/gsd/tests/preferences.test.ts +183 -0
  451. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +46 -0
  452. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +9 -0
  453. package/src/resources/extensions/gsd/tests/provider-payload-policy.test.ts +165 -0
  454. package/src/resources/extensions/gsd/tests/pull-request-process.test.ts +47 -0
  455. package/src/resources/extensions/gsd/tests/recovery-classification-illegal-transition.test.ts +30 -0
  456. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +185 -1
  457. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +40 -0
  458. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +25 -1
  459. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +38 -0
  460. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +80 -0
  461. package/src/resources/extensions/gsd/tests/session-switch-clears-pending-autostart.test.ts +108 -0
  462. package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +144 -7
  463. package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +27 -0
  464. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +2 -1
  465. package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +36 -0
  466. package/src/resources/extensions/gsd/tests/status-guards.test.ts +38 -0
  467. package/src/resources/extensions/gsd/tests/tool-availability-audit.test.ts +35 -0
  468. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +35 -42
  469. package/src/resources/extensions/gsd/tests/uat-policy.test.ts +23 -0
  470. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +47 -0
  471. package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +86 -1
  472. package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +39 -0
  473. package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +150 -0
  474. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +126 -9
  475. package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +15 -0
  476. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +41 -4
  477. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +43 -1
  478. package/src/resources/extensions/gsd/tests/worktree-placement.test.ts +113 -0
  479. package/src/resources/extensions/gsd/tests/worktree-projection-writers.test.ts +1 -1
  480. package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +1 -1
  481. package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +3 -1
  482. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +12 -6
  483. package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +2 -2
  484. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +22 -0
  485. package/src/resources/extensions/gsd/tests/write-gate.test.ts +121 -0
  486. package/src/resources/extensions/gsd/tool-contract.ts +86 -8
  487. package/src/resources/extensions/gsd/tool-presentation-plan.ts +16 -33
  488. package/src/resources/extensions/gsd/tool-surface-snapshot.ts +47 -0
  489. package/src/resources/extensions/gsd/tools/complete-slice.ts +23 -58
  490. package/src/resources/extensions/gsd/tools/exec-tool.ts +5 -5
  491. package/src/resources/extensions/gsd/tools/plan-milestone.ts +19 -160
  492. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +43 -0
  493. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +11 -38
  494. package/src/resources/extensions/gsd/tools/reopen-slice.ts +14 -42
  495. package/src/resources/extensions/gsd/tools/skip-slice.ts +18 -44
  496. package/src/resources/extensions/gsd/tools/validate-milestone.ts +25 -84
  497. package/src/resources/extensions/gsd/uat-policy.ts +19 -10
  498. package/src/resources/extensions/gsd/uat-run.ts +10 -14
  499. package/src/resources/extensions/gsd/undo.ts +9 -8
  500. package/src/resources/extensions/gsd/unit-context-composer.ts +85 -20
  501. package/src/resources/extensions/gsd/unit-runtime.ts +3 -2
  502. package/src/resources/extensions/gsd/unit-tool-contracts.ts +2 -1
  503. package/src/resources/extensions/gsd/user-input-boundary.ts +18 -0
  504. package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
  505. package/src/resources/extensions/gsd/web-app-uat.ts +101 -0
  506. package/src/resources/extensions/gsd/workflow-mcp.ts +22 -110
  507. package/src/resources/extensions/gsd/workflow-reconcile.ts +3 -3
  508. package/src/resources/extensions/gsd/workflow-tool-surface.ts +73 -0
  509. package/src/resources/extensions/gsd/workspace-git-guard.ts +1 -0
  510. package/src/resources/extensions/gsd/worktree-git-recovery.ts +308 -0
  511. package/src/resources/extensions/gsd/worktree-lifecycle.ts +17 -17
  512. package/src/resources/extensions/gsd/worktree-manager.ts +47 -28
  513. package/src/resources/extensions/gsd/worktree-placement.ts +63 -0
  514. package/src/resources/extensions/gsd/worktree-reentry.ts +10 -7
  515. package/src/resources/extensions/gsd/worktree-root.ts +17 -6
  516. package/src/resources/extensions/gsd/worktree-safety.ts +8 -5
  517. package/src/resources/extensions/gsd/worktree-session-state.ts +12 -10
  518. package/src/resources/extensions/gsd/worktree-state-projection.ts +55 -7
  519. package/src/resources/extensions/gsd/worktree-telemetry.ts +16 -0
  520. package/src/resources/extensions/shared/interview-ui.ts +15 -2
  521. package/src/resources/shared/claude-runtime-floor.ts +248 -0
  522. package/src/resources/skills/gsd-browser/SKILL.md +1 -1
  523. package/dist/web/standalone/.next/static/chunks/2659.feb6499ca863ebfc.js +0 -1
  524. package/dist/web/standalone/.next/static/chunks/2772.151789db0edea835.js +0 -1
  525. package/dist/web/standalone/.next/static/chunks/4283.10a065467b5340d8.js +0 -2
  526. package/dist/web/standalone/.next/static/chunks/5826.960dc4634cc9b0d3.js +0 -1
  527. package/dist/web/standalone/.next/static/chunks/796.46f811c0fac23aab.js +0 -10
  528. package/dist/web/standalone/.next/static/chunks/8785.d32f7a61f55c1600.js +0 -1
  529. /package/dist/web/standalone/.next/static/{Qbr81pQ-pbQXP4bq2VXLv → C24pqUd-aru-l0Dp0gLZP}/_buildManifest.js +0 -0
  530. /package/dist/web/standalone/.next/static/{Qbr81pQ-pbQXP4bq2VXLv → C24pqUd-aru-l0Dp0gLZP}/_ssgManifest.js +0 -0
@@ -0,0 +1,275 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Recover guided-unit completion signals that did not produce expected tool/file evidence.
3
+
4
+ import { existsSync } from "node:fs";
5
+ import { join } from "node:path";
6
+ import {
7
+ clearPathCache,
8
+ relMilestoneFile,
9
+ resolveMilestoneFile,
10
+ resolveMilestonePath,
11
+ } from "./paths.js";
12
+ import {
13
+ _getPendingAutoStart,
14
+ deletePendingAutoStart,
15
+ hasPendingAutoStart,
16
+ } from "./pending-auto-start.js";
17
+ import { logWarning } from "./workflow-logger.js";
18
+
19
+ // #4573: cap for how many times we nudge the LLM after a premature ready
20
+ // phrase before giving up and asking the user to re-run /gsd.
21
+ const MAX_READY_REJECTS = 2;
22
+
23
+ // #4573: matches the canonical ready phrase the discuss prompt asks the LLM
24
+ // to emit. Accepts any M-prefixed milestone ID (three digits + optional
25
+ // suffix) with optional trailing punctuation.
26
+ const READY_PHRASE_RE = /\bMilestone\s+M\d{3}[A-Z0-9-]*\s+ready\.?/i;
27
+
28
+ const emptyTurnCounterByBase = new Map<string, number>();
29
+ const MAX_EMPTY_TURN_RETRIES = 2;
30
+
31
+ // Phrases that indicate the LLM is about to do something but has not yet.
32
+ // Kept tight to avoid flagging legitimate narration like "I'll wait for your answer."
33
+ //
34
+ // "make" was previously in the verb list but matches conversational meta phrases
35
+ // like "Let me make sure I understand…" which are NOT action announcements —
36
+ // removed to prevent the empty-turn nudge from auto-replying to user questions
37
+ // in discuss flows.
38
+ const COMMIT_INTENT_RE =
39
+ /\b(?:I['’]ll|I will|Next,? I['’]ll|Now I['’]ll|Let me|I['’]m going to|I am going to)\s+(?:now\s+)?(?:write|create|call|invoke|update|add|run|execute|generate|produce|emit|compose|implement|save|apply|commit)\b/i;
40
+
41
+ /**
42
+ * Extract the concatenated text content from an assistant message, whether it
43
+ * stores content as a string or as an array of text blocks.
44
+ */
45
+ function extractAssistantText(msg: any): string {
46
+ if (!msg) return "";
47
+ const content = msg.content;
48
+ if (typeof content === "string") return content;
49
+ if (!Array.isArray(content)) return "";
50
+ const parts: string[] = [];
51
+ for (const block of content) {
52
+ if (!block || typeof block !== "object") continue;
53
+ if (block.type === "text" && typeof block.text === "string") parts.push(block.text);
54
+ }
55
+ return parts.join("\n");
56
+ }
57
+
58
+ /**
59
+ * Return true if the assistant message contains any tool-use block.
60
+ *
61
+ * The canonical pi-ai `AssistantMessage.content` (see packages/pi-ai/src/types.ts)
62
+ * uses `type: "toolCall"` and `type: "serverToolUse"` for tool invocations —
63
+ * every provider (anthropic-direct, claude-code-cli, openai, etc.) normalizes
64
+ * incoming tool blocks into these two shapes before they reach guided-flow.
65
+ *
66
+ * The Anthropic API wire shape `"tool_use"` / `"server_tool_use"` does NOT appear
67
+ * in the internal AssistantMessage — those literals are only used when sending
68
+ * messages back out to the Anthropic API. Matching them here was a latent bug:
69
+ * `hasToolUse` returned `false` for every real tool call, which let the
70
+ * empty-turn nudge fire and pre-empt MCP tools that block on the user
71
+ * (e.g. `ask_user_questions`). See investigation in PR for #4658.
72
+ */
73
+ function hasToolUse(msg: any): boolean {
74
+ if (!msg) return false;
75
+ const content = msg.content;
76
+ if (!Array.isArray(content)) return false;
77
+ return content.some(
78
+ (b: any) =>
79
+ b &&
80
+ typeof b === "object" &&
81
+ (b.type === "toolCall" || b.type === "serverToolUse"),
82
+ );
83
+ }
84
+
85
+ /**
86
+ * #4573 — Detect and recover from the "ready phrase without files" failure mode.
87
+ *
88
+ * When the LLM emits "Milestone {{id}} ready." but has not written the
89
+ * milestone CONTEXT/ROADMAP artifacts, `checkAutoStartAfterDiscuss()` silently
90
+ * returns false and the next /gsd invocation loops into the "All milestones
91
+ * complete" warning.
92
+ *
93
+ * This function, called from `handleAgentEnd` after `checkAutoStartAfterDiscuss`
94
+ * returns false, pattern-matches the ready phrase on the last assistant message.
95
+ * If it fired AND neither the canonical M###-CONTEXT.md/M###-ROADMAP.md nor
96
+ * legacy CONTEXT.md/ROADMAP.md files exist, it:
97
+ * 1. Notifies the user that the signal was rejected.
98
+ * 2. Injects a system message via `pi.sendMessage(..., {triggerTurn:true})`
99
+ * telling the LLM the signal was premature and to emit the writes now.
100
+ * 3. Caps at `MAX_READY_REJECTS` per-entry; beyond that, gives up and asks
101
+ * the user to re-run /gsd.
102
+ *
103
+ * Returns true when a nudge (or give-up) was emitted, signaling the caller to
104
+ * skip `resolveAgentEnd`.
105
+ */
106
+ export function maybeHandleReadyPhraseWithoutFiles(
107
+ event: { messages: any[] },
108
+ lookupBasePath?: string,
109
+ ): boolean {
110
+ const entry = _getPendingAutoStart(lookupBasePath);
111
+ if (!entry) return false;
112
+ const { ctx, pi, basePath, milestoneId } = entry;
113
+
114
+ // Gate: last assistant message must contain the ready phrase
115
+ const lastMsg = event.messages[event.messages.length - 1];
116
+ const text = extractAssistantText(lastMsg);
117
+ if (!READY_PHRASE_RE.test(text)) return false;
118
+
119
+ // Bust paths.ts cached dir listings before checking for fresh writes. The
120
+ // LLM's Write tool calls do not invalidate paths.ts caches, so a stale
121
+ // listing taken before the milestone dir or its CONTEXT/ROADMAP files
122
+ // existed would falsely report the artifacts as missing and trigger the
123
+ // 3-strike "ready without files" abort even though the writes succeeded.
124
+ clearPathCache();
125
+
126
+ // Gate: artifacts must still be missing — if they exist, the happy path
127
+ // already fired and we have nothing to do.
128
+ const contextFile = resolveMilestoneFile(basePath, milestoneId, "CONTEXT");
129
+ const roadmapFile = resolveMilestoneFile(basePath, milestoneId, "ROADMAP");
130
+ if (contextFile || roadmapFile) return false;
131
+
132
+ // Diagnostic: when the cached resolver reports both files missing, also probe
133
+ // the canonical paths with uncached existsSync so we can tell whether the
134
+ // recovery is firing on real-missing files or a path-resolution miss
135
+ // (basePath/symlink mismatch, stale cache despite agent-end-recovery flush,
136
+ // legacy descriptor dir not matching, etc.).
137
+ try {
138
+ const mDir = resolveMilestonePath(basePath, milestoneId);
139
+ const canonicalCtx = mDir ? join(mDir, `${milestoneId}-CONTEXT.md`) : null;
140
+ const canonicalRoadmap = mDir ? join(mDir, `${milestoneId}-ROADMAP.md`) : null;
141
+ logWarning(
142
+ "guided",
143
+ `ready-phrase-reject diagnostic mid=${milestoneId} basePath=${basePath} ` +
144
+ `mDir=${mDir ?? "null"} ` +
145
+ `canonical-ctx=${canonicalCtx ?? "null"} ctx-exists=${canonicalCtx ? existsSync(canonicalCtx) : "n/a"} ` +
146
+ `canonical-roadmap=${canonicalRoadmap ?? "null"} roadmap-exists=${canonicalRoadmap ? existsSync(canonicalRoadmap) : "n/a"}`,
147
+ );
148
+ } catch (e) {
149
+ logWarning("guided", `ready-phrase-reject diagnostic failed: ${(e as Error).message}`);
150
+ }
151
+
152
+ entry.readyRejectCount = (entry.readyRejectCount ?? 0) + 1;
153
+
154
+ if (entry.readyRejectCount > MAX_READY_REJECTS) {
155
+ // Give up: clear state and tell the user to re-run /gsd. Avoids an
156
+ // infinite nudge loop when the LLM never produces the writes.
157
+ deletePendingAutoStart(basePath);
158
+ ctx.ui.notify(
159
+ `Milestone ${milestoneId}: LLM signaled "ready" ${entry.readyRejectCount} times without writing files. ` +
160
+ `Stopping auto-nudge. Run /gsd to try again.`,
161
+ "error",
162
+ );
163
+ return true;
164
+ }
165
+
166
+ const contextRel = relMilestoneFile(basePath, milestoneId, "CONTEXT");
167
+ const roadmapRel = relMilestoneFile(basePath, milestoneId, "ROADMAP");
168
+ ctx.ui.notify(
169
+ `Milestone ${milestoneId}: "ready" signal rejected — ${contextRel} and ${roadmapRel} are missing. Asking the LLM to complete the writes.`,
170
+ "warning",
171
+ );
172
+
173
+ const nudge =
174
+ `You emitted "Milestone ${milestoneId} ready." but neither ` +
175
+ `${contextRel} nor ${roadmapRel} exists on disk. ` +
176
+ `The ready phrase is a POST-WRITE signal and has been rejected. ` +
177
+ `In this turn: (1) write PROJECT.md, REQUIREMENTS.md, and the milestone ` +
178
+ `CONTEXT.md, (2) call gsd_plan_milestone, then (3) emit the ready phrase. ` +
179
+ `Do not describe these steps — execute them as tool calls. ` +
180
+ `This is retry ${entry.readyRejectCount}/${MAX_READY_REJECTS}; further ` +
181
+ `premature signals will clear the session.`;
182
+
183
+ try {
184
+ pi.sendMessage(
185
+ { customType: "gsd-ready-no-files", content: nudge, display: false },
186
+ { triggerTurn: true },
187
+ );
188
+ } catch (e) {
189
+ logWarning("guided", `ready-phrase nudge sendMessage failed: ${(e as Error).message}`);
190
+ return false;
191
+ }
192
+ return true;
193
+ }
194
+
195
+ /**
196
+ * Reset the empty-turn counter for a basePath after a successful tool-use turn.
197
+ * Called from handleAgentEnd when the last message contains tool_use blocks.
198
+ */
199
+ export function resetEmptyTurnCounter(basePath?: string): void {
200
+ if (basePath) emptyTurnCounterByBase.delete(basePath);
201
+ else emptyTurnCounterByBase.clear();
202
+ }
203
+
204
+ export function maybeHandleEmptyIntentTurn(
205
+ event: { messages: any[] },
206
+ isAuto: boolean,
207
+ lookupBasePath?: string,
208
+ ): boolean {
209
+ // Gate: only fire when there is system-driven work in flight. Interactive
210
+ // /gsd discuss (user-driven) produces legitimate text-only turns.
211
+ if (!isAuto && !hasPendingAutoStart(lookupBasePath)) return false;
212
+
213
+ const lastMsg = event.messages[event.messages.length - 1];
214
+ if (!lastMsg) return false;
215
+ if (hasToolUse(lastMsg)) return false;
216
+
217
+ const text = extractAssistantText(lastMsg).trim();
218
+ if (!text) return false;
219
+
220
+ // Skip if the LLM is emitting the ready phrase — that is the ready-no-files
221
+ // path, handled by maybeHandleReadyPhraseWithoutFiles.
222
+ if (READY_PHRASE_RE.test(text)) return false;
223
+
224
+ // Skip if the LLM is clearly handing back to the user. Discuss flows
225
+ // often pose a question and follow it with a conditional intent on the
226
+ // same line ("Did I capture that correctly? If so, I'll write the
227
+ // requirements."). A line-trailing `?` check misses these because the
228
+ // line ends in `.`. Match any sentence-terminating `?` (followed by
229
+ // whitespace or end-of-text) — false negatives here auto-reply to the
230
+ // user, which is a much worse failure mode than a missed nudge.
231
+ if (/\?(?:\s|$)/.test(text)) return false;
232
+
233
+ // Must contain a commit-intent phrase — this is the stall we care about.
234
+ if (!COMMIT_INTENT_RE.test(text)) return false;
235
+
236
+ // Resolve the target basePath + pi for injection. Prefer the pending
237
+ // autostart entry (discuss flow); otherwise we cannot inject.
238
+ const entry = _getPendingAutoStart(lookupBasePath);
239
+ if (!entry) return false;
240
+ const { ctx, pi, basePath } = entry;
241
+
242
+ const count = (emptyTurnCounterByBase.get(basePath) ?? 0) + 1;
243
+ emptyTurnCounterByBase.set(basePath, count);
244
+
245
+ if (count > MAX_EMPTY_TURN_RETRIES) {
246
+ ctx.ui.notify(
247
+ `Empty-turn recovery: LLM announced intent ${count} times without calling any tool. ` +
248
+ `Stopping auto-nudge.`,
249
+ "error",
250
+ );
251
+ return false; // let the normal flow resolve/pause the unit
252
+ }
253
+
254
+ ctx.ui.notify(
255
+ `Empty-turn detected: LLM announced intent but called no tool. Prompting it to execute.`,
256
+ "info",
257
+ );
258
+
259
+ const nudge =
260
+ `Your last turn announced an action (e.g. "I'll write…" or "Let me call…") ` +
261
+ `but contained no tool call. The system records zero tool-use blocks for ` +
262
+ `that turn. Execute the announced action NOW as a tool call in this turn. ` +
263
+ `Do not describe it again. Retry ${count}/${MAX_EMPTY_TURN_RETRIES}.`;
264
+
265
+ try {
266
+ pi.sendMessage(
267
+ { customType: "gsd-empty-turn-recovery", content: nudge, display: false },
268
+ { triggerTurn: true },
269
+ );
270
+ } catch (e) {
271
+ logWarning("guided", `empty-turn nudge sendMessage failed: ${(e as Error).message}`);
272
+ return false;
273
+ }
274
+ return true;
275
+ }
@@ -171,7 +171,8 @@ function renderRoadmapMarkdown(milestone: MilestoneRow, slices: SliceRow[]): str
171
171
  lines.push("");
172
172
  for (const slice of slices) {
173
173
  const done = isClosedStatus(slice.status) ? "x" : " ";
174
- const depends = `[${(slice.depends ?? []).join(",")}]`;
174
+ const cleanDepends = (slice.depends ?? []).map(d => d.replace(/^\[|\]$/g, '')).filter(d => /^[A-Za-z0-9][A-Za-z0-9-]*$/.test(d));
175
+ const depends = `[${cleanDepends.join(",")}]`;
175
176
  const safeTitle = sanitizeInlineRoadmapText(slice.title || slice.id) || slice.id;
176
177
  const safeRisk = normalizeRiskLevel(slice.risk);
177
178
  // ADR-011: sketch slices get a `[sketch]` badge so the roadmap shows at a
@@ -3,6 +3,7 @@ import { homedir } from "node:os";
3
3
  import { resolve } from "node:path";
4
4
 
5
5
  import type { ClaudeCodeMcpConfig } from "./preferences-types.js";
6
+ import { toMcpWildcardToolName } from "./mcp-tool-name.js";
6
7
  import { resolveModelMcpConfig } from "./preferences-mcp.js";
7
8
 
8
9
  interface McpJsonFile {
@@ -159,5 +160,5 @@ export function computeMcpDisallowedTools(
159
160
  blocked.delete(workflowServerName);
160
161
  }
161
162
 
162
- return [...blocked].map((name) => `mcp__${name}__*`);
163
+ return [...blocked].map(toMcpWildcardToolName);
163
164
  }
@@ -0,0 +1,35 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Shared parsing and formatting helpers for MCP-scoped tool names.
3
+
4
+ const MCP_TOOL_PREFIX = "mcp__";
5
+
6
+ export interface ParsedMcpToolName {
7
+ serverName: string;
8
+ toolName: string;
9
+ }
10
+
11
+ export function parseMcpToolName(toolName: string): ParsedMcpToolName | null {
12
+ if (!toolName.startsWith(MCP_TOOL_PREFIX)) return null;
13
+ const toolSeparator = toolName.indexOf("__", MCP_TOOL_PREFIX.length);
14
+ if (toolSeparator < 0) return null;
15
+ return {
16
+ serverName: toolName.slice(MCP_TOOL_PREFIX.length, toolSeparator),
17
+ toolName: toolName.slice(toolSeparator + 2),
18
+ };
19
+ }
20
+
21
+ export function stripMcpToolPrefix(toolName: string): string {
22
+ return parseMcpToolName(toolName)?.toolName ?? toolName;
23
+ }
24
+
25
+ export function toMcpToolName(serverName: string, toolName: string): string {
26
+ return `${MCP_TOOL_PREFIX}${serverName}__${toolName}`;
27
+ }
28
+
29
+ export function toMcpWildcardToolName(serverName: string): string {
30
+ return toMcpToolName(serverName, "*");
31
+ }
32
+
33
+ export function mcpToolMatchesBaseName(toolName: string, baseName: string): boolean {
34
+ return parseMcpToolName(toolName)?.toolName === baseName;
35
+ }
@@ -14,12 +14,12 @@ import {
14
14
  insertMilestone,
15
15
  insertSlice,
16
16
  insertTask,
17
- openDatabase,
18
17
  transaction,
19
18
  updateMilestoneStatus,
20
19
  updateSliceStatus,
21
20
  _getAdapter,
22
21
  } from './gsd-db.js';
22
+ import { openWorkflowDatabasePath } from './db-workspace.js';
23
23
  import {
24
24
  resolveGsdRootFile,
25
25
  resolveMilestoneFile,
@@ -641,7 +641,7 @@ export function migrateHierarchyToDb(basePath: string): {
641
641
  title: sliceEntry.title,
642
642
  status: sliceStatus,
643
643
  risk: sliceEntry.risk,
644
- depends: sliceEntry.depends,
644
+ depends: (sliceEntry.depends ?? []).map(d => d.replace(/^\[|\]$/g, '')).filter(d => /^[A-Za-z0-9][A-Za-z0-9-]*$/.test(d)),
645
645
  demo: sliceEntry.demo,
646
646
  sequence: si + 1, // Preserve roadmap parse order (#3356)
647
647
  isSketch: sliceEntry.isSketch ?? false, // ADR-011: preserve the `[sketch]` flag on re-import
@@ -753,7 +753,7 @@ export function migrateFromMarkdown(gsdDir: string): {
753
753
 
754
754
  // Open DB if not already open
755
755
  if (!_getAdapter()) {
756
- openDatabase(dbPath);
756
+ openWorkflowDatabasePath(dbPath);
757
757
  }
758
758
 
759
759
  let decisions = 0;
@@ -7,7 +7,7 @@ import { homedir } from "node:os";
7
7
 
8
8
  import { ensureDbOpen } from "../bootstrap/dynamic-tools.js";
9
9
  import { readCrashLock, isLockProcessAlive } from "../crash-recovery.js";
10
- import { closeDatabase } from "../gsd-db.js";
10
+ import { closeWorkflowDatabase } from "../db-workspace.js";
11
11
  import { readPausedSessionMetadata } from "../interrupted-session.js";
12
12
  import { gsdRoot } from "../paths.js";
13
13
  import type { MigrationPreview } from "./writer.js";
@@ -106,14 +106,22 @@ export function assertMigrationHasSlices(preview: MigrationPreview): void {
106
106
  }
107
107
 
108
108
  function hasWorktreeState(targetRoot: string): boolean {
109
- const worktreesDir = join(gsdRoot(targetRoot), "worktrees");
110
- if (!existsSync(worktreesDir)) return false;
111
- try {
112
- return readdirSync(worktreesDir, { withFileTypes: true })
113
- .some((entry) => entry.isDirectory() || entry.isFile());
114
- } catch {
115
- return true;
109
+ const containers = [
110
+ join(targetRoot, ".gsd-worktrees"),
111
+ join(gsdRoot(targetRoot), "worktrees"),
112
+ ];
113
+ for (const worktreesDir of containers) {
114
+ if (!existsSync(worktreesDir)) continue;
115
+ try {
116
+ if (readdirSync(worktreesDir, { withFileTypes: true })
117
+ .some((entry) => entry.isDirectory() || entry.isFile())) {
118
+ return true;
119
+ }
120
+ } catch {
121
+ return true;
122
+ }
116
123
  }
124
+ return false;
117
125
  }
118
126
 
119
127
  export async function assertMigrationTargetAvailable(targetRoot: string): Promise<void> {
@@ -144,6 +152,6 @@ export async function assertMigrationTargetAvailable(targetRoot: string): Promis
144
152
  );
145
153
  }
146
154
  } finally {
147
- closeDatabase();
155
+ closeWorkflowDatabase();
148
156
  }
149
157
  }
@@ -6,8 +6,8 @@ import {
6
6
  getMilestoneSlices,
7
7
  getSliceTasks,
8
8
  isDbAvailable,
9
- refreshOpenDatabaseFromDisk,
10
9
  } from "./gsd-db.js";
10
+ import { refreshWorkflowDatabaseFromDisk } from "./db-workspace.js";
11
11
  import { parsePlan, parseRoadmap } from "./parsers-legacy.js";
12
12
  import {
13
13
  milestonesDir,
@@ -39,6 +39,9 @@ interface HierarchyScan {
39
39
  milestones: Set<string>;
40
40
  slices: Set<string>;
41
41
  tasks: Set<string>;
42
+ // Markdown milestones whose dir has no ROADMAP (CONTEXT/CONTEXT-DRAFT only
43
+ // or empty). Always empty for DB scans.
44
+ milestonesWithoutRoadmap: Set<string>;
42
45
  }
43
46
 
44
47
  function zeroCounts(): HierarchyCounts {
@@ -46,7 +49,13 @@ function zeroCounts(): HierarchyCounts {
46
49
  }
47
50
 
48
51
  function emptyScan(): HierarchyScan {
49
- return { counts: zeroCounts(), milestones: new Set(), slices: new Set(), tasks: new Set() };
52
+ return {
53
+ counts: zeroCounts(),
54
+ milestones: new Set(),
55
+ slices: new Set(),
56
+ tasks: new Set(),
57
+ milestonesWithoutRoadmap: new Set(),
58
+ };
50
59
  }
51
60
 
52
61
  function sameCounts(a: HierarchyCounts, b: HierarchyCounts): boolean {
@@ -109,7 +118,10 @@ export function scanMarkdownHierarchy(basePath: string): HierarchyScan {
109
118
  scan.milestones.add(milestoneId);
110
119
 
111
120
  const roadmapPath = resolveMilestoneFile(basePath, milestoneId, "ROADMAP");
112
- if (!roadmapPath || !existsSync(roadmapPath)) continue;
121
+ if (!roadmapPath || !existsSync(roadmapPath)) {
122
+ scan.milestonesWithoutRoadmap.add(milestoneId);
123
+ continue;
124
+ }
113
125
 
114
126
  const roadmap = parseRoadmap(readFileSync(roadmapPath, "utf-8"));
115
127
  scan.counts.slices += roadmap.slices.length;
@@ -164,7 +176,6 @@ export async function checkMarkdownHierarchyAgainstDb(
164
176
  basePath: string,
165
177
  ): Promise<MigrationAutoCheckResult> {
166
178
  const markdownScan = scanMarkdownHierarchy(basePath);
167
- const markdown = markdownScan.counts;
168
179
 
169
180
  // Always open the DB before deciding. An empty markdown tree does NOT imply
170
181
  // an empty project — the DB may hold authoritative rows whose markdown was
@@ -179,11 +190,25 @@ export async function checkMarkdownHierarchyAgainstDb(
179
190
  // The markdown projections may have just been written by a workflow/MCP
180
191
  // server in another process. Reopen before comparing so startup does not
181
192
  // warn from a stale long-lived SQLite handle.
182
- refreshOpenDatabaseFromDisk();
193
+ refreshWorkflowDatabaseFromDisk();
183
194
 
184
195
  const dbScan = scanDbHierarchy();
185
196
  const beforeDb = dbScan.counts;
186
197
 
198
+ // Discussion-phase scratch: a milestone dir with no ROADMAP and no DB row is
199
+ // a pre-registration discussion artifact (CONTEXT/CONTEXT-DRAFT only — the
200
+ // queued DB row is inserted only at discussion handoff). Treating it as
201
+ // drift would warn on every live discussion and recommend
202
+ // `/gsd recover --confirm`, an import that materializes abandoned-discussion
203
+ // dirs as ghost active milestones. Exclude such dirs from this comparison
204
+ // only; recover preflights use the raw scans and still see them.
205
+ for (const id of markdownScan.milestonesWithoutRoadmap) {
206
+ if (dbScan.milestones.has(id)) continue;
207
+ markdownScan.milestones.delete(id);
208
+ markdownScan.counts.milestones--;
209
+ }
210
+ const markdown = markdownScan.counts;
211
+
187
212
  const markdownEmpty = sameCounts(markdown, zeroCounts());
188
213
  const dbEmpty = sameCounts(beforeDb, zeroCounts());
189
214
 
@@ -0,0 +1,131 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Single proof surface for milestone closeout readiness/finality.
3
+
4
+ import { existsSync, readFileSync } from "node:fs";
5
+
6
+ import {
7
+ CLOSEOUT_CONSISTENCY_BLOCKED_REASON,
8
+ checkCloseoutConsistencyGate,
9
+ type CloseoutConsistencyFailureReason,
10
+ type CloseoutConsistencyResult,
11
+ } from "./closeout-consistency-gate.js";
12
+ import { resolveExpectedArtifactPath } from "./auto-artifact-paths.js";
13
+ import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.js";
14
+ import { hasImplementationArtifacts } from "./milestone-implementation-evidence.js";
15
+
16
+ export type CloseoutProofFailureReason =
17
+ | CloseoutConsistencyFailureReason
18
+ | "summary-artifact-missing"
19
+ | "summary-artifact-failed"
20
+ | "implementation-evidence-missing";
21
+
22
+ export type ImplementationEvidenceRequirement = "present" | "not-absent";
23
+
24
+ export type CloseoutProofResult =
25
+ | { ok: true }
26
+ | {
27
+ ok: false;
28
+ reason: CloseoutProofFailureReason;
29
+ recoveryReason: typeof CLOSEOUT_CONSISTENCY_BLOCKED_REASON;
30
+ message: string;
31
+ };
32
+
33
+ export interface CloseoutProofOptions {
34
+ refreshFromDisk?: boolean;
35
+ allowOpenMilestone?: boolean;
36
+ summaryArtifactBasePath?: string;
37
+ implementationEvidence?: {
38
+ basePath: string;
39
+ requirement: ImplementationEvidenceRequirement;
40
+ };
41
+ }
42
+
43
+ function blocked(reason: CloseoutProofFailureReason, message: string): CloseoutProofResult {
44
+ return {
45
+ ok: false,
46
+ reason,
47
+ recoveryReason: CLOSEOUT_CONSISTENCY_BLOCKED_REASON,
48
+ message,
49
+ };
50
+ }
51
+
52
+ function fromConsistencyResult(result: CloseoutConsistencyResult): CloseoutProofResult {
53
+ if (result.ok) return result;
54
+ return {
55
+ ok: false,
56
+ reason: result.reason,
57
+ recoveryReason: result.recoveryReason,
58
+ message: result.message,
59
+ };
60
+ }
61
+
62
+ function checkSummaryArtifact(milestoneId: string, basePath: string): CloseoutProofResult {
63
+ const summaryPath = resolveExpectedArtifactPath("complete-milestone", milestoneId, basePath);
64
+ if (!summaryPath || !existsSync(summaryPath)) {
65
+ return blocked(
66
+ "summary-artifact-missing",
67
+ `Closeout proof blocked for ${milestoneId}: milestone summary artifact is missing.`,
68
+ );
69
+ }
70
+
71
+ const summaryOutcome = classifyMilestoneSummaryContent(readFileSync(summaryPath, "utf-8"));
72
+ if (summaryOutcome === "failure") {
73
+ return blocked(
74
+ "summary-artifact-failed",
75
+ `Closeout proof blocked for ${milestoneId}: milestone summary records failed closeout.`,
76
+ );
77
+ }
78
+
79
+ return { ok: true };
80
+ }
81
+
82
+ function checkImplementationEvidence(
83
+ milestoneId: string,
84
+ basePath: string,
85
+ requirement: ImplementationEvidenceRequirement,
86
+ ): CloseoutProofResult {
87
+ const evidence = hasImplementationArtifacts(basePath, milestoneId);
88
+ if (requirement === "present" && evidence === "present") return { ok: true };
89
+ if (requirement === "not-absent" && evidence !== "absent") return { ok: true };
90
+
91
+ return blocked(
92
+ "implementation-evidence-missing",
93
+ `Closeout proof blocked for ${milestoneId}: implementation evidence is ${evidence}.`,
94
+ );
95
+ }
96
+
97
+ export function proveMilestoneCloseout(
98
+ milestoneId: string,
99
+ options: CloseoutProofOptions = {},
100
+ ): CloseoutProofResult {
101
+ const consistency = checkCloseoutConsistencyGate(milestoneId, {
102
+ refreshFromDisk: options.refreshFromDisk,
103
+ allowOpenMilestone: options.allowOpenMilestone,
104
+ artifactBasePath: options.summaryArtifactBasePath,
105
+ });
106
+ if (!consistency.ok) return fromConsistencyResult(consistency);
107
+
108
+ if (options.summaryArtifactBasePath) {
109
+ const summary = checkSummaryArtifact(milestoneId, options.summaryArtifactBasePath);
110
+ if (!summary.ok) return summary;
111
+ }
112
+
113
+ if (options.implementationEvidence) {
114
+ const implementation = checkImplementationEvidence(
115
+ milestoneId,
116
+ options.implementationEvidence.basePath,
117
+ options.implementationEvidence.requirement,
118
+ );
119
+ if (!implementation.ok) return implementation;
120
+ }
121
+
122
+ return { ok: true };
123
+ }
124
+
125
+ export function formatCloseoutProofBlock(result: CloseoutProofResult): string {
126
+ if (result.ok) return "";
127
+ if (result.reason.startsWith("summary-") || result.reason.startsWith("implementation-")) {
128
+ return `${result.message} Recovery reason: ${result.recoveryReason}. Resolve the closeout evidence and run /gsd auto to retry.`;
129
+ }
130
+ return `${result.message} Recovery reason: ${result.recoveryReason}. Resolve the canonical DB state and run /gsd auto to retry.`;
131
+ }
@@ -10,13 +10,13 @@ import { parseRoadmap } from "./parsers-legacy.js";
10
10
  import { resolveMilestoneFile } from "./paths.js";
11
11
  import { getMilestone, getMilestoneSlices, isDbAvailable } from "./gsd-db.js";
12
12
  import { isClosedStatus } from "./status-guards.js";
13
- import { verifyExpectedArtifact } from "./auto-recovery.js";
14
13
  import { runSafely } from "./auto-utils.js";
15
14
  import { extractVerdict, isAcceptableUatVerdict } from "./verdict-parser.js";
16
15
  import { logWarning } from "./workflow-logger.js";
17
16
  import { hasImplementationArtifacts } from "./milestone-implementation-evidence.js";
18
17
  import { buildCompleteMilestonePrompt } from "./auto-prompts.js";
19
- import { checkCloseoutConsistencyGate } from "./closeout-consistency-gate.js";
18
+ import { proveMilestoneCloseout } from "./milestone-closeout-proof.js";
19
+ import { resolveCanonicalMilestoneRoot } from "./worktree-manager.js";
20
20
  import type { DispatchAction, DispatchContext } from "./auto-dispatch.js";
21
21
  import {
22
22
  commitPendingMilestoneCloseoutChanges,
@@ -38,8 +38,16 @@ export async function isMilestoneCloseoutSettled(mid: string, basePath: string):
38
38
  if (isDbAvailable()) {
39
39
  const milestone = getMilestone(mid);
40
40
  if (milestone && isClosedStatus(milestone.status)) {
41
- const closeoutGate = checkCloseoutConsistencyGate(mid, { refreshFromDisk: true });
42
- if (closeoutGate.ok && verifyExpectedArtifact("complete-milestone", mid, basePath)) {
41
+ const artifactBasePath = resolveCanonicalMilestoneRoot(basePath, mid);
42
+ const closeoutProof = proveMilestoneCloseout(mid, {
43
+ refreshFromDisk: true,
44
+ summaryArtifactBasePath: artifactBasePath,
45
+ implementationEvidence: {
46
+ basePath,
47
+ requirement: "not-absent",
48
+ },
49
+ });
50
+ if (closeoutProof.ok) {
43
51
  return true;
44
52
  }
45
53
  }