gsd-pi 2.82.0-dev.c22380fc3 → 2.82.0-dev.e7a7f1ed5

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 (390) hide show
  1. package/README.md +5 -4
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/GSD-WORKFLOW.md +10 -1
  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/cmux/index.js +5 -0
  7. package/dist/resources/extensions/gsd/auto/infra-errors.js +9 -3
  8. package/dist/resources/extensions/gsd/auto/loop.js +5 -5
  9. package/dist/resources/extensions/gsd/auto/orchestrator.js +11 -0
  10. package/dist/resources/extensions/gsd/auto/phases.js +81 -31
  11. package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +12 -0
  12. package/dist/resources/extensions/gsd/auto-dashboard.js +66 -1
  13. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +1 -0
  14. package/dist/resources/extensions/gsd/auto-dispatch.js +18 -17
  15. package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
  16. package/dist/resources/extensions/gsd/auto-post-unit.js +233 -127
  17. package/dist/resources/extensions/gsd/auto-prompts.js +2 -2
  18. package/dist/resources/extensions/gsd/auto-recovery.js +71 -14
  19. package/dist/resources/extensions/gsd/auto-start.js +87 -14
  20. package/dist/resources/extensions/gsd/auto-verification.js +45 -26
  21. package/dist/resources/extensions/gsd/auto-worktree.js +176 -10
  22. package/dist/resources/extensions/gsd/auto.js +37 -5
  23. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +31 -7
  24. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +9 -8
  25. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +4 -2
  26. package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +21 -9
  27. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +16 -2
  28. package/dist/resources/extensions/gsd/clean-root-preflight.js +170 -8
  29. package/dist/resources/extensions/gsd/commands/catalog.js +4 -1
  30. package/dist/resources/extensions/gsd/commands/handlers/core.js +37 -0
  31. package/dist/resources/extensions/gsd/commands-bootstrap.js +5 -0
  32. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +7 -2
  33. package/dist/resources/extensions/gsd/crash-recovery.js +43 -5
  34. package/dist/resources/extensions/gsd/db/milestone-leases.js +24 -0
  35. package/dist/resources/extensions/gsd/db/unit-dispatches.js +3 -2
  36. package/dist/resources/extensions/gsd/dispatch-guard.js +2 -2
  37. package/dist/resources/extensions/gsd/doctor-git-checks.js +46 -1
  38. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +28 -11
  39. package/dist/resources/extensions/gsd/doctor.js +2 -28
  40. package/dist/resources/extensions/gsd/export-html.js +27 -425
  41. package/dist/resources/extensions/gsd/git-service.js +45 -3
  42. package/dist/resources/extensions/gsd/gsd-db.js +21 -6
  43. package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -3
  44. package/dist/resources/extensions/gsd/guided-flow.js +101 -116
  45. package/dist/resources/extensions/gsd/guided-unit-context.js +23 -0
  46. package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
  47. package/dist/resources/extensions/gsd/migration-auto-check.js +12 -17
  48. package/dist/resources/extensions/gsd/milestone-actions.js +11 -4
  49. package/dist/resources/extensions/gsd/native-git-bridge.js +48 -12
  50. package/dist/resources/extensions/gsd/pending-auto-start.js +52 -0
  51. package/dist/resources/extensions/gsd/post-execution-checks.js +73 -2
  52. package/dist/resources/extensions/gsd/pre-execution-checks.js +28 -1
  53. package/dist/resources/extensions/gsd/prompt-loader.js +1 -1
  54. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  55. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  56. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
  57. package/dist/resources/extensions/gsd/prompts/discuss.md +9 -9
  58. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
  59. package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
  60. package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -4
  61. package/dist/resources/extensions/gsd/prompts/queue.md +4 -4
  62. package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  63. package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  64. package/dist/resources/extensions/gsd/queue-reorder-ui.js +30 -13
  65. package/dist/resources/extensions/gsd/smart-entry-routing.js +36 -0
  66. package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +6 -1
  67. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +9 -14
  68. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +19 -24
  69. package/dist/resources/extensions/gsd/status-guards.js +11 -0
  70. package/dist/resources/extensions/gsd/templates/plan.md +8 -5
  71. package/dist/resources/extensions/gsd/templates/task-plan.md +4 -2
  72. package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -8
  73. package/dist/resources/extensions/gsd/tools/complete-slice.js +6 -8
  74. package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -1
  75. package/dist/resources/extensions/gsd/tools/plan-slice.js +89 -14
  76. package/dist/resources/extensions/gsd/unit-context-manifest.js +32 -10
  77. package/dist/resources/extensions/gsd/validation.js +23 -1
  78. package/dist/resources/extensions/gsd/verification-gate.js +68 -7
  79. package/dist/resources/extensions/gsd/verification-verdict.js +26 -0
  80. package/dist/resources/extensions/gsd/workflow-mcp.js +17 -1
  81. package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
  82. package/dist/resources/extensions/gsd/worktree-lifecycle.js +33 -8
  83. package/dist/resources/extensions/shared/html-shell.js +388 -0
  84. package/dist/resources/extensions/subagent/index.js +448 -78
  85. package/dist/resources/extensions/subagent/launch.js +77 -0
  86. package/dist/resources/extensions/subagent/run-store.js +148 -0
  87. package/dist/resources/extensions/visual-brief/artifact-policy.js +29 -0
  88. package/dist/resources/extensions/visual-brief/extension-manifest.json +8 -0
  89. package/dist/resources/extensions/visual-brief/index.js +5 -0
  90. package/dist/resources/extensions/visual-brief/page-contract.js +124 -0
  91. package/dist/resources/extensions/visual-brief/prompts.js +140 -0
  92. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  93. package/dist/web/standalone/.next/BUILD_ID +1 -1
  94. package/dist/web/standalone/.next/app-path-routes-manifest.json +13 -13
  95. package/dist/web/standalone/.next/build-manifest.json +3 -3
  96. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  97. package/dist/web/standalone/.next/react-loadable-manifest.json +3 -3
  98. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  99. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  100. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  108. package/dist/web/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  109. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  110. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  111. package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -7
  112. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
  113. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -5
  115. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -5
  118. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  120. package/dist/web/standalone/.next/server/app/index.html +1 -1
  121. package/dist/web/standalone/.next/server/app/index.rsc +4 -7
  122. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -7
  124. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -5
  126. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -5
  127. package/dist/web/standalone/.next/server/app/page.js +2 -2
  128. package/dist/web/standalone/.next/server/app/page.js.nft.json +1 -1
  129. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/app-paths-manifest.json +13 -13
  131. package/dist/web/standalone/.next/server/chunks/4266.js +2 -0
  132. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  136. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  137. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  138. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  139. package/dist/web/standalone/.next/static/chunks/2973.33f26573894b6153.js +2 -0
  140. package/dist/web/standalone/.next/static/chunks/{8359.e059d86b255fce1c.js → 8359.7eb3bb8f8ecf4c01.js} +2 -2
  141. package/dist/web/standalone/.next/static/chunks/app/layout-8c10ec293ae0f1d5.js +1 -0
  142. package/dist/web/standalone/.next/static/chunks/{webpack-de742b64187e13fe.js → webpack-9a4db269f9ed63ad.js} +1 -1
  143. package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
  144. package/package.json +4 -4
  145. package/packages/mcp-server/src/workflow-tools.test.ts +1 -1
  146. package/packages/native/tsconfig.json +2 -1
  147. package/packages/native/tsconfig.tsbuildinfo +1 -1
  148. package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts.map +1 -1
  149. package/packages/pi-ai/dist/providers/google-gemini-cli.js +5 -0
  150. package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
  151. package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts +2 -0
  152. package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts.map +1 -0
  153. package/packages/pi-ai/dist/providers/google-gemini-cli.test.js +41 -0
  154. package/packages/pi-ai/dist/providers/google-gemini-cli.test.js.map +1 -0
  155. package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
  156. package/packages/pi-ai/dist/providers/openai-codex-responses.js +82 -1
  157. package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  158. package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts +2 -0
  159. package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts.map +1 -0
  160. package/packages/pi-ai/dist/providers/openai-codex-responses.test.js +52 -0
  161. package/packages/pi-ai/dist/providers/openai-codex-responses.test.js.map +1 -0
  162. package/packages/pi-ai/dist/providers/simple-options.d.ts +2 -4
  163. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  164. package/packages/pi-ai/dist/providers/simple-options.js +5 -6
  165. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  166. package/packages/pi-ai/dist/providers/simple-options.test.d.ts +2 -0
  167. package/packages/pi-ai/dist/providers/simple-options.test.d.ts.map +1 -0
  168. package/packages/pi-ai/dist/providers/simple-options.test.js +50 -0
  169. package/packages/pi-ai/dist/providers/simple-options.test.js.map +1 -0
  170. package/packages/pi-ai/src/providers/google-gemini-cli.test.ts +49 -0
  171. package/packages/pi-ai/src/providers/google-gemini-cli.ts +7 -0
  172. package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +63 -0
  173. package/packages/pi-ai/src/providers/openai-codex-responses.ts +91 -1
  174. package/packages/pi-ai/src/providers/simple-options.test.ts +60 -0
  175. package/packages/pi-ai/src/providers/simple-options.ts +5 -6
  176. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  177. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts +2 -0
  178. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts.map +1 -0
  179. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js +66 -0
  180. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js.map +1 -0
  181. package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
  182. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  183. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  184. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +24 -6
  185. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  186. package/packages/pi-coding-agent/src/core/agent-session-thinking-level.test.ts +79 -0
  187. package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
  188. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +23 -7
  189. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  190. package/packages/pi-tui/dist/__tests__/terminal.test.d.ts +2 -0
  191. package/packages/pi-tui/dist/__tests__/terminal.test.d.ts.map +1 -0
  192. package/packages/pi-tui/dist/__tests__/terminal.test.js +103 -0
  193. package/packages/pi-tui/dist/__tests__/terminal.test.js.map +1 -0
  194. package/packages/pi-tui/dist/terminal.d.ts +2 -0
  195. package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
  196. package/packages/pi-tui/dist/terminal.js +12 -0
  197. package/packages/pi-tui/dist/terminal.js.map +1 -1
  198. package/packages/pi-tui/src/__tests__/terminal.test.ts +121 -0
  199. package/packages/pi-tui/src/terminal.ts +11 -0
  200. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  201. package/src/resources/GSD-WORKFLOW.md +10 -1
  202. package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
  203. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +1 -1
  204. package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
  205. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +9 -0
  206. package/src/resources/extensions/cmux/index.ts +6 -0
  207. package/src/resources/extensions/gsd/auto/contracts.ts +14 -6
  208. package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
  209. package/src/resources/extensions/gsd/auto/loop.ts +8 -5
  210. package/src/resources/extensions/gsd/auto/orchestrator.ts +11 -0
  211. package/src/resources/extensions/gsd/auto/phases.ts +90 -38
  212. package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +13 -0
  213. package/src/resources/extensions/gsd/auto-dashboard.ts +72 -1
  214. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +1 -0
  215. package/src/resources/extensions/gsd/auto-dispatch.ts +19 -17
  216. package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
  217. package/src/resources/extensions/gsd/auto-post-unit.ts +266 -139
  218. package/src/resources/extensions/gsd/auto-prompts.ts +2 -2
  219. package/src/resources/extensions/gsd/auto-recovery.ts +74 -11
  220. package/src/resources/extensions/gsd/auto-start.ts +94 -12
  221. package/src/resources/extensions/gsd/auto-verification.ts +58 -36
  222. package/src/resources/extensions/gsd/auto-worktree.ts +193 -10
  223. package/src/resources/extensions/gsd/auto.ts +40 -5
  224. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +42 -7
  225. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +9 -8
  226. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +4 -2
  227. package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +19 -7
  228. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +19 -3
  229. package/src/resources/extensions/gsd/clean-root-preflight.ts +174 -8
  230. package/src/resources/extensions/gsd/commands/catalog.ts +4 -1
  231. package/src/resources/extensions/gsd/commands/handlers/core.ts +40 -0
  232. package/src/resources/extensions/gsd/commands-bootstrap.ts +10 -0
  233. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +8 -3
  234. package/src/resources/extensions/gsd/crash-recovery.ts +44 -4
  235. package/src/resources/extensions/gsd/db/milestone-leases.ts +26 -0
  236. package/src/resources/extensions/gsd/db/unit-dispatches.ts +4 -3
  237. package/src/resources/extensions/gsd/dispatch-guard.ts +2 -2
  238. package/src/resources/extensions/gsd/doctor-git-checks.ts +45 -1
  239. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
  240. package/src/resources/extensions/gsd/doctor-types.ts +1 -0
  241. package/src/resources/extensions/gsd/doctor.ts +2 -27
  242. package/src/resources/extensions/gsd/export-html.ts +27 -427
  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/status-guards.ts +13 -0
  272. package/src/resources/extensions/gsd/templates/plan.md +8 -5
  273. package/src/resources/extensions/gsd/templates/task-plan.md +4 -2
  274. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +71 -0
  275. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +116 -0
  276. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +56 -0
  277. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +80 -1
  278. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +35 -7
  279. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +53 -2
  280. package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +12 -1
  281. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +91 -6
  282. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +1 -0
  283. package/src/resources/extensions/gsd/tests/auto-stop-notification.test.ts +20 -0
  284. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
  285. package/src/resources/extensions/gsd/tests/brief-command.test.ts +89 -0
  286. package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +87 -0
  287. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +107 -2
  288. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +11 -2
  289. package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +16 -0
  290. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +4 -1
  291. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +5 -9
  292. package/src/resources/extensions/gsd/tests/complete-task.test.ts +3 -1
  293. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +86 -2
  294. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
  295. package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
  296. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +59 -2
  297. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +66 -0
  298. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
  299. package/src/resources/extensions/gsd/tests/doctor-empty-worktree.test.ts +65 -0
  300. package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +38 -0
  301. package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
  302. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +11 -0
  303. package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +2 -0
  304. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +106 -0
  305. package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +59 -11
  306. package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
  307. package/src/resources/extensions/gsd/tests/guided-tool-contract.test.ts +65 -0
  308. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +7 -7
  309. package/src/resources/extensions/gsd/tests/hook-model-resolution.test.ts +5 -0
  310. package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -2
  311. package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +9 -0
  312. package/src/resources/extensions/gsd/tests/integration/doctor-runtime.test.ts +20 -0
  313. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +112 -1
  314. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
  315. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +46 -0
  316. package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +179 -0
  317. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -1
  318. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +26 -18
  319. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +63 -2
  320. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +121 -1
  321. package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +55 -1
  322. package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +29 -5
  323. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +26 -0
  324. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
  325. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +225 -1
  326. package/src/resources/extensions/gsd/tests/plan-task.test.ts +17 -0
  327. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
  328. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +86 -0
  329. package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
  330. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +53 -0
  331. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +59 -0
  332. package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
  333. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +37 -1
  334. package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +54 -0
  335. package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +89 -2
  336. package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +2 -3
  337. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
  338. package/src/resources/extensions/gsd/tests/smart-entry-routing.test.ts +113 -0
  339. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +53 -2
  340. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +119 -23
  341. package/src/resources/extensions/gsd/tests/status-guards.test.ts +13 -1
  342. package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +64 -1
  343. package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +7 -3
  344. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +86 -7
  345. package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +29 -2
  346. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
  347. package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +78 -0
  348. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +19 -1
  349. package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +21 -1
  350. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +1 -1
  351. package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +39 -0
  352. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +64 -12
  353. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +54 -0
  354. package/src/resources/extensions/gsd/tools/complete-milestone.ts +8 -10
  355. package/src/resources/extensions/gsd/tools/complete-slice.ts +6 -8
  356. package/src/resources/extensions/gsd/tools/plan-milestone.ts +5 -1
  357. package/src/resources/extensions/gsd/tools/plan-slice.ts +98 -12
  358. package/src/resources/extensions/gsd/types.ts +1 -1
  359. package/src/resources/extensions/gsd/unit-context-manifest.ts +47 -11
  360. package/src/resources/extensions/gsd/validation.ts +23 -1
  361. package/src/resources/extensions/gsd/verification-gate.ts +78 -6
  362. package/src/resources/extensions/gsd/verification-verdict.ts +47 -0
  363. package/src/resources/extensions/gsd/workflow-mcp.ts +18 -1
  364. package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
  365. package/src/resources/extensions/gsd/worktree-lifecycle.ts +41 -8
  366. package/src/resources/extensions/shared/html-shell.ts +412 -0
  367. package/src/resources/extensions/subagent/index.ts +567 -103
  368. package/src/resources/extensions/subagent/launch.ts +131 -0
  369. package/src/resources/extensions/subagent/run-store.ts +218 -0
  370. package/src/resources/extensions/subagent/tests/launch.test.ts +115 -0
  371. package/src/resources/extensions/subagent/tests/run-store.test.ts +111 -0
  372. package/src/resources/extensions/visual-brief/artifact-policy.ts +41 -0
  373. package/src/resources/extensions/visual-brief/extension-manifest.json +8 -0
  374. package/src/resources/extensions/visual-brief/index.ts +8 -0
  375. package/src/resources/extensions/visual-brief/page-contract.ts +136 -0
  376. package/src/resources/extensions/visual-brief/prompts.ts +183 -0
  377. package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +212 -0
  378. package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
  379. package/dist/web/standalone/.next/static/chunks/2556.0527fea66e123b7f.js +0 -1
  380. package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +0 -1
  381. package/dist/web/standalone/.next/static/css/54ec2745c1da488b.css +0 -1
  382. package/dist/web/standalone/.next/static/css/de70bee13400563f.css +0 -1
  383. package/dist/web/standalone/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
  384. package/dist/web/standalone/.next/static/media/747892c23ea88013-s.woff2 +0 -0
  385. package/dist/web/standalone/.next/static/media/8d697b304b401681-s.woff2 +0 -0
  386. package/dist/web/standalone/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  387. package/dist/web/standalone/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
  388. package/dist/web/standalone/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  389. /package/dist/web/standalone/.next/static/{Wop3A7KRGyR06H3rla_1- → 4dSwdrs__8NwCZggxP9KF}/_buildManifest.js +0 -0
  390. /package/dist/web/standalone/.next/static/{Wop3A7KRGyR06H3rla_1- → 4dSwdrs__8NwCZggxP9KF}/_ssgManifest.js +0 -0
