gsd-pi 2.81.0 → 2.82.0

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 (290) hide show
  1. package/README.md +36 -24
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/gsd/auto/loop.js +111 -8
  4. package/dist/resources/extensions/gsd/auto/phases.js +190 -97
  5. package/dist/resources/extensions/gsd/auto/run-unit.js +66 -3
  6. package/dist/resources/extensions/gsd/auto/session.js +9 -0
  7. package/dist/resources/extensions/gsd/auto/verification-retry-policy.js +43 -0
  8. package/dist/resources/extensions/gsd/auto-dashboard.js +182 -178
  9. package/dist/resources/extensions/gsd/auto-dispatch.js +14 -11
  10. package/dist/resources/extensions/gsd/auto-post-unit.js +7 -1
  11. package/dist/resources/extensions/gsd/auto-recovery.js +6 -181
  12. package/dist/resources/extensions/gsd/auto-runtime-state.js +5 -0
  13. package/dist/resources/extensions/gsd/auto-start.js +20 -23
  14. package/dist/resources/extensions/gsd/auto-unit-closeout.js +33 -5
  15. package/dist/resources/extensions/gsd/auto-verification.js +12 -6
  16. package/dist/resources/extensions/gsd/auto-worktree.js +8 -0
  17. package/dist/resources/extensions/gsd/auto.js +265 -76
  18. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +13 -6
  19. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +8 -2
  20. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +4 -8
  21. package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +4 -10
  22. package/dist/resources/extensions/gsd/commands/handlers/parallel.js +9 -0
  23. package/dist/resources/extensions/gsd/git-service.js +2 -1
  24. package/dist/resources/extensions/gsd/gsd-db.js +7 -23
  25. package/dist/resources/extensions/gsd/health-widget-core.js +1 -1
  26. package/dist/resources/extensions/gsd/health-widget.js +4 -10
  27. package/dist/resources/extensions/gsd/markdown-renderer.js +0 -95
  28. package/dist/resources/extensions/gsd/native-git-bridge.js +14 -14
  29. package/dist/resources/extensions/gsd/notification-overlay.js +35 -40
  30. package/dist/resources/extensions/gsd/parallel-merge.js +53 -30
  31. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +25 -33
  32. package/dist/resources/extensions/gsd/prompts/complete-slice.md +14 -12
  33. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
  34. package/dist/resources/extensions/gsd/prompts/discuss.md +20 -2
  35. package/dist/resources/extensions/gsd/recovery-classification.js +15 -1
  36. package/dist/resources/extensions/gsd/session-lock.js +40 -0
  37. package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +131 -0
  38. package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +247 -0
  39. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +50 -0
  40. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +87 -0
  41. package/dist/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.js +50 -0
  42. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +124 -0
  43. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-worker.js +32 -0
  44. package/dist/resources/extensions/gsd/state-reconciliation/errors.js +41 -0
  45. package/dist/resources/extensions/gsd/state-reconciliation/index.js +99 -0
  46. package/dist/resources/extensions/gsd/state-reconciliation/registry.js +24 -0
  47. package/dist/resources/extensions/gsd/state-reconciliation/spawn-gate.js +43 -0
  48. package/dist/resources/extensions/gsd/state-reconciliation/types.js +3 -0
  49. package/dist/resources/extensions/gsd/state-reconciliation.js +5 -26
  50. package/dist/resources/extensions/gsd/tui/render-kit.js +74 -0
  51. package/dist/resources/extensions/gsd/watch/header-renderer.js +92 -69
  52. package/dist/resources/extensions/gsd/watch/splash-palette.js +10 -0
  53. package/dist/resources/extensions/gsd/workflow-mcp.js +2 -2
  54. package/dist/resources/extensions/gsd/worktree-lifecycle.js +722 -316
  55. package/dist/resources/extensions/gsd/worktree-telemetry.js +3 -1
  56. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  57. package/dist/web/standalone/.next/BUILD_ID +1 -1
  58. package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
  59. package/dist/web/standalone/.next/build-manifest.json +2 -2
  60. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  61. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  64. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  65. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  66. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  67. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  68. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  69. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/index.html +1 -1
  77. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
  84. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  85. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  86. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  87. package/dist/welcome-screen.d.ts +0 -7
  88. package/dist/welcome-screen.js +60 -69
  89. package/package.json +1 -1
  90. package/packages/daemon/package.json +2 -2
  91. package/packages/mcp-server/package.json +2 -2
  92. package/packages/native/package.json +1 -1
  93. package/packages/pi-agent-core/package.json +1 -1
  94. package/packages/pi-ai/package.json +1 -1
  95. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts +2 -0
  96. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts.map +1 -0
  97. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js +47 -0
  98. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js.map +1 -0
  99. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +76 -9
  100. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  101. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts +2 -0
  102. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts.map +1 -0
  103. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js +40 -0
  104. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js.map +1 -0
  105. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +0 -1
  106. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -1
  107. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +30 -29
  108. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -1
  109. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +10 -3
  110. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -1
  111. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  112. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +13 -13
  113. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  114. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +1 -3
  115. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  116. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +58 -3
  117. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
  118. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts +2 -2
  119. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts.map +1 -1
  120. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js +12 -6
  121. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js.map +1 -1
  122. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  123. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -41
  124. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  125. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +0 -1
  126. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  127. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +86 -82
  128. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  129. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts +35 -0
  130. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts.map +1 -0
  131. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js +152 -0
  132. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js.map +1 -0
  133. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts +16 -0
  134. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts.map +1 -0
  135. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js +73 -0
  136. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js.map +1 -0
  137. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +1 -1
  138. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  139. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +12 -8
  140. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  141. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
  142. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
  143. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
  144. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
  145. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  146. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +105 -1
  147. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  148. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  149. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +27 -26
  150. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  151. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +9 -6
  152. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -1
  153. package/packages/pi-coding-agent/package.json +1 -1
  154. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/assistant-message-design.test.ts +56 -0
  155. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +113 -9
  156. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/user-message-design.test.ts +48 -0
  157. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +10 -3
  158. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +43 -42
  159. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +14 -14
  160. package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +64 -3
  161. package/packages/pi-coding-agent/src/modes/interactive/components/diff.ts +13 -7
  162. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +15 -42
  163. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +84 -104
  164. package/packages/pi-coding-agent/src/modes/interactive/components/transcript-design.ts +196 -0
  165. package/packages/pi-coding-agent/src/modes/interactive/components/tui-style-kit.ts +94 -0
  166. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +14 -9
  167. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-highlight.test.ts +23 -0
  168. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +106 -1
  169. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +27 -26
  170. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +9 -6
  171. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  172. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +14 -1
  173. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  174. package/packages/pi-tui/dist/overlay-layout.d.ts.map +1 -1
  175. package/packages/pi-tui/dist/overlay-layout.js +9 -6
  176. package/packages/pi-tui/dist/overlay-layout.js.map +1 -1
  177. package/packages/pi-tui/package.json +1 -1
  178. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +20 -1
  179. package/packages/pi-tui/src/overlay-layout.ts +10 -7
  180. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  181. package/packages/rpc-client/package.json +1 -1
  182. package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
  183. package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
  184. package/pkg/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
  185. package/pkg/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
  186. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  187. package/pkg/dist/modes/interactive/theme/theme.js +105 -1
  188. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  189. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  190. package/pkg/dist/modes/interactive/theme/themes.js +27 -26
  191. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  192. package/pkg/package.json +1 -1
  193. package/src/resources/extensions/gsd/auto/loop-deps.ts +9 -5
  194. package/src/resources/extensions/gsd/auto/loop.ts +113 -9
  195. package/src/resources/extensions/gsd/auto/phases.ts +144 -19
  196. package/src/resources/extensions/gsd/auto/run-unit.ts +69 -4
  197. package/src/resources/extensions/gsd/auto/session.ts +10 -0
  198. package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +82 -0
  199. package/src/resources/extensions/gsd/auto-dashboard.ts +230 -183
  200. package/src/resources/extensions/gsd/auto-dispatch.ts +15 -1
  201. package/src/resources/extensions/gsd/auto-post-unit.ts +7 -1
  202. package/src/resources/extensions/gsd/auto-recovery.ts +7 -209
  203. package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
  204. package/src/resources/extensions/gsd/auto-start.ts +22 -22
  205. package/src/resources/extensions/gsd/auto-unit-closeout.ts +51 -0
  206. package/src/resources/extensions/gsd/auto-verification.ts +12 -6
  207. package/src/resources/extensions/gsd/auto-worktree.ts +8 -0
  208. package/src/resources/extensions/gsd/auto.ts +295 -75
  209. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +21 -6
  210. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +6 -2
  211. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +5 -8
  212. package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +4 -10
  213. package/src/resources/extensions/gsd/commands/handlers/parallel.ts +12 -0
  214. package/src/resources/extensions/gsd/git-service.ts +2 -0
  215. package/src/resources/extensions/gsd/gsd-db.ts +7 -23
  216. package/src/resources/extensions/gsd/health-widget-core.ts +1 -1
  217. package/src/resources/extensions/gsd/health-widget.ts +6 -10
  218. package/src/resources/extensions/gsd/journal.ts +2 -0
  219. package/src/resources/extensions/gsd/markdown-renderer.ts +4 -95
  220. package/src/resources/extensions/gsd/native-git-bridge.ts +14 -13
  221. package/src/resources/extensions/gsd/notification-overlay.ts +50 -46
  222. package/src/resources/extensions/gsd/parallel-merge.ts +61 -34
  223. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +33 -35
  224. package/src/resources/extensions/gsd/prompts/complete-slice.md +14 -12
  225. package/src/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
  226. package/src/resources/extensions/gsd/prompts/discuss.md +20 -2
  227. package/src/resources/extensions/gsd/recovery-classification.ts +18 -1
  228. package/src/resources/extensions/gsd/session-lock.ts +41 -0
  229. package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +172 -0
  230. package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +337 -0
  231. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +69 -0
  232. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +109 -0
  233. package/src/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.ts +68 -0
  234. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +185 -0
  235. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-worker.ts +46 -0
  236. package/src/resources/extensions/gsd/state-reconciliation/errors.ts +67 -0
  237. package/src/resources/extensions/gsd/state-reconciliation/index.ts +142 -0
  238. package/src/resources/extensions/gsd/state-reconciliation/registry.ts +27 -0
  239. package/src/resources/extensions/gsd/state-reconciliation/spawn-gate.ts +60 -0
  240. package/src/resources/extensions/gsd/state-reconciliation/types.ts +83 -0
  241. package/src/resources/extensions/gsd/state-reconciliation.ts +21 -53
  242. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +1 -1
  243. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +99 -0
  244. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +654 -176
  245. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +291 -4
  246. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +16 -1
  247. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +18 -0
  248. package/src/resources/extensions/gsd/tests/auto-unit-closeout.test.ts +68 -0
  249. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +28 -1
  250. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +20 -2
  251. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +44 -0
  252. package/src/resources/extensions/gsd/tests/header-renderer.test.ts +40 -0
  253. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +10 -0
  254. package/src/resources/extensions/gsd/tests/health-widget.test.ts +14 -4
  255. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +26 -0
  256. package/src/resources/extensions/gsd/tests/integration/integration-proof.test.ts +1 -1
  257. package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +116 -24
  258. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -1
  259. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +1 -1
  260. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +46 -11
  261. package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +78 -41
  262. package/src/resources/extensions/gsd/tests/notifications-handler.test.ts +44 -0
  263. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +12 -217
  264. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +38 -6
  265. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +2 -2
  266. package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +1 -1
  267. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +24 -1
  268. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +7 -3
  269. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +6 -3
  270. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +24 -0
  271. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +65 -58
  272. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +952 -0
  273. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +4 -0
  274. package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +121 -1
  275. package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +66 -0
  276. package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +83 -0
  277. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +6 -0
  278. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +158 -58
  279. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +572 -118
  280. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +59 -2
  281. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +18 -0
  282. package/src/resources/extensions/gsd/tui/render-kit.ts +109 -0
  283. package/src/resources/extensions/gsd/watch/header-renderer.ts +121 -79
  284. package/src/resources/extensions/gsd/watch/splash-palette.ts +11 -0
  285. package/src/resources/extensions/gsd/workflow-mcp.ts +2 -2
  286. package/src/resources/extensions/gsd/worktree-lifecycle.ts +1151 -524
  287. package/src/resources/extensions/gsd/worktree-telemetry.ts +7 -2
  288. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +0 -1544
  289. /package/dist/web/standalone/.next/static/{drLMkgfHQ8lzS229_HWYR → S44UQTFCUdA44dkjfYt6S}/_buildManifest.js +0 -0
  290. /package/dist/web/standalone/.next/static/{drLMkgfHQ8lzS229_HWYR → S44UQTFCUdA44dkjfYt6S}/_ssgManifest.js +0 -0
