gsd-pi 2.80.0-dev.8b3a59f5c → 2.80.0-dev.a947d025c

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 (714) hide show
  1. package/README.md +35 -59
  2. package/dist/claude-cli-check.d.ts +30 -0
  3. package/dist/claude-cli-check.js +18 -7
  4. package/dist/cli.js +0 -19
  5. package/dist/headless-query.d.ts +10 -0
  6. package/dist/headless-query.js +6 -4
  7. package/dist/loader-entrypoint.d.ts +8 -0
  8. package/dist/loader-entrypoint.js +27 -0
  9. package/dist/loader.js +2 -11
  10. package/dist/mcp-server.d.ts +1 -0
  11. package/dist/mcp-server.js +6 -3
  12. package/dist/resources/.managed-resources-content-hash +1 -1
  13. package/dist/resources/GSD-WORKFLOW.md +2 -2
  14. package/dist/resources/extensions/claude-code-cli/readiness.js +18 -7
  15. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +40 -3
  16. package/dist/resources/extensions/github-sync/sync.js +4 -1
  17. package/dist/resources/extensions/gsd/auto/contracts.js +2 -0
  18. package/dist/resources/extensions/gsd/auto/loop.js +103 -9
  19. package/dist/resources/extensions/gsd/auto/orchestrator.js +48 -4
  20. package/dist/resources/extensions/gsd/auto/phases.js +311 -154
  21. package/dist/resources/extensions/gsd/auto/resolve.js +29 -0
  22. package/dist/resources/extensions/gsd/auto/run-unit.js +22 -30
  23. package/dist/resources/extensions/gsd/auto/session.js +9 -1
  24. package/dist/resources/extensions/gsd/auto/unit-runner-events.js +7 -0
  25. package/dist/resources/extensions/gsd/auto/workflow-dispatch-claim.js +33 -1
  26. package/dist/resources/extensions/gsd/auto/workflow-worker-heartbeat.js +9 -1
  27. package/dist/resources/extensions/gsd/auto-dashboard.js +18 -0
  28. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +5 -32
  29. package/dist/resources/extensions/gsd/auto-dispatch.js +26 -0
  30. package/dist/resources/extensions/gsd/auto-post-unit.js +122 -88
  31. package/dist/resources/extensions/gsd/auto-prompts.js +214 -17
  32. package/dist/resources/extensions/gsd/auto-recovery.js +43 -1
  33. package/dist/resources/extensions/gsd/auto-start.js +254 -17
  34. package/dist/resources/extensions/gsd/auto-supervisor.js +8 -1
  35. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +2 -2
  36. package/dist/resources/extensions/gsd/auto-worktree.js +229 -336
  37. package/dist/resources/extensions/gsd/auto.js +273 -87
  38. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +122 -11
  39. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +44 -37
  40. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +37 -10
  41. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +30 -20
  42. package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +4 -1
  43. package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +6 -4
  44. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +5 -3
  45. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +1 -1
  46. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +330 -54
  47. package/dist/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.js +4 -0
  48. package/dist/resources/extensions/gsd/bootstrap/system-context.js +82 -23
  49. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +19 -2
  50. package/dist/resources/extensions/gsd/clean-root-preflight.js +65 -9
  51. package/dist/resources/extensions/gsd/commands/dispatcher.js +5 -0
  52. package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -2
  53. package/dist/resources/extensions/gsd/commands-config.js +1 -1
  54. package/dist/resources/extensions/gsd/commands-eval-review.js +2 -2
  55. package/dist/resources/extensions/gsd/commands-handlers.js +23 -9
  56. package/dist/resources/extensions/gsd/context-budget.js +37 -2
  57. package/dist/resources/extensions/gsd/crash-recovery.js +56 -10
  58. package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -1
  59. package/dist/resources/extensions/gsd/db/unit-dispatches.js +92 -0
  60. package/dist/resources/extensions/gsd/db-base-schema.js +4 -2
  61. package/dist/resources/extensions/gsd/db-migration-steps.js +6 -0
  62. package/dist/resources/extensions/gsd/detection.js +106 -0
  63. package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +2 -0
  64. package/dist/resources/extensions/gsd/git-service.js +73 -5
  65. package/dist/resources/extensions/gsd/gsd-db.js +46 -13
  66. package/dist/resources/extensions/gsd/guided-flow.js +149 -48
  67. package/dist/resources/extensions/gsd/health-widget.js +3 -0
  68. package/dist/resources/extensions/gsd/init-wizard.js +4 -1
  69. package/dist/resources/extensions/gsd/memory-store.js +69 -12
  70. package/dist/resources/extensions/gsd/migrate/command.js +40 -1
  71. package/dist/resources/extensions/gsd/migration-auto-check.js +87 -0
  72. package/dist/resources/extensions/gsd/native-git-bridge.js +32 -8
  73. package/dist/resources/extensions/gsd/orphan-stash-audit.js +101 -0
  74. package/dist/resources/extensions/gsd/parallel-orchestrator.js +13 -3
  75. package/dist/resources/extensions/gsd/planning-path-scope.js +26 -0
  76. package/dist/resources/extensions/gsd/pre-execution-checks.js +22 -0
  77. package/dist/resources/extensions/gsd/prompt-loader.js +28 -2
  78. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +27 -23
  79. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  80. package/dist/resources/extensions/gsd/prompts/execute-task.md +4 -2
  81. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  82. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
  83. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  84. package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -5
  85. package/dist/resources/extensions/gsd/prompts/replan-slice.md +2 -2
  86. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  87. package/dist/resources/extensions/gsd/quick.js +34 -2
  88. package/dist/resources/extensions/gsd/recovery-classification.js +94 -0
  89. package/dist/resources/extensions/gsd/safety/evidence-collector.js +10 -2
  90. package/dist/resources/extensions/gsd/slice-cadence.js +45 -2
  91. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +15 -9
  92. package/dist/resources/extensions/gsd/state-reconciliation.js +27 -0
  93. package/dist/resources/extensions/gsd/tool-contract.js +50 -0
  94. package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -7
  95. package/dist/resources/extensions/gsd/tools/complete-task.js +1 -1
  96. package/dist/resources/extensions/gsd/tools/context-mode-tool-result.js +15 -0
  97. package/dist/resources/extensions/gsd/tools/exec-search-tool.js +5 -0
  98. package/dist/resources/extensions/gsd/tools/exec-tool.js +3 -15
  99. package/dist/resources/extensions/gsd/tools/memory-tools.js +1 -0
  100. package/dist/resources/extensions/gsd/tools/plan-slice.js +9 -0
  101. package/dist/resources/extensions/gsd/tools/plan-task.js +9 -0
  102. package/dist/resources/extensions/gsd/tools/resume-tool.js +5 -0
  103. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +1 -1
  104. package/dist/resources/extensions/gsd/unit-context-composer.js +12 -3
  105. package/dist/resources/extensions/gsd/unit-runtime.js +22 -0
  106. package/dist/resources/extensions/gsd/workflow-protocol.js +131 -0
  107. package/dist/resources/extensions/gsd/worktree-lifecycle.js +958 -0
  108. package/dist/resources/extensions/gsd/worktree-manager.js +16 -14
  109. package/dist/resources/extensions/gsd/worktree-safety.js +119 -0
  110. package/dist/resources/extensions/gsd/worktree-state-projection.js +317 -0
  111. package/dist/resources/skills/web-quality-audit/scripts/analyze.sh +0 -0
  112. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  113. package/dist/web/standalone/.next/BUILD_ID +1 -1
  114. package/dist/web/standalone/.next/app-path-routes-manifest.json +16 -16
  115. package/dist/web/standalone/.next/build-manifest.json +3 -3
  116. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  117. package/dist/web/standalone/.next/react-loadable-manifest.json +2 -2
  118. package/dist/web/standalone/.next/required-server-files.json +1 -1
  119. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  121. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  122. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  128. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  130. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  131. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  132. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  133. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  134. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  135. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  136. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  137. package/dist/web/standalone/.next/server/app/index.html +1 -1
  138. package/dist/web/standalone/.next/server/app/index.rsc +2 -2
  139. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  140. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
  141. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  142. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  143. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  144. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app-paths-manifest.json +16 -16
  146. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  148. package/dist/web/standalone/.next/server/middleware.js +3 -3
  149. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  150. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  151. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  152. package/dist/web/standalone/.next/static/chunks/8359.e059d86b255fce1c.js +10 -0
  153. package/dist/web/standalone/.next/static/chunks/app/{page-fab3ebb85b006001.js → page-752f1e2ebdaa3e45.js} +1 -1
  154. package/dist/web/standalone/.next/static/chunks/{webpack-0481f1221120a7c6.js → webpack-de742b64187e13fe.js} +1 -1
  155. package/dist/web/standalone/server.js +1 -1
  156. package/dist/welcome-screen.d.ts +2 -0
  157. package/dist/welcome-screen.js +9 -7
  158. package/package.json +6 -4
  159. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  160. package/packages/mcp-server/dist/workflow-tools.js +22 -17
  161. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  162. package/packages/mcp-server/src/workflow-tools.test.ts +75 -2
  163. package/packages/mcp-server/src/workflow-tools.ts +30 -16
  164. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  165. package/packages/native/tsconfig.tsbuildinfo +1 -1
  166. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  167. package/packages/pi-agent-core/dist/agent-loop.js +4 -1
  168. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  169. package/packages/pi-agent-core/dist/agent.d.ts +9 -2
  170. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  171. package/packages/pi-agent-core/dist/agent.js +43 -11
  172. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  173. package/packages/pi-agent-core/dist/index.d.ts +1 -0
  174. package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
  175. package/packages/pi-agent-core/dist/index.js +2 -0
  176. package/packages/pi-agent-core/dist/index.js.map +1 -1
  177. package/packages/pi-agent-core/dist/token-audit.d.ts +47 -0
  178. package/packages/pi-agent-core/dist/token-audit.d.ts.map +1 -0
  179. package/packages/pi-agent-core/dist/token-audit.js +221 -0
  180. package/packages/pi-agent-core/dist/token-audit.js.map +1 -0
  181. package/packages/pi-agent-core/dist/types.d.ts +31 -0
  182. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  183. package/packages/pi-agent-core/dist/types.js.map +1 -1
  184. package/packages/pi-agent-core/src/agent-loop.test.ts +128 -0
  185. package/packages/pi-agent-core/src/agent-loop.ts +4 -1
  186. package/packages/pi-agent-core/src/agent.ts +52 -11
  187. package/packages/pi-agent-core/src/index.ts +2 -0
  188. package/packages/pi-agent-core/src/token-audit.test.ts +189 -0
  189. package/packages/pi-agent-core/src/token-audit.ts +287 -0
  190. package/packages/pi-agent-core/src/types.ts +26 -10
  191. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  192. package/packages/pi-ai/dist/providers/anthropic-auth.test.js +35 -13
  193. package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
  194. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js +21 -11
  195. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js.map +1 -1
  196. package/packages/pi-ai/dist/providers/anthropic.d.ts +7 -0
  197. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  198. package/packages/pi-ai/dist/providers/anthropic.js +9 -7
  199. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  200. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +23 -14
  201. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -1
  202. package/packages/pi-ai/dist/types.d.ts +2 -0
  203. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  204. package/packages/pi-ai/dist/types.js.map +1 -1
  205. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js +48 -21
  206. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js.map +1 -1
  207. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js +22 -21
  208. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js.map +1 -1
  209. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js +22 -21
  210. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js.map +1 -1
  211. package/packages/pi-ai/src/providers/anthropic-auth.test.ts +39 -25
  212. package/packages/pi-ai/src/providers/anthropic-bearer-auth.test.ts +26 -22
  213. package/packages/pi-ai/src/providers/anthropic.ts +22 -9
  214. package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +34 -21
  215. package/packages/pi-ai/src/types.ts +3 -0
  216. package/packages/pi-ai/src/utils/oauth/github-copilot.test.ts +56 -22
  217. package/packages/pi-ai/src/utils/oauth/google-antigravity.test.ts +24 -28
  218. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.test.ts +24 -28
  219. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  220. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +36 -1
  221. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  222. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +30 -1
  223. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  224. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +21 -2
  225. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  226. package/packages/pi-coding-agent/dist/core/agent-session.js +94 -16
  227. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  228. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +35 -1
  229. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  230. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +11 -0
  231. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  232. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +9 -0
  233. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  234. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts +2 -0
  235. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts.map +1 -0
  236. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js +103 -0
  237. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js.map +1 -0
  238. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts +15 -0
  239. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts.map +1 -0
  240. package/packages/pi-coding-agent/dist/core/db-snapshot.js +66 -0
  241. package/packages/pi-coding-agent/dist/core/db-snapshot.js.map +1 -0
  242. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts +2 -0
  243. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts.map +1 -0
  244. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js +24 -0
  245. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js.map +1 -0
  246. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  247. package/packages/pi-coding-agent/dist/core/extensions/loader.js +8 -0
  248. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  249. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +5 -0
  250. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  251. package/packages/pi-coding-agent/dist/core/extensions/runner.js +20 -7
  252. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  253. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +102 -3
  254. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  255. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +60 -4
  256. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  257. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  258. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js +2 -0
  259. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js.map +1 -1
  260. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts +2 -0
  261. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts.map +1 -0
  262. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js +46 -0
  263. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js.map +1 -0
  264. package/packages/pi-coding-agent/dist/core/sdk.d.ts +10 -2
  265. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  266. package/packages/pi-coding-agent/dist/core/sdk.js +81 -4
  267. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  268. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +20 -0
  269. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  270. package/packages/pi-coding-agent/dist/core/settings-manager.js +25 -0
  271. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  272. package/packages/pi-coding-agent/dist/core/skill-tool.test.js +22 -0
  273. package/packages/pi-coding-agent/dist/core/skill-tool.test.js.map +1 -1
  274. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +6 -7
  275. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  276. package/packages/pi-coding-agent/dist/core/system-prompt.js +2 -3
  277. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  278. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js +22 -56
  279. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js.map +1 -1
  280. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +1 -0
  281. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
  282. package/packages/pi-coding-agent/dist/core/tools/bash.js +3 -1
  283. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  284. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts +2 -0
  285. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
  286. package/packages/pi-coding-agent/dist/core/tools/edit.js +12 -1
  287. package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
  288. package/packages/pi-coding-agent/dist/core/tools/find.d.ts +2 -0
  289. package/packages/pi-coding-agent/dist/core/tools/find.d.ts.map +1 -1
  290. package/packages/pi-coding-agent/dist/core/tools/find.js +14 -6
  291. package/packages/pi-coding-agent/dist/core/tools/find.js.map +1 -1
  292. package/packages/pi-coding-agent/dist/core/tools/grep.d.ts +2 -0
  293. package/packages/pi-coding-agent/dist/core/tools/grep.d.ts.map +1 -1
  294. package/packages/pi-coding-agent/dist/core/tools/grep.js +12 -3
  295. package/packages/pi-coding-agent/dist/core/tools/grep.js.map +1 -1
  296. package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts +2 -0
  297. package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts.map +1 -1
  298. package/packages/pi-coding-agent/dist/core/tools/hashline-read.js +3 -1
  299. package/packages/pi-coding-agent/dist/core/tools/hashline-read.js.map +1 -1
  300. package/packages/pi-coding-agent/dist/core/tools/index.d.ts +2 -1
  301. package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
  302. package/packages/pi-coding-agent/dist/core/tools/index.js +1 -0
  303. package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
  304. package/packages/pi-coding-agent/dist/core/tools/ls.d.ts +2 -0
  305. package/packages/pi-coding-agent/dist/core/tools/ls.d.ts.map +1 -1
  306. package/packages/pi-coding-agent/dist/core/tools/ls.js +10 -3
  307. package/packages/pi-coding-agent/dist/core/tools/ls.js.map +1 -1
  308. package/packages/pi-coding-agent/dist/core/tools/read.d.ts +2 -0
  309. package/packages/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
  310. package/packages/pi-coding-agent/dist/core/tools/read.js +3 -1
  311. package/packages/pi-coding-agent/dist/core/tools/read.js.map +1 -1
  312. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js +7 -62
  313. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js.map +1 -1
  314. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.d.ts +2 -0
  315. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.d.ts.map +1 -0
  316. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.js +115 -0
  317. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.js.map +1 -0
  318. package/packages/pi-coding-agent/dist/core/tools/tool-target.d.ts +19 -0
  319. package/packages/pi-coding-agent/dist/core/tools/tool-target.d.ts.map +1 -0
  320. package/packages/pi-coding-agent/dist/core/tools/tool-target.js +20 -0
  321. package/packages/pi-coding-agent/dist/core/tools/tool-target.js.map +1 -0
  322. package/packages/pi-coding-agent/dist/core/tools/write.d.ts +4 -0
  323. package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
  324. package/packages/pi-coding-agent/dist/core/tools/write.js +9 -1
  325. package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
  326. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js +6 -4
  327. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js.map +1 -1
  328. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +114 -22
  329. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  330. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +2 -2
  331. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -1
  332. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  333. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  334. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
  335. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +2 -1
  336. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
  337. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +32 -7
  338. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -1
  339. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +6 -0
  340. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  341. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +177 -19
  342. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  343. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  344. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +33 -6
  345. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  346. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +71 -0
  347. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
  348. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +2 -0
  349. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  350. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +25 -3
  351. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  352. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  353. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +36 -27
  354. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  355. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +21 -0
  356. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -1
  357. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +1 -1
  358. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  359. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts +2 -0
  360. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts.map +1 -0
  361. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +28 -0
  362. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -0
  363. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
  364. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +3 -2
  365. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
  366. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +40 -1
  367. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +40 -1
  368. package/packages/pi-coding-agent/src/core/agent-session.ts +102 -16
  369. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +41 -1
  370. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +18 -0
  371. package/packages/pi-coding-agent/src/core/compaction-threshold.test.ts +121 -0
  372. package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
  373. package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -0
  374. package/packages/pi-coding-agent/src/core/extensions/loader.ts +10 -0
  375. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +113 -3
  376. package/packages/pi-coding-agent/src/core/extensions/runner.ts +24 -6
  377. package/packages/pi-coding-agent/src/core/extensions/types.ts +63 -2
  378. package/packages/pi-coding-agent/src/core/hooks-runner.test.ts +2 -0
  379. package/packages/pi-coding-agent/src/core/sdk-tool-filter.test.ts +60 -0
  380. package/packages/pi-coding-agent/src/core/sdk.ts +92 -4
  381. package/packages/pi-coding-agent/src/core/settings-manager.ts +39 -1
  382. package/packages/pi-coding-agent/src/core/skill-tool.test.ts +28 -0
  383. package/packages/pi-coding-agent/src/core/system-prompt.ts +8 -10
  384. package/packages/pi-coding-agent/src/core/tools/bash-spawn-windows.test.ts +22 -66
  385. package/packages/pi-coding-agent/src/core/tools/bash.ts +4 -1
  386. package/packages/pi-coding-agent/src/core/tools/edit.ts +13 -1
  387. package/packages/pi-coding-agent/src/core/tools/find.ts +15 -6
  388. package/packages/pi-coding-agent/src/core/tools/grep.ts +13 -3
  389. package/packages/pi-coding-agent/src/core/tools/hashline-read.ts +4 -1
  390. package/packages/pi-coding-agent/src/core/tools/index.ts +8 -0
  391. package/packages/pi-coding-agent/src/core/tools/ls.ts +11 -3
  392. package/packages/pi-coding-agent/src/core/tools/read.ts +4 -1
  393. package/packages/pi-coding-agent/src/core/tools/spawn-shell-windows.test.ts +11 -72
  394. package/packages/pi-coding-agent/src/core/tools/tool-target-metadata.test.ts +127 -0
  395. package/packages/pi-coding-agent/src/core/tools/tool-target.ts +48 -0
  396. package/packages/pi-coding-agent/src/core/tools/write.ts +14 -2
  397. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.ts +7 -5
  398. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +144 -22
  399. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +2 -2
  400. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +1 -0
  401. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +2 -1
  402. package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +41 -10
  403. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +208 -19
  404. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +75 -0
  405. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +41 -8
  406. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +27 -3
  407. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +36 -27
  408. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +25 -0
  409. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +1 -1
  410. package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +31 -0
  411. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +3 -2
  412. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  413. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  414. package/packages/pi-tui/dist/tui.js +18 -8
  415. package/packages/pi-tui/dist/tui.js.map +1 -1
  416. package/packages/pi-tui/src/tui.ts +20 -8
  417. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  418. package/packages/rpc-client/README.md +7 -0
  419. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  420. package/pkg/dist/modes/interactive/theme/themes.js +36 -27
  421. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  422. package/src/resources/GSD-WORKFLOW.md +2 -2
  423. package/src/resources/extensions/claude-code-cli/readiness.ts +25 -7
  424. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +42 -3
  425. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +67 -0
  426. package/src/resources/extensions/github-sync/sync.ts +8 -1
  427. package/src/resources/extensions/github-sync/tests/sync-source.test.ts +6 -18
  428. package/src/resources/extensions/gsd/auto/contracts.ts +19 -2
  429. package/src/resources/extensions/gsd/auto/loop-deps.ts +11 -11
  430. package/src/resources/extensions/gsd/auto/loop.ts +134 -16
  431. package/src/resources/extensions/gsd/auto/orchestrator.ts +52 -4
  432. package/src/resources/extensions/gsd/auto/phases.ts +427 -220
  433. package/src/resources/extensions/gsd/auto/resolve.ts +42 -1
  434. package/src/resources/extensions/gsd/auto/run-unit.ts +28 -30
  435. package/src/resources/extensions/gsd/auto/session.ts +9 -1
  436. package/src/resources/extensions/gsd/auto/types.ts +3 -0
  437. package/src/resources/extensions/gsd/auto/unit-runner-events.ts +15 -0
  438. package/src/resources/extensions/gsd/auto/workflow-dispatch-claim.ts +63 -1
  439. package/src/resources/extensions/gsd/auto/workflow-worker-heartbeat.ts +14 -1
  440. package/src/resources/extensions/gsd/auto-dashboard.ts +20 -0
  441. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +8 -34
  442. package/src/resources/extensions/gsd/auto-dispatch.ts +33 -0
  443. package/src/resources/extensions/gsd/auto-post-unit.ts +134 -90
  444. package/src/resources/extensions/gsd/auto-prompts.ts +228 -16
  445. package/src/resources/extensions/gsd/auto-recovery.ts +54 -0
  446. package/src/resources/extensions/gsd/auto-start.ts +326 -25
  447. package/src/resources/extensions/gsd/auto-supervisor.ts +7 -0
  448. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +2 -2
  449. package/src/resources/extensions/gsd/auto-worktree.ts +259 -360
  450. package/src/resources/extensions/gsd/auto.ts +336 -89
  451. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +147 -11
  452. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +45 -37
  453. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +36 -10
  454. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +32 -19
  455. package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +5 -1
  456. package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +7 -4
  457. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +6 -3
  458. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +1 -1
  459. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +379 -54
  460. package/src/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.ts +4 -0
  461. package/src/resources/extensions/gsd/bootstrap/system-context.ts +90 -22
  462. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +19 -2
  463. package/src/resources/extensions/gsd/clean-root-preflight.ts +72 -9
  464. package/src/resources/extensions/gsd/commands/dispatcher.ts +6 -0
  465. package/src/resources/extensions/gsd/commands/handlers/ops.ts +4 -2
  466. package/src/resources/extensions/gsd/commands-config.ts +1 -1
  467. package/src/resources/extensions/gsd/commands-eval-review.ts +2 -2
  468. package/src/resources/extensions/gsd/commands-handlers.ts +34 -15
  469. package/src/resources/extensions/gsd/context-budget.ts +44 -2
  470. package/src/resources/extensions/gsd/crash-recovery.ts +67 -10
  471. package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -1
  472. package/src/resources/extensions/gsd/db/unit-dispatches.ts +107 -0
  473. package/src/resources/extensions/gsd/db-base-schema.ts +4 -2
  474. package/src/resources/extensions/gsd/db-migration-steps.ts +8 -0
  475. package/src/resources/extensions/gsd/detection.ts +128 -0
  476. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +3 -0
  477. package/src/resources/extensions/gsd/git-service.ts +87 -10
  478. package/src/resources/extensions/gsd/gsd-db.ts +50 -13
  479. package/src/resources/extensions/gsd/guided-flow.ts +175 -55
  480. package/src/resources/extensions/gsd/health-widget.ts +3 -0
  481. package/src/resources/extensions/gsd/init-wizard.ts +5 -1
  482. package/src/resources/extensions/gsd/memory-store.ts +77 -12
  483. package/src/resources/extensions/gsd/migrate/command.ts +47 -1
  484. package/src/resources/extensions/gsd/migration-auto-check.ts +129 -0
  485. package/src/resources/extensions/gsd/native-git-bridge.ts +39 -6
  486. package/src/resources/extensions/gsd/orphan-stash-audit.ts +117 -0
  487. package/src/resources/extensions/gsd/parallel-orchestrator.ts +13 -3
  488. package/src/resources/extensions/gsd/planning-path-scope.ts +35 -0
  489. package/src/resources/extensions/gsd/pre-execution-checks.ts +23 -0
  490. package/src/resources/extensions/gsd/preferences-types.ts +1 -1
  491. package/src/resources/extensions/gsd/prompt-loader.ts +27 -2
  492. package/src/resources/extensions/gsd/prompts/complete-milestone.md +27 -23
  493. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  494. package/src/resources/extensions/gsd/prompts/execute-task.md +4 -2
  495. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  496. package/src/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
  497. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  498. package/src/resources/extensions/gsd/prompts/quick-task.md +1 -5
  499. package/src/resources/extensions/gsd/prompts/replan-slice.md +2 -2
  500. package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  501. package/src/resources/extensions/gsd/quick.ts +37 -2
  502. package/src/resources/extensions/gsd/recovery-classification.ts +122 -0
  503. package/src/resources/extensions/gsd/safety/evidence-collector.ts +11 -2
  504. package/src/resources/extensions/gsd/slice-cadence.ts +49 -2
  505. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +23 -9
  506. package/src/resources/extensions/gsd/state-reconciliation.ts +57 -0
  507. package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +59 -89
  508. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +47 -172
  509. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +0 -35
  510. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +35 -9
  511. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +544 -41
  512. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +80 -59
  513. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +119 -2
  514. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +3 -47
  515. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +76 -18
  516. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +175 -11
  517. package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +54 -95
  518. package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +67 -26
  519. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +14 -1
  520. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +32 -30
  521. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +32 -128
  522. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +20 -54
  523. package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +20 -30
  524. package/src/resources/extensions/gsd/tests/auto-start-index-lock.test.ts +17 -29
  525. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +142 -0
  526. package/src/resources/extensions/gsd/tests/auto-start-time-persistence.test.ts +21 -39
  527. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +15 -24
  528. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +44 -29
  529. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +39 -51
  530. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +159 -213
  531. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +15 -32
  532. package/src/resources/extensions/gsd/tests/browser-teardown.test.ts +0 -41
  533. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +97 -2
  534. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +34 -27
  535. package/src/resources/extensions/gsd/tests/cmux.test.ts +51 -53
  536. package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +39 -61
  537. package/src/resources/extensions/gsd/tests/commands-config.test.ts +26 -19
  538. package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +14 -1
  539. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +31 -0
  540. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +140 -0
  541. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +3 -2
  542. package/src/resources/extensions/gsd/tests/complete-task-normalize-lists.test.ts +29 -33
  543. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +45 -108
  544. package/src/resources/extensions/gsd/tests/context-budget.test.ts +10 -1
  545. package/src/resources/extensions/gsd/tests/context-store.test.ts +7 -1
  546. package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +90 -31
  547. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +22 -0
  548. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +18 -10
  549. package/src/resources/extensions/gsd/tests/cwd-fallback-hardening.test.ts +138 -0
  550. package/src/resources/extensions/gsd/tests/dashboard-custom-engine.test.ts +4 -68
  551. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +6 -11
  552. package/src/resources/extensions/gsd/tests/deferred-milestone-dir-4996.test.ts +14 -65
  553. package/src/resources/extensions/gsd/tests/detection.test.ts +140 -0
  554. package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +44 -37
  555. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +58 -40
  556. package/src/resources/extensions/gsd/tests/dispatch-guard-closed-status.test.ts +25 -15
  557. package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +313 -0
  558. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +35 -17
  559. package/src/resources/extensions/gsd/tests/error-success-mask.test.ts +16 -21
  560. package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +15 -82
  561. package/src/resources/extensions/gsd/tests/exec-history.test.ts +15 -0
  562. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +65 -0
  563. package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +5 -2
  564. package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +219 -0
  565. package/src/resources/extensions/gsd/tests/finalize-survivor-branch.test.ts +151 -0
  566. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +2 -20
  567. package/src/resources/extensions/gsd/tests/frontmatter-parse-noise.test.ts +18 -26
  568. package/src/resources/extensions/gsd/tests/has-pending-deep-stage.test.ts +33 -1
  569. package/src/resources/extensions/gsd/tests/init-skip-git.test.ts +9 -12
  570. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +40 -0
  571. package/src/resources/extensions/gsd/tests/integration/commands-eval-review.integration.test.ts +4 -2
  572. package/src/resources/extensions/gsd/tests/integration/git-locale.test.ts +31 -20
  573. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +66 -0
  574. package/src/resources/extensions/gsd/tests/integration/milestone-transition-worktree.test.ts +0 -47
  575. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +60 -202
  576. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +13 -56
  577. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +248 -10
  578. package/src/resources/extensions/gsd/tests/journal-query-tool.test.ts +32 -0
  579. package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -0
  580. package/src/resources/extensions/gsd/tests/lazy-pi-tui-import.test.ts +44 -6
  581. package/src/resources/extensions/gsd/tests/memory-decay-factor.test.ts +90 -0
  582. package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +21 -35
  583. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +37 -7
  584. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +48 -0
  585. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +127 -0
  586. package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +267 -0
  587. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +88 -98
  588. package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +70 -278
  589. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +34 -2
  590. package/src/resources/extensions/gsd/tests/needs-remediation-revalidation.test.ts +37 -30
  591. package/src/resources/extensions/gsd/tests/note-captures-executed.test.ts +32 -28
  592. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +44 -9
  593. package/src/resources/extensions/gsd/tests/orphan-merge-bootstrap.test.ts +144 -0
  594. package/src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts +201 -0
  595. package/src/resources/extensions/gsd/tests/parallel-orchestrator-fast-forward.test.ts +113 -0
  596. package/src/resources/extensions/gsd/tests/phantom-ghost-detection.test.ts +24 -37
  597. package/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts +9 -24
  598. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +95 -75
  599. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +50 -0
  600. package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
  601. package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +36 -22
  602. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +36 -30
  603. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +45 -5
  604. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +74 -4
  605. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +20 -22
  606. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +130 -32
  607. package/src/resources/extensions/gsd/tests/project-root-cwd-crash.test.ts +18 -36
  608. package/src/resources/extensions/gsd/tests/projection-no-plan-overwrite.test.ts +35 -73
  609. package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +76 -138
  610. package/src/resources/extensions/gsd/tests/prompt-duplication-cuts.test.ts +230 -0
  611. package/src/resources/extensions/gsd/tests/prompt-path-audit.test.ts +40 -0
  612. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +70 -106
  613. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +59 -161
  614. package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +33 -29
  615. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +22 -196
  616. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +23 -93
  617. package/src/resources/extensions/gsd/tests/quick-external-gsd.test.ts +40 -0
  618. package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +50 -79
  619. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +27 -13
  620. package/src/resources/extensions/gsd/tests/remote-questions.test.ts +151 -251
  621. package/src/resources/extensions/gsd/tests/resource-loader-import-path.test.ts +41 -29
  622. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +58 -69
  623. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +32 -164
  624. package/src/resources/extensions/gsd/tests/right-sized-workflow-prompts.test.ts +192 -0
  625. package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +57 -41
  626. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +91 -0
  627. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +29 -0
  628. package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +156 -0
  629. package/src/resources/extensions/gsd/tests/select-resumable-milestone.test.ts +96 -0
  630. package/src/resources/extensions/gsd/tests/session-model-override.test.ts +14 -9
  631. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +77 -0
  632. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +222 -0
  633. package/src/resources/extensions/gsd/tests/show-config-command.test.ts +44 -42
  634. package/src/resources/extensions/gsd/tests/signal-handlers.test.ts +27 -0
  635. package/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts +56 -24
  636. package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +51 -11
  637. package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +23 -0
  638. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +66 -50
  639. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +68 -107
  640. package/src/resources/extensions/gsd/tests/slice-sequence-insert.test.ts +115 -42
  641. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +21 -59
  642. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +25 -116
  643. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +21 -57
  644. package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +29 -76
  645. package/src/resources/extensions/gsd/tests/stale-lockfile-recovery.test.ts +33 -24
  646. package/src/resources/extensions/gsd/tests/stale-slice-rows.test.ts +39 -30
  647. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +49 -1
  648. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +101 -2
  649. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +6 -4
  650. package/src/resources/extensions/gsd/tests/status-db-open.test.ts +35 -40
  651. package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +48 -46
  652. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +14 -102
  653. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +78 -232
  654. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +32 -35
  655. package/src/resources/extensions/gsd/tests/system-context-memory.test.ts +112 -0
  656. package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +7 -9
  657. package/src/resources/extensions/gsd/tests/token-profile.test.ts +84 -309
  658. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +291 -0
  659. package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +134 -341
  660. package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +210 -0
  661. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +136 -4
  662. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +8 -25
  663. package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +80 -1
  664. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +37 -0
  665. package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +5 -99
  666. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +43 -36
  667. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -444
  668. package/src/resources/extensions/gsd/tests/workflow-dispatch-claim.test.ts +142 -0
  669. package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +44 -189
  670. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -57
  671. package/src/resources/extensions/gsd/tests/workflow-protocol-excerpt.test.ts +99 -0
  672. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +3 -0
  673. package/src/resources/extensions/gsd/tests/workflow-worker-heartbeat.test.ts +32 -1
  674. package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +21 -44
  675. package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +27 -26
  676. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +38 -6
  677. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +50 -31
  678. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +434 -0
  679. package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +20 -18
  680. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +7 -0
  681. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +9 -2
  682. package/src/resources/extensions/gsd/tests/worktree-path-injection.test.ts +22 -19
  683. package/src/resources/extensions/gsd/tests/worktree-project-root-degrade.test.ts +66 -0
  684. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +373 -76
  685. package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +327 -0
  686. package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +120 -0
  687. package/src/resources/extensions/gsd/tests/write-gate.test.ts +40 -1
  688. package/src/resources/extensions/gsd/tests/zero-slice-roadmap-guided.test.ts +19 -13
  689. package/src/resources/extensions/gsd/tool-contract.ts +82 -0
  690. package/src/resources/extensions/gsd/tools/complete-milestone.ts +14 -15
  691. package/src/resources/extensions/gsd/tools/complete-task.ts +1 -1
  692. package/src/resources/extensions/gsd/tools/context-mode-tool-result.ts +25 -0
  693. package/src/resources/extensions/gsd/tools/exec-search-tool.ts +7 -7
  694. package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -23
  695. package/src/resources/extensions/gsd/tools/memory-tools.ts +1 -0
  696. package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -0
  697. package/src/resources/extensions/gsd/tools/plan-task.ts +10 -0
  698. package/src/resources/extensions/gsd/tools/resume-tool.ts +7 -7
  699. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +1 -1
  700. package/src/resources/extensions/gsd/unit-context-composer.ts +19 -4
  701. package/src/resources/extensions/gsd/unit-runtime.ts +25 -0
  702. package/src/resources/extensions/gsd/workflow-protocol.ts +160 -0
  703. package/src/resources/extensions/gsd/worktree-lifecycle.ts +1255 -0
  704. package/src/resources/extensions/gsd/worktree-manager.ts +15 -4
  705. package/src/resources/extensions/gsd/worktree-safety.ts +282 -0
  706. package/src/resources/extensions/gsd/worktree-state-projection.ts +404 -0
  707. package/src/resources/skills/create-gsd-extension/templates/templates.test.ts +86 -40
  708. package/src/resources/skills/web-quality-audit/scripts/analyze.sh +0 -0
  709. package/dist/resources/extensions/gsd/worktree-resolver.js +0 -733
  710. package/dist/web/standalone/.next/static/chunks/8336.631939fb583761fa.js +0 -10
  711. package/src/resources/extensions/gsd/tests/sync-layer-scope.test.ts +0 -434
  712. package/src/resources/extensions/gsd/worktree-resolver.ts +0 -909
  713. /package/dist/web/standalone/.next/static/{k-MDjzPMF62Rg1-FR437h → 8G7Lc96dfT0V6VXh6O6Ka}/_buildManifest.js +0 -0
  714. /package/dist/web/standalone/.next/static/{k-MDjzPMF62Rg1-FR437h → 8G7Lc96dfT0V6VXh6O6Ka}/_ssgManifest.js +0 -0