@@ -7,8 +7,8 @@
7
7
  *
8
8
  * Split into two functions called sequentially by auto-loop with
9
9
  * the verification gate between them:
10
- * 1. postUnitPreVerification() — commit, doctor, state rebuild, worktree sync, artifact verification
11
- * 2. postUnitPostVerification() — DB dual-write, hooks, triage, quick-tasks
10
+ * 1. postUnitPreVerification() — closeout git for non-task units, doctor, state rebuild, worktree sync, artifact verification
11
+ * 2. postUnitPostVerification() — post-verified task git, DB dual-write, hooks, triage, quick-tasks
12
12
  *
13
13
  * Extracted from the pre-loop agent_end handler in auto.ts.
14
14
  */
@@ -41,6 +41,7 @@ import {
41
41
  resolveExpectedArtifactPath,
42
42
  writeBlockerPlaceholder,
43
43
  diagnoseExpectedArtifact,
44
+ diagnoseWorktreeIntegrityFailure,
44
45
  } from "./auto-recovery.js";
45
46
  import { regenerateIfMissing } from "./workflow-projections.js";
46
47
  import { WorktreeStateProjection } from "./worktree-state-projection.js";
@@ -62,8 +63,7 @@ import { runSafely } from "./auto-utils.js";
62
63
  import type { AutoSession, SidecarItem } from "./auto/session.js";
