@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
@@ -201,6 +201,41 @@ export function attachExternalResultsToToolBlocks(
201
201
  }
202
202
  }
203
203
 
204
+ function textFromExternalResult(result: ExternalToolResultPayload | undefined): string {
205
+ return (result?.content ?? [])
206
+ .map((block) => typeof block.text === "string" ? block.text : "")
207
+ .join("\n");
208
+ }
209
+
210
+ function isEmptyToolArguments(value: unknown): boolean {
211
+ return !!value
212
+ && typeof value === "object"
213
+ && !Array.isArray(value)
214
+ && Object.keys(value as Record<string, unknown>).length === 0;
215
+ }
216
+
217
+ function sameToolSurface(a: ToolCall, b: ToolCall): boolean {
218
+ return a.name === b.name
219
+ && (a as ToolCall & { mcpServer?: string }).mcpServer === (b as ToolCall & { mcpServer?: string }).mcpServer;
220
+ }
221
+
222
+ export function shouldSuppressDuplicateToolUnavailableBlock(
223
+ block: AssistantMessage["content"][number],
224
+ allBlocks: AssistantMessage["content"],
225
+ ): boolean {
226
+ if (block.type !== "toolCall") return false;
227
+ const externalResult = (block as ToolCallWithExternalResult).externalResult;
228
+ if (!externalResult?.isError) return false;
229
+ if (!isEmptyToolArguments(block.arguments)) return false;
230
+ if (!/No such tool available:/i.test(textFromExternalResult(externalResult))) return false;
231
+
232
+ return allBlocks.some((candidate) => {
233
+ if (candidate.type !== "toolCall" || candidate.id === block.id) return false;
234
+ const candidateResult = (candidate as ToolCallWithExternalResult).externalResult;
235
+ return candidateResult?.isError === false && sameToolSurface(block, candidate);
236
+ });
237
+ }
238
+
204
239
  /**
205
240
  * Build the final assistant content that Agent Core consumes in
206
241
  * `externalToolExecution` mode. This preserves tool-call blocks, attaches any
@@ -221,7 +256,9 @@ export function buildFinalAssistantContent(params: {
221
256
  }
222
257
  attachExternalResultsToToolBlocks(mergedToolBlocks, params.toolResultsById);
223
258
 
224
- const finalContent: AssistantMessage["content"] = [...mergedToolBlocks];
259
+ const finalContent: AssistantMessage["content"] = mergedToolBlocks.filter(
260
+ (block) => !shouldSuppressDuplicateToolUnavailableBlock(block, mergedToolBlocks),
261
+ );
225
262
  if (params.pendingContent && params.pendingContent.length > 0) {
226
263
  for (const block of params.pendingContent) {
227
264
  if (block.type === "text" || block.type === "thinking") {
@@ -0,0 +1,309 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Auto-loop closeout, milestone report, and merge helpers.
3
+
4
+ import { importExtensionModule, type ExtensionAPI, type ExtensionContext } from "@gsd/pi-coding-agent";
5
+
6
+ import { join, basename } from "node:path";
7
+ import { existsSync, cpSync } from "node:fs";
8
+ import type { AutoSession } from "./session.js";
9
+ import type { LoopDeps } from "./loop-deps.js";
10
+ import type { GSDState } from "../types.js";
11
+ import type { IterationContext } from "./types.js";
12
+ import type { PostflightResult, PreflightResult } from "../clean-root-preflight.js";
13
+ import { MergeConflictError } from "../git-service.js";
14
+ import { findUnmergedCompletedMilestones } from "../unmerged-milestone-guard.js";
15
+ import { getIsolationMode } from "../preferences.js";
16
+ import { isDbAvailable, getMilestone } from "../gsd-db.js";
17
+ import { refreshWorkflowDatabaseFromDisk } from "../db-workspace.js";
18
+ import { isClosedStatus } from "../status-guards.js";
19
+ import { gsdRoot } from "../paths.js";
20
+ import { atomicWriteSync } from "../atomic-write.js";
21
+ import { logWarning, logError } from "../workflow-logger.js";
22
+ import { debugLog } from "../debug-logger.js";
23
+ import { _resolveReportBasePath } from "./phase-helpers.js";
24
+
25
+ /**
26
+ * If a unit is in-flight, close it out, then stop auto-mode.
27
+ */
28
+ export async function closeoutAndStop(
29
+ ctx: ExtensionContext,
30
+ pi: ExtensionAPI,
31
+ s: AutoSession,
32
+ deps: LoopDeps,
33
+ reason: string,
34
+ ): Promise<void> {
35
+ if (s.currentUnit) {
36
+ await deps.closeoutUnit(
37
+ ctx,
38
+ s.basePath,
39
+ s.currentUnit.type,
40
+ s.currentUnit.id,
41
+ s.currentUnit.startedAt,
42
+ deps.buildSnapshotOpts(s.currentUnit.type, s.currentUnit.id),
43
+ );
44
+ s.clearCurrentUnit();
45
+ }
46
+ await deps.stopAuto(ctx, pi, reason);
47
+ }
48
+
49
+ export async function stopOnPostflightRecoveryNeeded(
50
+ ic: IterationContext,
51
+ result: PostflightResult,
52
+ milestoneId: string,
53
+ ): Promise<{ action: "break"; reason: string } | null> {
54
+ if (!result.needsManualRecovery) return null;
55
+ const { ctx, pi, deps } = ic;
56
+ const reason = `Post-merge stash restore failed for milestone ${milestoneId}`;
57
+ ctx.ui.notify(
58
+ `${reason}. Resolve the working tree before resuming auto-mode. ${result.message}`,
59
+ "error",
60
+ );
61
+ await deps.stopAuto(ctx, pi, reason);
62
+ return { action: "break", reason: "postflight-stash-restore-failed" };
63
+ }
64
+
65
+ export async function restorePreflightStashOrStop(
66
+ ic: IterationContext,
67
+ preflight: PreflightResult,
68
+ milestoneId: string,
69
+ ): Promise<{ action: "break"; reason: string } | null> {
70
+ if (!preflight.stashPushed) return null;
71
+ const { s, deps } = ic;
72
+ const result = deps.postflightPopStash(
73
+ s.originalBasePath || s.basePath,
74
+ milestoneId,
75
+ preflight.stashMarker,
76
+ ic.ctx.ui.notify.bind(ic.ctx.ui),
77
+ );
78
+ return stopOnPostflightRecoveryNeeded(ic, result, milestoneId);
79
+ }
80
+
81
+ /**
82
+ * Run a milestone merge surrounded by preflight stash + always-on postflight
83
+ * pop. The previous code popped the stash only after a successful merge, which
84
+ * leaked `gsd-preflight-stash:M00x:*` entries whenever `mergeAndExit` threw —
85
+ * leaving the user's pre-merge working tree silently stashed away after a
86
+ * merge-conflict or other merge error. This helper restores the stash on
87
+ * every exit path, then surfaces the merge or stash failure (in priority
88
+ * order) as the loop's stop reason.
89
+ *
90
+ * Returns a `break` action when auto-mode must stop, or `null` when the merge
91
+ * succeeded and the stash (if any) was restored cleanly.
92
+ */
93
+ export async function _runMilestoneMergeWithStashRestore(
94
+ ic: IterationContext,
95
+ milestoneId: string,
96
+ options: { preserveCloseoutTranscript?: boolean } = {},
97
+ ): Promise<{ action: "break"; reason: string } | null> {
98
+ const { ctx, pi, s, deps } = ic;
99
+
100
+ const preflight = deps.preflightCleanRoot(
101
+ s.originalBasePath || s.basePath,
102
+ milestoneId,
103
+ ctx.ui.notify.bind(ctx.ui),
104
+ );
105
+ if (preflight.blocked) {
106
+ const reason = preflight.blockedReason === "unmerged-conflicts"
107
+ ? `Pre-merge unresolved Git conflicts block milestone ${milestoneId}`
108
+ : `Pre-merge dirty working tree overlaps milestone ${milestoneId}`;
109
+ await deps.stopAuto(ctx, pi, reason, {
110
+ preserveCompletedMilestoneBranch: true,
111
+ preserveCloseoutTranscript: options.preserveCloseoutTranscript,
112
+ });
113
+ return {
114
+ action: "break",
115
+ reason: preflight.blockedReason === "unmerged-conflicts"
116
+ ? "preflight-unmerged-conflicts"
117
+ : "preflight-dirty-overlap",
118
+ };
119
+ }
120
+
121
+ let mergeError: unknown = null;
122
+ const exitResult = deps.lifecycle.exitMilestone(
123
+ milestoneId,
124
+ { merge: true },
125
+ ctx.ui,
126
+ );
127
+ if (exitResult.ok) {
128
+ s.milestoneMergedInPhases = true;
129
+ try {
130
+ const projectRoot = s.originalBasePath || s.canonicalProjectRoot || s.basePath;
131
+ const { rebuildMarkdownProjectionsFromDb } = await import("../commands-maintenance.js");
132
+ await rebuildMarkdownProjectionsFromDb(projectRoot);
133
+ } catch (err) {
134
+ logWarning(
135
+ "engine",
136
+ `markdown projection rebuild after milestone merge failed: ${err instanceof Error ? err.message : String(err)}`,
137
+ );
138
+ }
139
+ } else {
140
+ mergeError = exitResult.cause ?? new Error(`exit ${exitResult.reason}`);
141
+ }
142
+
143
+ // Always attempt to restore the stashed working tree, even on merge error.
144
+ // postflightPopStash itself does not throw; failures surface via the
145
+ // PostflightResult.needsManualRecovery flag.
146
+ let stashResult: PostflightResult | null = null;
147
+ if (preflight.stashPushed) {
148
+ stashResult = deps.postflightPopStash(
149
+ s.originalBasePath || s.basePath,
150
+ milestoneId,
151
+ preflight.stashMarker,
152
+ ctx.ui.notify.bind(ctx.ui),
153
+ );
154
+ }
155
+
156
+ // Merge failure takes priority over stash recovery — the merge is the
157
+ // authoritative gate. If the stash also needed manual recovery, the user
158
+ // already saw the postflightPopStash notify above.
159
+ if (mergeError) {
160
+ if (mergeError instanceof MergeConflictError) {
161
+ // A merge conflict is a recoverable human checkpoint, not an
162
+ // infrastructure failure — the user resolves the conflict and runs
163
+ // `/gsd auto` to resume. Pause (don't stop): stopAuto tears down the
164
+ // session and, because `milestoneMergedInPhases` stays false here,
165
+ // re-runs the already-failed worktree merge in its cleanup step
166
+ // (#2645), then drops the user out of the interactive TUI onto a
167
+ // "stopped" surface.
168
+ const conflictReason = `Merge conflict on milestone ${milestoneId}: ${mergeError.conflictedFiles.join(", ")}. Resolve conflicts manually and run /gsd auto to resume.`;
169
+ ctx.ui.notify(conflictReason, "error");
170
+ await deps.pauseAuto(ctx, pi, {
171
+ message: conflictReason,
172
+ category: "unknown",
173
+ });
174
+ return { action: "break", reason: "merge-conflict" };
175
+ }
176
+ logError("engine", "Milestone merge failed with non-conflict error", {
177
+ milestone: milestoneId,
178
+ error: String(mergeError),
179
+ });
180
+ // Like a merge conflict, a non-conflict merge failure (index lock,
181
+ // network, permissions) is recoverable — the user fixes the cause and
182
+ // runs `/gsd auto` to resume. Pause (don't stop) so the session stays
183
+ // resumable and stopAuto's teardown does not re-run the failed merge.
184
+ const mergeFailReason = `Merge error on milestone ${milestoneId}: ${mergeError instanceof Error ? mergeError.message : String(mergeError)}. Resolve and run /gsd auto to resume.`;
185
+ ctx.ui.notify(mergeFailReason, "error");
186
+ await deps.pauseAuto(ctx, pi, {
187
+ message: mergeFailReason,
188
+ category: "unknown",
189
+ });
190
+ return { action: "break", reason: "merge-failed" };
191
+ }
192
+
193
+ if (stashResult) {
194
+ return stopOnPostflightRecoveryNeeded(ic, stashResult, milestoneId);
195
+ }
196
+ return null;
197
+ }
198
+
199
+ export async function _runMilestoneMergeOnceWithStashRestore(
200
+ ic: IterationContext,
201
+ milestoneId: string,
202
+ options: { preserveCloseoutTranscript?: boolean } = {},
203
+ ): Promise<{ action: "break"; reason: string } | null> {
204
+ if (ic.s.milestoneMergedInPhases) {
205
+ debugLog("autoLoop", {
206
+ phase: "milestone-merge-skip",
207
+ reason: "already-merged-in-phases",
208
+ milestoneId,
209
+ });
210
+ return null;
211
+ }
212
+ return _runMilestoneMergeWithStashRestore(ic, milestoneId, options);
213
+ }
214
+
215
+ export async function shouldSkipTerminalMilestoneCloseout(
216
+ s: AutoSession,
217
+ state: Pick<GSDState, "phase" | "lastCompletedMilestone" | "activeMilestone">,
218
+ mid?: string | null,
219
+ ): Promise<{ skip: boolean; milestoneId?: string }> {
220
+ const closeoutMilestoneId = mid ?? s.currentMilestoneId ?? state.lastCompletedMilestone?.id;
221
+ if (s.completionStopInProgress) {
222
+ return { skip: true, milestoneId: closeoutMilestoneId };
223
+ }
224
+ if (!closeoutMilestoneId) {
225
+ return { skip: false };
226
+ }
227
+ if (isDbAvailable()) refreshWorkflowDatabaseFromDisk();
228
+ const closeoutBasePath = s.originalBasePath || s.canonicalProjectRoot || s.basePath;
229
+ let closeoutMergePending = false;
230
+ if (getIsolationMode(closeoutBasePath) !== "none") {
231
+ try {
232
+ const blockers = await findUnmergedCompletedMilestones(closeoutBasePath);
233
+ closeoutMergePending = blockers.some((blocker) => blocker.milestoneId === closeoutMilestoneId);
234
+ } catch {
235
+ // Fail open: without git/DB inspection we cannot safely treat closeout as done.
236
+ closeoutMergePending = true;
237
+ }
238
+ }
239
+ const milestoneAlreadyClosedOut = isDbAvailable()
240
+ && isClosedStatus(getMilestone(closeoutMilestoneId)?.status ?? "")
241
+ && !closeoutMergePending;
242
+ if (milestoneAlreadyClosedOut) {
243
+ return { skip: true, milestoneId: closeoutMilestoneId };
244
+ }
245
+ return { skip: false, milestoneId: closeoutMilestoneId };
246
+ }
247
+
248
+ /**
249
+ * Generate and write an HTML milestone report snapshot.
250
+ */
251
+ export async function generateMilestoneReport(
252
+ s: AutoSession,
253
+ ctx: ExtensionContext,
254
+ milestoneId: string,
255
+ ): Promise<void> {
256
+ const { loadVisualizerData } = await importExtensionModule<typeof import("../visualizer-data.js")>(import.meta.url, "../visualizer-data.js");
257
+ const { generateHtmlReport } = await importExtensionModule<typeof import("../export-html.js")>(import.meta.url, "../export-html.js");
258
+ const { writeReportSnapshot } = await importExtensionModule<typeof import("../reports.js")>(import.meta.url, "../reports.js");
259
+ const { basename } = await import("node:path");
260
+
261
+ const reportBasePath = _resolveReportBasePath(s);
262
+
263
+ const snapData = await loadVisualizerData(reportBasePath);
264
+ const completedMs = snapData.milestones.find(
265
+ (m: { id: string }) => m.id === milestoneId,
266
+ );
267
+ const msTitle = completedMs?.title ?? milestoneId;
268
+ const gsdVersion = process.env.GSD_VERSION ?? "0.0.0";
269
+ const projName = basename(reportBasePath);
270
+ const doneSlices = snapData.milestones.reduce(
271
+ (acc: number, m: { slices: { done: boolean }[] }) =>
272
+ acc + m.slices.filter((sl: { done: boolean }) => sl.done).length,
273
+ 0,
274
+ );
275
+ const totalSlices = snapData.milestones.reduce(
276
+ (acc: number, m: { slices: unknown[] }) => acc + m.slices.length,
277
+ 0,
278
+ );
279
+ const outPath = writeReportSnapshot({
280
+ basePath: reportBasePath,
281
+ html: generateHtmlReport(snapData, {
282
+ projectName: projName,
283
+ projectPath: reportBasePath,
284
+ gsdVersion,
285
+ milestoneId,
286
+ indexRelPath: "index.html",
287
+ }),
288
+ milestoneId,
289
+ milestoneTitle: msTitle,
290
+ kind: "milestone",
291
+ projectName: projName,
292
+ projectPath: reportBasePath,
293
+ gsdVersion,
294
+ totalCost: snapData.totals?.cost ?? 0,
295
+ totalTokens: snapData.totals?.tokens.total ?? 0,
296
+ totalDuration: snapData.totals?.duration ?? 0,
297
+ doneSlices,
298
+ totalSlices,
299
+ doneMilestones: snapData.milestones.filter(
300
+ (m: { status: string }) => m.status === "complete",
301
+ ).length,
302
+ totalMilestones: snapData.milestones.length,
303
+ phase: snapData.phase,
304
+ });
305
+ ctx.ui.notify(
306
+ `Report saved: .gsd/reports/${basename(outPath)} — open index.html to browse progression.`,
307
+ "info",
308
+ );
309
+ }
@@ -28,7 +28,7 @@
28
28
  */
