gsd-pi 2.82.0-dev.2841a1e44 → 2.82.0-dev.3a3c6509d

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 (377) hide show
  1. package/README.md +3 -3
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/GSD-WORKFLOW.md +7 -0
  4. package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
  5. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +1 -1
  6. package/dist/resources/extensions/gsd/auto/infra-errors.js +9 -3
  7. package/dist/resources/extensions/gsd/auto/loop.js +5 -5
  8. package/dist/resources/extensions/gsd/auto/orchestrator.js +11 -0
  9. package/dist/resources/extensions/gsd/auto/phases.js +81 -31
  10. package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +12 -0
  11. package/dist/resources/extensions/gsd/auto-dashboard.js +66 -1
  12. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +1 -0
  13. package/dist/resources/extensions/gsd/auto-dispatch.js +20 -19
  14. package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
  15. package/dist/resources/extensions/gsd/auto-post-unit.js +71 -10
  16. package/dist/resources/extensions/gsd/auto-recovery.js +71 -14
  17. package/dist/resources/extensions/gsd/auto-start.js +87 -14
  18. package/dist/resources/extensions/gsd/auto-verification.js +17 -4
  19. package/dist/resources/extensions/gsd/auto-worktree.js +176 -10
  20. package/dist/resources/extensions/gsd/auto.js +37 -5
  21. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +31 -7
  22. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +10 -9
  23. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +4 -2
  24. package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +5 -2
  25. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +14 -2
  26. package/dist/resources/extensions/gsd/commands/handlers/core.js +17 -1
  27. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +7 -2
  28. package/dist/resources/extensions/gsd/crash-recovery.js +43 -5
  29. package/dist/resources/extensions/gsd/db/milestone-leases.js +24 -0
  30. package/dist/resources/extensions/gsd/db/unit-dispatches.js +3 -2
  31. package/dist/resources/extensions/gsd/dispatch-guard.js +2 -2
  32. package/dist/resources/extensions/gsd/doctor-git-checks.js +46 -1
  33. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +28 -11
  34. package/dist/resources/extensions/gsd/doctor.js +2 -28
  35. package/dist/resources/extensions/gsd/export-html.js +27 -425
  36. package/dist/resources/extensions/gsd/forensics.js +3 -3
  37. package/dist/resources/extensions/gsd/git-service.js +45 -3
  38. package/dist/resources/extensions/gsd/gsd-db.js +21 -6
  39. package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -3
  40. package/dist/resources/extensions/gsd/guided-flow.js +101 -116
  41. package/dist/resources/extensions/gsd/guided-unit-context.js +23 -0
  42. package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
  43. package/dist/resources/extensions/gsd/migration-auto-check.js +12 -17
  44. package/dist/resources/extensions/gsd/milestone-actions.js +11 -4
  45. package/dist/resources/extensions/gsd/native-git-bridge.js +48 -12
  46. package/dist/resources/extensions/gsd/pending-auto-start.js +52 -0
  47. package/dist/resources/extensions/gsd/post-execution-checks.js +73 -2
  48. package/dist/resources/extensions/gsd/pre-execution-checks.js +28 -1
  49. package/dist/resources/extensions/gsd/prompt-loader.js +1 -1
  50. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  51. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  52. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
  53. package/dist/resources/extensions/gsd/prompts/discuss.md +9 -9
  54. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
  55. package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
  56. package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -4
  57. package/dist/resources/extensions/gsd/prompts/queue.md +4 -4
  58. package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  59. package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  60. package/dist/resources/extensions/gsd/queue-reorder-ui.js +30 -13
  61. package/dist/resources/extensions/gsd/smart-entry-routing.js +36 -0
  62. package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +6 -1
  63. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +9 -14
  64. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +19 -24
  65. package/dist/resources/extensions/gsd/state.js +1 -1
  66. package/dist/resources/extensions/gsd/status-guards.js +11 -0
  67. package/dist/resources/extensions/gsd/templates/plan.md +8 -5
  68. package/dist/resources/extensions/gsd/templates/task-plan.md +4 -2
  69. package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -8
  70. package/dist/resources/extensions/gsd/tools/complete-slice.js +6 -8
  71. package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -1
  72. package/dist/resources/extensions/gsd/tools/plan-slice.js +89 -14
  73. package/dist/resources/extensions/gsd/unit-context-manifest.js +7 -8
  74. package/dist/resources/extensions/gsd/validation.js +23 -1
  75. package/dist/resources/extensions/gsd/verification-gate.js +68 -7
  76. package/dist/resources/extensions/gsd/workflow-mcp.js +17 -1
  77. package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
  78. package/dist/resources/extensions/gsd/worktree-lifecycle.js +33 -8
  79. package/dist/resources/extensions/gsd/worktree-manager.js +1 -1
  80. package/dist/resources/extensions/shared/html-shell.js +388 -0
  81. package/dist/resources/extensions/visual-brief/page-contract.js +2 -0
  82. package/dist/resources/extensions/visual-brief/prompts.js +29 -0
  83. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  84. package/dist/web/standalone/.next/BUILD_ID +1 -1
  85. package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
  86. package/dist/web/standalone/.next/build-manifest.json +3 -3
  87. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  88. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  89. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  90. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  98. package/dist/web/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -7
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
  103. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -5
  105. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -5
  108. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  110. package/dist/web/standalone/.next/server/app/index.html +1 -1
  111. package/dist/web/standalone/.next/server/app/index.rsc +4 -7
  112. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -7
  114. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -5
  116. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -5
  117. package/dist/web/standalone/.next/server/app/page.js +2 -2
  118. package/dist/web/standalone/.next/server/app/page.js.nft.json +1 -1
  119. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
  121. package/dist/web/standalone/.next/server/chunks/4266.js +2 -0
  122. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  125. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  126. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  127. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  128. package/dist/web/standalone/.next/static/chunks/app/layout-8c10ec293ae0f1d5.js +1 -0
  129. package/dist/web/standalone/.next/static/chunks/{webpack-6a95bc41e0f7ec89.js → webpack-9a4db269f9ed63ad.js} +1 -1
  130. package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
  131. package/package.json +2 -2
  132. package/packages/mcp-server/src/workflow-tools.test.ts +1 -1
  133. package/packages/native/tsconfig.json +2 -1
  134. package/packages/native/tsconfig.tsbuildinfo +1 -1
  135. package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts.map +1 -1
  136. package/packages/pi-ai/dist/providers/google-gemini-cli.js +5 -0
  137. package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
  138. package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts +2 -0
  139. package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts.map +1 -0
  140. package/packages/pi-ai/dist/providers/google-gemini-cli.test.js +41 -0
  141. package/packages/pi-ai/dist/providers/google-gemini-cli.test.js.map +1 -0
  142. package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
  143. package/packages/pi-ai/dist/providers/openai-codex-responses.js +82 -1
  144. package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  145. package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts +2 -0
  146. package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts.map +1 -0
  147. package/packages/pi-ai/dist/providers/openai-codex-responses.test.js +52 -0
  148. package/packages/pi-ai/dist/providers/openai-codex-responses.test.js.map +1 -0
  149. package/packages/pi-ai/dist/providers/simple-options.d.ts +2 -4
  150. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  151. package/packages/pi-ai/dist/providers/simple-options.js +5 -6
  152. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  153. package/packages/pi-ai/dist/providers/simple-options.test.d.ts +2 -0
  154. package/packages/pi-ai/dist/providers/simple-options.test.d.ts.map +1 -0
  155. package/packages/pi-ai/dist/providers/simple-options.test.js +50 -0
  156. package/packages/pi-ai/dist/providers/simple-options.test.js.map +1 -0
  157. package/packages/pi-ai/src/providers/google-gemini-cli.test.ts +49 -0
  158. package/packages/pi-ai/src/providers/google-gemini-cli.ts +7 -0
  159. package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +63 -0
  160. package/packages/pi-ai/src/providers/openai-codex-responses.ts +91 -1
  161. package/packages/pi-ai/src/providers/simple-options.test.ts +60 -0
  162. package/packages/pi-ai/src/providers/simple-options.ts +5 -6
  163. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  164. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts +2 -0
  165. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts.map +1 -0
  166. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js +66 -0
  167. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js.map +1 -0
  168. package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
  169. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  170. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +44 -3
  171. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  172. package/packages/pi-coding-agent/dist/core/sdk.js +1 -1
  173. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  174. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  175. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +24 -6
  176. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  177. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  178. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +71 -97
  179. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  180. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js +12 -0
  181. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js.map +1 -1
  182. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  183. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +19 -8
  184. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  185. package/packages/pi-coding-agent/src/core/agent-session-thinking-level.test.ts +79 -0
  186. package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
  187. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +53 -3
  188. package/packages/pi-coding-agent/src/core/sdk.ts +1 -1
  189. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +23 -7
  190. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +75 -102
  191. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-ordering.test.ts +14 -0
  192. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +23 -8
  193. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  194. package/packages/pi-tui/dist/__tests__/terminal.test.d.ts +2 -0
  195. package/packages/pi-tui/dist/__tests__/terminal.test.d.ts.map +1 -0
  196. package/packages/pi-tui/dist/__tests__/terminal.test.js +103 -0
  197. package/packages/pi-tui/dist/__tests__/terminal.test.js.map +1 -0
  198. package/packages/pi-tui/dist/terminal.d.ts +2 -0
  199. package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
  200. package/packages/pi-tui/dist/terminal.js +12 -0
  201. package/packages/pi-tui/dist/terminal.js.map +1 -1
  202. package/packages/pi-tui/src/__tests__/terminal.test.ts +121 -0
  203. package/packages/pi-tui/src/terminal.ts +11 -0
  204. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  205. package/src/resources/GSD-WORKFLOW.md +7 -0
  206. package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
  207. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +1 -1
  208. package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
  209. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +9 -0
  210. package/src/resources/extensions/gsd/auto/contracts.ts +14 -6
  211. package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
  212. package/src/resources/extensions/gsd/auto/loop.ts +8 -5
  213. package/src/resources/extensions/gsd/auto/orchestrator.ts +11 -0
  214. package/src/resources/extensions/gsd/auto/phases.ts +90 -38
  215. package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +13 -0
  216. package/src/resources/extensions/gsd/auto-dashboard.ts +72 -1
  217. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +1 -0
  218. package/src/resources/extensions/gsd/auto-dispatch.ts +21 -19
  219. package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
  220. package/src/resources/extensions/gsd/auto-post-unit.ts +78 -8
  221. package/src/resources/extensions/gsd/auto-recovery.ts +74 -11
  222. package/src/resources/extensions/gsd/auto-start.ts +94 -12
  223. package/src/resources/extensions/gsd/auto-verification.ts +22 -2
  224. package/src/resources/extensions/gsd/auto-worktree.ts +193 -10
  225. package/src/resources/extensions/gsd/auto.ts +40 -5
  226. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +42 -7
  227. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +10 -9
  228. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +4 -2
  229. package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +3 -1
  230. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +17 -2
  231. package/src/resources/extensions/gsd/commands/handlers/core.ts +17 -1
  232. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +8 -3
  233. package/src/resources/extensions/gsd/crash-recovery.ts +44 -4
  234. package/src/resources/extensions/gsd/db/milestone-leases.ts +26 -0
  235. package/src/resources/extensions/gsd/db/unit-dispatches.ts +4 -3
  236. package/src/resources/extensions/gsd/dispatch-guard.ts +2 -2
  237. package/src/resources/extensions/gsd/doctor-git-checks.ts +45 -1
  238. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
  239. package/src/resources/extensions/gsd/doctor-types.ts +1 -0
  240. package/src/resources/extensions/gsd/doctor.ts +2 -27
  241. package/src/resources/extensions/gsd/export-html.ts +27 -427
  242. package/src/resources/extensions/gsd/forensics.ts +3 -3
  243. package/src/resources/extensions/gsd/git-service.ts +51 -4
  244. package/src/resources/extensions/gsd/gsd-db.ts +21 -6
  245. package/src/resources/extensions/gsd/guided-flow-queue.ts +4 -3
  246. package/src/resources/extensions/gsd/guided-flow.ts +134 -133
  247. package/src/resources/extensions/gsd/guided-unit-context.ts +30 -0
  248. package/src/resources/extensions/gsd/migrate/parsers.ts +11 -0
  249. package/src/resources/extensions/gsd/migration-auto-check.ts +15 -23
  250. package/src/resources/extensions/gsd/milestone-actions.ts +10 -4
  251. package/src/resources/extensions/gsd/native-git-bridge.ts +54 -12
  252. package/src/resources/extensions/gsd/pending-auto-start.ts +79 -0
  253. package/src/resources/extensions/gsd/post-execution-checks.ts +87 -2
  254. package/src/resources/extensions/gsd/pre-execution-checks.ts +32 -1
  255. package/src/resources/extensions/gsd/prompt-loader.ts +1 -1
  256. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  257. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  258. package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
  259. package/src/resources/extensions/gsd/prompts/discuss.md +9 -9
  260. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
  261. package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
  262. package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -4
  263. package/src/resources/extensions/gsd/prompts/queue.md +4 -4
  264. package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  265. package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  266. package/src/resources/extensions/gsd/queue-reorder-ui.ts +31 -13
  267. package/src/resources/extensions/gsd/smart-entry-routing.ts +77 -0
  268. package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +8 -1
  269. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +12 -15
  270. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +17 -25
  271. package/src/resources/extensions/gsd/state.ts +1 -1
  272. package/src/resources/extensions/gsd/status-guards.ts +13 -0
  273. package/src/resources/extensions/gsd/templates/plan.md +8 -5
  274. package/src/resources/extensions/gsd/templates/task-plan.md +4 -2
  275. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +71 -0
  276. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +116 -0
  277. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +56 -0
  278. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +80 -1
  279. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +35 -7
  280. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +53 -2
  281. package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +12 -1
  282. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +91 -6
  283. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +1 -0
  284. package/src/resources/extensions/gsd/tests/auto-stop-notification.test.ts +20 -0
  285. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
  286. package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +87 -0
  287. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +11 -2
  288. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +4 -1
  289. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +5 -9
  290. package/src/resources/extensions/gsd/tests/complete-task.test.ts +3 -1
  291. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +86 -2
  292. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
  293. package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
  294. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +59 -2
  295. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +66 -0
  296. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
  297. package/src/resources/extensions/gsd/tests/doctor-empty-worktree.test.ts +65 -0
  298. package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
  299. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +11 -0
  300. package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +2 -0
  301. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +106 -0
  302. package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +59 -11
  303. package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
  304. package/src/resources/extensions/gsd/tests/guided-tool-contract.test.ts +65 -0
  305. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +7 -7
  306. package/src/resources/extensions/gsd/tests/hook-model-resolution.test.ts +5 -0
  307. package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -2
  308. package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +9 -0
  309. package/src/resources/extensions/gsd/tests/integration/doctor-runtime.test.ts +20 -0
  310. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +112 -1
  311. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
  312. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +46 -0
  313. package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +179 -0
  314. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -1
  315. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +26 -18
  316. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +63 -2
  317. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +121 -1
  318. package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +55 -1
  319. package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +29 -5
  320. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +2 -1
  321. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +26 -0
  322. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
  323. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +225 -1
  324. package/src/resources/extensions/gsd/tests/plan-task.test.ts +17 -0
  325. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +86 -0
  326. package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
  327. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +53 -0
  328. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +59 -0
  329. package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
  330. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +37 -1
  331. package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +54 -0
  332. package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +89 -2
  333. package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +2 -3
  334. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
  335. package/src/resources/extensions/gsd/tests/smart-entry-routing.test.ts +113 -0
  336. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +53 -2
  337. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +119 -23
  338. package/src/resources/extensions/gsd/tests/status-guards.test.ts +13 -1
  339. package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +64 -1
  340. package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +7 -3
  341. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +82 -7
  342. package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +29 -2
  343. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
  344. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +19 -1
  345. package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +21 -1
  346. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +1 -1
  347. package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +39 -0
  348. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +64 -12
  349. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +38 -0
  350. package/src/resources/extensions/gsd/tools/complete-milestone.ts +8 -10
  351. package/src/resources/extensions/gsd/tools/complete-slice.ts +6 -8
  352. package/src/resources/extensions/gsd/tools/plan-milestone.ts +5 -1
  353. package/src/resources/extensions/gsd/tools/plan-slice.ts +98 -12
  354. package/src/resources/extensions/gsd/types.ts +1 -1
  355. package/src/resources/extensions/gsd/unit-context-manifest.ts +12 -9
  356. package/src/resources/extensions/gsd/validation.ts +23 -1
  357. package/src/resources/extensions/gsd/verification-gate.ts +78 -6
  358. package/src/resources/extensions/gsd/workflow-mcp.ts +18 -1
  359. package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
  360. package/src/resources/extensions/gsd/worktree-lifecycle.ts +41 -8
  361. package/src/resources/extensions/gsd/worktree-manager.ts +1 -1
  362. package/src/resources/extensions/shared/html-shell.ts +412 -0
  363. package/src/resources/extensions/visual-brief/page-contract.ts +2 -0
  364. package/src/resources/extensions/visual-brief/prompts.ts +37 -1
  365. package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +40 -0
  366. package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
  367. package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +0 -1
  368. package/dist/web/standalone/.next/static/css/0262768ec1b89d34.css +0 -1
  369. package/dist/web/standalone/.next/static/css/de70bee13400563f.css +0 -1
  370. package/dist/web/standalone/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
  371. package/dist/web/standalone/.next/static/media/747892c23ea88013-s.woff2 +0 -0
  372. package/dist/web/standalone/.next/static/media/8d697b304b401681-s.woff2 +0 -0
  373. package/dist/web/standalone/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  374. package/dist/web/standalone/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
  375. package/dist/web/standalone/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  376. /package/dist/web/standalone/.next/static/{Qgr2B_MRhPxC0z8fwv4vT → O6femb9LLl3nlgsDaYwS-}/_buildManifest.js +0 -0
  377. /package/dist/web/standalone/.next/static/{Qgr2B_MRhPxC0z8fwv4vT → O6femb9LLl3nlgsDaYwS-}/_ssgManifest.js +0 -0