63
64
  import { getEvidence, clearEvidenceFromDisk } from "./safety/evidence-collector.js";
64
65
  import { validateFileChanges } from "./safety/file-change-validator.js";
65
- // crossReferenceEvidence available for future use when verification_evidence is stored in DB
66
- // import { crossReferenceEvidence, type ClaimedEvidence } from "./safety/evidence-cross-ref.js";
66
+ import { crossReferenceEvidence, type ClaimedEvidence } from "./safety/evidence-cross-ref.js";
67
67
  import { validateContent } from "./safety/content-validator.js";
68
68
  import { resolveSafetyHarnessConfig } from "./safety/safety-harness.js";
69
69
  import { resolveExpectedArtifactPath as resolveArtifactForContent } from "./auto-artifact-paths.js";
@@ -164,7 +164,7 @@ async function buildTaskCommitContextForUnit(
164
164
  sliceTitle: stripKnownIdPrefix(slice?.title, sid),
165
165
  oneLiner: summary?.oneLiner || task?.one_liner || undefined,
166
166
  keyFiles:
167
- summary?.frontmatter.key_files?.filter(f => !f.includes("{{")) ??
167
+ summary?.frontmatter.key_files?.filter(f => !f.includes("{{") && f.trim() !== "(none)") ??
168
168
  task?.key_files ??
169
169
  undefined,
170
170
  issueNumber: ghIssueNumber,
@@ -222,6 +222,10 @@ export function _shouldDispatchQuickTaskForTest(
222
222
  state.currentUnit.type !== "quick-task";
223
223
  }
224
224
 
225
+ export function shouldDeferCloseoutGitAction(unitType: string): boolean {
226
+ return unitType === "execute-task";
227
+ }
228
+
225
229
  /** Unit types that only touch `.gsd/` internal state files (no code changes).
226
230
  * Auto-commit is skipped for these — their state files are picked up by the
227
231
  * next actual task commit via `smartStage()`. */
@@ -378,6 +382,23 @@ export function buildStepCompleteMessage(nextState: import("./types.js").GSDStat
378
382
  + `Run /clear, then /gsd to continue (or /gsd auto to run continuously).`;
379
383
  }
380
384
 
385
+ /**
386
+ * Decide whether step mode should stop at the step wizard after a unit finishes.
387
+ *
388
+ * @param currentUnitType The just-finished unit type, such as "execute-task" or
389
+ * "complete-milestone"; may be null/undefined when no current unit is known.
390
+ * @param phaseAfterUnit The freshly derived next phase, such as "executing" or
391
+ * "complete"; may be null/undefined if state derivation failed.
392
+ * @returns true to show the step wizard; false to keep the loop running so
393
+ * terminal milestone completion can reach the merge/finalization path.
394
+ */
395
+ export function shouldReturnStepWizardAfterUnit(
396
+ currentUnitType: string | null | undefined,
397
+ phaseAfterUnit: string | null | undefined,
398
+ ): boolean {
399
+ return currentUnitType !== "complete-milestone" && phaseAfterUnit !== "complete";
400
+ }
401
+
381
402
  export interface PreVerificationOpts {
382
403
  skipSettleDelay?: boolean;
383
404
  skipWorktreeSync?: boolean;
@@ -410,6 +431,11 @@ function artifactValidationKind(unitType: string): "project" | "requirements" |
410
431
  }
411
432
 
412
433
  function describeArtifactVerificationFailure(unitType: string, unitId: string, basePath: string): string {
434
+ const worktreeFailure = diagnoseWorktreeIntegrityFailure(basePath);
435
+ if (worktreeFailure) {
436
+ return `${worktreeFailure} Unit: ${unitType} ${unitId}.`;
437
+ }
438
+
413
439
  const artifactPath = resolveExpectedArtifactPath(unitType, unitId, basePath);
414
440
  if (!artifactPath) {
415
441
  return `Artifact verification failed: ${unitType} "${unitId}" has no resolvable artifact path.`;
@@ -466,6 +492,164 @@ export async function autoCommitUnit(
466
492
  }
467
493
  }
468
494
 
495
+ /**
496
+ * Execute the turn-level git action (commit, snapshot, or status-only).
497
+ *
498
+ * @param opts.softFailure - Defaults to false. When true, retry git failures,
499
+ * warn, and continue without pausing auto-mode; use for best-effort deferred
500
+ * closeout work where a git failure should not block the run.
501
+ */
502
+ async function runCloseoutGitAction(
503
+ pctx: PostUnitContext,
504
+ unit: NonNullable<AutoSession["currentUnit"]>,
505
+ opts?: { softFailure?: boolean },
506
+ ): Promise<"continue" | "dispatched"> {
507
+ const { s, ctx, pi, pauseAuto } = pctx;
508
+ const prefs = loadEffectiveGSDPreferences()?.preferences;
509
+ const uokFlags = resolveUokFlags(prefs);
510
+ const turnAction: TurnGitActionMode = uokFlags.gitops ? uokFlags.gitopsTurnAction : "commit";
511
+ const traceId = s.currentTraceId ?? `turn:${unit.startedAt}`;
512
+ const turnId = s.currentTurnId ?? `${unit.type}/${unit.id}/${unit.startedAt}`;
513
+
514
+ s.lastGitActionFailure = null;
515
+ s.lastGitActionStatus = null;
516
+
517
+ try {
518
+ let taskContext: TaskCommitContext | undefined;
519
+
520
+ if (turnAction === "commit" && unit.type === "execute-task") {
521
+ taskContext = await buildTaskCommitContextForUnit(s.basePath, unit.id);
522
+ }
523
+
524
+ // Invalidate the nativeHasChanges cache before auto-commit (#1853).
525
+ // The cache has a 10-second TTL and is keyed by basePath. A stale
526
+ // `false` result causes autoCommit to skip staging entirely.
527
+ _resetHasChangesCache();
528
+
529
+ const skipLifecycleCommit =
530
+ turnAction === "commit" && LIFECYCLE_ONLY_UNITS.has(unit.type);
531
+
532
+ if (skipLifecycleCommit) {
533
+ debugLog("postUnit", {
534
+ phase: "git-action-skipped",
535
+ reason: "lifecycle-only-unit",
536
+ unitType: unit.type,
537
+ unitId: unit.id,
538
+ });
539
+ } else {
540
+ const maxAttempts = opts?.softFailure ? 3 : 1;
541
+ let gitResult = runTurnGitAction({
542
+ basePath: s.basePath,
543
+ action: turnAction,
544
+ unitType: unit.type,
545
+ unitId: unit.id,
546
+ taskContext,
547
+ });
548
+ for (let attempt = 1; gitResult.status === "failed" && attempt < maxAttempts; attempt++) {
549
+ await new Promise((resolve) => setTimeout(resolve, 250 * attempt));
550
+ gitResult = runTurnGitAction({
551
+ basePath: s.basePath,
552
+ action: turnAction,
553
+ unitType: unit.type,
554
+ unitId: unit.id,
555
+ taskContext,
556
+ });
557
+ }
558
+
559
+ if (uokFlags.gitops) {
560
+ writeTurnGitTransaction({
561
+ basePath: s.basePath,
562
+ traceId,
563
+ turnId,
564
+ unitType: unit.type,
565
+ unitId: unit.id,
566
+ stage: "publish",
567
+ action: turnAction,
568
+ push: uokFlags.gitopsTurnPush,
569
+ status: gitResult.status,
570
+ error: gitResult.error,
571
+ metadata: {
572
+ dirty: gitResult.dirty,
573
+ commitMessage: gitResult.commitMessage,
574
+ snapshotLabel: gitResult.snapshotLabel,
575
+ },
576
+ });
577
+ }
578
+
579
+ if (gitResult.status === "failed") {
580
+ s.lastGitActionFailure = gitResult.error ?? `git ${turnAction} failed`;
581
+ s.lastGitActionStatus = "failed";
582
+ if (uokFlags.gitops && uokFlags.gates) {
583
+ const parsed = parseUnitId(unit.id);
584
+ const gateRunner = new UokGateRunner();
585
+ gateRunner.register({
586
+ id: "closeout-git-action",
587
+ type: "closeout",
588
+ execute: async () => ({
589
+ outcome: "fail",
590
+ failureClass: "git",
591
+ rationale: `turn git action "${turnAction}" failed`,
592
+ findings: gitResult.error ?? "unknown git failure",
593
+ }),
594
+ });
595
+ await gateRunner.run("closeout-git-action", {
596
+ basePath: s.basePath,
597
+ traceId,
598
+ turnId,
599
+ milestoneId: parsed.milestone ?? undefined,
600
+ sliceId: parsed.slice ?? undefined,
601
+ taskId: parsed.task ?? undefined,
602
+ unitType: unit.type,
603
+ unitId: unit.id,
604
+ });
605
+ }
606
+
607
+ const failureMsg = `Git ${turnAction} failed: ${(gitResult.error ?? "unknown error").split("\n")[0]}`;
608
+ ctx.ui.notify(failureMsg, opts?.softFailure ? "warning" : "error");
609
+ debugLog("postUnit", {
610
+ phase: opts?.softFailure ? "git-action-failed-soft" : "git-action-failed-blocking",
611
+ action: turnAction,
612
+ error: gitResult.error ?? "unknown error",
613
+ });
614
+ if (opts?.softFailure) {
615
+ return "continue";
616
+ }
617
+ await pauseAuto(ctx, pi);
618
+ return "dispatched";
619
+ }
620
+
621
+ s.lastGitActionStatus = "ok";
622
+
623
+ if (turnAction === "commit" && gitResult.commitMessage) {
624
+ ctx.ui.notify(`Committed: ${gitResult.commitMessage.split("\n")[0]}`, "info");
625
+ } else if (turnAction === "snapshot" && gitResult.snapshotLabel) {
626
+ ctx.ui.notify(`Snapshot recorded: ${gitResult.snapshotLabel}`, "info");
627
+ }
628
+ }
629
+ } catch (e) {
630
+ const message = e instanceof Error ? e.message : String(e);
631
+ s.lastGitActionFailure = message;
632
+ s.lastGitActionStatus = "failed";
633
+ debugLog("postUnit", { phase: "git-action", error: message, action: turnAction });
634
+ ctx.ui.notify(`Git ${turnAction} failed: ${message.split("\n")[0]}`, opts?.softFailure ? "warning" : "error");
635
+ if (opts?.softFailure) {
636
+ return "continue";
637
+ }
638
+ if (uokFlags.gitops) {
639
+ await pauseAuto(ctx, pi);
640
+ return "dispatched";
641
+ }
642
+ }
643
+
644
+ // GitHub sync (non-blocking, opt-in)
645
+ await runSafely("postUnit", "github-sync", async () => {
646
+ const { runGitHubSync } = await import("../github-sync/sync.js");
647
+ await runGitHubSync(s.basePath, unit.type, unit.id);
648
+ });
649
+
650
+ return "continue";
651
+ }
652
+
469
653
  /**
470
654
  * Pre-verification processing: parallel worker signal check, cache invalidation,
471
655
  * auto-commit, doctor run, state rebuild, worktree sync, artifact verification.
@@ -476,7 +660,7 @@ export async function autoCommitUnit(
476
660
  * - "retry" — artifact verification failed, s.pendingVerificationRetry set for loop re-iteration
477
661
  */
478
662
  export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreVerificationOpts): Promise<"dispatched" | "continue" | "retry"> {
479
- const { s, ctx, pi, buildSnapshotOpts, stopAuto, pauseAuto } = pctx;
663
+ const { s, ctx, pi, stopAuto, pauseAuto } = pctx;
480
664
 
481
665
  // ── Parallel worker signal check ──
482
666
  const milestoneLock = process.env.GSD_MILESTONE_LOCK;
@@ -502,135 +686,22 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
502
686
  await new Promise(r => setTimeout(r, 100));
503
687
  }
504
688
 
505
- const prefs = loadEffectiveGSDPreferences()?.preferences;
506
- const uokFlags = resolveUokFlags(prefs);
507
-
508
689
  // Turn-level git action (commit | snapshot | status-only)
509
690
  if (s.currentUnit) {
510
691
  const unit = s.currentUnit;
511
- const turnAction: TurnGitActionMode = uokFlags.gitops ? uokFlags.gitopsTurnAction : "commit";
512
- const traceId = s.currentTraceId ?? `turn:${unit.startedAt}`;
513
- const turnId = s.currentTurnId ?? `${unit.type}/${unit.id}/${unit.startedAt}`;
514
- s.lastGitActionFailure = null;
515
- s.lastGitActionStatus = null;
516
- try {
517
- let taskContext: TaskCommitContext | undefined;
518
-
519
- if (turnAction === "commit" && s.currentUnit.type === "execute-task") {
520
- taskContext = await buildTaskCommitContextForUnit(s.basePath, s.currentUnit.id);
521
- }
522
-
523
- // Invalidate the nativeHasChanges cache before auto-commit (#1853).
524
- // The cache has a 10-second TTL and is keyed by basePath. A stale
525
- // `false` result causes autoCommit to skip staging entirely, leaving
526
- // code files only in the working tree where they are destroyed by
527
- // `git worktree remove --force` during teardown.
528
- _resetHasChangesCache();
529
-
530
- const skipLifecycleCommit =
531
- turnAction === "commit" && LIFECYCLE_ONLY_UNITS.has(s.currentUnit.type);
532
-
533
- if (skipLifecycleCommit) {
534
- debugLog("postUnit", {
535
- phase: "git-action-skipped",
536
- reason: "lifecycle-only-unit",
537
- unitType: s.currentUnit.type,
538
- unitId: s.currentUnit.id,
539
- });
540
- } else {
541
- const gitResult = runTurnGitAction({
542
- basePath: s.basePath,
543
- action: turnAction,
544
- unitType: s.currentUnit.type,
545
- unitId: s.currentUnit.id,
546
- taskContext,
547
- });
548
-
549
- if (uokFlags.gitops) {
550
- writeTurnGitTransaction({
551
- basePath: s.basePath,
552
- traceId,
553
- turnId,
554
- unitType: unit.type,
555
- unitId: unit.id,
556
- stage: "publish",
557
- action: turnAction,
558
- push: uokFlags.gitopsTurnPush,
559
- status: gitResult.status,
560
- error: gitResult.error,
561
- metadata: {
562
- dirty: gitResult.dirty,
563
- commitMessage: gitResult.commitMessage,
564
- snapshotLabel: gitResult.snapshotLabel,
565
- },
566
- });
567
- }
568
-
569
- if (gitResult.status === "failed") {
570
- s.lastGitActionFailure = gitResult.error ?? `git ${turnAction} failed`;
571
- s.lastGitActionStatus = "failed";
572
- if (uokFlags.gitops && uokFlags.gates) {
573
- const parsed = parseUnitId(unit.id);
574
- const gateRunner = new UokGateRunner();
575
- gateRunner.register({
576
- id: "closeout-git-action",
577
- type: "closeout",
578
- execute: async () => ({
579
- outcome: "fail",
580
- failureClass: "git",
581
- rationale: `turn git action "${turnAction}" failed`,
582
- findings: gitResult.error ?? "unknown git failure",
583
- }),
584
- });
585
- await gateRunner.run("closeout-git-action", {
586
- basePath: s.basePath,
587
- traceId,
588
- turnId,
589
- milestoneId: parsed.milestone ?? undefined,
590
- sliceId: parsed.slice ?? undefined,
591
- taskId: parsed.task ?? undefined,
592
- unitType: unit.type,
593
- unitId: unit.id,
594
- });
595
- }
596
-
597
- const failureMsg = `Git ${turnAction} failed: ${(gitResult.error ?? "unknown error").split("\n")[0]}`;
598
- ctx.ui.notify(failureMsg, "error");
599
- debugLog("postUnit", {
600
- phase: "git-action-failed-blocking",
601
- action: turnAction,
602
- error: gitResult.error ?? "unknown error",
603
- });
604
- await pauseAuto(ctx, pi);
605
- return "dispatched";
606
- }
607
-
608
- s.lastGitActionStatus = "ok";
609
-
610
- if (turnAction === "commit" && gitResult.commitMessage) {
611
- ctx.ui.notify(`Committed: ${gitResult.commitMessage.split("\n")[0]}`, "info");
612
- } else if (turnAction === "snapshot" && gitResult.snapshotLabel) {
613
- ctx.ui.notify(`Snapshot recorded: ${gitResult.snapshotLabel}`, "info");
614
- }
615
- }
616
- } catch (e) {
617
- const message = e instanceof Error ? e.message : String(e);
618
- s.lastGitActionFailure = message;
619
- s.lastGitActionStatus = "failed";
620
- debugLog("postUnit", { phase: "git-action", error: message, action: turnAction });
621
- ctx.ui.notify(`Git ${turnAction} failed: ${message.split("\n")[0]}`, uokFlags.gitops ? "error" : "warning");
622
- if (uokFlags.gitops) {
623
- await pauseAuto(ctx, pi);
692
+ if (shouldDeferCloseoutGitAction(unit.type)) {
693
+ debugLog("postUnit", {
694
+ phase: "git-action-deferred-until-verification",
695
+ unitType: unit.type,
696
+ unitId: unit.id,
697
+ });
698
+ } else {
699
+ const gitActionResult = await runCloseoutGitAction(pctx, unit);
700
+ if (gitActionResult === "dispatched") {
624
701
  return "dispatched";
625
702
  }
626
703
  }
627
704
 
628
- // GitHub sync (non-blocking, opt-in)
629
- await runSafely("postUnit", "github-sync", async () => {
630
- const { runGitHubSync } = await import("../github-sync/sync.js");
631
- await runGitHubSync(s.basePath, unit.type, unit.id);
632
- });
633
-
634
705
  // Prune dead bg-shell processes
635
706
  await runSafely("postUnit", "prune-bg-shell", async () => {
636
707
  const { pruneDeadProcesses } = await import("../bg-shell/process-manager.js");
@@ -866,7 +937,7 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
866
937
  if (safetyConfig.enabled) {
867
938
  const { milestone: sMid, slice: sSid, task: sTid } = parseUnitId(s.currentUnit.id);
868
939
 
869
- // File change validation (execute-task only, after auto-commit)
940
+ // File change validation (execute-task only, after unit execution)
870
941
  if (safetyConfig.file_change_validation && s.currentUnit.type === "execute-task" && sMid && sSid && sTid && isDbAvailable()) {
871
942
  try {
872
943
  const taskRow = getTask(sMid, sSid, sTid);
@@ -902,15 +973,42 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
902
973
  const bashCalls = actual.filter(e => e.kind === "bash");
903
974
  if (sMid && sSid && sTid && isDbAvailable()) {
904
975
  const taskRow = getTask(sMid, sSid, sTid);
905
- const claimedCommands = getVerificationEvidence(sMid, sSid, sTid)
906
- .map((row) => row.command)
907
- .filter((command): command is string => typeof command === "string" && command.trim().length > 0);
908
- if (taskRow?.status === "complete" && claimedCommands.length > 0 && bashCalls.length === 0) {
909
- logWarning("safety", "task claimed verification command evidence but no execution tool calls were recorded");
910
- ctx.ui.notify(
911
- `Safety: task ${sTid} claimed command evidence but no execution tool calls were recorded`,
912
- "warning",
913
- );
976
+ if (taskRow?.status === "complete") {
977
+ const claimedEvidence: ClaimedEvidence[] = getVerificationEvidence(sMid, sSid, sTid)
978
+ .map((row) => ({
979
+ command: row.command,
980
+ exitCode: row.exit_code,
981
+ verdict: row.verdict,
982
+ }))
983
+ .filter((row) => typeof row.command === "string" && row.command.trim().length > 0);
984
+ const mismatches = crossReferenceEvidence(claimedEvidence, actual);
985
+
986
+ for (const mismatch of mismatches) {
987
+ const logMessage = `evidence-xref: ${mismatch.reason}`;
988
+ if (mismatch.severity === "error") {
989
+ logError("safety", logMessage);
990
+ } else {
991
+ logWarning("safety", logMessage);
992
+ }
993
+ }
994
+
995
+ if (claimedEvidence.length > 0 && bashCalls.length === 0) {
996
+ logWarning("safety", "task claimed verification command evidence but no execution tool calls were recorded");
997
+ ctx.ui.notify(
998
+ `Safety: task ${sTid} claimed command evidence but no execution tool calls were recorded`,
999
+ "warning",
1000
+ );
1001
+ }
1002
+
1003
+ const blockingMismatch = mismatches.find((mismatch) => mismatch.severity === "error");
1004
+ if (blockingMismatch) {
1005
+ ctx.ui.notify(
1006
+ `Safety: task ${sTid} claimed passing verification that failed in recorded execution`,
1007
+ "error",
1008
+ );
1009
+ await pauseAuto(ctx, pi);
1010
+ return "dispatched";
1011
+ }
914
1012
  }
915
1013
  }
916
1014
  } catch (e) {
@@ -1083,6 +1181,24 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
1083
1181
  "warning",
1084
1182
  );
1085
1183
  // Fall through to "continue" — do NOT enter the retry or db-unavailable paths.
1184
+ } else if (!triggerArtifactVerified && diagnoseWorktreeIntegrityFailure(s.basePath)) {
1185
+ const retryKey = `${s.currentUnit.type}:${s.currentUnit.id}`;
1186
+ const worktreeFailure = diagnoseWorktreeIntegrityFailure(s.basePath)!;
1187
+ s.pendingVerificationRetry = null;
1188
+ s.verificationRetryCount.delete(retryKey);
1189
+ s.verificationRetryFailureHashes.delete(retryKey);
1190
+ debugLog("postUnit", {
1191
+ phase: "worktree-integrity-failure",
1192
+ unitType: s.currentUnit.type,
1193
+ unitId: s.currentUnit.id,
1194
+ basePath: s.basePath,
1195
+ });
1196
+ ctx.ui.notify(
1197
+ `${worktreeFailure} Retry ${s.currentUnit.id} after repair.`,
1198
+ "error",
1199
+ );
1200
+ await pauseAuto(ctx, pi);
1201
+ return "dispatched";
1086
1202
  } else if (!triggerArtifactVerified && !isDbAvailable()) {
1087
1203
  debugLog("postUnit", { phase: "artifact-verify-skip-db-unavailable", unitType: s.currentUnit.type, unitId: s.currentUnit.id });
1088
1204
  const dbSkipDiag = diagnoseExpectedArtifact(s.currentUnit.type, s.currentUnit.id, s.basePath);
@@ -1169,6 +1285,13 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
1169
1285
  const { s, ctx, pi, buildSnapshotOpts, lockBase, stopAuto, pauseAuto, updateProgressWidget } = pctx;
1170
1286
 
1171
1287
  if (s.currentUnit) {
1288
+ if (shouldDeferCloseoutGitAction(s.currentUnit.type)) {
1289
+ const gitActionResult = await runCloseoutGitAction(pctx, s.currentUnit, { softFailure: true });
1290
+ if (gitActionResult === "dispatched") {
1291
+ return "stopped";
1292
+ }
1293
+ }
1294
+
1172
1295
  try {
1173
1296
  const codebasePrefs = loadEffectiveGSDPreferences()?.preferences?.codebase;
1174
1297
  const refresh = ensureCodebaseMapFresh(
@@ -1611,14 +1734,18 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
1611
1734
  // Without this notify(), /gsd in step mode finishes a unit and silently
1612
1735
  // exits the loop, leaving the user with no hint to /clear and /gsd again.
1613
1736
  if (s.stepMode) {
1737
+ let phaseAfterUnit: string | null = null;
1614
1738
  try {
1615
1739
  const nextState = await deriveState(s.canonicalProjectRoot);
1740
+ phaseAfterUnit = nextState.phase;
1616
1741
  ctx.ui.notify(buildStepCompleteMessage(nextState), "info");
1617
1742
  } catch (e) {
1618
1743
  debugLog("postUnit", { phase: "step-wizard-notify", error: String(e) });
1619
1744
  ctx.ui.notify(STEP_COMPLETE_FALLBACK_MESSAGE, "info");
1620
1745
  }
1621
- return "step-wizard";
1746
+ return shouldReturnStepWizardAfterUnit(s.currentUnit?.type, phaseAfterUnit)
1747
+ ? "step-wizard"
1748
+ : "continue";
1622
1749
  }
1623
1750
 
1624
1751
  return "continue";
@@ -3197,7 +3197,7 @@ export async function buildParallelResearchSlicesPrompt(
3197
3197
  subagentSections.push([
3198
3198
  `### ${slice.id}: ${slice.title}`,
3199
3199
  "",
3200
- `Use this as the prompt for a \`subagent\` call${modelSuffix} (agent: \`gsd-executor\` or the default agent):`,
3200
+ `Use this as the prompt for a \`subagent\` call${modelSuffix} (agent: \`scout\`):`,
3201
3201
  "",
3202
3202
  "```",
3203
3203
  slicePrompt,
@@ -3279,7 +3279,7 @@ export async function buildGateEvaluatePrompt(
3279
3279
  subagentSections.push([
3280
3280
  `### ${def.id}: ${def.question}`,
3281
3281
  "",
3282
- `Use this as the prompt for a \`subagent\` call${modelSuffix}:`,
3282
+ `Use this as the prompt for a \`subagent\` call${modelSuffix} (agent: \`tester\`):`,
3283
3283
  "",
3284
3284
  "```",
3285
3285
  subPrompt,
@@ -46,6 +46,7 @@ import {
46
46
  import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.js";
47
47
  import { validateArtifact } from "./schemas/validate.js";
48
48
  import { getProjectResearchStatus } from "./project-research-policy.js";
49
+ import { isGsdWorktreePath } from "./worktree-root.js";
49
50
 
50
51
  // Re-export so existing consumers of auto-recovery.ts keep working.
51
52
  export { resolveExpectedArtifactPath, diagnoseExpectedArtifact };
@@ -56,6 +57,29 @@ export {
56
57
 
57
58
  // ─── Artifact Resolution & Verification ───────────────────────────────────────
58
59
 
60
+ export function diagnoseWorktreeIntegrityFailure(basePath: string): string | null {
61
+ if (!isGsdWorktreePath(basePath)) return null;
62
+ if (!existsSync(basePath)) {
63
+ return `Worktree integrity failure: ${basePath} does not exist. Repair or recreate the worktree before retrying.`;
64
+ }
65
+
66
+ const gitPath = join(basePath, ".git");
67
+ if (!existsSync(gitPath)) {
68
+ return `Worktree integrity failure: ${basePath} is not a valid git worktree (.git missing). Repair or recreate the worktree before retrying.`;
69
+ }
70
+
71
+ try {
72
+ execFileSync("git", ["rev-parse", "--git-dir"], {
73
+ cwd: basePath,
74
+ stdio: ["ignore", "pipe", "pipe"],
75
+ encoding: "utf-8",
76
+ });
77
+ return null;
78
+ } catch (err) {
79
+ return `Worktree integrity failure: ${basePath} is not a valid git worktree (git rev-parse failed: ${getErrorMessage(err).split("\n")[0]}). Repair or recreate the worktree before retrying.`;
80
+ }
81
+ }
82
+
59
83
  export type ArtifactRecoveryDbRefreshResult =
60
84
  | { ok: true }
61
85
  | { ok: false; fatal: boolean; message: string; reason: string };
@@ -177,9 +201,15 @@ export function hasImplementationArtifacts(basePath: string, milestoneId?: strin
177
201
  // Strategy: check `git diff --name-only` against the merge-base with the
178
202
  // main branch. This captures ALL files changed during the milestone's
179
203
  // lifetime while running on a milestone branch.
180
- const integrationBranch = milestoneId
181
- ? readIntegrationBranch(basePath, milestoneId) ?? detectMainBranch(basePath)
182
- : detectMainBranch(basePath);
204
+ const recordedIntegrationBranch = milestoneId
205
+ ? readIntegrationBranch(basePath, milestoneId)
206
+ : null;
207
+ let integrationBranch: string;
208
+ if (recordedIntegrationBranch?.startsWith("milestone/")) {
209
+ integrationBranch = detectMainBranch(basePath);
210
+ } else {
211
+ integrationBranch = recordedIntegrationBranch ?? detectMainBranch(basePath);
212
+ }
183
213
  const currentBranch = getCurrentBranch(basePath);
184
214
  const branchDiff = getChangedFilesSinceBranch(basePath, integrationBranch);
185
215
  if (!branchDiff.ok) return "unknown";
@@ -532,27 +562,55 @@ function commitMatchesMilestone(basePath: string, message: string, milestoneId:
532
562
  // rather than Mxx/Sxx/Tyy. Bind those commits back to the milestone when
533
563
  // either the commit touched this milestone's artifacts, or — for projects
534
564
  // where .gsd/ is gitignored/external (#5033) — the message explicitly
535
- // names the milestone or local GSD state proves the task belongs here.
565
+ // names the milestone, local GSD state proves the task belongs here, or the
566
+ // commit is implementation-bearing evidence itself (#5100).
536
567
  if (/^GSD-Task:\s*S[^/\s]+\/T\S+/m.test(message)) {
537
568
  if (files.some((file) => isMilestoneArtifactPath(file, milestoneId))) return true;
538
569
  if (commitMessageMentionsMilestone(message, milestoneId)) return true;
539
- if (commitTaskTrailerBelongsToMilestone(basePath, message, milestoneId)) return true;
570
+ const taskTrailerOwnership = getTaskOwnershipStatus(basePath, message, milestoneId);
571
+ if (taskTrailerOwnership === true) return true;
572
+ if (taskTrailerOwnership === false) return false;
573
+ // taskTrailerOwnership === null: unknown ownership. Apply fallback only
574
+ // in this case to avoid cross-milestone attribution.
575
+ if (MILESTONE_ID_RE.test(milestoneId) && classifyImplementationFiles(files) === "present") return true;
540
576
  }
541
577
 
542
578
  return false;
543
579
  }
544
580
 
545
- function commitTaskTrailerBelongsToMilestone(basePath: string, message: string, milestoneId: string): boolean {
581
+ /**
582
+ * Tri-state task ownership probe.
583
+ * true => DB or local files confirm this milestone owns the task.
584
+ * false => DB is available and this milestone is registered, but task is absent.
585
+ * null => ownership unknown (milestone not in DB yet, or no DB + no local files).
586
+ */
587
+ function getTaskOwnershipStatus(
588
+ basePath: string,
589
+ message: string,
590
+ milestoneId: string,
591
+ ): true | false | null {
546
592
  const match = message.match(/^GSD-Task:\s*(S[^/\s]+)\/(T[^\s]+)/m);
547
- if (!match) return false;
593
+ if (!match) return null;
548
594
  const [, sliceId, taskId] = match;
549
595
 
550
- if (getTask(milestoneId, sliceId, taskId)) return true;
596
+ if (isDbAvailable()) {
597
+ if (!getMilestone(milestoneId)) return null;
598
+ return getTask(milestoneId, sliceId, taskId) ? true : false;
599
+ }
551
600
 
601
+ // DB unavailable: fallback to local task-file presence.
552
602
  const tasksDir = resolveTasksDir(basePath, milestoneId, sliceId);
553
- if (!tasksDir) return false;
554
- return existsSync(join(tasksDir, `${taskId}-PLAN.md`))
555
- || existsSync(join(tasksDir, `${taskId}-SUMMARY.md`));
603
+ if (
604
+ tasksDir
605
+ && (
606
+ existsSync(join(tasksDir, `${taskId}-PLAN.md`))
607
+ || existsSync(join(tasksDir, `${taskId}-SUMMARY.md`))
608
+ )
609
+ ) {
610
+ return true;
611
+ }
612
+
613
+ return null;
556
614
  }
557
615
 
558
616
  function commitMessageMentionsMilestone(message: string, milestoneId: string): boolean {
@@ -752,6 +810,11 @@ export function verifyExpectedArtifact(
752
810
  return false;
753
811
  }
754
812
  if (!existsSync(absPath)) {
813
+ const worktreeFailure = diagnoseWorktreeIntegrityFailure(base);
814
+ if (worktreeFailure) {
815
+ logError("recovery", `${worktreeFailure} Unit: ${unitType} ${unitId}.`);
816
+ return false;
817
+ }
755
818
  logWarning("recovery", `verify-fail ${unitType} ${unitId}: existsSync false for ${absPath}`);
756
819
  return false;
757
820
  }