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
  */
@@ -23,7 +23,7 @@ import { rebuildState } from "./doctor.js";
23
23
  import { parseUnitId } from "./unit-id.js";
24
24
  import { closeoutUnit } from "./auto-unit-closeout.js";
25
25
  import { runTurnGitAction, } from "./git-service.js";
26
- import { verifyExpectedArtifact, resolveExpectedArtifactPath, writeBlockerPlaceholder, diagnoseExpectedArtifact, } from "./auto-recovery.js";
26
+ import { verifyExpectedArtifact, resolveExpectedArtifactPath, writeBlockerPlaceholder, diagnoseExpectedArtifact, diagnoseWorktreeIntegrityFailure, } from "./auto-recovery.js";
27
27
  import { regenerateIfMissing } from "./workflow-projections.js";
28
28
  import { WorktreeStateProjection } from "./worktree-state-projection.js";
29
29
  import { createWorkspace, scopeMilestone } from "./workspace.js";
@@ -37,8 +37,7 @@ import { debugLog } from "./debug-logger.js";
37
37
  import { runSafely } from "./auto-utils.js";
38
38
  import { getEvidence, clearEvidenceFromDisk } from "./safety/evidence-collector.js";
39
39
  import { validateFileChanges } from "./safety/file-change-validator.js";
40
- // crossReferenceEvidence available for future use when verification_evidence is stored in DB
41
- // import { crossReferenceEvidence, type ClaimedEvidence } from "./safety/evidence-cross-ref.js";
40
+ import { crossReferenceEvidence } from "./safety/evidence-cross-ref.js";
42
41
  import { validateContent } from "./safety/content-validator.js";
43
42
  import { resolveSafetyHarnessConfig } from "./safety/safety-harness.js";
44
43
  import { resolveExpectedArtifactPath as resolveArtifactForContent } from "./auto-artifact-paths.js";