package/README.md CHANGED
@@ -376,7 +376,7 @@ The database is authoritative for milestones, slices, tasks, requirements, summa
376
376
 
377
377
  10. **Adaptive replanning** — After each slice completes, the roadmap is reassessed. If the work revealed new information that changes the plan, slices are reordered, added, or removed before continuing.
378
378
 
379
- 11. **Verification enforcement** — Configure shell commands (`npm run lint`, `npm run test`, etc.) that run automatically after task execution. Failures trigger auto-fix retries before advancing. Execute-task commits and snapshots are deferred until verification passes; failed or incomplete verification blocks closeout instead of publishing changes. Auto-discovered checks from `package.json` run in advisory mode — they log warnings but don't block on pre-existing errors. Configurable via `verification_commands`, `verification_auto_fix`, and `verification_max_retries` preferences.
379
+ 11. **Verification enforcement** — Configure simple executable commands (`npm run lint`, `npm run test`, etc.) that run automatically after task execution. Verification commands must not use shell composition or control syntax such as pipes, redirects, semicolons, backticks, or command substitution. Failures trigger auto-fix retries before advancing. Execute-task commits and snapshots are deferred until verification passes; failed or incomplete verification blocks closeout instead of publishing changes. Auto-discovered checks from `package.json` and Python pytest project markers (`python-project`) run in advisory mode — they log warnings but don't block on pre-existing errors. Configurable via `verification_commands`, `verification_auto_fix`, and `verification_max_retries` preferences.
380
380
 