@@ -1,3 +1,5 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: Auto-loop pipeline phases, merge closeout, and finalize handling.
1
3
  /**
2
4
  * auto/phases.ts — Pipeline phases for the auto-loop.
3
5
  *
@@ -32,13 +34,13 @@ import { detectStuck } from "./detect-stuck.js";
32
34
  import { runUnit } from "./run-unit.js";
33
35
  import { debugLog } from "../debug-logger.js";
34
36
  import { resolveWorktreeProjectRoot, normalizeWorktreePathForCompare } from "../worktree-root.js";
35
- import { PROJECT_FILES, hasProjectFileInAncestor } from "../detection.js";
37
+ import { classifyProject } from "../detection.js";
36
38
  import { MergeConflictError } from "../git-service.js";
37
39
  import { setCurrentPhase, clearCurrentPhase } from "../../shared/gsd-phase-state.js";
38
40
  import { pauseAutoForProviderError } from "../provider-error-pause.js";
39
41
  import { resumeAutoAfterProviderDelay } from "../bootstrap/provider-error-resume.js";
40
42
  import { join, basename } from "node:path";
41
- import { existsSync, cpSync, readdirSync } from "node:fs";
43
+ import { existsSync, cpSync } from "node:fs";
42
44
  import {
43
45
  logWarning,
44
46
  logError,
@@ -50,13 +52,14 @@ import {
50
52
  } from "../workflow-logger.js";
51
53
  import { gsdRoot } from "../paths.js";
52
54
  import { atomicWriteSync } from "../atomic-write.js";
53
- import { verifyExpectedArtifact, diagnoseExpectedArtifact, buildLoopRemediationSteps } from "../auto-recovery.js";
55
+ import { verifyExpectedArtifact, diagnoseExpectedArtifact, buildLoopRemediationSteps, refreshRecoveryDbForArtifact } from "../auto-recovery.js";
54
56
  import { writeUnitRuntimeRecord } from "../unit-runtime.js";
55
57
  import { withTimeout, FINALIZE_PRE_TIMEOUT_MS, FINALIZE_POST_TIMEOUT_MS } from "./finalize-timeout.js";
56
58
  import { getEligibleSlices } from "../slice-parallel-eligibility.js";
57
59
  import { startSliceParallel } from "../slice-parallel-orchestrator.js";
58
- import { isDbAvailable, getMilestoneSlices, refreshOpenDatabaseFromDisk } from "../gsd-db.js";
60
+ import { isDbAvailable, getMilestoneSlices } from "../gsd-db.js";
59
61
  import type { MinimalModelRegistry } from "../context-budget.js";
62
+ import type { PostflightResult, PreflightResult } from "../clean-root-preflight.js";
60
63
  import { ensurePlanV2Graph, isEmptyPlanV2GraphResult, isMissingFinalizedContextResult } from "../uok/plan-v2.js";
61
64
  import { resolveUokFlags } from "../uok/flags.js";
62
65
  import { UokGateRunner } from "../uok/gate-runner.js";
@@ -69,6 +72,8 @@ import {
69
72
  getRequiredWorkflowToolsForAutoUnit,
70
73
  supportsStructuredQuestions,
71
74
  } from "../workflow-mcp.js";
75
+ import { resolveManifest } from "../unit-context-manifest.js";
76
+ import { createWorktreeSafetyModule, type WorktreeSafetyResult } from "../worktree-safety.js";
72
77
 
73
78
  // ─── Path Comparison Helper ───────────────────────────────────────────────
74
79
  /** Compare two paths for physical identity, tolerating trailing slashes and symlinks. */