@@ -126,7 +125,7 @@ async function buildTaskCommitContextForUnit(basePath, unitId) {
126
125
  sliceId: sid,
127
126
  sliceTitle: stripKnownIdPrefix(slice?.title, sid),
128
127
  oneLiner: summary?.oneLiner || task?.one_liner || undefined,
129
- keyFiles: summary?.frontmatter.key_files?.filter(f => !f.includes("{{")) ??
128
+ keyFiles: summary?.frontmatter.key_files?.filter(f => !f.includes("{{") && f.trim() !== "(none)") ??
130
129
  task?.key_files ??
131
130
  undefined,
132
131
  issueNumber: ghIssueNumber,
@@ -171,6 +170,9 @@ export function _shouldDispatchQuickTaskForTest(state) {
171
170
  !!state.currentUnit &&
172
171
  state.currentUnit.type !== "quick-task";
173
172
  }
173
+ export function shouldDeferCloseoutGitAction(unitType) {
174
+ return unitType === "execute-task";
175
+ }
174
176
  /** Unit types that only touch `.gsd/` internal state files (no code changes).
175
177
  * Auto-commit is skipped for these — their state files are picked up by the
176
178
  * next actual task commit via `smartStage()`. */
@@ -301,6 +303,19 @@ export function buildStepCompleteMessage(nextState) {
301
303
  return `Step complete. Next: ${next.label}\n`
302
304
  + `Run /clear, then /gsd to continue (or /gsd auto to run continuously).`;
303
305
  }
306
+ /**
307
+ * Decide whether step mode should stop at the step wizard after a unit finishes.
308
+ *
309
+ * @param currentUnitType The just-finished unit type, such as "execute-task" or
310
+ * "complete-milestone"; may be null/undefined when no current unit is known.
311
+ * @param phaseAfterUnit The freshly derived next phase, such as "executing" or
312
+ * "complete"; may be null/undefined if state derivation failed.
313
+ * @returns true to show the step wizard; false to keep the loop running so
314
+ * terminal milestone completion can reach the merge/finalization path.
315
+ */
316
+ export function shouldReturnStepWizardAfterUnit(currentUnitType, phaseAfterUnit) {
317
+ return currentUnitType !== "complete-milestone" && phaseAfterUnit !== "complete";
318
+ }
304
319
  export const USER_DRIVEN_DEEP_UNITS = new Set([
305
320
  "discuss-project",
306
321
  "discuss-requirements",
@@ -316,6 +331,10 @@ function artifactValidationKind(unitType) {
316
331
  return null;
317
332
  }
318
333
  function describeArtifactVerificationFailure(unitType, unitId, basePath) {
334
+ const worktreeFailure = diagnoseWorktreeIntegrityFailure(basePath);
335
+ if (worktreeFailure) {
336
+ return `${worktreeFailure} Unit: ${unitType} ${unitId}.`;
337
+ }
319
338
  const artifactPath = resolveExpectedArtifactPath(unitType, unitId, basePath);
320
339
  if (!artifactPath) {
321
340
  return `Artifact verification failed: ${unitType} "${unitId}" has no resolvable artifact path.`;
@@ -360,6 +379,148 @@ export async function autoCommitUnit(basePath, unitType, unitId, ctx) {
360
379
  return null;
361
380
  }
362
381
  }
382
+ /**
383
+ * Execute the turn-level git action (commit, snapshot, or status-only).
384
+ *
385
+ * @param opts.softFailure - Defaults to false. When true, retry git failures,
386
+ * warn, and continue without pausing auto-mode; use for best-effort deferred
387
+ * closeout work where a git failure should not block the run.
388
+ */
389
+ async function runCloseoutGitAction(pctx, unit, opts) {
390
+ const { s, ctx, pi, pauseAuto } = pctx;
391
+ const prefs = loadEffectiveGSDPreferences()?.preferences;
392
+ const uokFlags = resolveUokFlags(prefs);
393
+ const turnAction = uokFlags.gitops ? uokFlags.gitopsTurnAction : "commit";
394
+ const traceId = s.currentTraceId ?? `turn:${unit.startedAt}`;
395
+ const turnId = s.currentTurnId ?? `${unit.type}/${unit.id}/${unit.startedAt}`;
396
+ s.lastGitActionFailure = null;
397
+ s.lastGitActionStatus = null;
398
+ try {
399
+ let taskContext;
400
+ if (turnAction === "commit" && unit.type === "execute-task") {
401
+ taskContext = await buildTaskCommitContextForUnit(s.basePath, unit.id);
402
+ }
403
+ // Invalidate the nativeHasChanges cache before auto-commit (#1853).
404
+ // The cache has a 10-second TTL and is keyed by basePath. A stale
405
+ // `false` result causes autoCommit to skip staging entirely.
406
+ _resetHasChangesCache();
407
+ const skipLifecycleCommit = turnAction === "commit" && LIFECYCLE_ONLY_UNITS.has(unit.type);
408
+ if (skipLifecycleCommit) {
409
+ debugLog("postUnit", {
410
+ phase: "git-action-skipped",
411
+ reason: "lifecycle-only-unit",
412
+ unitType: unit.type,
413
+ unitId: unit.id,
414
+ });
415
+ }
416
+ else {
417
+ const maxAttempts = opts?.softFailure ? 3 : 1;
418
+ let gitResult = runTurnGitAction({
419
+ basePath: s.basePath,
420
+ action: turnAction,
421
+ unitType: unit.type,
422
+ unitId: unit.id,
423
+ taskContext,
424
+ });
425
+ for (let attempt = 1; gitResult.status === "failed" && attempt < maxAttempts; attempt++) {
426
+ await new Promise((resolve) => setTimeout(resolve, 250 * attempt));
427
+ gitResult = runTurnGitAction({
428
+ basePath: s.basePath,
429
+ action: turnAction,
430
+ unitType: unit.type,
431
+ unitId: unit.id,
432
+ taskContext,
433
+ });
434
+ }
435
+ if (uokFlags.gitops) {
436
+ writeTurnGitTransaction({
437
+ basePath: s.basePath,
438
+ traceId,
439
+ turnId,
440
+ unitType: unit.type,
441
+ unitId: unit.id,
442
+ stage: "publish",
443
+ action: turnAction,
444
+ push: uokFlags.gitopsTurnPush,
445
+ status: gitResult.status,
446
+ error: gitResult.error,
447
+ metadata: {
448
+ dirty: gitResult.dirty,
449
+ commitMessage: gitResult.commitMessage,
450
+ snapshotLabel: gitResult.snapshotLabel,
451
+ },
452
+ });
453
+ }
454
+ if (gitResult.status === "failed") {
455
+ s.lastGitActionFailure = gitResult.error ?? `git ${turnAction} failed`;
456
+ s.lastGitActionStatus = "failed";
457
+ if (uokFlags.gitops && uokFlags.gates) {
458
+ const parsed = parseUnitId(unit.id);
459
+ const gateRunner = new UokGateRunner();
460
+ gateRunner.register({
461
+ id: "closeout-git-action",
462
+ type: "closeout",
463
+ execute: async () => ({
464
+ outcome: "fail",
465
+ failureClass: "git",
466
+ rationale: `turn git action "${turnAction}" failed`,
467
+ findings: gitResult.error ?? "unknown git failure",
468
+ }),
469
+ });
470
+ await gateRunner.run("closeout-git-action", {
471
+ basePath: s.basePath,
472
+ traceId,
473
+ turnId,
474
+ milestoneId: parsed.milestone ?? undefined,
475
+ sliceId: parsed.slice ?? undefined,
476
+ taskId: parsed.task ?? undefined,
477
+ unitType: unit.type,
478
+ unitId: unit.id,
479
+ });
480
+ }
481
+ const failureMsg = `Git ${turnAction} failed: ${(gitResult.error ?? "unknown error").split("\n")[0]}`;
482
+ ctx.ui.notify(failureMsg, opts?.softFailure ? "warning" : "error");
483
+ debugLog("postUnit", {
484
+ phase: opts?.softFailure ? "git-action-failed-soft" : "git-action-failed-blocking",
485
+ action: turnAction,
486
+ error: gitResult.error ?? "unknown error",
487
+ });
488
+ if (opts?.softFailure) {
489
+ return "continue";
490
+ }
491
+ await pauseAuto(ctx, pi);
492
+ return "dispatched";
493
+ }
494
+ s.lastGitActionStatus = "ok";
495
+ if (turnAction === "commit" && gitResult.commitMessage) {
496
+ ctx.ui.notify(`Committed: ${gitResult.commitMessage.split("\n")[0]}`, "info");
497
+ }
498
+ else if (turnAction === "snapshot" && gitResult.snapshotLabel) {
499
+ ctx.ui.notify(`Snapshot recorded: ${gitResult.snapshotLabel}`, "info");
500
+ }
501
+ }
502
+ }
503
+ catch (e) {
504
+ const message = e instanceof Error ? e.message : String(e);
505
+ s.lastGitActionFailure = message;
506
+ s.lastGitActionStatus = "failed";
507
+ debugLog("postUnit", { phase: "git-action", error: message, action: turnAction });
508
+ ctx.ui.notify(`Git ${turnAction} failed: ${message.split("\n")[0]}`, opts?.softFailure ? "warning" : "error");
509
+ if (opts?.softFailure) {
510
+ return "continue";
511
+ }
512
+ if (uokFlags.gitops) {
513
+ await pauseAuto(ctx, pi);
514
+ return "dispatched";
515
+ }
516
+ }
517
+ // GitHub sync (non-blocking, opt-in)
518
+ await runSafely("postUnit", "github-sync", async () => {
519
+ const { runGitHubSync } = await import("../github-sync/sync.js");
520
+ await runGitHubSync(s.basePath, unit.type, unit.id);
521
+ });
522
+ return "continue";
523
+ }
363
524
  /**
364
525
  * Pre-verification processing: parallel worker signal check, cache invalidation,
365
526
  * auto-commit, doctor run, state rebuild, worktree sync, artifact verification.
@@ -370,7 +531,7 @@ export async function autoCommitUnit(basePath, unitType, unitId, ctx) {
370
531
  * - "retry" — artifact verification failed, s.pendingVerificationRetry set for loop re-iteration
371
532
  */
372
533
  export async function postUnitPreVerification(pctx, opts) {
373
- const { s, ctx, pi, buildSnapshotOpts, stopAuto, pauseAuto } = pctx;
534
+ const { s, ctx, pi, stopAuto, pauseAuto } = pctx;
374
535
  // ── Parallel worker signal check ──
375
536
  const milestoneLock = process.env.GSD_MILESTONE_LOCK;
376
537
  if (milestoneLock) {
@@ -392,125 +553,22 @@ export async function postUnitPreVerification(pctx, opts) {
392
553
  if (!opts?.skipSettleDelay) {
393
554
  await new Promise(r => setTimeout(r, 100));
394
555
  }
395
- const prefs = loadEffectiveGSDPreferences()?.preferences;
396
- const uokFlags = resolveUokFlags(prefs);
397
556
  // Turn-level git action (commit | snapshot | status-only)
398
557
  if (s.currentUnit) {
399
558
  const unit = s.currentUnit;
400
- const turnAction = uokFlags.gitops ? uokFlags.gitopsTurnAction : "commit";
401
- const traceId = s.currentTraceId ?? `turn:${unit.startedAt}`;
402
- const turnId = s.currentTurnId ?? `${unit.type}/${unit.id}/${unit.startedAt}`;
403
- s.lastGitActionFailure = null;
404
- s.lastGitActionStatus = null;
405
- try {
406
- let taskContext;
407
- if (turnAction === "commit" && s.currentUnit.type === "execute-task") {
408
- taskContext = await buildTaskCommitContextForUnit(s.basePath, s.currentUnit.id);
409
- }
410
- // Invalidate the nativeHasChanges cache before auto-commit (#1853).
411
- // The cache has a 10-second TTL and is keyed by basePath. A stale
412
- // `false` result causes autoCommit to skip staging entirely, leaving
413
- // code files only in the working tree where they are destroyed by
414
- // `git worktree remove --force` during teardown.
415
- _resetHasChangesCache();
416
- const skipLifecycleCommit = turnAction === "commit" && LIFECYCLE_ONLY_UNITS.has(s.currentUnit.type);
417
- if (skipLifecycleCommit) {
418
- debugLog("postUnit", {
419
- phase: "git-action-skipped",
420
- reason: "lifecycle-only-unit",
421
- unitType: s.currentUnit.type,
422
- unitId: s.currentUnit.id,
423
- });
424
- }
425
- else {
426
- const gitResult = runTurnGitAction({
427
- basePath: s.basePath,
428
- action: turnAction,
429
- unitType: s.currentUnit.type,
430
- unitId: s.currentUnit.id,
431
- taskContext,
432
- });
433
- if (uokFlags.gitops) {
434
- writeTurnGitTransaction({
435
- basePath: s.basePath,
436
- traceId,
437
- turnId,
438
- unitType: unit.type,
439
- unitId: unit.id,
440
- stage: "publish",
441
- action: turnAction,
442
- push: uokFlags.gitopsTurnPush,
443
- status: gitResult.status,
444
- error: gitResult.error,
445
- metadata: {
446
- dirty: gitResult.dirty,
447
- commitMessage: gitResult.commitMessage,
448
- snapshotLabel: gitResult.snapshotLabel,
449
- },
450
- });
451
- }
452
- if (gitResult.status === "failed") {
453
- s.lastGitActionFailure = gitResult.error ?? `git ${turnAction} failed`;
454
- s.lastGitActionStatus = "failed";
455
- if (uokFlags.gitops && uokFlags.gates) {
456
- const parsed = parseUnitId(unit.id);
457
- const gateRunner = new UokGateRunner();
458
- gateRunner.register({
459
- id: "closeout-git-action",
460
- type: "closeout",
461
- execute: async () => ({
462
- outcome: "fail",
463
- failureClass: "git",
464
- rationale: `turn git action "${turnAction}" failed`,
465
- findings: gitResult.error ?? "unknown git failure",
466
- }),
467
- });
468
- await gateRunner.run("closeout-git-action", {
469
- basePath: s.basePath,
470
- traceId,
471
- turnId,
472
- milestoneId: parsed.milestone ?? undefined,
473
- sliceId: parsed.slice ?? undefined,
474
- taskId: parsed.task ?? undefined,
475
- unitType: unit.type,
476
- unitId: unit.id,
477
- });
478
- }
479
- const failureMsg = `Git ${turnAction} failed: ${(gitResult.error ?? "unknown error").split("\n")[0]}`;
480
- ctx.ui.notify(failureMsg, "error");
481
- debugLog("postUnit", {
482
- phase: "git-action-failed-blocking",
483
- action: turnAction,
484
- error: gitResult.error ?? "unknown error",
485
- });
486
- await pauseAuto(ctx, pi);
487
- return "dispatched";
488
- }
489
- s.lastGitActionStatus = "ok";
490
- if (turnAction === "commit" && gitResult.commitMessage) {
491
- ctx.ui.notify(`Committed: ${gitResult.commitMessage.split("\n")[0]}`, "info");
492
- }
493
- else if (turnAction === "snapshot" && gitResult.snapshotLabel) {
494
- ctx.ui.notify(`Snapshot recorded: ${gitResult.snapshotLabel}`, "info");
495
- }
496
- }
559
+ if (shouldDeferCloseoutGitAction(unit.type)) {
560
+ debugLog("postUnit", {
561
+ phase: "git-action-deferred-until-verification",
562
+ unitType: unit.type,
563
+ unitId: unit.id,
564
+ });
497
565
  }
498
- catch (e) {
499
- const message = e instanceof Error ? e.message : String(e);
500
- s.lastGitActionFailure = message;
501
- s.lastGitActionStatus = "failed";
502
- debugLog("postUnit", { phase: "git-action", error: message, action: turnAction });
503
- ctx.ui.notify(`Git ${turnAction} failed: ${message.split("\n")[0]}`, uokFlags.gitops ? "error" : "warning");
504
- if (uokFlags.gitops) {
505
- await pauseAuto(ctx, pi);
566
+ else {
567
+ const gitActionResult = await runCloseoutGitAction(pctx, unit);
568
+ if (gitActionResult === "dispatched") {
506
569
  return "dispatched";
507
570
  }
508
571
  }
509
- // GitHub sync (non-blocking, opt-in)
510
- await runSafely("postUnit", "github-sync", async () => {
511
- const { runGitHubSync } = await import("../github-sync/sync.js");
512
- await runGitHubSync(s.basePath, unit.type, unit.id);
513
- });
514
572
  // Prune dead bg-shell processes
515
573
  await runSafely("postUnit", "prune-bg-shell", async () => {
516
574
  const { pruneDeadProcesses } = await import("../bg-shell/process-manager.js");
@@ -723,7 +781,7 @@ export async function postUnitPreVerification(pctx, opts) {
723
781
  const safetyConfig = resolveSafetyHarnessConfig(prefs?.safety_harness);
724
782
  if (safetyConfig.enabled) {
725
783
  const { milestone: sMid, slice: sSid, task: sTid } = parseUnitId(s.currentUnit.id);
726
- // File change validation (execute-task only, after auto-commit)
784
+ // File change validation (execute-task only, after unit execution)
727
785
  if (safetyConfig.file_change_validation && s.currentUnit.type === "execute-task" && sMid && sSid && sTid && isDbAvailable()) {
728
786
  try {
729
787
  const taskRow = getTask(sMid, sSid, sTid);
@@ -756,12 +814,34 @@ export async function postUnitPreVerification(pctx, opts) {
756
814
  const bashCalls = actual.filter(e => e.kind === "bash");
757
815
  if (sMid && sSid && sTid && isDbAvailable()) {
758
816
  const taskRow = getTask(sMid, sSid, sTid);
759
- const claimedCommands = getVerificationEvidence(sMid, sSid, sTid)
760
- .map((row) => row.command)
761
- .filter((command) => typeof command === "string" && command.trim().length > 0);
762
- if (taskRow?.status === "complete" && claimedCommands.length > 0 && bashCalls.length === 0) {
763
- logWarning("safety", "task claimed verification command evidence but no execution tool calls were recorded");
764
- ctx.ui.notify(`Safety: task ${sTid} claimed command evidence but no execution tool calls were recorded`, "warning");
817
+ if (taskRow?.status === "complete") {
818
+ const claimedEvidence = getVerificationEvidence(sMid, sSid, sTid)
819
+ .map((row) => ({
820
+ command: row.command,
821
+ exitCode: row.exit_code,
822
+ verdict: row.verdict,
823
+ }))
824
+ .filter((row) => typeof row.command === "string" && row.command.trim().length > 0);
825
+ const mismatches = crossReferenceEvidence(claimedEvidence, actual);
826
+ for (const mismatch of mismatches) {
827
+ const logMessage = `evidence-xref: ${mismatch.reason}`;
828
+ if (mismatch.severity === "error") {
829
+ logError("safety", logMessage);
830
+ }
831
+ else {
832
+ logWarning("safety", logMessage);
833
+ }
834
+ }
835
+ if (claimedEvidence.length > 0 && bashCalls.length === 0) {
836
+ logWarning("safety", "task claimed verification command evidence but no execution tool calls were recorded");
837
+ ctx.ui.notify(`Safety: task ${sTid} claimed command evidence but no execution tool calls were recorded`, "warning");
838
+ }
839
+ const blockingMismatch = mismatches.find((mismatch) => mismatch.severity === "error");
840
+ if (blockingMismatch) {
841
+ ctx.ui.notify(`Safety: task ${sTid} claimed passing verification that failed in recorded execution`, "error");
842
+ await pauseAuto(ctx, pi);
843
+ return "dispatched";
844
+ }
765
845
  }
766
846
  }
767
847
  }
@@ -922,6 +1002,22 @@ export async function postUnitPreVerification(pctx, opts) {
922
1002
  ctx.ui.notify(`${s.currentUnit.type} ${s.currentUnit.id} — deterministic policy rejection, wrote blocker placeholder (no retries) (#4973)`, "warning");
923
1003
  // Fall through to "continue" — do NOT enter the retry or db-unavailable paths.
924
1004
  }
1005
+ else if (!triggerArtifactVerified && diagnoseWorktreeIntegrityFailure(s.basePath)) {
1006
+ const retryKey = `${s.currentUnit.type}:${s.currentUnit.id}`;
1007
+ const worktreeFailure = diagnoseWorktreeIntegrityFailure(s.basePath);
1008
+ s.pendingVerificationRetry = null;
1009
+ s.verificationRetryCount.delete(retryKey);
1010
+ s.verificationRetryFailureHashes.delete(retryKey);
1011
+ debugLog("postUnit", {
1012
+ phase: "worktree-integrity-failure",
1013
+ unitType: s.currentUnit.type,
1014
+ unitId: s.currentUnit.id,
1015
+ basePath: s.basePath,
1016
+ });
1017
+ ctx.ui.notify(`${worktreeFailure} Retry ${s.currentUnit.id} after repair.`, "error");
1018
+ await pauseAuto(ctx, pi);
1019
+ return "dispatched";
1020
+ }
925
1021
  else if (!triggerArtifactVerified && !isDbAvailable()) {
926
1022
  debugLog("postUnit", { phase: "artifact-verify-skip-db-unavailable", unitType: s.currentUnit.type, unitId: s.currentUnit.id });
927
1023
  const dbSkipDiag = diagnoseExpectedArtifact(s.currentUnit.type, s.currentUnit.id, s.basePath);
@@ -992,6 +1088,12 @@ export async function postUnitPreVerification(pctx, opts) {
992
1088
  export async function postUnitPostVerification(pctx) {
993
1089
  const { s, ctx, pi, buildSnapshotOpts, lockBase, stopAuto, pauseAuto, updateProgressWidget } = pctx;
994
1090
  if (s.currentUnit) {
1091
+ if (shouldDeferCloseoutGitAction(s.currentUnit.type)) {
1092
+ const gitActionResult = await runCloseoutGitAction(pctx, s.currentUnit, { softFailure: true });
1093
+ if (gitActionResult === "dispatched") {
1094
+ return "stopped";
1095
+ }
1096
+ }
995
1097
  try {
996
1098
  const codebasePrefs = loadEffectiveGSDPreferences()?.preferences?.codebase;
997
1099
  const refresh = ensureCodebaseMapFresh(s.basePath, codebasePrefs
@@ -1359,15 +1461,19 @@ export async function postUnitPostVerification(pctx) {
1359
1461
  // Without this notify(), /gsd in step mode finishes a unit and silently
1360
1462
  // exits the loop, leaving the user with no hint to /clear and /gsd again.
1361
1463
  if (s.stepMode) {
1464
+ let phaseAfterUnit = null;
1362
1465
  try {
1363
1466
  const nextState = await deriveState(s.canonicalProjectRoot);
1467
+ phaseAfterUnit = nextState.phase;
1364
1468
  ctx.ui.notify(buildStepCompleteMessage(nextState), "info");
1365
1469
  }
1366
1470
  catch (e) {
1367
1471
  debugLog("postUnit", { phase: "step-wizard-notify", error: String(e) });
1368
1472
  ctx.ui.notify(STEP_COMPLETE_FALLBACK_MESSAGE, "info");
1369
1473
  }
1370
- return "step-wizard";
1474
+ return shouldReturnStepWizardAfterUnit(s.currentUnit?.type, phaseAfterUnit)
1475
+ ? "step-wizard"
1476
+ : "continue";
1371
1477
  }
1372
1478
  return "continue";
1373
1479
  }
@@ -2777,7 +2777,7 @@ export async function buildParallelResearchSlicesPrompt(mid, midTitle, slices, b
2777
2777
  subagentSections.push([
2778
2778
  `### ${slice.id}: ${slice.title}`,
2779
2779
  "",
2780
- `Use this as the prompt for a \`subagent\` call${modelSuffix} (agent: \`gsd-executor\` or the default agent):`,
2780
+ `Use this as the prompt for a \`subagent\` call${modelSuffix} (agent: \`scout\`):`,
2781
2781
  "",
2782
2782
  "```",
2783
2783
  slicePrompt,
@@ -2846,7 +2846,7 @@ export async function buildGateEvaluatePrompt(mid, midTitle, sid, sTitle, base,
2846
2846
  subagentSections.push([
2847
2847
  `### ${def.id}: ${def.question}`,
2848
2848
  "",
2849
- `Use this as the prompt for a \`subagent\` call${modelSuffix}:`,
2849
+ `Use this as the prompt for a \`subagent\` call${modelSuffix} (agent: \`tester\`):`,
2850
2850
  "",
2851
2851
  "```",
2852
2852
  subPrompt,
@@ -14,7 +14,8 @@ import { clearParseCache } from "./files.js";
14
14
  import { parseRoadmap as parseLegacyRoadmap, parsePlan as parseLegacyPlan } from "./parsers-legacy.js";
15
15
  import { isDbAvailable, getTask, getSlice, getSliceTasks, getPendingGates, updateTaskStatus, updateSliceStatus, insertSlice, getMilestone, refreshOpenDatabaseFromDisk, getCompletedMilestoneTaskFileHints, getMilestoneCommitAttributionShas, recordMilestoneCommitAttribution } from "./gsd-db.js";
16
16
  import { isValidationTerminal } from "./state.js";
17
- import { logWarning } from "./workflow-logger.js";
17
+ import { getErrorMessage } from "./error-utils.js";
18
+ import { logWarning, logError } from "./workflow-logger.js";
18
19
  import { readIntegrationBranch } from "./git-service.js";
19
20
  import { isClosedStatus } from "./status-guards.js";
20
21
  import { resolveSlicePath, resolveSliceFile, resolveTasksDir, resolveTaskFiles, relMilestoneFile, relSliceFile, buildSliceFileName, resolveMilestoneFile, clearPathCache, resolveGsdRootFile, } from "./paths.js";
@@ -25,9 +26,33 @@ import { resolveExpectedArtifactPath, diagnoseExpectedArtifact, } from "./auto-a
25
26
  import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.js";
26
27
  import { validateArtifact } from "./schemas/validate.js";
27
28
  import { getProjectResearchStatus } from "./project-research-policy.js";
29
+ import { isGsdWorktreePath } from "./worktree-root.js";
28
30
  // Re-export so existing consumers of auto-recovery.ts keep working.
29
31
  export { resolveExpectedArtifactPath, diagnoseExpectedArtifact };
30
32
  export { classifyMilestoneSummaryContent, } from "./milestone-summary-classifier.js";
33
+ // ─── Artifact Resolution & Verification ───────────────────────────────────────
34
+ export function diagnoseWorktreeIntegrityFailure(basePath) {
35
+ if (!isGsdWorktreePath(basePath))
36
+ return null;
37
+ if (!existsSync(basePath)) {
38
+ return `Worktree integrity failure: ${basePath} does not exist. Repair or recreate the worktree before retrying.`;
39
+ }
40
+ const gitPath = join(basePath, ".git");
41
+ if (!existsSync(gitPath)) {
42
+ return `Worktree integrity failure: ${basePath} is not a valid git worktree (.git missing). Repair or recreate the worktree before retrying.`;
43
+ }
44
+ try {
45
+ execFileSync("git", ["rev-parse", "--git-dir"], {
46
+ cwd: basePath,
47
+ stdio: ["ignore", "pipe", "pipe"],
48
+ encoding: "utf-8",
49
+ });
50
+ return null;
51
+ }
52
+ catch (err) {
53
+ 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.`;
54
+ }
55
+ }
31
56
  export function refreshRecoveryDbForArtifact(unitType, unitId) {
32
57
  if (unitType !== "plan-slice" && unitType !== "execute-task")
33
58
  return { ok: true };
@@ -137,9 +162,16 @@ export function hasImplementationArtifacts(basePath, milestoneId) {
137
162
  // Strategy: check `git diff --name-only` against the merge-base with the
138
163
  // main branch. This captures ALL files changed during the milestone's
139
164
  // lifetime while running on a milestone branch.
140
- const integrationBranch = milestoneId
141
- ? readIntegrationBranch(basePath, milestoneId) ?? detectMainBranch(basePath)
142
- : detectMainBranch(basePath);
165
+ const recordedIntegrationBranch = milestoneId
166
+ ? readIntegrationBranch(basePath, milestoneId)
167
+ : null;
168
+ let integrationBranch;
169
+ if (recordedIntegrationBranch?.startsWith("milestone/")) {
170
+ integrationBranch = detectMainBranch(basePath);
171
+ }
172
+ else {
173
+ integrationBranch = recordedIntegrationBranch ?? detectMainBranch(basePath);
174
+ }
143
175
  const currentBranch = getCurrentBranch(basePath);
144
176
  const branchDiff = getChangedFilesSinceBranch(basePath, integrationBranch);
145
177
  if (!branchDiff.ok)
@@ -471,29 +503,49 @@ function commitMatchesMilestone(basePath, message, milestoneId, files) {
471
503
  // rather than Mxx/Sxx/Tyy. Bind those commits back to the milestone when
472
504
  // either the commit touched this milestone's artifacts, or — for projects
473
505
  // where .gsd/ is gitignored/external (#5033) — the message explicitly
474
- // names the milestone or local GSD state proves the task belongs here.
506
+ // names the milestone, local GSD state proves the task belongs here, or the
507
+ // commit is implementation-bearing evidence itself (#5100).
475
508
  if (/^GSD-Task:\s*S[^/\s]+\/T\S+/m.test(message)) {
476
509
  if (files.some((file) => isMilestoneArtifactPath(file, milestoneId)))
477
510
  return true;
478
511
  if (commitMessageMentionsMilestone(message, milestoneId))
479
512
  return true;
480
- if (commitTaskTrailerBelongsToMilestone(basePath, message, milestoneId))
513
+ const taskTrailerOwnership = getTaskOwnershipStatus(basePath, message, milestoneId);
514
+ if (taskTrailerOwnership === true)
515
+ return true;
516
+ if (taskTrailerOwnership === false)
517
+ return false;
518
+ // taskTrailerOwnership === null: unknown ownership. Apply fallback only
519
+ // in this case to avoid cross-milestone attribution.
520
+ if (MILESTONE_ID_RE.test(milestoneId) && classifyImplementationFiles(files) === "present")
481
521
  return true;
482
522
  }
483
523
  return false;
484
524
  }
485
- function commitTaskTrailerBelongsToMilestone(basePath, message, milestoneId) {
525
+ /**
526
+ * Tri-state task ownership probe.
527
+ * true => DB or local files confirm this milestone owns the task.
528
+ * false => DB is available and this milestone is registered, but task is absent.
529
+ * null => ownership unknown (milestone not in DB yet, or no DB + no local files).
530
+ */
531
+ function getTaskOwnershipStatus(basePath, message, milestoneId) {
486
532
  const match = message.match(/^GSD-Task:\s*(S[^/\s]+)\/(T[^\s]+)/m);
487
533
  if (!match)
488
- return false;
534
+ return null;
489
535
  const [, sliceId, taskId] = match;
490
- if (getTask(milestoneId, sliceId, taskId))
491
- return true;
536
+ if (isDbAvailable()) {
537
+ if (!getMilestone(milestoneId))
538
+ return null;
539
+ return getTask(milestoneId, sliceId, taskId) ? true : false;
540
+ }
541
+ // DB unavailable: fallback to local task-file presence.
492
542
  const tasksDir = resolveTasksDir(basePath, milestoneId, sliceId);
493
- if (!tasksDir)
494
- return false;
495
- return existsSync(join(tasksDir, `${taskId}-PLAN.md`))
496
- || existsSync(join(tasksDir, `${taskId}-SUMMARY.md`));
543
+ if (tasksDir
544
+ && (existsSync(join(tasksDir, `${taskId}-PLAN.md`))
545
+ || existsSync(join(tasksDir, `${taskId}-SUMMARY.md`)))) {
546
+ return true;
547
+ }
548
+ return null;
497
549
  }
498
550
  function commitMessageMentionsMilestone(message, milestoneId) {
499
551
  if (!MILESTONE_ID_RE.test(milestoneId))
@@ -673,6 +725,11 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
673
725
  return false;
674
726
  }
675
727
  if (!existsSync(absPath)) {
728
+ const worktreeFailure = diagnoseWorktreeIntegrityFailure(base);
729
+ if (worktreeFailure) {
730
+ logError("recovery", `${worktreeFailure} Unit: ${unitType} ${unitId}.`);
731
+ return false;
732
+ }
676
733
  logWarning("recovery", `verify-fail ${unitType} ${unitId}: existsSync false for ${absPath}`);
677
734
  return false;
678
735
  }