381
381
  12. **Milestone validation** — After all slices complete, a `validate-milestone` gate compares roadmap success criteria against actual results before sealing the milestone.
382
382
 
@@ -503,7 +503,7 @@ On first run, GSD launches a branded setup wizard that walks you through LLM pro
503
503
  | `/gsd mcp` | MCP server status and connectivity |
504
504
  | `/gsd status` | Progress dashboard |
505
505
  | `/gsd brief <mode>` | Generate a visual HTML brief (diagram, plan, diff, recap, table, slides) |
506
- | `/gsd queue` | Queue future milestones (safe during auto mode) |
506
+ | `/gsd queue` | Queue/reorder future milestones (`pending`, `queued`, or legacy `planned`; safe during auto mode) |
507
507
  | `/gsd prefs` | Model selection, timeouts, budget ceiling |
508
508
  | `/gsd migrate` | Migrate a v1 `.planning` directory to `.gsd` format |
509
509
  | `/gsd help` | Categorized command reference for all GSD subcommands |
@@ -670,7 +670,7 @@ auto_report: true
670
670
  | `context_mode.exec_stdout_cap_bytes` | Persisted stdout cap for `gsd_exec` output (default: 1048576) |
671
671
  | `context_mode.exec_digest_chars` | Trailing stdout characters returned to the agent context (default: 300) |