@@ -16,6 +16,7 @@ import type {
16
16
  ExtensionAPI,
17
17
  ExtensionContext,
18
18
  ExtensionCommandContext,
19
+ SessionMessageEntry,
19
20
  } from "@gsd/pi-coding-agent";
20
21
 
21
22
  import { deriveState } from "./state.js";
@@ -32,7 +33,7 @@ import {
32
33
  setRuntimeKv,
33
34
  deleteRuntimeKv,
34
35
  } from "./db/runtime-kv.js";
35
- import { getManifestStatus } from "./files.js";
36
+ import { extractSection, getManifestStatus, splitFrontmatter, parseFrontmatterMap } from "./files.js";
36
37
  export { inlinePriorMilestoneSummary } from "./files.js";
37
38
  import { collectSecretsFromManifest } from "../get-secrets-from-user.js";
38
39
  import {
@@ -188,6 +189,8 @@ import { isClosedStatus } from "./status-guards.js";
188
189
  import {
189
190
  type AutoDashboardData,
190
191
  updateProgressWidget as _updateProgressWidget,
192
+ setCompletionProgressWidget,
193
+ setAutoOutcomeWidget,
191
194
  updateSliceProgressCache,
192
195
  clearSliceProgressCache,
193
196
  describeNextUnit as _describeNextUnit,
@@ -201,7 +204,7 @@ import {
201
204
  deregisterSigtermHandler as _deregisterSigtermHandler,
202
205
  detectWorkingTreeActivity,
203
206
  } from "./auto-supervisor.js";
204
- import { isDbAvailable, getMilestone } from "./gsd-db.js";
207
+ import { isDbAvailable, getMilestone, getMilestoneSlices } from "./gsd-db.js";
205
208
  import { markLatestActiveForWorkerCanceled } from "./db/unit-dispatches.js";
206
209
  import { writeUnitRuntimeRecord } from "./unit-runtime.js";
207
210
  import { countPendingCaptures } from "./captures.js";
@@ -231,7 +234,7 @@ import { bootstrapAutoSession, openProjectDbIfPresent, type BootstrapDeps } from
231
234
  import { initHealthWidget } from "./health-widget.js";
232
235
  import { runLegacyAutoLoop, runUokKernelLoop } from "./auto/loop.js";
233
236
  import { resolveAgentEnd, resolveAgentEndCancelled, _resetPendingResolve, isSessionSwitchInFlight } from "./auto/resolve.js";
234
- import type { LoopDeps } from "./auto/loop-deps.js";
237
+ import type { LoopDeps, StopAutoOptions } from "./auto/loop-deps.js";
235
238
  import type { ErrorContext } from "./auto/types.js";
236
239
  import { runAutoLoopWithUok } from "./uok/kernel.js";
237
240
  import { resolveUokFlags } from "./uok/flags.js";
@@ -456,15 +459,10 @@ export function _synthesizePausedSessionRecoveryForTest(
456
459
  return synthesizePausedSessionRecovery(basePath, unitType, unitId, sessionFile);
457
460
  }
458
461
 
459
- export function _resolvePausedResumeBasePathForTest(
460
- basePath: string,
461
- pausedWorktreePath: string | null | undefined,
462
- pathExists: (path: string) => boolean = existsSync,
463
- ): string {
464
- return pausedWorktreePath && pathExists(pausedWorktreePath)
465
- ? pausedWorktreePath
466
- : basePath;
467
- }
462
+ // `_resolvePausedResumeBasePathForTest` was retired in ADR-016 phase 2 / B3
463
+ // (#5621). Production callers go through
464
+ // `WorktreeLifecycle.resumeFromPausedSession`; the pure helper for tests is
465
+ // `resolvePausedResumeBasePath` exported from `worktree-lifecycle.ts`.
468
466
 
469
467
  const DETACHED_AUTO_KEEPALIVE_INTERVAL_MS = 30_000;
470
468
 
@@ -668,6 +666,10 @@ export function isAutoActive(): boolean {
668
666
  return s.active;
669
667
  }
670
668
 
669
+ export function isAutoCompletionStopInProgress(): boolean {
670
+ return s.completionStopInProgress;
671
+ }
672
+
671
673
  /** Test-only seam for validating auto-mode guards (#4704). Do not use in production code. */
672
674
  export function _setAutoActiveForTest(active: boolean): void {
673
675
  s.active = active;
@@ -928,6 +930,31 @@ function buildSnapshotOpts(
928
930
  };
929
931
  }
930
932
 
933
+ function currentUnitLabel(): string | null {
934
+ if (!s.currentUnit) return null;
935
+ return `${unitVerb(s.currentUnit.type)} ${s.currentUnit.id}`;
936
+ }
937
+
938
+ function setLifecycleOutcome(
939
+ ctx: ExtensionContext | undefined,
940
+ input: {
941
+ status: "paused" | "stopped" | "blocked" | "failed" | "complete" | "waiting" | "step";
942
+ title: string;
943
+ detail?: string | null;
944
+ nextAction: string;
945
+ commands?: string[];
946
+ unitLabel?: string | null;
947
+ },
948
+ ): void {
949
+ if (!ctx?.hasUI) return;
950
+ const { unitLabel: unitLabelOverride, ...rest } = input;
951
+ setAutoOutcomeWidget(ctx, {
952
+ ...rest,
953
+ unitLabel: unitLabelOverride !== undefined ? unitLabelOverride : currentUnitLabel(),
954
+ startedAt: s.autoStartTime,
955
+ });
956
+ }
957
+
931
958
  function handleLostSessionLock(
932
959
  ctx?: ExtensionContext,
933
960
  lockStatus?: SessionLockStatus,
@@ -1015,27 +1042,42 @@ export async function cleanupAfterLoopExit(ctx: ExtensionContext): Promise<void>
1015
1042
  // visible so the user still has a resumable auto-mode signal on screen.
1016
1043
  if (!s.paused) {
1017
1044
  ctx.ui.setStatus("gsd-auto", undefined);
1018
- ctx.ui.setWidget("gsd-progress", undefined);
1045
+ if (s.completionStopInProgress) {
1046
+ s.completionStopInProgress = false;
1047
+ }
1019
1048
  initHealthWidget(ctx);
1020
1049
  }
1021
1050
 
1022
- // Restore CWD out of worktree back to original project root
1051
+ // ADR-016 phase 3 (#5693): the stop-path basePath restore routes through
1052
+ // `Lifecycle.restoreToProjectRoot()`, the sole owner of `s.basePath`
1053
+ // mutation. The verb assigns `s.basePath` before any throwable work
1054
+ // (rebuildGitService, cache invalidation), so a thrown error still leaves
1055
+ // basePath restored — no fallback assignment needed at the call site.
1056
+ // The chdir stays here because `restoreToProjectRoot` is a pure
1057
+ // session-state mutation.
1023
1058
  if (s.originalBasePath) {
1024
- s.basePath = s.originalBasePath;
1025
1059
  try {
1026
- process.chdir(s.basePath);
1060
+ buildLifecycle().restoreToProjectRoot();
1061
+ } catch (err) {
1062
+ logWarning(
1063
+ "engine",
1064
+ `restore project root failed: ${err instanceof Error ? err.message : String(err)}`,
1065
+ { file: "auto.ts" },
1066
+ );
1067
+ }
1068
+ try {
1069
+ process.chdir(s.originalBasePath);
1027
1070
  } catch (err) {
1028
- /* best-effort */
1029
- logWarning("engine", `chdir failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
1071
+ logWarning("engine", `basePath restore/chdir failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
1030
1072
  }
1031
1073
  }
1032
1074
 
1033
1075
  if (s.originalBasePath && s.cmdCtx) {
1034
- const result = await rerootCommandSession(s.cmdCtx, s.basePath);
1076
+ const result = await rerootCommandSession(s.cmdCtx, s.originalBasePath);
1035
1077
  if (result.status === "cancelled") {
1036
- logWarning("engine", "post-loop session re-root was cancelled", { file: "auto.ts", basePath: s.basePath });
1078
+ logWarning("engine", "post-loop session re-root was cancelled", { file: "auto.ts", basePath: s.originalBasePath });
1037
1079
  } else if (result.status === "failed") {
1038
- logWarning("engine", `post-loop session re-root failed: ${result.error ?? "unknown"}`, { file: "auto.ts", basePath: s.basePath });
1080
+ logWarning("engine", `post-loop session re-root failed: ${result.error ?? "unknown"}`, { file: "auto.ts", basePath: s.originalBasePath });
1039
1081
  }
1040
1082
  }
1041
1083
  }
@@ -1046,6 +1088,58 @@ export function _cleanupAfterLoopExitForTest(ctx: ExtensionContext): Promise<voi
1046
1088
 
1047
1089
  export type AutoWorktreeExitAction = "skip" | "merge" | "preserve";
1048
1090
 
1091
+ interface MilestoneCompletionRollup {
1092
+ milestoneTitle?: string;
1093
+ oneLiner?: string;
1094
+ successCriteriaResults?: string;
1095
+ definitionOfDoneResults?: string;
1096
+ requirementOutcomes?: string;
1097
+ deviations?: string;
1098
+ followUps?: string;
1099
+ keyDecisions?: string[];
1100
+ keyFiles?: string[];
1101
+ lessonsLearned?: string[];
1102
+ }
1103
+
1104
+ function normalizeFrontmatterList(value: unknown): string[] {
1105
+ if (!Array.isArray(value)) return [];
1106
+ return value
1107
+ .map(item => typeof item === "string" ? item.trim() : "")
1108
+ .filter(item => item.length > 0 && item !== "(none)");
1109
+ }
1110
+
1111
+ function firstBoldParagraph(body: string): string | undefined {
1112
+ const match = body.match(/\*\*([^*\n][\s\S]*?)\*\*/);
1113
+ return match?.[1]?.replace(/\s+/g, " ").trim() || undefined;
1114
+ }
1115
+
1116
+ function loadMilestoneCompletionRollup(basePath: string, milestoneId: string | null | undefined): MilestoneCompletionRollup {
1117
+ if (!milestoneId) return {};
1118
+ const summaryPath = resolveMilestoneFile(basePath, milestoneId, "SUMMARY");
1119
+ if (!summaryPath || !existsSync(summaryPath)) return {};
1120
+
1121
+ try {
1122
+ const raw = readFileSync(summaryPath, "utf-8");
1123
+ const [frontmatterLines, body] = splitFrontmatter(raw);
1124
+ const frontmatter = frontmatterLines ? parseFrontmatterMap(frontmatterLines) : {};
1125
+ return {
1126
+ milestoneTitle: typeof frontmatter.title === "string" ? frontmatter.title : undefined,
1127
+ oneLiner: firstBoldParagraph(body),
1128
+ successCriteriaResults: extractSection(body, "Success Criteria Results") ?? undefined,
1129
+ definitionOfDoneResults: extractSection(body, "Definition of Done Results") ?? undefined,
1130
+ requirementOutcomes: extractSection(body, "Requirement Outcomes") ?? undefined,
1131
+ deviations: extractSection(body, "Deviations") ?? undefined,
1132
+ followUps: extractSection(body, "Follow-ups") ?? undefined,
1133
+ keyDecisions: normalizeFrontmatterList(frontmatter.key_decisions),
1134
+ keyFiles: normalizeFrontmatterList(frontmatter.key_files),
1135
+ lessonsLearned: normalizeFrontmatterList(frontmatter.lessons_learned),
1136
+ };
1137
+ } catch (err) {
1138
+ logWarning("dashboard", `completion roll-up summary read failed: ${err instanceof Error ? err.message : String(err)}`);
1139
+ return {};
1140
+ }
1141
+ }
1142
+
1049
1143
  export function _resolveAutoWorktreeExitActionForTest(
1050
1144
  currentMilestoneId: string | null | undefined,
1051
1145
  milestoneMergedInPhases: boolean,
@@ -1063,15 +1157,17 @@ export async function stopAuto(
1063
1157
  ctx?: ExtensionContext,
1064
1158
  pi?: ExtensionAPI,
1065
1159
  reason?: string,
1160
+ options: StopAutoOptions = {},
1066
1161
  ): Promise<void> {
1067
1162
  if (!s.active && !s.paused) return;
1068
1163
  const loadedPreferences = loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences;
1069
1164
  const reasonSuffix = reason ? ` — ${reason}` : "";
1165
+ const preserveCompletionSurface = Boolean(options.completionWidget);
1166
+ s.completionStopInProgress = preserveCompletionSurface;
1070
1167
 
1071
- // #4764 — telemetry: record the exit reason and whether the current milestone
1072
- // was merged before we entered stopAuto. This is the producer-side signal for
1073
- // the #4761 orphan class: milestoneMerged=false + currentMilestoneId present
1074
- // is exactly the pattern that strands work.
1168
+ // #4764 — telemetry: record the exit reason, isolation mode, whether an auto
1169
+ // worktree was active, and whether the current milestone was merged before
1170
+ // stopAuto. The unmerged-work warning is only meaningful for real worktrees.
1075
1171
  try {
1076
1172
  const { emitAutoExit } = await import("./worktree-telemetry.js");
1077
1173
  type AutoExitReason =
@@ -1096,10 +1192,13 @@ export async function stopAuto(
1096
1192
  : rawReason === "stop" || rawReason === "pause"
1097
1193
  ? rawReason
1098
1194
  : "other";
1099
- emitAutoExit(s.originalBasePath || s.basePath, {
1195
+ const telemetryBase = s.originalBasePath || s.basePath;
1196
+ emitAutoExit(telemetryBase, {
1100
1197
  reason: normalizedReason,
1101
1198
  milestoneId: s.currentMilestoneId ?? undefined,
1102
1199
  milestoneMerged: s.milestoneMergedInPhases === true,
1200
+ isolationMode: getIsolationMode(telemetryBase),
1201
+ worktreeActive: isInAutoWorktree(s.basePath),
1103
1202
  });
1104
1203
  } catch (err) {
1105
1204
  logWarning("engine", `auto-exit telemetry failed: ${err instanceof Error ? err.message : String(err)}`);
@@ -1257,6 +1356,21 @@ export async function stopAuto(
1257
1356
  }
1258
1357
  }
1259
1358
 
1359
+ // Pre-compute completion widget slice counts while the DB is still open.
1360
+ // Step 8 runs after closeDatabase(), so DB-backed slice lookups must happen here.
1361
+ const completionMilestoneId = options.completionWidget?.milestoneId ?? s.currentMilestoneId;
1362
+ let completedSlices: number | null = null;
1363
+ let totalSlices: number | null = null;
1364
+ if (preserveCompletionSurface && options.completionWidget && completionMilestoneId && isDbAvailable()) {
1365
+ try {
1366
+ const slices = getMilestoneSlices(completionMilestoneId);
1367
+ completedSlices = slices.filter(slice => isClosedStatus(slice.status)).length;
1368
+ totalSlices = slices.length;
1369
+ } catch (err) {
1370
+ logWarning("dashboard", `completion slice stats lookup failed: ${err instanceof Error ? err.message : String(err)}`);
1371
+ }
1372
+ }
1373
+
1260
1374
  // ── Step 6: DB cleanup ──
1261
1375
  if (isDbAvailable()) {
1262
1376
  try {
@@ -1269,19 +1383,21 @@ export async function stopAuto(
1269
1383
  }
1270
1384
  }
1271
1385
 
1272
- // ── Step 7: Restore basePath and chdir ──
1273
- try {
1274
- if (s.originalBasePath) {
1275
- s.basePath = s.originalBasePath;
1276
- try {
1277
- process.chdir(s.basePath);
1278
- } catch (err) {
1279
- /* best-effort */
1280
- logWarning("engine", `chdir failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
1281
- }
1386
+ // ── Step 7: Restore basePath and chdir (ADR-016 phase 3, #5693) ──
1387
+ // `restoreToProjectRoot` assigns s.basePath before any throwable work;
1388
+ // no fallback assignment is needed at the call site.
1389
+ if (s.originalBasePath) {
1390
+ try {
1391
+ buildLifecycle().restoreToProjectRoot();
1392
+ } catch (e) {
1393
+ debugLog("stop-cleanup-basepath", { error: e instanceof Error ? e.message : String(e) });
1394
+ }
1395
+ try {
1396
+ process.chdir(s.basePath);
1397
+ } catch (err) {
1398
+ /* best-effort */
1399
+ logWarning("engine", `chdir failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
1282
1400
  }
1283
- } catch (e) {
1284
- debugLog("stop-cleanup-basepath", { error: e instanceof Error ? e.message : String(e) });
1285
1401
  }
1286
1402
 
1287
1403
  // Re-root the active command session/tool runtime after worktree teardown.
@@ -1289,30 +1405,91 @@ export async function stopAuto(
1289
1405
  // its own cwd for tools and system prompt; refresh it before returning to the
1290
1406
  // user so follow-up commands do not target a removed milestone worktree.
1291
1407
  if (s.originalBasePath && ctx && s.cmdCtx) {
1292
- const result = await rerootCommandSession(s.cmdCtx, s.basePath);
1408
+ const result = await rerootCommandSession(s.cmdCtx, s.originalBasePath);
1293
1409
  if (result.status === "cancelled") {
1294
- logWarning("engine", "post-stop session re-root was cancelled", { file: "auto.ts", basePath: s.basePath });
1410
+ logWarning("engine", "post-stop session re-root was cancelled", { file: "auto.ts", basePath: s.originalBasePath });
1295
1411
  } else if (result.status === "failed") {
1296
- logWarning("engine", `post-stop session re-root failed: ${result.error ?? "unknown"}`, { file: "auto.ts", basePath: s.basePath });
1412
+ logWarning("engine", `post-stop session re-root failed: ${result.error ?? "unknown"}`, { file: "auto.ts", basePath: s.originalBasePath });
1297
1413
  }
1298
1414
  }
1299
1415
 
1300
1416
  // ── Step 8: Ledger notification ──
1301
1417
  try {
1302
1418
  const ledger = getLedger();
1419
+ const isAllComplete = reason === "All milestones complete";
1420
+ const isMilestoneComplete = /^Milestone\s+\S+\s+complete$/i.test(reason ?? "");
1421
+ const notificationPrefix = isAllComplete
1422
+ ? "All milestones complete"
1423
+ : isMilestoneComplete
1424
+ ? `${reason}. Auto-mode finished this milestone`
1425
+ : `Auto-mode stopped${reasonSuffix}`;
1303
1426
  if (ledger && ledger.units.length > 0) {
1304
1427
  const totals = getProjectTotals(ledger.units);
1305
1428
  ctx?.ui.notify(
1306
- `Auto-mode stopped${reasonSuffix}. Session: ${formatCost(totals.cost)} · ${formatTokenCount(totals.tokens.total)} tokens · ${ledger.units.length} units`,
1429
+ `${notificationPrefix}. Session: ${formatCost(totals.cost)} · ${formatTokenCount(totals.tokens.total)} tokens · ${ledger.units.length} units`,
1307
1430
  "info",
1308
1431
  );
1309
1432
  } else {
1310
- ctx?.ui.notify(`Auto-mode stopped${reasonSuffix}.`, "info");
1433
+ ctx?.ui.notify(`${notificationPrefix}.`, "info");
1311
1434
  }
1312
1435
  } catch (e) {
1313
1436
  debugLog("stop-cleanup-ledger", { error: e instanceof Error ? e.message : String(e) });
1314
1437
  }
1315
1438
 
1439
+ if (preserveCompletionSurface && ctx && options.completionWidget) {
1440
+ const ledger = getLedger();
1441
+ const units = ledger?.units ?? [];
1442
+ const totals = units.length > 0 ? getProjectTotals(units) : null;
1443
+ let totalInput = 0;
1444
+ let totalCacheRead = 0;
1445
+ try {
1446
+ for (const entry of s.cmdCtx?.sessionManager?.getEntries?.() ?? []) {
1447
+ if (entry.type === "message") {
1448
+ const msgEntry = entry as SessionMessageEntry;
1449
+ if (msgEntry.message?.role === "assistant") {
1450
+ const usage = (msgEntry.message as any).usage;
1451
+ if (usage) {
1452
+ totalInput += usage.input || 0;
1453
+ totalCacheRead += usage.cacheRead || 0;
1454
+ }
1455
+ }
1456
+ }
1457
+ }
1458
+ } catch (err) {
1459
+ logWarning("dashboard", `completion stats lookup failed: ${err instanceof Error ? err.message : String(err)}`);
1460
+ }
1461
+ const contextUsage = s.cmdCtx?.getContextUsage?.();
1462
+ const milestoneId = completionMilestoneId;
1463
+ const rollup = loadMilestoneCompletionRollup(s.originalBasePath || s.basePath, milestoneId);
1464
+ setCompletionProgressWidget(ctx, {
1465
+ milestoneId,
1466
+ milestoneTitle: options.completionWidget.milestoneTitle ?? rollup.milestoneTitle,
1467
+ oneLiner: rollup.oneLiner,
1468
+ successCriteriaResults: rollup.successCriteriaResults,
1469
+ definitionOfDoneResults: rollup.definitionOfDoneResults,
1470
+ requirementOutcomes: rollup.requirementOutcomes,
1471
+ deviations: rollup.deviations,
1472
+ followUps: rollup.followUps,
1473
+ keyDecisions: rollup.keyDecisions,
1474
+ keyFiles: rollup.keyFiles,
1475
+ lessonsLearned: rollup.lessonsLearned,
1476
+ reason: reason ?? "Milestone complete",
1477
+ startedAt: s.autoStartTime,
1478
+ totalCost: totals?.cost ?? 0,
1479
+ totalTokens: totals?.tokens.total ?? 0,
1480
+ unitCount: units.length,
1481
+ cacheHitRate: totalCacheRead + totalInput > 0
1482
+ ? (totalCacheRead / (totalCacheRead + totalInput)) * 100
1483
+ : null,
1484
+ contextPercent: contextUsage?.percent ?? null,
1485
+ contextWindow: contextUsage?.contextWindow ?? s.cmdCtx?.model?.contextWindow ?? null,
1486
+ completedSlices,
1487
+ totalSlices,
1488
+ allMilestonesComplete: options.completionWidget.allMilestonesComplete,
1489
+ basePath: s.originalBasePath || s.basePath || null,
1490
+ });
1491
+ }
1492
+
1316
1493
  // ── Step 9: Cmux sidebar / event log ──
1317
1494
  try {
1318
1495
  pi?.events.emit(CMUX_CHANNELS.SIDEBAR, { action: "clear" as const, preferences: loadedPreferences });
@@ -1403,8 +1580,20 @@ export async function stopAuto(
1403
1580
 
1404
1581
  // UI cleanup
1405
1582
  ctx?.ui.setStatus("gsd-auto", undefined);
1406
- ctx?.ui.setWidget("gsd-progress", undefined);
1407
- if (ctx) initHealthWidget(ctx);
1583
+ if (!preserveCompletionSurface) {
1584
+ ctx?.ui.setWidget("gsd-progress", undefined);
1585
+ const status = reason?.startsWith("Blocked:") ? "blocked" : reason?.toLowerCase().includes("fail") ? "failed" : "stopped";
1586
+ setLifecycleOutcome(ctx, {
1587
+ status,
1588
+ title: status === "blocked" ? "Auto-mode blocked" : status === "failed" ? "Auto-mode stopped with an issue" : "Auto-mode stopped",
1589
+ detail: reason ?? "Auto-mode stopped.",
1590
+ nextAction: status === "blocked"
1591
+ ? "Fix the blocker, then run /gsd auto to resume."
1592
+ : "Run /gsd status for the current project state, or /gsd auto to continue.",
1593
+ commands: ["/gsd status for overview", "/gsd auto to run", "/gsd visualize to inspect", "/gsd notifications for history"],
1594
+ });
1595
+ if (ctx) initHealthWidget(ctx);
1596
+ }
1408
1597
  restoreProjectRootEnv();
1409
1598
  restoreMilestoneLockEnv();
1410
1599
 
@@ -1421,7 +1610,7 @@ export async function stopAuto(
1421
1610
  }
1422
1611
 
1423
1612
  // Reset all session state in one call
1424
- s.reset();
1613
+ s.resetAfterStop({ preserveCompletionSurface });
1425
1614
  }
1426
1615
  }
1427
1616
 
@@ -1495,6 +1684,8 @@ export async function pauseAuto(
1495
1684
  logWarning("engine", `paused-session DB write failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
1496
1685
  }
1497
1686
 
1687
+ const pausedUnitLabel = currentUnitLabel();
1688
+
1498
1689
  // Close out the current unit so its runtime record doesn't stay at "dispatched"
1499
1690
  if (s.currentUnit && ctx) {
1500
1691
  try {
@@ -1545,8 +1736,16 @@ export async function pauseAuto(
1545
1736
  s.verificationRetryCount.clear();
1546
1737
  ctx?.ui.setStatus("gsd-auto", "paused");
1547
1738
  ctx?.ui.setWidget("gsd-progress", undefined);
1548
- if (ctx) initHealthWidget(ctx);
1549
1739
  const resumeCmd = s.stepMode ? "/gsd next" : "/gsd auto";
1740
+ setLifecycleOutcome(ctx, {
1741
+ status: "paused",
1742
+ title: `${s.stepMode ? "Step" : "Auto"}-mode paused`,
1743
+ detail: _errorContext?.message ?? "Paused by user request.",
1744
+ nextAction: `Type to steer, or run ${resumeCmd} to resume.`,
1745
+ commands: [resumeCmd, "/gsd status for overview", "/gsd notifications for history"],
1746
+ unitLabel: pausedUnitLabel,
1747
+ });
1748
+ if (ctx) initHealthWidget(ctx);
1550
1749
  ctx?.ui.notify(
1551
1750
  `${s.stepMode ? "Step" : "Auto"}-mode paused (Escape). Type to interact, or ${resumeCmd} to resume.`,
1552
1751
  "info",
@@ -1561,29 +1760,36 @@ export async function pauseAuto(
1561
1760
  * deps bag is intentionally focused — Lifecycle does not see the wider auto-
1562
1761
  * mode dependency graph.
1563
1762
  */
1564
- function buildLifecycle(): WorktreeLifecycle {
1565
- const lifecycleDeps = {
1566
- enterAutoWorktree,
1567
- createAutoWorktree,
1568
- enterBranchModeForMilestone,
1569
- getAutoWorktreePath,
1570
- getIsolationMode,
1571
- invalidateAllCaches,
1572
- GitServiceImpl,
1573
- loadEffectiveGSDPreferences,
1763
+ /**
1764
+ * Construct a `WorktreeLifecycleDeps` bag without binding to any session.
1765
+ *
1766
+ * Exported so session-less callers (currently `parallel-merge.ts`) can build
1767
+ * the same deps and call `mergeMilestoneStandalone` through the Worktree
1768
+ * Lifecycle Module instead of bypassing it (ADR-016 phase 2 / A2).
1769
+ */
1770
+ export function buildWorktreeLifecycleDeps(): WorktreeLifecycleDeps {
1771
+ // ADR-016 phase 2 / C-track close-out:
1772
+ // C1 (#5624) — fs + git-CLI primitives inlined
1773
+ // C2 (#5625) — worktree-manager helpers inlined
1774
+ // C3 (#5626) — cache + preferences + paths inlined
1775
+ // C4 (#5627) — GitServiceImpl constructor → gitServiceFactory
1776
+ //
1777
+ // Final WorktreeLifecycleDeps shape: 3 fields (gitServiceFactory,
1778
+ // worktreeProjection, mergeMilestoneToMain). Down from 18 at slice-7
1779
+ // closure.
1780
+ return {
1781
+ gitServiceFactory: (basePath: string) => {
1782
+ const gitConfig =
1783
+ loadEffectiveGSDPreferences()?.preferences?.git ?? {};
1784
+ return new GitServiceImpl(basePath, gitConfig);
1785
+ },
1574
1786
  worktreeProjection: new WorktreeStateProjection(),
1575
- isInAutoWorktree,
1576
- autoCommitCurrentBranch,
1577
- autoWorktreeBranch,
1578
- teardownAutoWorktree,
1579
1787
  mergeMilestoneToMain,
1580
- getCurrentBranch,
1581
- checkoutBranch: nativeCheckoutBranch,
1582
- resolveMilestoneFile,
1583
- readFileSync: (path: string, encoding: string) =>
1584
- readFileSync(path, encoding as BufferEncoding),
1585
- } as unknown as WorktreeLifecycleDeps;
1586
- return new WorktreeLifecycle(s, lifecycleDeps);
1788
+ };
1789
+ }
1790
+
1791
+ function buildLifecycle(): WorktreeLifecycle {
1792
+ return new WorktreeLifecycle(s, buildWorktreeLifecycleDeps());
1587
1793
  }
1588
1794
 
1589
1795
  /**
@@ -1606,16 +1812,20 @@ export function createWiredAutoOrchestrationModule(
1606
1812
  stateReconciliation: {
1607
1813
  async reconcileBeforeDispatch() {
1608
1814
  const result = await reconcileBeforeDispatch(dispatchBasePath);
1609
- if (!result.ok) {
1815
+ if (result.blockers.length > 0) {
1610
1816
  return {
1611
1817
  ok: false,
1612
- reason: result.reason,
1818
+ reason: result.blockers[0],
1613
1819
  stateSnapshot: result.stateSnapshot,
1614
1820
  };
1615
1821
  }
1822
+ const repairedKinds = result.repaired.map((d) => d.kind);
1616
1823
  return {
1617
1824
  ok: true,
1618
- reason: result.repaired.join(", "),
1825
+ reason:
1826
+ repairedKinds.length > 0
1827
+ ? `repaired: ${repairedKinds.join(", ")}`
1828
+ : "clean",
1619
1829
  stateSnapshot: result.stateSnapshot,
1620
1830
  };
1621
1831
  },
@@ -1825,7 +2035,6 @@ function buildLoopDeps(pi: ExtensionAPI): LoopDeps {
1825
2035
  pruneQueueOrder,
1826
2036
  isInAutoWorktree,
1827
2037
  shouldUseWorktreeIsolation,
1828
- mergeMilestoneToMain,
1829
2038
  teardownAutoWorktree,
1830
2039
  createAutoWorktree,
1831
2040
  captureIntegrationBranch,
@@ -2145,7 +2354,12 @@ export async function startAuto(
2145
2354
  s.verbose = verboseMode;
2146
2355
  s.stepMode = requestedStepMode;
2147
2356
  s.cmdCtx = ctx;
2148
- s.basePath = base;
2357
+ // ADR-016 phase 2 / B2 (#5620): bootstrap basePath transition before
2358
+ // the resume path consults persisted worktree state. Defensive about
2359
+ // s.originalBasePath — the meta-restore above (line 2003 / 2055) may
2360
+ // have already populated it from paused metadata; the verb preserves
2361
+ // that value.
2362
+ buildLifecycle().adoptSessionRoot(base);
2149
2363
  // ── Resume worktree: if the paused session was inside a milestone worktree,
2150
2364
  // apply that path as the dispatch basePath immediately (#3723).
2151
2365
  // This ensures the dispatch loop runs from the worktree directory even when
@@ -2161,7 +2375,8 @@ export async function startAuto(
2161
2375
  { file: "auto.ts", milestoneId: s.currentMilestoneId ?? "" },
2162
2376
  );
2163
2377
  }
2164
- s.basePath = _resolvePausedResumeBasePathForTest(base, resumeWorktreePath);
2378
+ // ADR-016 phase 2 / B3 (#5621): paused-resume worktree-path adoption.
2379
+ buildLifecycle().resumeFromPausedSession(base, resumeWorktreePath);
2165
2380
  // Rebuild scope now that s.basePath reflects the actual worktree (or project root).
2166
2381
  rebuildScope(s.basePath, s.currentMilestoneId);
2167
2382
  // Ensure the workflow-logger audit log is pinned to the project root
@@ -2463,7 +2678,12 @@ export async function dispatchHookUnit(
2463
2678
  s.pendingQuickTasks = [];
2464
2679
  }
2465
2680
 
2466
- s.basePath = targetBasePath;
2681
+ // ADR-016 phase 2 / B2 (#5620): hook-trigger basePath transition. Treats
2682
+ // the trigger as a bootstrap variant — if the session is fresh,
2683
+ // `originalBasePath` gets set to `targetBasePath`; if the session was
2684
+ // already active with an established `originalBasePath`, the verb
2685
+ // preserves it.
2686
+ buildLifecycle().adoptSessionRoot(targetBasePath);
2467
2687
  if (!s.orchestration) {
2468
2688
  ensureOrchestrationModule(ctx, pi, s.basePath);
2469
2689
  }
@@ -12,7 +12,14 @@ import {
12
12
  resetEmptyTurnCounter,
13
13
  } from "../guided-flow.js";
14
14
  import { clearPathCache } from "../paths.js";
15
- import { getAutoDashboardData, getAutoModeStartModel, isAutoActive, pauseAuto, setCurrentDispatchedModelId } from "../auto.js";
15
+ import {
16
+ getAutoDashboardData,
17
+ getAutoModeStartModel,
18
+ isAutoActive,
19
+ isAutoCompletionStopInProgress,
20
+ pauseAuto,
21
+ setCurrentDispatchedModelId,
22
+ } from "../auto.js";
16
23
  import { getNextFallbackModel, resolveModelWithFallbacksForUnit } from "../preferences.js";
17
24
  import { pauseAutoForProviderError } from "../provider-error-pause.js";
18
25
  import {
@@ -146,8 +153,7 @@ export function isBareClaudeCodeStreamAbortPlaceholder(lastMsg: unknown): boolea
146
153
  * Claude Code abort markers are intentionally ignored when the abort fires
147
154
  * while the session-switch is in flight: the abort is the expected side-effect
148
155
  * of the transition, not a user signal. Other branches (genuine `stopReason
149
- * === "aborted"` with diagnostic content/errorMessage) preserve the prior
150
- * behavior.
156
+ * === "aborted"` with explicit errorMessage) preserve the prior behavior.
151
157
  */
152
158
  export function _handleSessionSwitchAgentEnd(
153
159
  lastMsg: unknown,
@@ -171,10 +177,8 @@ export function _handleSessionSwitchAgentEnd(
171
177
  }
172
178
 
173
179
  if (m.stopReason === "aborted") {
174
- const content = m.content;
175
- const hasEmptyContent = Array.isArray(content) && content.length === 0;
176
180
  const hasErrorMessage = !!m.errorMessage;
177
- if (!hasEmptyContent || hasErrorMessage) {
181
+ if (hasErrorMessage) {
178
182
  resolveCancelled(_buildAbortedPauseContext(m as { errorMessage?: unknown }));
179
183
  }
180
184
  }
@@ -295,6 +299,12 @@ export async function handleAgentEnd(
295
299
  }
296
300
 
297
301
  if (isObjectRecord(lastMsg) && "stopReason" in lastMsg && lastMsg.stopReason === "aborted") {
302
+ if (isAutoCompletionStopInProgress()) {
303
+ resetRetryState(retryState);
304
+ resolveAgentEnd(event);
305
+ return;
306
+ }
307
+
298
308
  // Empty content with aborted stopReason is a non-fatal agent stop (the LLM
299
309
  // chose to end without producing output). Only pause on genuine fatal aborts
300
310
  // that carry error context — e.g. errorMessage field or non-empty content
@@ -326,6 +336,11 @@ export async function handleAgentEnd(
326
336
  // errorMessage looks uninformative.
327
337
  const rawErrorMsg = ("errorMessage" in lastMsg && lastMsg.errorMessage) ? String(lastMsg.errorMessage) : "";
328
338
  if (isUserInitiatedAbortMessage(rawErrorMsg)) {
339
+ if (isAutoCompletionStopInProgress()) {
340
+ resetRetryState(retryState);
341
+ resolveAgentEnd(event);
342
+ return;
343
+ }
329
344
  resolveAgentEndCancelled({
330
345
  message: rawErrorMsg,
331
346
  category: "aborted",