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
@@ -83,6 +83,7 @@ import {
83
83
  finalizeProjectResearchTimeout,
84
84
  } from "./project-research-policy.js";
85
85
  import { validateArtifact } from "./schemas/validate.js";
86
+ import { verificationRetryKey } from "./auto/verification-retry-policy.js";
86
87
 
87
88
  // ─── Path Comparison Helper ───────────────────────────────────────────────
88
89
  /** Compare two paths for physical identity, tolerating trailing slashes and symlinks. */
@@ -1016,6 +1017,7 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
1016
1017
  );
1017
1018
  s.pendingVerificationRetry = null;
1018
1019
  s.verificationRetryCount.delete(retryKey);
1020
+ s.verificationRetryFailureHashes.delete(retryKey);
1019
1021
  triggerArtifactVerified = verifyExpectedArtifact(s.currentUnit.type, s.currentUnit.id, s.basePath);
1020
1022
  if (triggerArtifactVerified) {
1021
1023
  invalidateAllCaches();
@@ -1074,6 +1076,7 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
1074
1076
  s.lastToolInvocationError = null;
1075
1077
  s.pendingVerificationRetry = null;
1076
1078
  s.verificationRetryCount.delete(retryKey);
1079
+ s.verificationRetryFailureHashes.delete(retryKey);
1077
1080
  writeBlockerPlaceholder(s.currentUnit.type, s.currentUnit.id, s.basePath, reason);
1078
1081
  ctx.ui.notify(
1079
1082
  `${s.currentUnit.type} ${s.currentUnit.id} — deterministic policy rejection, wrote blocker placeholder (no retries) (#4973)`,
@@ -1111,6 +1114,7 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
1111
1114
  );
1112
1115
  if (attempt > MAX_ARTIFACT_VERIFICATION_RETRIES) {
1113
1116
  s.verificationRetryCount.delete(retryKey);
1117
+ s.verificationRetryFailureHashes.delete(retryKey);
1114
1118
  debugLog("postUnit", { phase: "artifact-verify-exhausted", unitType: s.currentUnit.type, unitId: s.currentUnit.id, attempt });
1115
1119
  ctx.ui.notify(
1116
1120
  `${failureDetails} Pausing auto-mode after ${MAX_ARTIFACT_VERIFICATION_RETRIES} retries.`,
@@ -1137,7 +1141,9 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
1137
1141
  // Verification succeeded — clear the retry counter so a future failure
1138
1142
  // of the same unit gets a full retry budget instead of the stale count.
1139
1143
  if (triggerArtifactVerified) {
1140
- s.verificationRetryCount.delete(`${s.currentUnit.type}:${s.currentUnit.id}`);
1144
+ const retryKey = verificationRetryKey(s.currentUnit.type, s.currentUnit.id);
1145
+ s.verificationRetryCount.delete(retryKey);
1146
+ s.verificationRetryFailureHashes.delete(retryKey);
1141
1147
  }
1142
1148
  } else {
1143
1149
  // Hook unit completed — no additional processing needed
@@ -7,7 +7,6 @@
7
7
  * globals or AutoContext dependency.
8
8
  */
9
9
 
10
- import type { ExtensionContext } from "@gsd/pi-coding-agent";
11
10
  import { parseUnitId } from "./unit-id.js";
12
11
  import { MILESTONE_ID_RE } from "./milestone-ids.js";
13
12
  import { appendEvent } from "./workflow-events.js";
@@ -20,15 +19,6 @@ import { getErrorMessage } from "./error-utils.js";
20
19
  import { logWarning, logError } from "./workflow-logger.js";
21
20
  import { readIntegrationBranch } from "./git-service.js";
22
21
  import { isClosedStatus } from "./status-guards.js";
23
- import {
24
- nativeConflictFiles,
25
- nativeCommit,
26
- nativeCheckoutTheirs,
27
- nativeAddPaths,
28
- nativeMergeAbort,
29
- nativeRebaseAbort,
30
- nativeResetHard,
31
- } from "./native-git-bridge.js";
32
22
  import {
33
23
  resolveSlicePath,
34
24
  resolveSliceFile,
@@ -46,7 +36,6 @@ import {
46
36
  mkdirSync,
47
37
  readFileSync,
48
38
  writeFileSync,
49
- unlinkSync,
50
39
  } from "node:fs";
51
40
  import { execFileSync } from "node:child_process";
52
41
  import { dirname, join } from "node:path";
@@ -1001,205 +990,14 @@ export function writeBlockerPlaceholder(
1001
990
  }
1002
991
 
1003
992
  // ─── Merge State Reconciliation ───────────────────────────────────────────────
993
+ // Body relocated to state-reconciliation/drift/merge-state.ts (ADR-017 #5701).
994
+ // Re-exported here for backward compatibility with existing call sites:
995
+ // auto.ts, auto/loop-deps.ts, tests/integration/auto-recovery.test.ts.
1004
996
 
1005
- /**
1006
- * Best-effort abort of a pending merge/squash and hard-reset to HEAD.
1007
- * Handles both real merges (MERGE_HEAD) and squash merges (SQUASH_MSG).
1008
- */
1009
- function abortAndResetMerge(
1010
- basePath: string,
1011
- hasMergeHead: boolean,
1012
- squashMsgPath: string,
1013
- ): void {
1014
- if (hasMergeHead) {
1015
- try {
1016
- nativeMergeAbort(basePath);
1017
- } catch (err) {
1018
- /* best-effort */
1019
- logWarning("recovery", `git merge-abort failed: ${err instanceof Error ? err.message : String(err)}`);
1020
- }
1021
- } else if (squashMsgPath) {
1022
- try {
1023
- unlinkSync(squashMsgPath);
1024
- } catch (err) {
1025
- /* best-effort */
1026
- logWarning("recovery", `file unlink failed: ${err instanceof Error ? err.message : String(err)}`);
1027
- }
1028
- }
1029
- try {
1030
- nativeResetHard(basePath);
1031
- } catch (err) {
1032
- /* best-effort */
1033
- logError("recovery", `git reset failed: ${err instanceof Error ? err.message : String(err)}`);
1034
- }
1035
- }
1036
-
1037
- export type MergeReconcileResult = "clean" | "reconciled" | "blocked";
1038
-
1039
- /**
1040
- * Detect and abort other in-progress git operations left behind by a SIGKILL'd
1041
- * worker (rebase, cherry-pick, revert). Without this, a killed worker mid-rebase
1042
- * leaves `.git/rebase-merge/` or `.git/CHERRY_PICK_HEAD` and the worktree is
1043
- * wedged until the user manually runs the matching `--abort`.
1044
- *
1045
- * Called before merge-state reconciliation because these states block any
1046
- * subsequent merge/commit operation. (Issue #4980 HIGH-7)
1047
- */
1048
- function reconcileOtherInProgressGitOps(
1049
- basePath: string,
1050
- ctx: ExtensionContext,
1051
- ): "clean" | "reconciled" | "blocked" {
1052
- const gitDir = join(basePath, ".git");
1053
- const states: Array<{
1054
- label: string;
1055
- indicators: string[];
1056
- abort: () => void;
1057
- }> = [
1058
- {
1059
- label: "rebase",
1060
- indicators: [join(gitDir, "rebase-merge"), join(gitDir, "rebase-apply")],
1061
- abort: () => nativeRebaseAbort(basePath),
1062
- },
1063
- {
1064
- label: "cherry-pick",
1065
- indicators: [join(gitDir, "CHERRY_PICK_HEAD")],
1066
- abort: () => {
1067
- // No native helper; fall back to git CLI.
1068
- try {
1069
- execFileSync("git", ["cherry-pick", "--abort"], {
1070
- cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8",
1071
- });
1072
- } catch (err) { logWarning("recovery", `cherry-pick --abort failed: ${getErrorMessage(err)}`); }
1073
- },
1074
- },
1075
- {
1076
- label: "revert",
1077
- indicators: [join(gitDir, "REVERT_HEAD")],
1078
- abort: () => {
1079
- try {
1080
- execFileSync("git", ["revert", "--abort"], {
1081
- cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8",
1082
- });
1083
- } catch (err) { logWarning("recovery", `revert --abort failed: ${getErrorMessage(err)}`); }
1084
- },
1085
- },
1086
- ];
1087
-
1088
- let reconciled = false;
1089
- for (const s of states) {
1090
- const present = s.indicators.some((p) => existsSync(p));
1091
- if (!present) continue;
1092
- try {
1093
- s.abort();
1094
- ctx.ui.notify(
1095
- `Detected leftover ${s.label} state from prior session — aborted.`,
1096
- "warning",
1097
- );
1098
- reconciled = true;
1099
- } catch (err) {
1100
- logError("recovery", `${s.label} abort failed: ${getErrorMessage(err)}`);
1101
- ctx.ui.notify(
1102
- `Detected leftover ${s.label} state but auto-abort failed. ` +
1103
- `Run \`git ${s.label} --abort\` manually before retrying.`,
1104
- "error",
1105
- );
1106
- return "blocked";
1107
- }
1108
- }
1109
- return reconciled ? "reconciled" : "clean";
1110
- }
1111
-
1112
- /**
1113
- * Detect leftover merge state from a prior session and reconcile it.
1114
- * If MERGE_HEAD or SQUASH_MSG exists, check whether conflicts are resolved.
1115
- * If resolved: finalize the commit. If only .gsd conflicts remain: auto-resolve.
1116
- * If code conflicts remain: fail safe without modifying the worktree.
1117
- */
1118
- export function reconcileMergeState(
1119
- basePath: string,
1120
- ctx: ExtensionContext,
1121
- ): MergeReconcileResult {
1122
- // First, abort any rebase/cherry-pick/revert left over from a SIGKILL'd
1123
- // worker. Doing this before the merge-state check unblocks any merge that
1124
- // would otherwise refuse with "you have unfinished operation". (HIGH-7)
1125
- const otherOpsResult = reconcileOtherInProgressGitOps(basePath, ctx);
1126
- if (otherOpsResult === "blocked") return "blocked";
1127
-
1128
- const mergeHeadPath = join(basePath, ".git", "MERGE_HEAD");
1129
- const squashMsgPath = join(basePath, ".git", "SQUASH_MSG");
1130
- const hasMergeHead = existsSync(mergeHeadPath);
1131
- const hasSquashMsg = existsSync(squashMsgPath);
1132
- if (!hasMergeHead && !hasSquashMsg) {
1133
- // If we cleaned up another op type, return "reconciled" so the caller
1134
- // re-derives state from a known-good baseline.
1135
- return otherOpsResult === "reconciled" ? "reconciled" : "clean";
1136
- }
1137
-
1138
- const conflictedFiles = nativeConflictFiles(basePath);
1139
- if (conflictedFiles.length === 0) {
1140
- // All conflicts resolved — finalize the merge/squash commit
1141
- try {
1142
- const commitSha = nativeCommit(basePath, "chore(gsd): reconcile merge state");
1143
- if (commitSha) {
1144
- const mode = hasMergeHead ? "merge" : "squash commit";
1145
- ctx.ui.notify(`Finalized leftover ${mode} from prior session.`, "info");
1146
- } else {
1147
- ctx.ui.notify("No new commit needed for leftover merge/squash state — already committed.", "info");
1148
- }
1149
- } catch (err) {
1150
- const errorMessage = getErrorMessage(err);
1151
- ctx.ui.notify(`Failed to finalize leftover merge/squash commit: ${errorMessage}`, "error");
1152
- return "blocked";
1153
- }
1154
- } else {
1155
- // Still conflicted — try auto-resolving .gsd/ state file conflicts (#530)
1156
- const gsdConflicts = conflictedFiles.filter((f) => f.startsWith(".gsd/"));
1157
- const codeConflicts = conflictedFiles.filter((f) => !f.startsWith(".gsd/"));
1158
-
1159
- if (gsdConflicts.length > 0 && codeConflicts.length === 0) {
1160
- // All conflicts are in .gsd/ state files — auto-resolve by accepting theirs
1161
- let resolved = true;
1162
- try {
1163
- nativeCheckoutTheirs(basePath, gsdConflicts);
1164
- nativeAddPaths(basePath, gsdConflicts);
1165
- } catch (e) {
1166
- logError("recovery", `auto-resolve .gsd/ conflicts failed: ${(e as Error).message}`);
1167
- resolved = false;
1168
- }
1169
- if (resolved) {
1170
- try {
1171
- nativeCommit(
1172
- basePath,
1173
- "chore: auto-resolve .gsd/ state file conflicts",
1174
- );
1175
- ctx.ui.notify(
1176
- `Auto-resolved ${gsdConflicts.length} .gsd/ state file conflict(s) from prior merge.`,
1177
- "info",
1178
- );
1179
- } catch (e) {
1180
- logError("recovery", `auto-commit .gsd/ conflict resolution failed: ${(e as Error).message}`);
1181
- resolved = false;
1182
- }
1183
- }
1184
- if (!resolved) {
1185
- abortAndResetMerge(basePath, hasMergeHead, squashMsgPath);
1186
- ctx.ui.notify(
1187
- "Detected leftover merge state — auto-resolve failed, cleaned up. Re-deriving state.",
1188
- "warning",
1189
- );
1190
- }
1191
- } else {
1192
- // Code conflicts present — fail safe and preserve any manual resolution
1193
- // work instead of discarding it with merge --abort/reset --hard.
1194
- ctx.ui.notify(
1195
- "Detected leftover merge state with unresolved code conflicts. Auto-mode will pause without modifying the worktree so manual conflict resolution is preserved.",
1196
- "error",
1197
- );
1198
- return "blocked";
1199
- }
1200
- }
1201
- return "reconciled";
1202
- }
997
+ export {
998
+ reconcileMergeState,
999
+ type MergeReconcileResult,
1000
+ } from "./state-reconciliation/drift/merge-state.js";
1203
1001
 
1204
1002
  // ─── Loop Remediation ─────────────────────────────────────────────────────────
1205
1003
 
@@ -56,3 +56,8 @@ export function recordToolInvocationError(toolName: string, errorMsg: string): v
56
56
  autoSession.lastToolInvocationError = `${toolName}: ${errorMsg}`;
57
57
  }
58
58
  }
59
+
60
+ export function clearToolInvocationError(): void {
61
+ if (!autoSession.active) return;
62
+ autoSession.lastToolInvocationError = null;
63
+ }
@@ -904,29 +904,24 @@ export async function bootstrapAutoSession(
904
904
  {
905
905
  const orphan = findUnmergedCompletedMilestone(base, getIsolationMode(base));
906
906
  if (orphan && orphan !== state.activeMilestone?.id) {
907
- const priorBasePath = s.basePath;
908
- const priorOriginalBasePath = s.originalBasePath;
909
- s.originalBasePath = base;
910
- s.basePath = getAutoWorktreePath(base, orphan) ?? base;
911
- const result = _mergeOrphanCompletedMilestone(buildLifecycle(), orphan, ctx.ui);
907
+ // ADR-016 phase 2 / B4 (#5622): the swap-run-revert protocol for
908
+ // the orphan-merge dance is owned by `adoptOrphanWorktree`. The
909
+ // verb snapshots prior `s.basePath` / `s.originalBasePath`, swaps
910
+ // into the orphan worktree, runs the merge callback under the
911
+ // swap, and reverts (or holds the swap) based on the result.
912
+ // Callers can no longer forget the revert step on failure — the
913
+ // pattern that originally motivated this verb.
914
+ const lifecycle = buildLifecycle();
915
+ const result = lifecycle.adoptOrphanWorktree(orphan, base, () =>
916
+ _mergeOrphanCompletedMilestone(lifecycle, orphan, ctx.ui),
917
+ );
912
918
  if (!result.merged) {
913
- s.basePath = base;
914
- s.originalBasePath = base;
915
- try {
916
- process.chdir(base);
917
- } catch (err) {
918
- logWarning("bootstrap", `could not restore cwd after orphan merge failure: ${err instanceof Error ? err.message : String(err)}`);
919
- }
919
+ // Verb already restored basePath/originalBasePath to `base` and
920
+ // chdir'd there. Return early.
920
921
  return releaseLockAndReturn();
921
922
  }
922
- if (!s.active) {
923
- s.basePath = priorBasePath || base;
924
- s.originalBasePath = priorOriginalBasePath || base;
925
- }
926
- if (result.merged) {
927
- invalidateAllCaches();
928
- state = await deriveState(base);
929
- }
923
+ invalidateAllCaches();
924
+ state = await deriveState(base);
930
925
  }
931
926
  }
932
927
 
@@ -1040,7 +1035,10 @@ export async function bootstrapAutoSession(
1040
1035
  s.stepMode = requestedStepMode;
1041
1036
  s.verbose = verboseMode;
1042
1037
  s.cmdCtx = ctx;
1043
- s.basePath = base;
1038
+ // ADR-016 phase 2 / B2 (#5620): single owner of bootstrap basePath
1039
+ // mutation. Sets s.basePath = base and s.originalBasePath = base
1040
+ // (originalBasePath is empty on a fresh bootstrap).
1041
+ buildLifecycle().adoptSessionRoot(base);
1044
1042
  s.unitDispatchCount.clear();
1045
1043
  s.unitRecoveryCount.clear();
1046
1044
  s.lastBudgetAlertLevel = 0;
@@ -1098,7 +1096,9 @@ export async function bootstrapAutoSession(
1098
1096
  }
1099
1097
 
1100
1098
  // ── Auto-worktree setup ──
1101
- s.originalBasePath = base;
1099
+ // s.originalBasePath was set to `base` by `adoptSessionRoot(base)` above
1100
+ // (ADR-016 phase 2 / B2, #5620). The redundant assignment that used to
1101
+ // live here is gone.
1102
1102
 
1103
1103
  const isUnderGsdWorktrees = (p: string): boolean => {
1104
1104
  // Direct layout: /.gsd/worktrees/
@@ -1,3 +1,6 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: Auto-mode unit closeout metrics, activity capture, and ghost-run detection.
3
+
1
4
  /**
2
5
  * Unit closeout helper — consolidates the repeated pattern of
3
6
  * snapshotting metrics + saving activity log + extracting memories
@@ -24,6 +27,54 @@ export interface CloseoutOptions {
24
27
  gitError?: string;
25
28
  }
26
29
 
30
+ export interface UnitActivitySnapshot {
31
+ elapsedMs: number;
32
+ toolCalls: number;
33
+ assistantMessages: number;
34
+ }
35
+
36
+ export const GHOST_COMPLETION_MAX_ELAPSED_MS = 500;
37
+
38
+ export function snapshotUnitActivity(
39
+ ctx: ExtensionContext,
40
+ startedAt: number,
41
+ now = Date.now(),
42
+ ): UnitActivitySnapshot {
43
+ let toolCalls = 0;
44
+ let assistantMessages = 0;
45
+ const entries = ctx.sessionManager.getEntries() ?? [];
46
+
47
+ for (const entry of entries) {
48
+ if (entry.type !== "message") continue;
49
+ const msg = (entry as any).message;
50
+ if (!msg || msg.role !== "assistant") continue;
51
+ assistantMessages++;
52
+ if (!Array.isArray(msg.content)) continue;
53
+ for (const block of msg.content) {
54
+ if (block?.type === "toolCall") toolCalls++;
55
+ }
56
+ }
57
+
58
+ return {
59
+ elapsedMs: Math.max(0, now - startedAt),
60
+ toolCalls,
61
+ assistantMessages,
62
+ };
63
+ }
64
+
65
+ export function isSuspiciousGhostCompletion(
66
+ ctx: ExtensionContext,
67
+ startedAt: number,
68
+ maxElapsedMs = GHOST_COMPLETION_MAX_ELAPSED_MS,
69
+ ): boolean {
70
+ const activity = snapshotUnitActivity(ctx, startedAt);
71
+ return (
72
+ activity.elapsedMs < maxElapsedMs &&
73
+ activity.toolCalls === 0 &&
74
+ activity.assistantMessages === 0
75
+ );
76
+ }
77
+
27
78
  /**
28
79
  * Snapshot metrics, save activity log, and fire-and-forget memory extraction
29
80
  * for a completed unit. Returns the activity log file path (if any).
@@ -39,6 +39,7 @@ import type { VerificationResult as VerificationGateResult } from "./types.js";
39
39
  import { join } from "node:path";
40
40
  import { resolveUokFlags } from "./uok/flags.js";
41
41
  import { UokGateRunner } from "./uok/gate-runner.js";
42
+ import { verificationRetryKey } from "./auto/verification-retry-policy.js";
42
43
 
43
44
  export interface VerificationContext {
44
45
  s: AutoSession;
@@ -331,7 +332,8 @@ export async function runPostUnitVerification(
331
332
  }
332
333
 
333
334
  // Write verification evidence JSON
334
- const attempt = s.verificationRetryCount.get(s.currentUnit.id) ?? 0;
335
+ const retryKey = verificationRetryKey(s.currentUnit.type, s.currentUnit.id);
336
+ const attempt = s.verificationRetryCount.get(retryKey) ?? 0;
335
337
  if (mid && sid && tid) {
336
338
  try {
337
339
  const sDir = resolveSlicePath(s.basePath, mid, sid);
@@ -364,7 +366,8 @@ export async function runPostUnitVerification(
364
366
  ));
365
367
 
366
368
  if (advisoryFailure) {
367
- s.verificationRetryCount.delete(s.currentUnit.id);
369
+ s.verificationRetryCount.delete(retryKey);
370
+ s.verificationRetryFailureHashes.delete(retryKey);
368
371
  s.pendingVerificationRetry = null;
369
372
  ctx.ui.notify(
370
373
  result.discoverySource === "package-json"
@@ -565,13 +568,15 @@ export async function runPostUnitVerification(
565
568
 
566
569
  // ── Auto-fix retry logic ──
567
570
  if (result.passed) {
568
- s.verificationRetryCount.delete(s.currentUnit.id);
571
+ s.verificationRetryCount.delete(retryKey);
572
+ s.verificationRetryFailureHashes.delete(retryKey);
569
573
  s.pendingVerificationRetry = null;
570
574
  return "continue";
571
575
  } else if (postExecBlockingFailure) {
572
576
  // Post-execution failures are cross-task consistency issues — retrying the same task won't fix them.
573
577
  // Skip retry and pause immediately for human review.
574
- s.verificationRetryCount.delete(s.currentUnit.id);
578
+ s.verificationRetryCount.delete(retryKey);
579
+ s.verificationRetryFailureHashes.delete(retryKey);
575
580
  s.pendingVerificationRetry = null;
576
581
  ctx.ui.notify(
577
582
  `Post-execution checks failed — cross-task consistency issue detected, pausing for human review`,
@@ -581,7 +586,7 @@ export async function runPostUnitVerification(
581
586
  return "pause";
582
587
  } else if (autoFixEnabled && attempt + 1 <= maxRetries) {
583
588
  const nextAttempt = attempt + 1;
584
- s.verificationRetryCount.set(s.currentUnit.id, nextAttempt);
589
+ s.verificationRetryCount.set(retryKey, nextAttempt);
585
590
  s.pendingVerificationRetry = {
586
591
  unitId: s.currentUnit.id,
587
592
  failureContext: formatFailureContext(result),
@@ -601,7 +606,8 @@ export async function runPostUnitVerification(
601
606
  return "retry";
602
607
  } else {
603
608
  // Gate failed, retries exhausted
604
- s.verificationRetryCount.delete(s.currentUnit.id);
609
+ s.verificationRetryCount.delete(retryKey);
610
+ s.verificationRetryFailureHashes.delete(retryKey);
605
611
  s.pendingVerificationRetry = null;
606
612
  const exhaustedFails = result.checks
607
613
  .filter((c) => c.exitCode !== 0)
@@ -1502,6 +1502,14 @@ function autoCommitDirtyState(cwd: string): boolean {
1502
1502
  * On merge conflict: throws MergeConflictError.
1503
1503
  * On "nothing to commit" after squash: safe only if milestone work is already
1504
1504
  * on the integration branch. Throws if unanchored code changes would be lost.
1505
+ *
1506
+ * @internal **Do not call directly.** This is the inner squash-merge primitive
1507
+ * for the Worktree Lifecycle Module (ADR-016 phase 2 / A3, issue #5619).
1508
+ * Production callers must go through `WorktreeLifecycle.mergeMilestoneStandalone`
1509
+ * or `WorktreeLifecycle.exitMilestone({ merge: true })`. The export keyword
1510
+ * is preserved only so `auto.ts:buildWorktreeLifecycleDeps()` can wire this
1511
+ * function through the Module's deps seam — that is the construction of the
1512
+ * seam, not a bypass.
1505
1513
  */
1506
1514
  export function mergeMilestoneToMain(
1507
1515
  originalBasePath_: string,