672
672
  | `context_mode.exec_env_allowlist` | Environment variables forwarded to sandboxed `gsd_exec` runs in addition to `PATH` and `HOME` |
673
- | `verification_commands` | Array of shell commands to run after task execution (e.g., `["npm run lint", "npm run test"]`) |
673
+ | `verification_commands` | Array of simple executable commands to run after task execution (e.g., `["npm run lint", "npm run test"]`); avoid pipes, redirects, semicolons, backticks, and command substitution |
674
674
  | `verification_auto_fix` | Auto-retry on verification failures (default: true) |
675
675
  | `verification_max_retries` | Max retries for verification failures (default: 2) |
676
676
  | `phases.require_slice_discussion` | Pause auto-mode before each slice for human discussion review |
@@ -1 +1 @@
1
- 0829fe9060dc3f75
1
+ b9c1b29c0681f84f
@@ -448,6 +448,13 @@ What differed from the plan and why (or "None").
448
448
 
449
449
  The one-liner must be substantive: "JWT auth with refresh rotation using jose" not "Authentication implemented."
450
450
 
451
+ When `key_files` or `key_decisions` are empty, render them as empty YAML lists:
452
+
453
+ ```yaml
454
+ key_files: []
455
+ key_decisions: []
456
+ ```
457
+
451
458
  **Slice summary:** Written when all tasks in a slice complete. Compresses all task summaries. Includes `drill_down_paths` to each task summary. During slice completion, review task summaries for `key_decisions` and ensure any significant ones are captured in `.gsd/DECISIONS.md`.
452
459
 
453
460
  **Milestone summary:** Updated each time a slice completes. Compresses all slice summaries. This is what gets injected into later slice planning instead of loading many individual summaries.