@@ -76,10 +81,111 @@ function isSamePathLocal(a: string, b: string): boolean {
76
81
  return normalizeWorktreePathForCompare(a) === normalizeWorktreePathForCompare(b);
77
82
  }
78
83
 
79
- function refreshPlanSliceRecoveryDbIfNeeded(unitType: string): boolean {
80
- if (unitType !== "plan-slice") return true;
81
- if (!isDbAvailable()) return true;
82
- return refreshOpenDatabaseFromDisk();
84
+ export function shouldDegradeEmptyWorktreeToProjectRoot(
85
+ worktreeClassification: ReturnType<typeof classifyProject>,
86
+ projectRootClassification: ReturnType<typeof classifyProject>,
87
+ ): boolean {
88
+ return (
89
+ worktreeClassification.kind === "greenfield" &&
90
+ projectRootClassification.kind !== "greenfield" &&
91
+ projectRootClassification.kind !== "invalid-repo"
92
+ );
93
+ }
94
+
95
+ function unitWritesSource(unitType: string): boolean | null {
96
+ const manifest = resolveManifest(unitType);
97
+ if (!manifest) return null;
98
+ return manifest.tools.mode === "all" || manifest.tools.mode === "docs";
99
+ }
100
+
101
+ function formatWorktreeSafetyFailure(result: Extract<WorktreeSafetyResult, { ok: false }>): string {
102
+ return `Worktree Safety failed (${result.kind}): ${result.reason} ${result.remediation}`;
103
+ }
104
+
105
+ function resolveEmptyWorktreeWithProjectContent(
106
+ unitRoot: string,
107
+ projectRoot: string,
108
+ ): boolean {
109
+ if (isSamePathLocal(unitRoot, projectRoot)) return false;
110
+ const worktreeClassification = classifyProject(unitRoot);
111
+ if (worktreeClassification.kind !== "greenfield") return false;
112
+ const projectRootClassification = classifyProject(projectRoot);
113
+ return shouldDegradeEmptyWorktreeToProjectRoot(worktreeClassification, projectRootClassification);
114
+ }
115
+
116
+ async function validateSourceWriteWorktreeSafety(
117
+ ic: IterationContext,
118
+ unitType: string,
119
+ unitId: string,
120
+ milestoneId: string | undefined,
121
+ phase: string,
122
+ ): Promise<{ action: "break"; reason: string } | null> {
123
+ const { ctx, pi, s, deps } = ic;
124
+ if (!s.basePath) return null;
125
+
126
+ // Custom engine workflows (graph-driven, registered via run dirs) define
127
+ // their own step ids that are not in the GSD UnitContextManifest. Don't
128
+ // fail closed for those — the custom engine owns its own dispatch
129
+ // contract. The fail-closed safety check applies only to built-in GSD
130
+ // units whose Tool Contract is registered in the manifest. Use a truthy
131
+ // check so undefined (test sessions that never set the field) routes
132
+ // through the safety check, matching the regression test contract.
133
+ if (s.activeEngineId) return null;
134
+
135
+ const writesSource = unitWritesSource(unitType);
136
+ if (writesSource === null) {
137
+ const msg = `Worktree Safety failed (missing-tool-contract): missing Tool Contract for ${unitType}. Add a UnitContextManifest entry before dispatching this Unit.`;
138
+ debugLog("worktreeSafety", {
139
+ phase,
140
+ unitType,
141
+ unitId,
142
+ milestoneId,
143
+ result: { ok: false, kind: "missing-tool-contract", reason: msg },
144
+ basePath: s.basePath,
145
+ });
146
+ ctx.ui.notify(msg, "error");
147
+ await deps.stopAuto(ctx, pi, msg);
148
+ return { action: "break", reason: "missing-tool-contract" };
149
+ }
150
+ if (!writesSource) return null;
151
+
152
+ const projectRoot = s.canonicalProjectRoot ?? resolveWorktreeProjectRoot(s.basePath, s.originalBasePath);
153
+ if (deps.getIsolationMode(projectRoot) !== "worktree") return null;
154
+
155
+ const safety = createWorktreeSafetyModule();
156
+ const result = safety.validateUnitRoot({
157
+ unitType,
158
+ unitId,
159
+ writeScope: "source-writing",
160
+ projectRoot,
161
+ unitRoot: s.basePath,
162
+ milestoneId,
163
+ expectedBranch: milestoneId ? deps.autoWorktreeBranch(milestoneId) : null,
164
+ emptyWorktreeWithProjectContent: resolveEmptyWorktreeWithProjectContent(s.basePath, projectRoot),
165
+ lease: s.workerId
166
+ ? {
167
+ required: true,
168
+ held: s.currentMilestoneId === milestoneId && s.milestoneLeaseToken !== null,
169
+ owner: s.workerId,
170
+ }
171
+ : undefined,
172
+ });
173
+
174
+ if (result.ok) return null;
175
+
176
+ const msg = formatWorktreeSafetyFailure(result);
177
+ debugLog("worktreeSafety", {
178
+ phase,
179
+ unitType,
180
+ unitId,
181
+ milestoneId,
182
+ result,
183
+ basePath: s.basePath,
184
+ projectRoot,
185
+ });
186
+ ctx.ui.notify(msg, "error");
187
+ await deps.stopAuto(ctx, pi, msg);
188
+ return { action: "break", reason: result.kind };
83
189
  }
84
190
 
85
191
  // ─── Session timeout auto-resume state ────────────────────────────────────────
@@ -120,10 +226,23 @@ const PLAN_V2_GATE_PHASES: ReadonlySet<Phase> = new Set([
120
226
  "completing-milestone",
121
227
  ]);
122
228
 
123
- function shouldRunPlanV2Gate(phase: Phase): boolean {
229
+ export function shouldRunPlanV2Gate(phase: Phase): boolean {
124
230
  return PLAN_V2_GATE_PHASES.has(phase);
125
231
  }
126
232
 
233
+ export function _shouldProceedWithInvalidRepoClassificationForTest(
234
+ reason: string | undefined,
235
+ hasGit: boolean,
236
+ ): boolean {
237
+ return reason === "missing .git" && hasGit;
238
+ }
239
+
240
+ export function _resolveCurrentUnitStartedAtForTest(
241
+ currentUnit: { startedAt: number } | null | undefined,
242
+ ): number | undefined {
243
+ return currentUnit?.startedAt;
244
+ }
245
+
127
246
  /**
128
247
  * Generate and write an HTML milestone report snapshot.
129
248
  * Extracted from the milestone-transition block in autoLoop.
@@ -215,6 +334,136 @@ async function closeoutAndStop(
215
334
  await deps.stopAuto(ctx, pi, reason);
216
335
  }
217
336
 
337
+ async function stopOnPostflightRecoveryNeeded(
338
+ ic: IterationContext,
339
+ result: PostflightResult,
340
+ milestoneId: string,
341
+ ): Promise<{ action: "break"; reason: string } | null> {
342
+ if (!result.needsManualRecovery) return null;
343
+ const { ctx, pi, deps } = ic;
344
+ const reason = `Post-merge stash restore failed for milestone ${milestoneId}`;
345
+ ctx.ui.notify(
346
+ `${reason}. Resolve the working tree before resuming auto-mode. ${result.message}`,
347
+ "error",
348
+ );
349
+ await deps.stopAuto(ctx, pi, reason);
350
+ return { action: "break", reason: "postflight-stash-restore-failed" };
351
+ }
352
+
353
+ async function restorePreflightStashOrStop(
354
+ ic: IterationContext,
355
+ preflight: PreflightResult,
356
+ milestoneId: string,
357
+ ): Promise<{ action: "break"; reason: string } | null> {
358
+ if (!preflight.stashPushed) return null;
359
+ const { ctx, s, deps } = ic;
360
+ const result = deps.postflightPopStash(
361
+ s.originalBasePath || s.basePath,
362
+ milestoneId,
363
+ preflight.stashMarker,
364
+ ctx.ui.notify.bind(ctx.ui),
365
+ );
366
+ return stopOnPostflightRecoveryNeeded(ic, result, milestoneId);
367
+ }
368
+
369
+ /**
370
+ * Run a milestone merge surrounded by preflight stash + always-on postflight
371
+ * pop. The previous code popped the stash only after a successful merge, which
372
+ * leaked `gsd-preflight-stash:M00x:*` entries whenever `mergeAndExit` threw —
373
+ * leaving the user's pre-merge working tree silently stashed away after a
374
+ * merge-conflict or other merge error. This helper restores the stash on
375
+ * every exit path, then surfaces the merge or stash failure (in priority
376
+ * order) as the loop's stop reason.
377
+ *
378
+ * Returns a `break` action when auto-mode must stop, or `null` when the merge
379
+ * succeeded and the stash (if any) was restored cleanly.
380
+ */
381
+ export async function _runMilestoneMergeWithStashRestore(
382
+ ic: IterationContext,
383
+ milestoneId: string,
384
+ ): Promise<{ action: "break"; reason: string } | null> {
385
+ const { ctx, pi, s, deps } = ic;
386
+
387
+ const preflight = deps.preflightCleanRoot(
388
+ s.originalBasePath || s.basePath,
389
+ milestoneId,
390
+ ctx.ui.notify.bind(ctx.ui),
391
+ );
392
+
393
+ let mergeError: unknown = null;
394
+ const exitResult = deps.lifecycle.exitMilestone(
395
+ milestoneId,
396
+ { merge: true },
397
+ ctx.ui,
398
+ );
399
+ if (exitResult.ok) {
400
+ s.milestoneMergedInPhases = true;
401
+ } else {
402
+ mergeError = exitResult.cause ?? new Error(`exit ${exitResult.reason}`);
403
+ }
404
+
405
+ // Always attempt to restore the stashed working tree, even on merge error.
406
+ // postflightPopStash itself does not throw; failures surface via the
407
+ // PostflightResult.needsManualRecovery flag.
408
+ let stashResult: PostflightResult | null = null;
409
+ if (preflight.stashPushed) {
410
+ stashResult = deps.postflightPopStash(
411
+ s.originalBasePath || s.basePath,
412
+ milestoneId,
413
+ preflight.stashMarker,
414
+ ctx.ui.notify.bind(ctx.ui),
415
+ );
416
+ }
417
+
418
+ // Merge failure takes priority over stash recovery — the merge is the
419
+ // authoritative gate. If the stash also needed manual recovery, the user
420
+ // already saw the postflightPopStash notify above.
421
+ if (mergeError) {
422
+ if (mergeError instanceof MergeConflictError) {
423
+ ctx.ui.notify(
424
+ `Merge conflict: ${mergeError.conflictedFiles.join(", ")}. Resolve conflicts manually and run /gsd auto to resume.`,
425
+ "error",
426
+ );
427
+ await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${milestoneId}`);
428
+ return { action: "break", reason: "merge-conflict" };
429
+ }
430
+ logError("engine", "Milestone merge failed with non-conflict error", {
431
+ milestone: milestoneId,
432
+ error: String(mergeError),
433
+ });
434
+ ctx.ui.notify(
435
+ `Merge failed: ${mergeError instanceof Error ? mergeError.message : String(mergeError)}. Resolve and run /gsd auto to resume.`,
436
+ "error",
437
+ );
438
+ await deps.stopAuto(
439
+ ctx,
440
+ pi,
441
+ `Merge error on milestone ${milestoneId}: ${String(mergeError)}`,
442
+ );
443
+ return { action: "break", reason: "merge-failed" };
444
+ }
445
+
446
+ if (stashResult) {
447
+ return stopOnPostflightRecoveryNeeded(ic, stashResult, milestoneId);
448
+ }
449
+ return null;
450
+ }
451
+
452
+ export async function _runMilestoneMergeOnceWithStashRestore(
453
+ ic: IterationContext,
454
+ milestoneId: string,
455
+ ): Promise<{ action: "break"; reason: string } | null> {
456
+ if (ic.s.milestoneMergedInPhases) {
457
+ debugLog("autoLoop", {
458
+ phase: "milestone-merge-skip",
459
+ reason: "already-merged-in-phases",
460
+ milestoneId,
461
+ });
462
+ return null;
463
+ }
464
+ return _runMilestoneMergeWithStashRestore(ic, milestoneId);
465
+ }
466
+
218
467
  async function emitCancelledUnitEnd(
219
468
  ic: IterationContext,
220
469
  unitType: string,
@@ -442,13 +691,10 @@ export async function runPreDispatch(
442
691
  if (
443
692
  s.originalBasePath &&
444
693
  !isSamePathLocal(s.basePath, s.originalBasePath) &&
445
- s.currentMilestoneId
694
+ s.currentMilestoneId &&
695
+ s.scope
446
696
  ) {
447
- deps.syncProjectRootToWorktree(
448
- s.originalBasePath,
449
- s.basePath,
450
- s.currentMilestoneId,
451
- );
697
+ deps.worktreeProjection.projectRootToWorktree(s.scope);
452
698
  }
453
699
 
454
700
  // Derive state — use canonical project root so the cache key is stable
@@ -651,41 +897,11 @@ export async function runPreDispatch(
651
897
  loopState.recentUnits.length = 0;
652
898
  loopState.stuckRecoveryAttempts = 0;
653
899
 
654
- // Worktree lifecycle on milestone transition — merge current, enter next
655
- // #2909: preflight warn + stash dirty working tree before merge
656
- const preflightTransition = deps.preflightCleanRoot(
657
- s.originalBasePath || s.basePath,
658
- s.currentMilestoneId!,
659
- ctx.ui.notify.bind(ctx.ui),
660
- );
661
- try {
662
- deps.resolver.mergeAndExit(s.currentMilestoneId!, ctx.ui);
663
- } catch (mergeErr) {
664
- if (mergeErr instanceof MergeConflictError) {
665
- // Real code conflicts — stop the loop instead of retrying forever (#2330)
666
- ctx.ui.notify(
667
- `Merge conflict: ${mergeErr.conflictedFiles.join(", ")}. Resolve conflicts manually and run /gsd auto to resume.`,
668
- "error",
669
- );
670
- await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${s.currentMilestoneId}`);
671
- return { action: "break", reason: "merge-conflict" };
672
- }
673
- // Non-conflict merge errors — stop auto to avoid advancing with unmerged work
674
- logError("engine", "Milestone merge failed with non-conflict error", { milestone: s.currentMilestoneId!, error: String(mergeErr) });
675
- ctx.ui.notify(
676
- `Merge failed: ${mergeErr instanceof Error ? mergeErr.message : String(mergeErr)}. Resolve and run /gsd auto to resume.`,
677
- "error",
678
- );
679
- await deps.stopAuto(ctx, pi, `Merge error on milestone ${s.currentMilestoneId}: ${String(mergeErr)}`);
680
- return { action: "break", reason: "merge-failed" };
681
- }
682
- // #2909: postflight — restore stashed changes after successful merge
683
- if (preflightTransition.stashPushed) {
684
- deps.postflightPopStash(
685
- s.originalBasePath || s.basePath,
686
- s.currentMilestoneId!,
687
- ctx.ui.notify.bind(ctx.ui),
688
- );
900
+ // Worktree lifecycle on milestone transition — merge current, enter next.
901
+ // #2909 / #5538-followup: preflight stash + always-on postflight pop.
902
+ {
903
+ const stop = await _runMilestoneMergeOnceWithStashRestore(ic, s.currentMilestoneId!);
904
+ if (stop) return stop;
689
905
  }
690
906
 
691
907
  // PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
@@ -700,7 +916,17 @@ export async function runPreDispatch(
700
916
  if (deps.getIsolationMode(s.basePath) !== "none") {
701
917
  deps.captureIntegrationBranch(s.basePath, mid);
702
918
  }
703
- deps.resolver.enterMilestone(mid, ctx.ui);
919
+ const enterResult = deps.lifecycle.enterMilestone(mid, ctx.ui);
920
+ if (!enterResult.ok) {
921
+ ctx.ui.notify(
922
+ `Milestone transition stopped: failed to enter ${mid} (${enterResult.reason}).`,
923
+ "error",
924
+ );
925
+ if (enterResult.reason === "lease-conflict") {
926
+ await deps.pauseAuto(ctx, pi);
927
+ }
928
+ return { action: "break", reason: "milestone-enter-failed" };
929
+ }
704
930
  } else {
705
931
  // mid is undefined — no milestone to capture integration branch for
706
932
  }
@@ -763,44 +989,11 @@ export async function runPreDispatch(
763
989
  m.status !== "complete" && m.status !== "parked",
764
990
  );
765
991
  if (incomplete.length === 0 && state.registry.length > 0) {
766
- // All milestones complete — merge milestone branch before stopping
992
+ // All milestones complete — merge milestone branch before stopping.
767
993
  if (s.currentMilestoneId) {
768
- // #2909: preflight warn + stash dirty working tree before merge
769
- const preflightAllComplete = deps.preflightCleanRoot(
770
- s.originalBasePath || s.basePath,
771
- s.currentMilestoneId,
772
- ctx.ui.notify.bind(ctx.ui),
773
- );
774
- try {
775
- deps.resolver.mergeAndExit(s.currentMilestoneId, ctx.ui);
776
- // Prevent stopAuto from attempting the same merge (#2645)
777
- s.milestoneMergedInPhases = true;
778
- } catch (mergeErr) {
779
- if (mergeErr instanceof MergeConflictError) {
780
- ctx.ui.notify(
781
- `Merge conflict: ${mergeErr.conflictedFiles.join(", ")}. Resolve conflicts manually and run /gsd auto to resume.`,
782
- "error",
783
- );
784
- await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${s.currentMilestoneId}`);
785
- return { action: "break", reason: "merge-conflict" };
786
- }
787
- logError("engine", "Milestone merge failed with non-conflict error", { milestone: s.currentMilestoneId!, error: String(mergeErr) });
788
- ctx.ui.notify(
789
- `Merge failed: ${mergeErr instanceof Error ? mergeErr.message : String(mergeErr)}. Resolve and run /gsd auto to resume.`,
790
- "error",
791
- );
792
- await deps.stopAuto(ctx, pi, `Merge error on milestone ${s.currentMilestoneId}: ${String(mergeErr)}`);
793
- return { action: "break", reason: "merge-failed" };
794
- }
795
- // #2909: postflight — restore stashed changes after successful merge
796
- if (preflightAllComplete.stashPushed) {
797
- deps.postflightPopStash(
798
- s.originalBasePath || s.basePath,
799
- s.currentMilestoneId,
800
- ctx.ui.notify.bind(ctx.ui),
801
- );
802
- }
803
-
994
+ // #2909 / #5538-followup: preflight stash + always-on postflight pop.
995
+ const stop = await _runMilestoneMergeOnceWithStashRestore(ic, s.currentMilestoneId);
996
+ if (stop) return stop;
804
997
  // PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
805
998
  }
806
999
  deps.sendDesktopNotification(
@@ -891,44 +1084,11 @@ export async function runPreDispatch(
891
1084
 
892
1085
  // Terminal: complete
893
1086
  if (state.phase === "complete") {
894
- // Milestone merge on complete (before closeout so branch state is clean)
1087
+ // Milestone merge on complete (before closeout so branch state is clean).
895
1088
  if (s.currentMilestoneId) {
896
- // #2909: preflight warn + stash dirty working tree before merge
897
- const preflightComplete = deps.preflightCleanRoot(
898
- s.originalBasePath || s.basePath,
899
- s.currentMilestoneId,
900
- ctx.ui.notify.bind(ctx.ui),
901
- );
902
- try {
903
- deps.resolver.mergeAndExit(s.currentMilestoneId, ctx.ui);
904
- // Prevent stopAuto from attempting the same merge (#2645)
905
- s.milestoneMergedInPhases = true;
906
- } catch (mergeErr) {
907
- if (mergeErr instanceof MergeConflictError) {
908
- ctx.ui.notify(
909
- `Merge conflict: ${mergeErr.conflictedFiles.join(", ")}. Resolve conflicts manually and run /gsd auto to resume.`,
910
- "error",
911
- );
912
- await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${s.currentMilestoneId}`);
913
- return { action: "break", reason: "merge-conflict" };
914
- }
915
- logError("engine", "Milestone merge failed with non-conflict error", { milestone: s.currentMilestoneId!, error: String(mergeErr) });
916
- ctx.ui.notify(
917
- `Merge failed: ${mergeErr instanceof Error ? mergeErr.message : String(mergeErr)}. Resolve and run /gsd auto to resume.`,
918
- "error",
919
- );
920
- await deps.stopAuto(ctx, pi, `Merge error on milestone ${s.currentMilestoneId}: ${String(mergeErr)}`);
921
- return { action: "break", reason: "merge-failed" };
922
- }
923
- // #2909: postflight — restore stashed changes after successful merge
924
- if (preflightComplete.stashPushed) {
925
- deps.postflightPopStash(
926
- s.originalBasePath || s.basePath,
927
- s.currentMilestoneId,
928
- ctx.ui.notify.bind(ctx.ui),
929
- );
930
- }
931
-
1089
+ // #2909 / #5538-followup: preflight stash + always-on postflight pop.
1090
+ const stop = await _runMilestoneMergeOnceWithStashRestore(ic, s.currentMilestoneId);
1091
+ if (stop) return stop;
932
1092
  // PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
933
1093
  }
934
1094
  deps.sendDesktopNotification(
@@ -1051,6 +1211,58 @@ export async function runDispatch(
1051
1211
  let prompt = dispatchResult.prompt;
1052
1212
  const pauseAfterUatDispatch = dispatchResult.pauseAfterDispatch ?? false;
1053
1213
 
1214
+ // Resolve hooks and prior-slice gating before health/stuck accounting so
1215
+ // those checks run against the final dispatch unit.
1216
+ const preDispatchResult = deps.runPreDispatchHooks(
1217
+ unitType,
1218
+ unitId,
1219
+ prompt,
1220
+ s.basePath,
1221
+ );
1222
+ if (preDispatchResult.firedHooks.length > 0) {
1223
+ ctx.ui.notify(
1224
+ `Pre-dispatch hook${preDispatchResult.firedHooks.length > 1 ? "s" : ""}: ${preDispatchResult.firedHooks.join(", ")}`,
1225
+ "info",
1226
+ );
1227
+ deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "pre-dispatch-hook", data: { firedHooks: preDispatchResult.firedHooks, action: preDispatchResult.action } });
1228
+ }
1229
+ if (preDispatchResult.action === "skip") {
1230
+ ctx.ui.notify(
1231
+ `Skipping ${unitType} ${unitId} (pre-dispatch hook).`,
1232
+ "info",
1233
+ );
1234
+ await new Promise((r) => setImmediate(r));
1235
+ return { action: "continue" };
1236
+ }
1237
+ if (preDispatchResult.action === "replace") {
1238
+ prompt = preDispatchResult.prompt ?? prompt;
1239
+ if (preDispatchResult.unitType) unitType = preDispatchResult.unitType;
1240
+ } else if (preDispatchResult.prompt) {
1241
+ prompt = preDispatchResult.prompt;
1242
+ }
1243
+
1244
+ const guardBasePath = _resolveDispatchGuardBasePath(s);
1245
+ const priorSliceBlocker = deps.getPriorSliceCompletionBlocker(
1246
+ guardBasePath,
1247
+ deps.getMainBranch(guardBasePath),
1248
+ unitType,
1249
+ unitId,
1250
+ );
1251
+ if (priorSliceBlocker) {
1252
+ await deps.stopAuto(ctx, pi, priorSliceBlocker);
1253
+ debugLog("autoLoop", { phase: "exit", reason: "prior-slice-blocker" });
1254
+ return { action: "break", reason: "prior-slice-blocker" };
1255
+ }
1256
+
1257
+ const worktreeSafetyBlock = await validateSourceWriteWorktreeSafety(
1258
+ ic,
1259
+ unitType,
1260
+ unitId,
1261
+ mid,
1262
+ "pre-dispatch",
1263
+ );
1264
+ if (worktreeSafetyBlock) return worktreeSafetyBlock;
1265
+
1054
1266
  // ── Sliding-window stuck detection with graduated recovery ──
1055
1267
  const derivedKey = `${unitType}/${unitId}`;
1056
1268
 
@@ -1097,17 +1309,24 @@ export async function runDispatch(
1097
1309
  level: 1,
1098
1310
  action: "artifact-found",
1099
1311
  });
1100
- ctx.ui.notify(
1101
- `Stuck recovery: artifact for ${unitType} ${unitId} found on disk. Invalidating caches.`,
1102
- "info",
1103
- );
1104
- if (!refreshPlanSliceRecoveryDbIfNeeded(unitType)) {
1312
+ const recoveryDb = refreshRecoveryDbForArtifact(unitType, unitId);
1313
+ if (!recoveryDb.ok) {
1105
1314
  ctx.ui.notify(
1106
- `Stuck recovery found ${unitType} ${unitId} artifacts, but the DB refresh failed. Keeping stuck state for retry.`,
1315
+ recoveryDb.fatal
1316
+ ? `${recoveryDb.message} Pausing auto-mode for manual recovery.`
1317
+ : `${recoveryDb.message} Keeping stuck state for retry.`,
1107
1318
  "warning",
1108
1319
  );
1320
+ if (recoveryDb.fatal) {
1321
+ await deps.pauseAuto(ctx, pi);
1322
+ return { action: "break", reason: recoveryDb.reason };
1323
+ }
1109
1324
  return { action: "continue" };
1110
1325
  }
1326
+ ctx.ui.notify(
1327
+ `Stuck recovery: artifact for ${unitType} ${unitId} found on disk. Invalidating caches.`,
1328
+ "info",
1329
+ );
1111
1330
  deps.invalidateAllCaches();
1112
1331
  loopState.recentUnits.length = 0;
1113
1332
  loopState.stuckRecoveryAttempts = 0;
@@ -1132,19 +1351,26 @@ export async function runDispatch(
1132
1351
  level: 2,
1133
1352
  action: "artifact-found",
1134
1353
  });
1135
- ctx.ui.notify(
1136
- `Stuck recovery: artifact for ${unitType} ${unitId} found on disk after cache invalidation. Continuing.`,
1137
- "info",
1138
- );
1139
- if (refreshPlanSliceRecoveryDbIfNeeded(unitType)) {
1354
+ const recoveryDb = refreshRecoveryDbForArtifact(unitType, unitId);
1355
+ if (recoveryDb.ok) {
1356
+ ctx.ui.notify(
1357
+ `Stuck recovery: artifact for ${unitType} ${unitId} found on disk after cache invalidation. Continuing.`,
1358
+ "info",
1359
+ );
1140
1360
  loopState.recentUnits.length = 0;
1141
1361
  loopState.stuckRecoveryAttempts = 0;
1142
1362
  return { action: "continue" };
1143
1363
  }
1144
1364
  ctx.ui.notify(
1145
- `Stuck recovery found ${unitType} ${unitId} artifacts, but the DB refresh failed. Stopping for manual recovery.`,
1365
+ recoveryDb.fatal
1366
+ ? `${recoveryDb.message} Pausing auto-mode for manual recovery.`
1367
+ : `${recoveryDb.message} Stopping for manual recovery.`,
1146
1368
  "warning",
1147
1369
  );
1370
+ if (recoveryDb.fatal) {
1371
+ await deps.pauseAuto(ctx, pi);
1372
+ return { action: "break", reason: recoveryDb.reason };
1373
+ }
1148
1374
  }
1149
1375
  debugLog("autoLoop", {
1150
1376
  phase: "stuck-detected",
@@ -1178,48 +1404,6 @@ export async function runDispatch(
1178
1404
  }
1179
1405
  }
1180
1406
 
1181
- // Pre-dispatch hooks
1182
- const preDispatchResult = deps.runPreDispatchHooks(
1183
- unitType,
1184
- unitId,
1185
- prompt,
1186
- s.basePath,
1187
- );
1188
- if (preDispatchResult.firedHooks.length > 0) {
1189
- ctx.ui.notify(
1190
- `Pre-dispatch hook${preDispatchResult.firedHooks.length > 1 ? "s" : ""}: ${preDispatchResult.firedHooks.join(", ")}`,
1191
- "info",
1192
- );
1193
- deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "pre-dispatch-hook", data: { firedHooks: preDispatchResult.firedHooks, action: preDispatchResult.action } });
1194
- }
1195
- if (preDispatchResult.action === "skip") {
1196
- ctx.ui.notify(
1197
- `Skipping ${unitType} ${unitId} (pre-dispatch hook).`,
1198
- "info",
1199
- );
1200
- await new Promise((r) => setImmediate(r));
1201
- return { action: "continue" };
1202
- }
1203
- if (preDispatchResult.action === "replace") {
1204
- prompt = preDispatchResult.prompt ?? prompt;
1205
- if (preDispatchResult.unitType) unitType = preDispatchResult.unitType;
1206
- } else if (preDispatchResult.prompt) {
1207
- prompt = preDispatchResult.prompt;
1208
- }
1209
-
1210
- const guardBasePath = _resolveDispatchGuardBasePath(s);
1211
- const priorSliceBlocker = deps.getPriorSliceCompletionBlocker(
1212
- guardBasePath,
1213
- deps.getMainBranch(guardBasePath),
1214
- unitType,
1215
- unitId,
1216
- );
1217
- if (priorSliceBlocker) {
1218
- await deps.stopAuto(ctx, pi, priorSliceBlocker);
1219
- debugLog("autoLoop", { phase: "exit", reason: "prior-slice-blocker" });
1220
- return { action: "break", reason: "prior-slice-blocker" };
1221
- }
1222
-
1223
1407
  return {
1224
1408
  action: "next",
1225
1409
  data: {
@@ -1480,46 +1664,46 @@ export async function runUnitPhase(
1480
1664
  unitId,
1481
1665
  });
1482
1666
 
1483
- // ── Worktree health check (#1833, #1843) ────────────────────────────
1484
- // Verify the working directory is a valid git checkout with project
1485
- // files before dispatching work. A broken worktree causes agents to
1486
- // hallucinate summaries since they cannot read or write any files.
1487
- // Uses the shared PROJECT_FILES list from detection.ts to support all
1488
- // ecosystems (Rust, Go, Python, Java, etc.), not just JS.
1667
+ const worktreeSafetyBlock = await validateSourceWriteWorktreeSafety(
1668
+ ic,
1669
+ unitType,
1670
+ unitId,
1671
+ mid,
1672
+ "unit-execution",
1673
+ );
1674
+ if (worktreeSafetyBlock) return worktreeSafetyBlock;
1675
+
1676
+ // ── Project classification notice (#1833, #1843) ─────────────────────
1677
+ // Worktree Safety owns source-write root validity. Classification now only
1678
+ // shapes user/model guidance for valid roots.
1679
+ let projectClassification: ReturnType<typeof classifyProject> | null = null;
1489
1680
  if (s.basePath && unitType === "execute-task") {
1490
- const gitMarker = join(s.basePath, ".git");
1491
- const hasGit = deps.existsSync(gitMarker);
1492
- if (!hasGit) {
1493
- const msg = `Worktree health check failed: ${s.basePath} has no .git — refusing to dispatch ${unitType} ${unitId}`;
1494
- debugLog("runUnitPhase", { phase: "worktree-health-fail", basePath: s.basePath, hasGit });
1495
- ctx.ui.notify(msg, "error");
1496
- await deps.stopAuto(ctx, pi, msg);
1497
- return { action: "break", reason: "worktree-invalid" };
1498
- }
1499
- const hasProjectFile = PROJECT_FILES.some((f) => deps.existsSync(join(s.basePath, f)));
1500
- const hasSrcDir = deps.existsSync(join(s.basePath, "src"));
1501
- // Xcode bundles have project-specific names (*.xcodeproj, *.xcworkspace)
1502
- // that cannot be matched by exact filename — scan the directory by suffix.
1503
- let hasXcodeBundle = false;
1504
- try {
1505
- const entries = deps.existsSync(s.basePath) ? readdirSync(s.basePath) : [];
1506
- hasXcodeBundle = entries.some((e: string) => e.endsWith(".xcodeproj") || e.endsWith(".xcworkspace"));
1507
- } catch (err) {
1508
- debugLog("runUnitPhase", { phase: "xcode-bundle-scan-failed", basePath: s.basePath, error: String(err) });
1681
+ projectClassification = classifyProject(s.basePath);
1682
+ if (projectClassification.kind === "invalid-repo") {
1683
+ const msg = `Worktree health check failed: ${s.basePath} classified as invalid-repo (${projectClassification.reason}) — refusing to dispatch ${unitType} ${unitId}`;
1684
+ debugLog("runUnitPhase", { phase: "worktree-health-invalid-repo", basePath: s.basePath, classification: projectClassification });
1685
+ const hasGit = deps.existsSync(join(s.basePath, ".git"));
1686
+ if (_shouldProceedWithInvalidRepoClassificationForTest(projectClassification.reason, hasGit)) {
1687
+ ctx.ui.notify(
1688
+ `Warning: ${s.basePath} project classification could not confirm .git; assuming it has no project content yet — proceeding as greenfield project because worktree health reported .git present`,
1689
+ "warning",
1690
+ );
1691
+ } else {
1692
+ ctx.ui.notify(msg, "error");
1693
+ await deps.stopAuto(ctx, pi, msg);
1694
+ return { action: "break", reason: "worktree-invalid" };
1695
+ }
1509
1696
  }
1510
- // Monorepo support (#2347): if no project files in the worktree directory,
1511
- // walk parent directories up to the filesystem root. In monorepos,
1512
- // package.json / Cargo.toml etc. live in a parent directory.
1513
- const hasProjectFileInParent =
1514
- !hasProjectFile && !hasSrcDir && !hasXcodeBundle
1515
- ? hasProjectFileInAncestor(s.basePath, deps.existsSync)
1516
- : false;
1517
- if (!hasProjectFile && !hasSrcDir && !hasXcodeBundle && !hasProjectFileInParent) {
1518
- // Greenfield projects won't have project files yet — the first task creates them.
1519
- // Log a warning but allow execution to proceed. The .git check above is sufficient
1520
- // to ensure we're in a valid working directory.
1521
- debugLog("runUnitPhase", { phase: "worktree-health-warn-greenfield", basePath: s.basePath, hasProjectFile, hasSrcDir, hasXcodeBundle });
1522
- ctx.ui.notify(`Warning: ${s.basePath} has no recognized project files — proceeding as greenfield project`, "warning");
1697
+
1698
+ if (projectClassification.kind === "greenfield") {
1699
+ debugLog("runUnitPhase", { phase: "worktree-health-greenfield", basePath: s.basePath, classification: projectClassification });
1700
+ ctx.ui.notify(`Warning: ${s.basePath} has no project content yet — proceeding as greenfield project`, "warning");
1701
+ } else if (projectClassification.kind === "untyped-existing") {
1702
+ debugLog("runUnitPhase", { phase: "worktree-health-untyped-existing", basePath: s.basePath, classification: projectClassification });
1703
+ ctx.ui.notify(
1704
+ `Notice: ${s.basePath} has existing project content but no recognized tooling markers — using generic file-level workflow guidance`,
1705
+ "info",
1706
+ );
1523
1707
  }
1524
1708
  }
1525
1709
 
@@ -1598,6 +1782,17 @@ export async function runUnitPhase(
1598
1782
  // Prompt injection
1599
1783
  let finalPrompt = prompt;
1600
1784
 
1785
+ if (unitType === "execute-task") {
1786
+ projectClassification ??= classifyProject(s.basePath);
1787
+ if (projectClassification.kind === "untyped-existing") {
1788
+ const samples = projectClassification.contentFiles.slice(0, 8).join(", ") || "project files";
1789
+ finalPrompt +=
1790
+ "\n\n**Project classification:** Existing untyped project. No recognized build/tooling markers were detected, " +
1791
+ "so use generic file-level workflow guidance. Task plans and completion summaries must list every concrete " +
1792
+ `project file changed in \`files\` or \`expected_output\`. Detected content sample: ${samples}.`;
1793
+ }
1794
+ }
1795
+
1601
1796
  if (s.pendingVerificationRetry) {
1602
1797
  const retryCtx = s.pendingVerificationRetry;
1603
1798
  s.pendingVerificationRetry = null;
@@ -1982,7 +2177,7 @@ export async function runUnitPhase(
1982
2177
  const currentLedger = deps.getLedger() as { units: Array<{ type: string; id: string; startedAt: number; toolCalls: number }> } | null;
1983
2178
  if (currentLedger?.units) {
1984
2179
  const lastUnit = [...currentLedger.units].reverse().find(
1985
- (u: { type: string; id: string; startedAt: number; toolCalls: number }) => u.type === unitType && u.id === unitId && u.startedAt === s.currentUnit?.startedAt,
2180
+ (u: { type: string; id: string; startedAt: number; toolCalls: number }) => u.type === unitType && u.id === unitId && u.startedAt === _resolveCurrentUnitStartedAtForTest(s.currentUnit),
1986
2181
  );
1987
2182
  if (lastUnit && lastUnit.toolCalls === 0) {
1988
2183
  if (USER_DRIVEN_DEEP_UNITS.has(unitType) && isAwaitingUserInput(s.lastUnitAgentEndMessages ?? undefined)) {
@@ -2004,7 +2199,7 @@ export async function runUnitPhase(
2004
2199
  );
2005
2200
  // Fall through to next iteration where dispatch will re-derive
2006
2201
  // and re-dispatch this unit.
2007
- return { action: "next", data: { unitStartedAt: s.currentUnit?.startedAt, requestDispatchedAt: unitResult.requestDispatchedAt } };
2202
+ return { action: "next", data: { unitStartedAt: _resolveCurrentUnitStartedAtForTest(s.currentUnit), requestDispatchedAt: unitResult.requestDispatchedAt } };
2008
2203
  }
2009
2204
  }
2010
2205
  }
@@ -2069,7 +2264,7 @@ export async function runUnitPhase(
2069
2264
  s.checkpointSha = null;
2070
2265
  }
2071
2266
 
2072
- return { action: "next", data: { unitStartedAt: s.currentUnit?.startedAt, requestDispatchedAt: unitResult.requestDispatchedAt } };
2267
+ return { action: "next", data: { unitStartedAt: _resolveCurrentUnitStartedAtForTest(s.currentUnit), requestDispatchedAt: unitResult.requestDispatchedAt } };
2073
2268
  }
2074
2269
 
2075
2270
  // ─── runFinalize ──────────────────────────────────────────────────────────────
@@ -2249,8 +2444,20 @@ export async function runFinalize(
2249
2444
  return { action: "break", reason: "step-wizard" };
2250
2445
  }
2251
2446
 
2447
+ if (preUnitSnapshot?.type === "complete-milestone" && s.currentMilestoneId) {
2448
+ const stop = await _runMilestoneMergeOnceWithStashRestore(ic, s.currentMilestoneId);
2449
+ if (stop) return stop;
2450
+ }
2451
+
2252
2452
  // Both pre and post verification completed without timeout — reset counter
2253
2453
  loopState.consecutiveFinalizeTimeouts = 0;
2454
+ if (preUnitSnapshot) {
2455
+ writeUnitRuntimeRecord(s.basePath, preUnitSnapshot.type, preUnitSnapshot.id, preUnitSnapshot.startedAt, {
2456
+ phase: "finalized",
2457
+ lastProgressAt: Date.now(),
2458
+ lastProgressKind: "finalize-success",
2459
+ });
2460
+ }
2254
2461
  s.currentUnit = null;
2255
2462
  clearCurrentPhase();
2256
2463