29
29
 
30
30
  import type { WindowEntry } from "./types.js";
31
- import { buildDispatchKey, normalizeDispatchKey } from "./dispatch-key.js";
31
+ import { buildDispatchKey, normalizeDispatchKey, parseDispatchKey } from "./dispatch-key.js";
32
32
  import { detectStuck } from "./detect-stuck.js";
33
33
  import {
34
34
  getLatestForUnit,
@@ -84,12 +84,18 @@ export interface DispatchHistoryOptions {
84
84
  windowSize?: number;
85
85
  }
86
86
 
87
- function lookupLatestLedgerError(unitType: string, unitId: string): string | undefined {
87
+ /**
88
+ * Fetch the latest dispatch ledger error for a unit, the single canonical
89
+ * lookup shared by the DispatchHistory window and the legacy
90
+ * `loopState.recentUnits` path in dispatch.ts. The ledger keys rows by the
91
+ * bare unit id with the unit type in its own column, so the lookup must use
92
+ * the bare id and require a unit_type match (a compound `type/id` key would
93
+ * miss the row, and another unit type's error on the same id must never be
94
+ * attached — it would trip the repeat-error rule spuriously).
95
+ */
96
+ export function lookupLatestLedgerError(unitType: string, unitId: string): string | undefined {
88
97
  try {
89
98
  const row = getLatestForUnit(unitId);
90
- // The ledger keys rows by bare unit id; require a unit_type match so
91
- // another unit type's error on the same id is never attached (it would
92
- // trip the repeat-error rule spuriously).
93
99
  if (!row || row.unit_type !== unitType) return undefined;
94
100
  return row.error_summary ?? undefined;
95
101
  } catch {
@@ -133,7 +139,17 @@ export function createDispatchHistory(options: DispatchHistoryOptions): Dispatch
133
139
  try {
134
140
  const persisted = getRecentUnitKeysForProjectRoot(scopeId, windowSize);
135
141
  if (persisted.length === 0) return 0;
136
- window = persisted.map(({ key }) => ({ key: normalizeDispatchKey(key) }));
142
+ const rebuilt: WindowEntry[] = [];
143
+ for (const { key } of persisted) {
144
+ const normalized = normalizeDispatchKey(key);
145
+ const parsed = parseDispatchKey(normalized);
146
+ const error =
147
+ parsed && rebuilt.some((entry) => entry.key === normalized)
148
+ ? lookupLatestLedgerError(parsed.unitType, parsed.unitId)
149
+ : undefined;
150
+ rebuilt.push({ key: normalized, error });
151
+ }
152
+ window = rebuilt;
137
153
  while (window.length > windowSize) window.shift();
138
154
  return window.length;
139
155
  } catch (err) {