@@ -105,9 +105,10 @@ export function mapUsage(sdkUsage, totalCostUsd) {
105
105
  output: sdkUsage.output_tokens,
106
106
  cacheRead: sdkUsage.cache_read_input_tokens,
107
107
  cacheWrite: sdkUsage.cache_creation_input_tokens,
108
+ // Claude Agent SDK result usage is cumulative across its internal loop;
109
+ // repeated cache reads do not represent additional live context.
108
110
  totalTokens: sdkUsage.input_tokens +
109
111
  sdkUsage.output_tokens +
110
- sdkUsage.cache_read_input_tokens +
111
112
  sdkUsage.cache_creation_input_tokens,
112
113
  cost: {
113
114
  input: 0,
@@ -269,7 +269,7 @@ function makeErrorMessage(model, errorMsg) {
269
269
  export function isClaudeCodeAbortErrorMessage(message) {
270
270
  if (!message)
271
271
  return false;
272
- return /\b(?:claude code process aborted by user|request aborted by user|process aborted by user)\b/i.test(message);
272
+ return /\b(?:claude code process aborted by user|request aborted by user|process aborted by user|aborterror)\b/i.test(message);
273
273
  }
274
274
  function isBareClaudeCodeAbortErrorMessage(message) {
275
275
  if (!message)
@@ -6,9 +6,14 @@
6
6
  * failures that merit retry.
7
7
  */
8
8
  /**
9
- * Error codes indicating infrastructure failures that cannot be recovered by
10
- * retrying. Each retry re-dispatches the unit at full LLM cost, so we bail
11
- * immediately rather than burning budget on guaranteed failures.
9
+ * Error codes indicating infrastructure-level failures from the OS,
10
+ * filesystem, or network. This set includes permanent resource failures
11
+ * (ENOSPC, ENOMEM, EROFS), transient resource exhaustion (EAGAIN, ENOBUFS),
12
+ * and network/offline errors (ECONNREFUSED, ENOTFOUND, ENETUNREACH).
13
+ *
14
+ * Transient git failures are retried separately through
15
+ * TRANSIENT_GIT_RETRY_CODES in native-git-bridge.ts before escalating to the
16
+ * auto-loop.
12
17
  */
13
18
  export const INFRA_ERROR_CODES = new Set([
14
19
  "ENOSPC", // disk full
@@ -18,6 +23,7 @@ export const INFRA_ERROR_CODES = new Set([
18
23
  "EMFILE", // too many open files (process)
19
24
  "ENFILE", // too many open files (system)
20
25
  "EAGAIN", // resource temporarily unavailable (resource exhaustion)
26
+ "ENOBUFS", // no buffer space available (transient pipe exhaustion)
21
27
  "ECONNREFUSED", // connection refused (offline / local server down)
22
28
  "ENOTFOUND", // DNS lookup failed (offline / no network)
23
29
  "ENETUNREACH", // network unreachable (offline / no route)
@@ -35,7 +35,7 @@ import { createWorkflowTurnReporter } from "./workflow-turn-reporter.js";
35
35
  import { validateWorkflowSessionLock } from "./workflow-session-lock.js";
36
36
  import { dequeueSidecarItem } from "./workflow-sidecar-queue.js";
37
37
  import { maintainWorkerHeartbeat } from "./workflow-worker-heartbeat.js";
38
- import { measureMemoryPressure } from "./workflow-memory-pressure.js";
38
+ import { measureMemoryPressure, shouldCheckMemoryPressure, } from "./workflow-memory-pressure.js";
39
39
  import { buildSidecarIterationData } from "./workflow-sidecar-iteration.js";
40
40
  import { createExecutionGraphUnitDispatchDeps, runUnitPhaseViaContract, } from "./workflow-unit-dispatch.js";
41
41
  import { handleCustomEngineDispatchOutcome } from "./workflow-custom-engine-dispatch-outcome.js";
@@ -130,9 +130,9 @@ function logCustomVerifyRetrySaveFailure(err) {
130
130
  });
131
131
  }
132
132
  // ── Memory pressure monitoring (#3331) ──────────────────────────────────
133
- // Check heap usage every N iterations and trigger graceful shutdown before
134
- // the OS OOM killer sends SIGKILL. The threshold is 90% of the V8 heap
135
- // limit (--max-old-space-size or default ~1.5-4GB depending on platform).
133
+ // Check heap usage on session startup, then every N iterations, and trigger
134
+ // graceful shutdown before the OS OOM killer sends SIGKILL. The threshold is
135
+ // 90% of the V8 heap limit (--max-old-space-size or default ~1.5-4GB depending on platform).
136
136
  const MEMORY_CHECK_INTERVAL = 5; // check every 5 iterations
137
137
  const MAX_CUSTOM_ENGINE_VERIFY_RETRIES = 3;
138
138
  async function enforceMinRequestInterval(s, prefs) {
@@ -262,7 +262,7 @@ export async function autoLoop(ctx, pi, s, deps, options) {
262
262
  }
263
263
  // ── Memory pressure check (#3331) ──
264
264
  // Graceful shutdown before OOM killer sends SIGKILL.
265
- if (iteration % MEMORY_CHECK_INTERVAL === 0) {
265
+ if (shouldCheckMemoryPressure(iteration, MEMORY_CHECK_INTERVAL)) {
266
266
  const mem = measureMemoryPressure();
267
267
  debugLog("autoLoop", { phase: "memory-check", ...mem });
268
268
  const memoryDecision = decideMemoryPressure({ ...mem, iteration });
@@ -117,6 +117,17 @@ export class AutoOrchestrator {
117
117
  await this.deps.health.postAdvanceRecord(stopped);
118
118
  return stopped;
119
119
  }
120
+ if (!("unitType" in decision)) {
121
+ const blocked = {
122
+ kind: "blocked",
123
+ reason: decision.reason,
124
+ action: decision.action,
125
+ stateSnapshot: reconciliation.stateSnapshot,
126
+ };
127
+ await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
128
+ await this.deps.health.postAdvanceRecord(blocked);
129
+ return blocked;
130
+ }
120
131
  const nextKey = `${decision.unitType}:${decision.unitId}`;
121
132
  // Record every dispatch decision in the ring buffer before pre-flight
122
133
  // checks so the stuck-loop detector observes the full decision history
@@ -44,6 +44,7 @@ import { resolveManifest } from "../unit-context-manifest.js";
44
44
  import { createWorktreeSafetyModule } from "../worktree-safety.js";
45
45
  import { isSuspiciousGhostCompletion } from "../auto-unit-closeout.js";
46
46
  import { decideVerificationRetry, verificationRetryKey } from "./verification-retry-policy.js";
47
+ import { buildPhaseHandoffOutcome, setAutoOutcomeWidget } from "../auto-dashboard.js";
47
48
  // ─── Path Comparison Helper ───────────────────────────────────────────────
48
49
  /** Compare two paths for physical identity, tolerating trailing slashes and symlinks. */
49
50
  function isSamePathLocal(a, b) {
@@ -103,6 +104,12 @@ function unitWritesSource(unitType) {
103
104
  function formatWorktreeSafetyFailure(result) {
104
105
  return `Worktree Safety failed (${result.kind}): ${result.reason} ${result.remediation}`;
105
106
  }
107
+ function formatWorktreeSafetyStopReason(result) {
108
+ if (result.kind === "empty-worktree-with-project-content") {
109
+ return `Worktree Safety failed (${result.kind}). Run /gsd doctor fix, then /gsd auto.`;
110
+ }
111
+ return `Worktree Safety failed (${result.kind}).`;
112
+ }
106
113
  function resolveEmptyWorktreeWithProjectContent(unitRoot, projectRoot) {
107
114
  if (isSamePathLocal(unitRoot, projectRoot))
108
115
  return false;
@@ -176,7 +183,7 @@ async function validateSourceWriteWorktreeSafety(ic, unitType, unitId, milestone
176
183
  projectRoot,
177
184
  });
178
185
  ctx.ui.notify(msg, "error");
179
- await deps.stopAuto(ctx, pi, msg);
186
+ await deps.stopAuto(ctx, pi, formatWorktreeSafetyStopReason(result));
180
187
  return { action: "break", reason: result.kind };
181
188
  }
182
189
  // ─── Session timeout auto-resume state ────────────────────────────────────────
@@ -968,7 +975,14 @@ export async function runDispatch(ic, preData, loopState) {
968
975
  prompt = preDispatchResult.prompt;
969
976
  }
970
977
  const guardBasePath = _resolveDispatchGuardBasePath(s);
971
- const priorSliceBlocker = deps.getPriorSliceCompletionBlocker(guardBasePath, deps.getMainBranch(guardBasePath), unitType, unitId);
978
+ let mainBranch = "main";
979
+ try {
980
+ mainBranch = deps.getMainBranch(guardBasePath);
981
+ }
982
+ catch (err) {
983
+ debugLog("autoLoop", { phase: "getMainBranch-failed", error: String(err) });
984
+ }
985
+ const priorSliceBlocker = deps.getPriorSliceCompletionBlocker(guardBasePath, mainBranch, unitType, unitId);
972
986
  if (priorSliceBlocker) {
973
987
  await deps.stopAuto(ctx, pi, priorSliceBlocker);
974
988
  debugLog("autoLoop", { phase: "exit", reason: "prior-slice-blocker" });
@@ -1324,35 +1338,8 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
1324
1338
  s.currentUnit.type === unitType &&
1325
1339
  s.currentUnit.id === unitId);
1326
1340
  const previousTier = s.currentUnitRouting?.tier;
1327
- // Scope workflow-logger buffer to this unit so post-finalize drains are
1328
- // per-unit. Without this, the module-level _buffer accumulates across every
1329
- // unit in the same Node process (see workflow-logger.ts module header).
1330
- _resetLogs();
1331
1341
  const dispatchKey = `${unitType}/${unitId}`;
1332
- s.unitDispatchCount.set(dispatchKey, (s.unitDispatchCount.get(dispatchKey) ?? 0) + 1);
1333
- s.currentUnit = { type: unitType, id: unitId, startedAt: Date.now() };
1334
- s.lastGitActionFailure = null;
1335
- s.lastGitActionStatus = null;
1336
- s.lastUnitAgentEndMessages = null;
1337
- setCurrentPhase(unitType, {
1338
- basePath: s.basePath,
1339
- traceId: ic.flowId,
1340
- turnId: `iter-${ic.iteration}`,
1341
- causedBy: "unit-start",
1342
- });
1343
- s.lastToolInvocationError = null; // #2883: clear stale error from previous unit
1344
- const unitStartSeq = ic.nextSeq();
1345
- deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: unitStartSeq, eventType: "unit-start", data: { unitType, unitId } });
1346
- deps.captureAvailableSkills();
1347
- writeUnitRuntimeRecord(s.basePath, unitType, unitId, s.currentUnit.startedAt, {
1348
- phase: "dispatched",
1349
- wrapupWarningSent: false,
1350
- timeoutAt: null,
1351
- lastProgressAt: s.currentUnit.startedAt,
1352
- progressCount: 0,
1353
- lastProgressKind: "dispatch",
1354
- recoveryAttempts: 0, // Reset so re-dispatched units get full recovery budget (#2322)
1355
- });
1342
+ const nextDispatchCount = (s.unitDispatchCount.get(dispatchKey) ?? 0) + 1;
1356
1343
  // Status bar (widget + preconditions deferred until after model selection — see #2899)
1357
1344
  ctx.ui.setStatus("gsd-auto", "auto");
1358
1345
  if (mid)
@@ -1406,7 +1393,7 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
1406
1393
  finalPrompt = `${capped}\n\n---\n\n${finalPrompt}`;
1407
1394
  s.pendingCrashRecovery = null;
1408
1395
  }
1409
- else if ((s.unitDispatchCount.get(dispatchKey) ?? 0) > 1) {
1396
+ else if (nextDispatchCount > 1) {
1410
1397
  const diagnostic = deps.getDeepDiagnostic(s.basePath);
1411
1398
  if (diagnostic) {
1412
1399
  const cappedDiag = diagnostic.length > MAX_RECOVERY_CHARS
@@ -1445,6 +1432,11 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
1445
1432
  logWarning("engine", "Prompt reorder failed", { error: msg });
1446
1433
  }
1447
1434
  // Select and apply model (with tier escalation on retry — normal units only)
1435
+ const prevUnitRouting = s.currentUnitRouting;
1436
+ const prevUnitModel = s.currentUnitModel;
1437
+ const prevDispatchedModelId = s.currentDispatchedModelId;
1438
+ const prevSessionModel = ctx.model;
1439
+ const prevSessionThinkingLevel = pi.getThinkingLevel();
1448
1440
  const modelResult = await deps.selectAndApplyModel(ctx, pi, unitType, unitId, s.basePath, prefs, s.verbose, s.autoModeStartModel, sidecarItem ? undefined : { isRetry, previousTier }, undefined, s.manualSessionModelOverride, s.autoModeStartThinkingLevel);
1449
1441
  s.currentUnitRouting =
1450
1442
  modelResult.routing;
@@ -1488,12 +1480,58 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
1488
1480
  ? ctx.modelRegistry.getProviderAuthMode(ctx.model.provider)
1489
1481
  : undefined,
1490
1482
  baseUrl: s.currentUnitModel?.baseUrl ?? ctx.model?.baseUrl,
1483
+ activeTools: typeof pi.getActiveTools === "function" ? pi.getActiveTools() : [],
1491
1484
  });
1492
1485
  if (compatibilityError) {
1486
+ s.currentUnitRouting = prevUnitRouting;
1487
+ s.currentUnitModel = prevUnitModel;
1488
+ s.currentDispatchedModelId = prevDispatchedModelId;
1489
+ if (s.checkpointSha) {
1490
+ cleanupCheckpoint(s.basePath, unitId);
1491
+ s.checkpointSha = null;
1492
+ }
1493
+ if (prevSessionModel) {
1494
+ const ok = await pi.setModel(prevSessionModel, { persist: false });
1495
+ if (!ok) {
1496
+ ctx.ui.notify("Failed to restore previous session model after compatibility check failure.", "warning");
1497
+ }
1498
+ if (prevSessionThinkingLevel) {
1499
+ pi.setThinkingLevel(prevSessionThinkingLevel);
1500
+ }
1501
+ }
1493
1502
  ctx.ui.notify(compatibilityError, "error");
1494
1503
  await deps.stopAuto(ctx, pi, compatibilityError);
1495
1504
  return { action: "break", reason: "workflow-capability" };
1496
1505
  }
1506
+ // Scope workflow-logger buffer to this unit so post-finalize drains are
1507
+ // per-unit. Without this, the module-level _buffer accumulates across every
1508
+ // unit in the same Node process (see workflow-logger.ts module header).
1509
+ _resetLogs();
1510
+ const unitStartedAt = Date.now();
1511
+ s.unitDispatchCount.set(dispatchKey, nextDispatchCount);
1512
+ s.currentUnit = { type: unitType, id: unitId, startedAt: unitStartedAt };
1513
+ s.lastGitActionFailure = null;
1514
+ s.lastGitActionStatus = null;
1515
+ s.lastUnitAgentEndMessages = null;
1516
+ setCurrentPhase(unitType, {
1517
+ basePath: s.basePath,
1518
+ traceId: ic.flowId,
1519
+ turnId: `iter-${ic.iteration}`,
1520
+ causedBy: "unit-start",
1521
+ });
1522
+ s.lastToolInvocationError = null; // #2883: clear stale error from previous unit
1523
+ const unitStartSeq = ic.nextSeq();
1524
+ deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: unitStartSeq, eventType: "unit-start", data: { unitType, unitId } });
1525
+ deps.captureAvailableSkills();
1526
+ writeUnitRuntimeRecord(s.basePath, unitType, unitId, unitStartedAt, {
1527
+ phase: "dispatched",
1528
+ wrapupWarningSent: false,
1529
+ timeoutAt: null,
1530
+ lastProgressAt: unitStartedAt,
1531
+ progressCount: 0,
1532
+ lastProgressKind: "dispatch",
1533
+ recoveryAttempts: 0, // Reset so re-dispatched units get full recovery budget (#2322)
1534
+ });
1497
1535
  // Progress widget + preconditions — deferred to after model selection so the
1498
1536
  // widget's first render tick shows the correct model (#2899).
1499
1537
  deps.updateProgressWidget(ctx, unitType, unitId, state);
@@ -1923,6 +1961,18 @@ export async function runFinalize(ic, iterData, loopState, sidecarItem) {
1923
1961
  lastProgressAt: Date.now(),
1924
1962
  lastProgressKind: "finalize-success",
1925
1963
  });
1964
+ if (!preUnitSnapshot.type.startsWith("hook/") &&
1965
+ preUnitSnapshot.type !== "custom-step" &&
1966
+ preUnitSnapshot.type !== "complete-milestone") {
1967
+ setAutoOutcomeWidget(ctx, {
1968
+ ...buildPhaseHandoffOutcome({
1969
+ unitType: preUnitSnapshot.type,
1970
+ unitId: preUnitSnapshot.id,
1971
+ agentEndMessages: s.lastUnitAgentEndMessages,
1972
+ }),
1973
+ startedAt: s.autoStartTime,
1974
+ });
1975
+ }
1926
1976
  }
1927
1977
  s.currentUnit = null;
1928
1978
  clearCurrentPhase();
@@ -4,6 +4,18 @@ import { createRequire } from "node:module";
4
4
  const require = createRequire(import.meta.url);
5
5
  const DEFAULT_MEMORY_PRESSURE_THRESHOLD = 0.85;
6
6
  const DEFAULT_HEAP_LIMIT_MB = 4096;
7
+ /**
8
+ * Returns true on auto-mode startup, then every configured interval.
9
+ *
10
+ * Iteration 1 is checked explicitly so early session memory pressure cannot
11
+ * bypass the periodic interval guard.
12
+ */
13
+ export function shouldCheckMemoryPressure(iteration, interval) {
14
+ if (!Number.isInteger(interval) || interval <= 0) {
15
+ throw new Error("Memory pressure check interval must be a positive integer");
16
+ }
17
+ return iteration === 1 || iteration % interval === 0;
18
+ }
7
19
  function defaultHeapLimitBytes() {
8
20
  const v8 = require("node:v8");
9
21
  const limit = v8.getHeapStatistics?.().heap_size_limit;
@@ -27,6 +27,19 @@ export function extractUatSliceId(unitId) {
27
27
  return slice;
28
28
  return null;
29
29
  }
30
+ export function buildPhaseHandoffOutcome(input) {
31
+ const phase = unitPhaseLabel(input.unitType);
32
+ const detail = extractLastAssistantSummary(input.agentEndMessages) ??
33
+ `Completed ${unitVerb(input.unitType)} ${input.unitId}.`;
34
+ return {
35
+ status: "complete",
36
+ title: `${phase} complete`,
37
+ detail,
38
+ unitLabel: `${unitVerb(input.unitType)} ${input.unitId}`,
39
+ nextAction: "Preparing the next phase. Review this handoff while the next session starts.",
40
+ commands: ["/gsd status for overview", "/gsd visualize to inspect", "/gsd notifications for history"],
41
+ };
42
+ }
30
43
  // ─── Unit Description Helpers ─────────────────────────────────────────────────
31
44
  export function unitVerb(unitType) {
32
45
  if (unitType.startsWith("hook/"))
@@ -464,7 +477,6 @@ export function _resetWidgetModeForTests() {
464
477
  export function updateProgressWidget(ctx, unitType, unitId, state, accessors, tierBadge) {
465
478
  if (!ctx.hasUI)
466
479
  return;
467
- ctx.ui.setWidget("gsd-outcome", undefined);
468
480
  // Welcome header is a startup-only banner — permanently suppress it once
469
481
  // auto-mode activates. The dashboard widget owns all status from here.
470
482
  // Note: setHeader(undefined) restores the built-in header (logo +
@@ -927,3 +939,56 @@ function normalizeRollupText(value) {
927
939
  return null;
928
940
  return clean;
929
941
  }
942
+ function isAssistantMessage(value) {
943
+ if (!value || typeof value !== "object")
944
+ return false;
945
+ const record = value;
946
+ if (record.role === "assistant")
947
+ return true;
948
+ const message = record.message;
949
+ if (message && typeof message === "object") {
950
+ return message.role === "assistant";
951
+ }
952
+ return false;
953
+ }
954
+ function extractLastAssistantSummary(messages) {
955
+ if (!messages || messages.length === 0)
956
+ return null;
957
+ for (let i = messages.length - 1; i >= 0; i--) {
958
+ if (!isAssistantMessage(messages[i]))
959
+ continue;
960
+ const text = extractMessageText(messages[i]);
961
+ const clean = normalizeRollupText(text);
962
+ if (clean)
963
+ return truncateToWidth(clean, 220, "…");
964
+ }
965
+ return null;
966
+ }
967
+ function extractMessageText(value) {
968
+ if (typeof value === "string")
969
+ return value;
970
+ if (!value || typeof value !== "object")
971
+ return null;
972
+ const record = value;
973
+ if (typeof record.content === "string")
974
+ return record.content;
975
+ const message = record.message;
976
+ if (message && typeof message === "object") {
977
+ return extractMessageText(message);
978
+ }
979
+ const content = record.content;
980
+ if (Array.isArray(content)) {
981
+ const parts = content
982
+ .map((part) => {
983
+ if (typeof part === "string")
984
+ return part;
985
+ if (!part || typeof part !== "object")
986
+ return "";
987
+ const partRecord = part;
988
+ return typeof partRecord.text === "string" ? partRecord.text : "";
989
+ })
990
+ .filter(Boolean);
991
+ return parts.length > 0 ? parts.join(" ") : null;
992
+ }
993
+ return null;
994
+ }
@@ -224,6 +224,7 @@ export async function dispatchDirectPhase(ctx, pi, phase, base) {
224
224
  unitType,
225
225
  authMode: ctx.model?.provider ? ctx.modelRegistry.getProviderAuthMode(ctx.model.provider) : undefined,
226
226
  baseUrl: ctx.model?.baseUrl,
227
+ activeTools: typeof pi.getActiveTools === "function" ? pi.getActiveTools() : [],
227
228
  });
228
229
  if (compatibilityError) {
229
230
  ctx.ui.notify(compatibilityError, "error");
@@ -102,6 +102,9 @@ function missingSliceStop(mid, phase) {
102
102
  level: "error",
103
103
  };
104
104
  }
105
+ function isRegistryMilestoneComplete(state, mid) {
106
+ return state.registry.some((milestone) => milestone.id === mid && milestone.status === "complete");
107
+ }
105
108
  /**
106
109
  * Check for milestone slices missing SUMMARY files.
107
110
  * Returns array of missing slice IDs, or empty array if all present or DB unavailable.
@@ -247,6 +250,8 @@ export const DISPATCH_RULES = [
247
250
  return null;
248
251
  if (!MILESTONE_ID_RE.test(mid))
249
252
  return null;
253
+ if (isRegistryMilestoneComplete(state, mid))
254
+ return null;
250
255
  // Align with the plan-v2 gate's lookup semantics: whitespace-only counts
251
256
  // as missing, and an auto worktree may fall back to GSD_PROJECT_ROOT.
252
257
  if (hasFinalizedMilestoneContext(basePath, mid))
@@ -294,9 +299,7 @@ export const DISPATCH_RULES = [
294
299
  const attempts = incrementUatCount(basePath, mid, sliceId);
295
300
  if (attempts > MAX_UAT_ATTEMPTS) {
296
301
  return {
297
- action: "stop",
298
- reason: `run-uat for ${mid}/${sliceId} has been dispatched ${attempts - 1} times without producing a verdict. Verification commands may be broken — fix the UAT spec or manually write an ASSESSMENT verdict.`,
299
- level: "warning",
302
+ action: "skip",
300
303
  };
301
304
  }
302
305
  const uatFile = resolveSliceFile(basePath, mid, sliceId, "UAT");
@@ -557,6 +560,8 @@ export const DISPATCH_RULES = [
557
560
  match: async ({ state, mid, midTitle, basePath, prefs, structuredQuestionsAvailable }) => {
558
561
  if (state.phase !== "pre-planning")
559
562
  return null;
563
+ if (isRegistryMilestoneComplete(state, mid))
564
+ return null;
560
565
  const contextFile = resolveMilestoneFile(basePath, mid, "CONTEXT");
561
566
  const hasContext = !!(contextFile && (await loadFile(contextFile)));
562
567
  if (hasContext)
@@ -609,7 +614,7 @@ export const DISPATCH_RULES = [
609
614
  },
610
615
  },
611
616
  {
612
- name: "planning (require_slice_discussion) → pause for discussion (#3454)",
617
+ name: "planning (require_slice_discussion) → pause for discussion",
613
618
  match: async ({ state, mid, basePath, prefs }) => {
614
619
  if (state.phase !== "planning")
615
620
  return null;
@@ -1016,7 +1021,7 @@ export const DISPATCH_RULES = [
1016
1021
  mkdirSync(mDir, { recursive: true });
1017
1022
  const validationPath = join(mDir, buildMilestoneFileName(mid, "VALIDATION"));
1018
1023
  const skipSource = trivialVariant
1019
- ? "trivial-scope pipeline variant (#4781)"
1024
+ ? "trivial-scope pipeline variant"
1020
1025
  : "`skip_milestone_validation` preference";
1021
1026
  const skipValidationReason = trivialVariant ? "trivial-scope" : "preference";
1022
1027
  const content = [
@@ -1091,19 +1096,19 @@ export const DISPATCH_RULES = [
1091
1096
  return { action: "skip" };
1092
1097
  }
1093
1098
  }
1094
- // Safety guard (#2675): block completion when VALIDATION verdict is
1095
- // needs-remediation. The state machine treats needs-remediation as
1096
- // terminal (to prevent validate-milestone loops per #832), but
1097
- // completing-milestone should NOT proceed — remediation work is needed.
1099
+ // Safety guard (#2675, #5747, #5920): block completion when VALIDATION
1100
+ // verdict is anything other than pass. The state machine treats these
1101
+ // verdicts as terminal, but completing-milestone should NOT proceed
1102
+ // remediation or human attention is needed.
1098
1103
  const validationFile = resolveMilestoneFile(basePath, mid, "VALIDATION");
1099
1104
  if (validationFile) {
1100
1105
  const validationContent = await loadFile(validationFile);
1101
1106
  if (validationContent) {
1102
1107
  const verdict = extractVerdict(validationContent);
1103
- if (verdict === "needs-remediation") {
1108
+ if (verdict !== "pass") {
1104
1109
  return {
1105
1110
  action: "stop",
1106
- reason: `Cannot complete milestone ${mid}: VALIDATION verdict is "needs-remediation". Address the remediation findings and re-run validation, or update the verdict manually.`,
1111
+ reason: `Cannot complete milestone ${mid}: VALIDATION verdict is "${verdict}". Address the validation findings and re-run validation, or update the verdict manually.`,
1107
1112
  level: "warning",
1108
1113
  };
1109
1114
  }
@@ -1118,16 +1123,12 @@ export const DISPATCH_RULES = [
1118
1123
  level: "error",
1119
1124
  };
1120
1125
  }
1121
- // Safety guard (#1703): verify the milestone produced implementation
1122
- // artifacts (non-.gsd/ files). A milestone with only plan files and
1123
- // zero implementation code should not be marked complete.
1126
+ // Safety signal (#1703, #5097): detect milestones with only .gsd/
1127
+ // artifacts. This no longer hard-blocks completion because some
1128
+ // milestones are intentionally planning/documentation-only.
1124
1129
  const artifactCheck = hasImplementationArtifacts(basePath, mid);
1125
1130
  if (artifactCheck === "absent") {
1126
- return {
1127
- action: "stop",
1128
- reason: `Cannot complete milestone ${mid}: no implementation files found outside .gsd/. The milestone has only plan files — actual code changes are required.`,
1129
- level: "error",
1130
- };
1131
+ logWarning("dispatch", `Milestone ${mid} has no implementation files outside .gsd/ — continuing complete-milestone dispatch (planning-only/documentation-only milestone).`);
1131
1132
  }
1132
1133
  if (artifactCheck === "unknown") {
1133
1134
  logWarning("dispatch", `Implementation artifact check inconclusive for ${mid} — proceeding (git context unavailable)`);
@@ -494,6 +494,8 @@ autoModeStartThinkingLevel) {
494
494
  * Handles formats: "provider/model", "bare-id", "org/model-name" (OpenRouter).
495
495
  */
496
496
  export function resolveModelId(modelId, availableModels, currentProvider) {
497
+ if (!modelId)
498
+ return undefined;
497
499
  const slashIdx = modelId.indexOf("/");
498
500
  if (slashIdx !== -1) {
499
501
  const maybeProvider = modelId.substring(0, slashIdx);