gsd-pi 2.81.0 → 2.82.0-dev.725028083

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 (482) hide show
  1. package/README.md +60 -30
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/browser-tools/tools/screenshot.js +1 -0
  4. package/dist/resources/extensions/browser-tools/tools/zoom.js +1 -0
  5. package/dist/resources/extensions/gsd/auto/loop.js +111 -8
  6. package/dist/resources/extensions/gsd/auto/phases.js +199 -97
  7. package/dist/resources/extensions/gsd/auto/run-unit.js +66 -3
  8. package/dist/resources/extensions/gsd/auto/session.js +9 -0
  9. package/dist/resources/extensions/gsd/auto/verification-retry-policy.js +43 -0
  10. package/dist/resources/extensions/gsd/auto-dashboard.js +182 -178
  11. package/dist/resources/extensions/gsd/auto-dispatch.js +14 -11
  12. package/dist/resources/extensions/gsd/auto-post-unit.js +7 -1
  13. package/dist/resources/extensions/gsd/auto-prompts.js +11 -3
  14. package/dist/resources/extensions/gsd/auto-recovery.js +6 -181
  15. package/dist/resources/extensions/gsd/auto-runtime-state.js +5 -0
  16. package/dist/resources/extensions/gsd/auto-start.js +20 -23
  17. package/dist/resources/extensions/gsd/auto-unit-closeout.js +33 -5
  18. package/dist/resources/extensions/gsd/auto-verification.js +12 -6
  19. package/dist/resources/extensions/gsd/auto-worktree.js +8 -0
  20. package/dist/resources/extensions/gsd/auto.js +265 -76
  21. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +13 -6
  22. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +13 -2
  23. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +4 -8
  24. package/dist/resources/extensions/gsd/bootstrap/system-context.js +55 -12
  25. package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -1
  26. package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +4 -10
  27. package/dist/resources/extensions/gsd/commands/handlers/parallel.js +9 -0
  28. package/dist/resources/extensions/gsd/commands-handlers.js +15 -2
  29. package/dist/resources/extensions/gsd/context-store.js +112 -0
  30. package/dist/resources/extensions/gsd/db-writer.js +150 -84
  31. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  32. package/dist/resources/extensions/gsd/doctor-git-checks.js +41 -6
  33. package/dist/resources/extensions/gsd/git-service.js +2 -1
  34. package/dist/resources/extensions/gsd/gsd-db.js +7 -23
  35. package/dist/resources/extensions/gsd/health-widget-core.js +1 -1
  36. package/dist/resources/extensions/gsd/health-widget.js +4 -10
  37. package/dist/resources/extensions/gsd/knowledge-backfill.js +144 -0
  38. package/dist/resources/extensions/gsd/knowledge-capture.js +136 -0
  39. package/dist/resources/extensions/gsd/knowledge-parser.js +154 -0
  40. package/dist/resources/extensions/gsd/knowledge-projection.js +210 -0
  41. package/dist/resources/extensions/gsd/markdown-renderer.js +6 -96
  42. package/dist/resources/extensions/gsd/memory-backfill.js +73 -17
  43. package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +222 -0
  44. package/dist/resources/extensions/gsd/native-git-bridge.js +14 -14
  45. package/dist/resources/extensions/gsd/notification-overlay.js +35 -40
  46. package/dist/resources/extensions/gsd/parallel-merge.js +53 -30
  47. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +25 -33
  48. package/dist/resources/extensions/gsd/prompts/complete-slice.md +14 -12
  49. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
  50. package/dist/resources/extensions/gsd/prompts/discuss.md +20 -2
  51. package/dist/resources/extensions/gsd/prompts/system.md +2 -2
  52. package/dist/resources/extensions/gsd/provider-switch-observer.js +146 -0
  53. package/dist/resources/extensions/gsd/recovery-classification.js +15 -1
  54. package/dist/resources/extensions/gsd/session-lock.js +40 -0
  55. package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +131 -0
  56. package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +247 -0
  57. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +50 -0
  58. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +87 -0
  59. package/dist/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.js +50 -0
  60. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +124 -0
  61. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-worker.js +32 -0
  62. package/dist/resources/extensions/gsd/state-reconciliation/errors.js +41 -0
  63. package/dist/resources/extensions/gsd/state-reconciliation/index.js +99 -0
  64. package/dist/resources/extensions/gsd/state-reconciliation/registry.js +24 -0
  65. package/dist/resources/extensions/gsd/state-reconciliation/spawn-gate.js +43 -0
  66. package/dist/resources/extensions/gsd/state-reconciliation/types.js +3 -0
  67. package/dist/resources/extensions/gsd/state-reconciliation.js +5 -26
  68. package/dist/resources/extensions/gsd/templates/knowledge.md +2 -2
  69. package/dist/resources/extensions/gsd/tui/render-kit.js +74 -0
  70. package/dist/resources/extensions/gsd/watch/header-renderer.js +92 -69
  71. package/dist/resources/extensions/gsd/watch/splash-palette.js +10 -0
  72. package/dist/resources/extensions/gsd/workflow-mcp.js +2 -2
  73. package/dist/resources/extensions/gsd/worktree-lifecycle.js +722 -316
  74. package/dist/resources/extensions/gsd/worktree-telemetry.js +3 -1
  75. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  76. package/dist/web/standalone/.next/BUILD_ID +1 -1
  77. package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
  78. package/dist/web/standalone/.next/build-manifest.json +3 -3
  79. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  80. package/dist/web/standalone/.next/required-server-files.json +3 -3
  81. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  82. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  83. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  84. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  92. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  93. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  94. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  95. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  96. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  98. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  108. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  120. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  140. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  150. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  156. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  172. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +2 -2
  176. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  185. package/dist/web/standalone/.next/server/app/index.html +1 -1
  186. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  187. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  188. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  189. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  190. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  191. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  192. package/dist/web/standalone/.next/server/app/page.js +2 -2
  193. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  194. package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
  195. package/dist/web/standalone/.next/server/chunks/63.js +3 -3
  196. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  197. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  198. package/dist/web/standalone/.next/server/middleware.js +2 -2
  199. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  200. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  201. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  202. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  203. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  204. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  205. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  206. package/dist/web/standalone/.next/static/chunks/app/page-752f1e2ebdaa3e45.js +1 -0
  207. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  208. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  209. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  210. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  211. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  212. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  213. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  214. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  215. package/dist/web/standalone/server.js +1 -1
  216. package/dist/welcome-screen.d.ts +0 -7
  217. package/dist/welcome-screen.js +60 -69
  218. package/package.json +3 -2
  219. package/packages/daemon/package.json +2 -2
  220. package/packages/mcp-server/README.md +2 -0
  221. package/packages/mcp-server/package.json +2 -2
  222. package/packages/mcp-server/src/workflow-tools-parity.test.ts +244 -0
  223. package/packages/native/package.json +1 -1
  224. package/packages/pi-agent-core/package.json +1 -1
  225. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  226. package/packages/pi-ai/dist/index.d.ts +2 -2
  227. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  228. package/packages/pi-ai/dist/index.js +1 -1
  229. package/packages/pi-ai/dist/index.js.map +1 -1
  230. package/packages/pi-ai/dist/providers/transform-messages.d.ts +11 -0
  231. package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
  232. package/packages/pi-ai/dist/providers/transform-messages.js +20 -0
  233. package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
  234. package/packages/pi-ai/package.json +1 -1
  235. package/packages/pi-ai/src/index.ts +7 -2
  236. package/packages/pi-ai/src/providers/transform-messages.ts +24 -0
  237. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  238. package/packages/pi-coding-agent/dist/core/system-prompt.js +4 -4
  239. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  240. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts +2 -0
  241. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts.map +1 -0
  242. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js +47 -0
  243. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js.map +1 -0
  244. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +76 -9
  245. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  246. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts +2 -0
  247. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts.map +1 -0
  248. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js +40 -0
  249. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js.map +1 -0
  250. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +0 -1
  251. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -1
  252. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +30 -29
  253. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -1
  254. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +10 -3
  255. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -1
  256. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  257. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +13 -13
  258. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  259. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +1 -3
  260. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  261. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +58 -3
  262. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
  263. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts +2 -2
  264. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts.map +1 -1
  265. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js +12 -6
  266. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js.map +1 -1
  267. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  268. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -41
  269. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  270. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +0 -1
  271. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  272. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +86 -82
  273. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  274. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts +35 -0
  275. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts.map +1 -0
  276. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js +152 -0
  277. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js.map +1 -0
  278. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts +16 -0
  279. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts.map +1 -0
  280. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js +73 -0
  281. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js.map +1 -0
  282. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +1 -1
  283. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  284. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +12 -8
  285. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  286. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
  287. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
  288. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
  289. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
  290. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  291. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +105 -1
  292. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  293. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  294. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +27 -26
  295. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  296. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +9 -6
  297. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -1
  298. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts +2 -0
  299. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts.map +1 -0
  300. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js +17 -0
  301. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js.map +1 -0
  302. package/packages/pi-coding-agent/package.json +1 -1
  303. package/packages/pi-coding-agent/src/core/system-prompt.ts +4 -4
  304. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/assistant-message-design.test.ts +56 -0
  305. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +113 -9
  306. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/user-message-design.test.ts +48 -0
  307. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +10 -3
  308. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +43 -42
  309. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +14 -14
  310. package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +64 -3
  311. package/packages/pi-coding-agent/src/modes/interactive/components/diff.ts +13 -7
  312. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +15 -42
  313. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +84 -104
  314. package/packages/pi-coding-agent/src/modes/interactive/components/transcript-design.ts +196 -0
  315. package/packages/pi-coding-agent/src/modes/interactive/components/tui-style-kit.ts +94 -0
  316. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +14 -9
  317. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-highlight.test.ts +23 -0
  318. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +106 -1
  319. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +27 -26
  320. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +9 -6
  321. package/packages/pi-coding-agent/src/tests/system-prompt-file-safety.test.ts +22 -0
  322. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  323. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +14 -1
  324. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  325. package/packages/pi-tui/dist/overlay-layout.d.ts.map +1 -1
  326. package/packages/pi-tui/dist/overlay-layout.js +9 -6
  327. package/packages/pi-tui/dist/overlay-layout.js.map +1 -1
  328. package/packages/pi-tui/package.json +1 -1
  329. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +20 -1
  330. package/packages/pi-tui/src/overlay-layout.ts +10 -7
  331. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  332. package/packages/rpc-client/package.json +1 -1
  333. package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
  334. package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
  335. package/pkg/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
  336. package/pkg/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
  337. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  338. package/pkg/dist/modes/interactive/theme/theme.js +105 -1
  339. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  340. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  341. package/pkg/dist/modes/interactive/theme/themes.js +27 -26
  342. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  343. package/pkg/package.json +1 -1
  344. package/src/resources/extensions/browser-tools/tools/screenshot.ts +1 -0
  345. package/src/resources/extensions/browser-tools/tools/zoom.ts +1 -0
  346. package/src/resources/extensions/gsd/auto/loop-deps.ts +9 -5
  347. package/src/resources/extensions/gsd/auto/loop.ts +113 -9
  348. package/src/resources/extensions/gsd/auto/phases.ts +158 -19
  349. package/src/resources/extensions/gsd/auto/run-unit.ts +69 -4
  350. package/src/resources/extensions/gsd/auto/session.ts +10 -0
  351. package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +82 -0
  352. package/src/resources/extensions/gsd/auto-dashboard.ts +230 -183
  353. package/src/resources/extensions/gsd/auto-dispatch.ts +15 -1
  354. package/src/resources/extensions/gsd/auto-post-unit.ts +7 -1
  355. package/src/resources/extensions/gsd/auto-prompts.ts +11 -3
  356. package/src/resources/extensions/gsd/auto-recovery.ts +7 -209
  357. package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
  358. package/src/resources/extensions/gsd/auto-start.ts +22 -22
  359. package/src/resources/extensions/gsd/auto-unit-closeout.ts +51 -0
  360. package/src/resources/extensions/gsd/auto-verification.ts +12 -6
  361. package/src/resources/extensions/gsd/auto-worktree.ts +8 -0
  362. package/src/resources/extensions/gsd/auto.ts +295 -75
  363. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +21 -6
  364. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +12 -2
  365. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +5 -8
  366. package/src/resources/extensions/gsd/bootstrap/system-context.ts +58 -15
  367. package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -1
  368. package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +4 -10
  369. package/src/resources/extensions/gsd/commands/handlers/parallel.ts +12 -0
  370. package/src/resources/extensions/gsd/commands-handlers.ts +19 -2
  371. package/src/resources/extensions/gsd/context-store.ts +120 -1
  372. package/src/resources/extensions/gsd/db-writer.ts +167 -84
  373. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  374. package/src/resources/extensions/gsd/doctor-git-checks.ts +44 -6
  375. package/src/resources/extensions/gsd/doctor-types.ts +2 -0
  376. package/src/resources/extensions/gsd/git-service.ts +2 -0
  377. package/src/resources/extensions/gsd/gsd-db.ts +7 -23
  378. package/src/resources/extensions/gsd/health-widget-core.ts +1 -1
  379. package/src/resources/extensions/gsd/health-widget.ts +6 -10
  380. package/src/resources/extensions/gsd/journal.ts +2 -0
  381. package/src/resources/extensions/gsd/knowledge-backfill.ts +164 -0
  382. package/src/resources/extensions/gsd/knowledge-capture.ts +160 -0
  383. package/src/resources/extensions/gsd/knowledge-parser.ts +174 -0
  384. package/src/resources/extensions/gsd/knowledge-projection.ts +241 -0
  385. package/src/resources/extensions/gsd/markdown-renderer.ts +10 -96
  386. package/src/resources/extensions/gsd/memory-backfill.ts +89 -17
  387. package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +277 -0
  388. package/src/resources/extensions/gsd/native-git-bridge.ts +14 -13
  389. package/src/resources/extensions/gsd/notification-overlay.ts +50 -46
  390. package/src/resources/extensions/gsd/parallel-merge.ts +61 -34
  391. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +33 -35
  392. package/src/resources/extensions/gsd/prompts/complete-slice.md +14 -12
  393. package/src/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
  394. package/src/resources/extensions/gsd/prompts/discuss.md +20 -2
  395. package/src/resources/extensions/gsd/prompts/system.md +2 -2
  396. package/src/resources/extensions/gsd/provider-switch-observer.ts +185 -0
  397. package/src/resources/extensions/gsd/recovery-classification.ts +18 -1
  398. package/src/resources/extensions/gsd/session-lock.ts +41 -0
  399. package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +172 -0
  400. package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +337 -0
  401. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +69 -0
  402. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +109 -0
  403. package/src/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.ts +68 -0
  404. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +185 -0
  405. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-worker.ts +46 -0
  406. package/src/resources/extensions/gsd/state-reconciliation/errors.ts +67 -0
  407. package/src/resources/extensions/gsd/state-reconciliation/index.ts +142 -0
  408. package/src/resources/extensions/gsd/state-reconciliation/registry.ts +27 -0
  409. package/src/resources/extensions/gsd/state-reconciliation/spawn-gate.ts +60 -0
  410. package/src/resources/extensions/gsd/state-reconciliation/types.ts +83 -0
  411. package/src/resources/extensions/gsd/state-reconciliation.ts +21 -53
  412. package/src/resources/extensions/gsd/templates/knowledge.md +2 -2
  413. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +1 -1
  414. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +99 -0
  415. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +729 -176
  416. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +291 -4
  417. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +16 -1
  418. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +18 -0
  419. package/src/resources/extensions/gsd/tests/auto-unit-closeout.test.ts +68 -0
  420. package/src/resources/extensions/gsd/tests/browser-tools-compatibility-declarations.test.ts +62 -0
  421. package/src/resources/extensions/gsd/tests/context-store-decisions-from-memories.test.ts +312 -0
  422. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +28 -1
  423. package/src/resources/extensions/gsd/tests/db-writer.test.ts +13 -8
  424. package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +453 -0
  425. package/src/resources/extensions/gsd/tests/decisions-stop-table-writes.test.ts +348 -0
  426. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +20 -2
  427. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +44 -0
  428. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +8 -4
  429. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +11 -7
  430. package/src/resources/extensions/gsd/tests/header-renderer.test.ts +40 -0
  431. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +10 -0
  432. package/src/resources/extensions/gsd/tests/health-widget.test.ts +14 -4
  433. package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +44 -0
  434. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +26 -0
  435. package/src/resources/extensions/gsd/tests/integration/integration-lifecycle.test.ts +13 -5
  436. package/src/resources/extensions/gsd/tests/integration/integration-proof.test.ts +1 -1
  437. package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +116 -24
  438. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -1
  439. package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +323 -0
  440. package/src/resources/extensions/gsd/tests/knowledge-capture.test.ts +242 -0
  441. package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -2
  442. package/src/resources/extensions/gsd/tests/load-knowledge-block-rules-only.test.ts +209 -0
  443. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +1 -1
  444. package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +316 -0
  445. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +46 -11
  446. package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +78 -41
  447. package/src/resources/extensions/gsd/tests/notifications-handler.test.ts +44 -0
  448. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +12 -217
  449. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +38 -6
  450. package/src/resources/extensions/gsd/tests/plan-milestone-sketch-render.test.ts +157 -0
  451. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +2 -2
  452. package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +1 -1
  453. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +32 -1
  454. package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +252 -0
  455. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +7 -3
  456. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +6 -3
  457. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +16 -4
  458. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +24 -0
  459. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +65 -58
  460. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +952 -0
  461. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +4 -0
  462. package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +121 -1
  463. package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +66 -0
  464. package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +83 -0
  465. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +6 -0
  466. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +158 -58
  467. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +572 -118
  468. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +59 -2
  469. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +18 -0
  470. package/src/resources/extensions/gsd/tui/render-kit.ts +109 -0
  471. package/src/resources/extensions/gsd/watch/header-renderer.ts +121 -79
  472. package/src/resources/extensions/gsd/watch/splash-palette.ts +11 -0
  473. package/src/resources/extensions/gsd/workflow-logger.ts +4 -0
  474. package/src/resources/extensions/gsd/workflow-mcp.ts +2 -2
  475. package/src/resources/extensions/gsd/worktree-lifecycle.ts +1151 -524
  476. package/src/resources/extensions/gsd/worktree-telemetry.ts +7 -2
  477. package/dist/web/standalone/.next/static/chunks/app/page-200592a7f3baf579.js +0 -1
  478. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  479. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  480. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +0 -1544
  481. /package/dist/web/standalone/.next/static/{drLMkgfHQ8lzS229_HWYR → KDRTXR-22LPCsa80X9dey}/_buildManifest.js +0 -0
  482. /package/dist/web/standalone/.next/static/{drLMkgfHQ8lzS229_HWYR → KDRTXR-22LPCsa80X9dey}/_ssgManifest.js +0 -0
@@ -31,6 +31,7 @@ import { withTimeout, FINALIZE_PRE_TIMEOUT_MS, FINALIZE_POST_TIMEOUT_MS } from "
31
31
  import { getEligibleSlices } from "../slice-parallel-eligibility.js";
32
32
  import { startSliceParallel } from "../slice-parallel-orchestrator.js";
33
33
  import { isDbAvailable, getMilestoneSlices } from "../gsd-db.js";
34
+ import { reconcileBeforeSpawn } from "../state-reconciliation.js";
34
35
  import { ensurePlanV2Graph, isEmptyPlanV2GraphResult, isMissingFinalizedContextResult } from "../uok/plan-v2.js";
35
36
  import { resolveUokFlags } from "../uok/flags.js";
36
37
  import { UokGateRunner } from "../uok/gate-runner.js";
@@ -41,11 +42,53 @@ import { resolveSafetyHarnessConfig } from "../safety/safety-harness.js";
41
42
  import { getWorkflowTransportSupportError, getRequiredWorkflowToolsForAutoUnit, supportsStructuredQuestions, } from "../workflow-mcp.js";
42
43
  import { resolveManifest } from "../unit-context-manifest.js";
43
44
  import { createWorktreeSafetyModule } from "../worktree-safety.js";
45
+ import { isSuspiciousGhostCompletion } from "../auto-unit-closeout.js";
46
+ import { decideVerificationRetry, verificationRetryKey } from "./verification-retry-policy.js";
44
47
  // ─── Path Comparison Helper ───────────────────────────────────────────────
45
48
  /** Compare two paths for physical identity, tolerating trailing slashes and symlinks. */
46
49
  function isSamePathLocal(a, b) {
47
50
  return normalizeWorktreePathForCompare(a) === normalizeWorktreePathForCompare(b);
48
51
  }
52
+ async function applyVerificationRetryPolicy(ic, unitType, phase) {
53
+ const { ctx, pi, s, deps } = ic;
54
+ const retryInfo = s.pendingVerificationRetry;
55
+ const key = unitType && retryInfo
56
+ ? verificationRetryKey(unitType, retryInfo.unitId)
57
+ : undefined;
58
+ const decision = decideVerificationRetry({
59
+ unitType,
60
+ retryInfo,
61
+ previousFailureHash: key ? s.verificationRetryFailureHashes.get(key) : undefined,
62
+ });
63
+ if (decision.action === "pause") {
64
+ s.pendingVerificationRetry = null;
65
+ debugLog("autoLoop", {
66
+ phase: `${phase}-paused`,
67
+ reason: decision.reason,
68
+ unitType,
69
+ unitId: retryInfo?.unitId,
70
+ failureHash: decision.failureHash,
71
+ });
72
+ ctx.ui.notify(decision.reason === "duplicate-failure-context"
73
+ ? `Verification retry for ${unitType ?? "unit"} ${retryInfo?.unitId ?? "unknown"} produced the same failure context. Pausing auto-mode instead of re-dispatching.`
74
+ : "Verification retry requested without retry context. Pausing auto-mode instead of re-dispatching.", "warning");
75
+ await deps.pauseAuto(ctx, pi);
76
+ return { action: "break", reason: decision.reason };
77
+ }
78
+ s.verificationRetryFailureHashes.set(decision.key, decision.failureHash);
79
+ debugLog("autoLoop", {
80
+ phase: `${phase}-backoff`,
81
+ iteration: ic.iteration,
82
+ unitType,
83
+ unitId: retryInfo?.unitId,
84
+ attempt: retryInfo?.attempt,
85
+ delayMs: decision.delayMs,
86
+ baseDelayMs: decision.baseDelayMs,
87
+ failureHash: decision.failureHash,
88
+ });
89
+ await new Promise((resolve) => setTimeout(resolve, decision.delayMs));
90
+ return null;
91
+ }
49
92
  export function shouldDegradeEmptyWorktreeToProjectRoot(worktreeClassification, projectRootClassification) {
50
93
  return (worktreeClassification.kind === "greenfield" &&
51
94
  projectRootClassification.kind !== "greenfield" &&
@@ -605,6 +648,13 @@ export async function runPreDispatch(ic, loopState) {
605
648
  eligibleSlices: eligible.map(e => e.id),
606
649
  });
607
650
  ctx.ui.notify(`Slice-parallel: dispatching ${eligible.length} eligible slices for ${mid}.`, "info");
651
+ // ADR-017 #5707: reconcile before spawning so each worker doesn't
652
+ // independently race on the same drift. Failure aborts the spawn.
653
+ const spawnGate = await reconcileBeforeSpawn(s.basePath);
654
+ if (!spawnGate.ok) {
655
+ ctx.ui.notify(`Slice-parallel: aborting spawn — ${spawnGate.reason}`, "error");
656
+ return { action: "break", reason: `slice-parallel-reconciliation-failed: ${spawnGate.reason}` };
657
+ }
608
658
  const result = await startSliceParallel(s.basePath, mid, eligible, {
609
659
  maxWorkers: prefs.slice_parallel.max_workers ?? 2,
610
660
  useExecutionGraph: uokFlags.executionGraph,
@@ -726,7 +776,13 @@ export async function runPreDispatch(ic, loopState) {
726
776
  }
727
777
  deps.sendDesktopNotification("GSD", "All milestones complete!", "success", "milestone", basename(s.originalBasePath || s.basePath));
728
778
  deps.logCmuxEvent(prefs, "All milestones complete.", "success");
729
- await deps.stopAuto(ctx, pi, "All milestones complete");
779
+ await deps.stopAuto(ctx, pi, "All milestones complete", {
780
+ completionWidget: {
781
+ milestoneId: s.currentMilestoneId,
782
+ milestoneTitle: midTitle,
783
+ allMilestonesComplete: true,
784
+ },
785
+ });
730
786
  }
731
787
  else if (incomplete.length === 0 && state.registry.length === 0) {
732
788
  // Empty registry — no milestones visible, likely a path resolution bug
@@ -794,7 +850,16 @@ export async function runPreDispatch(ic, loopState) {
794
850
  }
795
851
  deps.sendDesktopNotification("GSD", `Milestone ${mid} complete!`, "success", "milestone", basename(s.originalBasePath || s.basePath));
796
852
  deps.logCmuxEvent(prefs, `Milestone ${mid} complete.`, "success");
797
- await closeoutAndStop(ctx, pi, s, deps, `Milestone ${mid} complete`);
853
+ if (s.currentUnit) {
854
+ await deps.closeoutUnit(ctx, s.basePath, s.currentUnit.type, s.currentUnit.id, s.currentUnit.startedAt, deps.buildSnapshotOpts(s.currentUnit.type, s.currentUnit.id));
855
+ s.currentUnit = null;
856
+ }
857
+ await deps.stopAuto(ctx, pi, `Milestone ${mid} complete`, {
858
+ completionWidget: {
859
+ milestoneId: mid,
860
+ milestoneTitle: midTitle,
861
+ },
862
+ });
798
863
  debugLog("autoLoop", { phase: "exit", reason: "milestone-complete" });
799
864
  deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "terminal", data: { reason: "milestone-complete", milestoneId: mid } });
800
865
  return { action: "break", reason: "milestone-complete" };
@@ -914,118 +979,115 @@ export async function runDispatch(ic, preData, loopState) {
914
979
  return worktreeSafetyBlock;
915
980
  // ── Sliding-window stuck detection with graduated recovery ──
916
981
  const derivedKey = `${unitType}/${unitId}`;
917
- // Always record this dispatch in the sliding window so detectStuck() has
918
- // accurate history. Skipping the push when pendingVerificationRetry is set
919
- // caused infinite artifact-retry loops to be invisible to stuck detection
920
- // (#2007). Only the *response* to a stuck signal is suppressed during retries.
982
+ // Always record this dispatch in the sliding window and run detection so
983
+ // Rules 1/3/4 can catch retry loops with repeated failure content (#5719).
984
+ // Rules 2/2b suppress legitimate retry backoff through the dispatch ledger.
921
985
  loopState.recentUnits.push({ key: derivedKey });
922
986
  if (loopState.recentUnits.length > STUCK_WINDOW_SIZE)
923
987
  loopState.recentUnits.shift();
924
- if (!s.pendingVerificationRetry) {
925
- const stuckSignal = detectStuck(loopState.recentUnits);
926
- if (stuckSignal) {
927
- debugLog("autoLoop", {
928
- phase: "stuck-check",
929
- unitType,
930
- unitId,
931
- reason: stuckSignal.reason,
932
- recoveryAttempts: loopState.stuckRecoveryAttempts,
933
- });
934
- if (loopState.stuckRecoveryAttempts === 0) {
935
- // Level 1: try verifying the artifact, then cache invalidation + retry
936
- loopState.stuckRecoveryAttempts++;
937
- const artifactExists = verifyExpectedArtifact(unitType, unitId, s.basePath);
938
- if (artifactExists) {
939
- if (unitType === "complete-milestone") {
940
- const stuckDiag = diagnoseExpectedArtifact(unitType, unitId, s.basePath);
941
- const stuckParts = [
942
- `Detected ${unitType} ${unitId} output on disk, but the same unit is still being derived.`,
943
- "This usually means the milestone summary exists while the DB row still does not mark the milestone complete.",
944
- ];
945
- if (stuckDiag)
946
- stuckParts.push(`Expected: ${stuckDiag}`);
947
- ctx.ui.notify(stuckParts.join(" "), "warning");
948
- await deps.pauseAuto(ctx, pi);
949
- return { action: "break", reason: "complete-milestone-artifact-db-mismatch" };
950
- }
951
- debugLog("autoLoop", {
952
- phase: "stuck-recovery",
953
- level: 1,
954
- action: "artifact-found",
955
- });
956
- const recoveryDb = refreshRecoveryDbForArtifact(unitType, unitId);
957
- if (!recoveryDb.ok) {
958
- ctx.ui.notify(recoveryDb.fatal
959
- ? `${recoveryDb.message} Pausing auto-mode for manual recovery.`
960
- : `${recoveryDb.message} Keeping stuck state for retry.`, "warning");
961
- if (recoveryDb.fatal) {
962
- await deps.pauseAuto(ctx, pi);
963
- return { action: "break", reason: recoveryDb.reason };
964
- }
965
- return { action: "continue" };
966
- }
967
- ctx.ui.notify(`Stuck recovery: artifact for ${unitType} ${unitId} found on disk. Invalidating caches.`, "info");
968
- deps.invalidateAllCaches();
969
- loopState.recentUnits.length = 0;
970
- loopState.stuckRecoveryAttempts = 0;
971
- return { action: "continue" };
988
+ const stuckSignal = detectStuck(loopState.recentUnits);
989
+ if (stuckSignal) {
990
+ debugLog("autoLoop", {
991
+ phase: "stuck-check",
992
+ unitType,
993
+ unitId,
994
+ reason: stuckSignal.reason,
995
+ recoveryAttempts: loopState.stuckRecoveryAttempts,
996
+ });
997
+ if (loopState.stuckRecoveryAttempts === 0) {
998
+ // Level 1: try verifying the artifact, then cache invalidation + retry
999
+ loopState.stuckRecoveryAttempts++;
1000
+ const artifactExists = verifyExpectedArtifact(unitType, unitId, s.basePath);
1001
+ if (artifactExists) {
1002
+ if (unitType === "complete-milestone") {
1003
+ const stuckDiag = diagnoseExpectedArtifact(unitType, unitId, s.basePath);
1004
+ const stuckParts = [
1005
+ `Detected ${unitType} ${unitId} output on disk, but the same unit is still being derived.`,
1006
+ "This usually means the milestone summary exists while the DB row still does not mark the milestone complete.",
1007
+ ];
1008
+ if (stuckDiag)
1009
+ stuckParts.push(`Expected: ${stuckDiag}`);
1010
+ ctx.ui.notify(stuckParts.join(" "), "warning");
1011
+ await deps.pauseAuto(ctx, pi);
1012
+ return { action: "break", reason: "complete-milestone-artifact-db-mismatch" };
972
1013
  }
973
- ctx.ui.notify(`Stuck on ${unitType} ${unitId} (${stuckSignal.reason}). Invalidating caches and retrying.`, "warning");
974
- deps.invalidateAllCaches();
975
- }
976
- else {
977
- // Level 2: hard stop — genuinely stuck
978
- deps.invalidateAllCaches();
979
- const artifactExists = verifyExpectedArtifact(unitType, unitId, s.basePath);
980
- if (artifactExists && unitType !== "complete-milestone") {
981
- debugLog("autoLoop", {
982
- phase: "stuck-recovery",
983
- level: 2,
984
- action: "artifact-found",
985
- });
986
- const recoveryDb = refreshRecoveryDbForArtifact(unitType, unitId);
987
- if (recoveryDb.ok) {
988
- ctx.ui.notify(`Stuck recovery: artifact for ${unitType} ${unitId} found on disk after cache invalidation. Continuing.`, "info");
989
- loopState.recentUnits.length = 0;
990
- loopState.stuckRecoveryAttempts = 0;
991
- return { action: "continue" };
992
- }
1014
+ debugLog("autoLoop", {
1015
+ phase: "stuck-recovery",
1016
+ level: 1,
1017
+ action: "artifact-found",
1018
+ });
1019
+ const recoveryDb = refreshRecoveryDbForArtifact(unitType, unitId);
1020
+ if (!recoveryDb.ok) {
993
1021
  ctx.ui.notify(recoveryDb.fatal
994
1022
  ? `${recoveryDb.message} Pausing auto-mode for manual recovery.`
995
- : `${recoveryDb.message} Stopping for manual recovery.`, "warning");
1023
+ : `${recoveryDb.message} Keeping stuck state for retry.`, "warning");
996
1024
  if (recoveryDb.fatal) {
997
1025
  await deps.pauseAuto(ctx, pi);
998
1026
  return { action: "break", reason: recoveryDb.reason };
999
1027
  }
1028
+ return { action: "continue" };
1000
1029
  }
1001
- debugLog("autoLoop", {
1002
- phase: "stuck-detected",
1003
- unitType,
1004
- unitId,
1005
- reason: stuckSignal.reason,
1006
- });
1007
- const stuckDiag = diagnoseExpectedArtifact(unitType, unitId, s.basePath);
1008
- const stuckRemediation = buildLoopRemediationSteps(unitType, unitId, s.basePath);
1009
- const stuckParts = [`Stuck on ${unitType} ${unitId} — ${stuckSignal.reason}.`];
1010
- if (stuckDiag)
1011
- stuckParts.push(`Expected: ${stuckDiag}`);
1012
- if (stuckRemediation)
1013
- stuckParts.push(`To recover:\n${stuckRemediation}`);
1014
- ctx.ui.notify(stuckParts.join(" "), "error");
1015
- await deps.stopAuto(ctx, pi, `Stuck: ${stuckSignal.reason}`);
1016
- return { action: "break", reason: "stuck-detected" };
1030
+ ctx.ui.notify(`Stuck recovery: artifact for ${unitType} ${unitId} found on disk. Invalidating caches.`, "info");
1031
+ deps.invalidateAllCaches();
1032
+ loopState.recentUnits.length = 0;
1033
+ loopState.stuckRecoveryAttempts = 0;
1034
+ return { action: "continue" };
1017
1035
  }
1036
+ ctx.ui.notify(`Stuck on ${unitType} ${unitId} (${stuckSignal.reason}). Invalidating caches and retrying.`, "warning");
1037
+ deps.invalidateAllCaches();
1018
1038
  }
1019
1039
  else {
1020
- // Progress detectedreset recovery counter
1021
- if (loopState.stuckRecoveryAttempts > 0) {
1040
+ // Level 2: hard stop genuinely stuck
1041
+ deps.invalidateAllCaches();
1042
+ const artifactExists = verifyExpectedArtifact(unitType, unitId, s.basePath);
1043
+ if (artifactExists && unitType !== "complete-milestone") {
1022
1044
  debugLog("autoLoop", {
1023
- phase: "stuck-counter-reset",
1024
- from: loopState.recentUnits[loopState.recentUnits.length - 2]?.key ?? "",
1025
- to: derivedKey,
1045
+ phase: "stuck-recovery",
1046
+ level: 2,
1047
+ action: "artifact-found",
1026
1048
  });
1027
- loopState.stuckRecoveryAttempts = 0;
1049
+ const recoveryDb = refreshRecoveryDbForArtifact(unitType, unitId);
1050
+ if (recoveryDb.ok) {
1051
+ ctx.ui.notify(`Stuck recovery: artifact for ${unitType} ${unitId} found on disk after cache invalidation. Continuing.`, "info");
1052
+ loopState.recentUnits.length = 0;
1053
+ loopState.stuckRecoveryAttempts = 0;
1054
+ return { action: "continue" };
1055
+ }
1056
+ ctx.ui.notify(recoveryDb.fatal
1057
+ ? `${recoveryDb.message} Pausing auto-mode for manual recovery.`
1058
+ : `${recoveryDb.message} Stopping for manual recovery.`, "warning");
1059
+ if (recoveryDb.fatal) {
1060
+ await deps.pauseAuto(ctx, pi);
1061
+ return { action: "break", reason: recoveryDb.reason };
1062
+ }
1028
1063
  }
1064
+ debugLog("autoLoop", {
1065
+ phase: "stuck-detected",
1066
+ unitType,
1067
+ unitId,
1068
+ reason: stuckSignal.reason,
1069
+ });
1070
+ const stuckDiag = diagnoseExpectedArtifact(unitType, unitId, s.basePath);
1071
+ const stuckRemediation = buildLoopRemediationSteps(unitType, unitId, s.basePath);
1072
+ const stuckParts = [`Stuck on ${unitType} ${unitId} — ${stuckSignal.reason}.`];
1073
+ if (stuckDiag)
1074
+ stuckParts.push(`Expected: ${stuckDiag}`);
1075
+ if (stuckRemediation)
1076
+ stuckParts.push(`To recover:\n${stuckRemediation}`);
1077
+ ctx.ui.notify(stuckParts.join(" "), "error");
1078
+ await deps.stopAuto(ctx, pi, `Stuck: ${stuckSignal.reason}`);
1079
+ return { action: "break", reason: "stuck-detected" };
1080
+ }
1081
+ }
1082
+ else {
1083
+ // Progress detected — reset recovery counter
1084
+ if (loopState.stuckRecoveryAttempts > 0) {
1085
+ debugLog("autoLoop", {
1086
+ phase: "stuck-counter-reset",
1087
+ from: loopState.recentUnits[loopState.recentUnits.length - 2]?.key ?? "",
1088
+ to: derivedKey,
1089
+ });
1090
+ loopState.stuckRecoveryAttempts = 0;
1029
1091
  }
1030
1092
  }
1031
1093
  return {
@@ -1472,6 +1534,29 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
1472
1534
  unitId,
1473
1535
  status: unitResult.status,
1474
1536
  });
1537
+ if (unitResult.status === "completed" &&
1538
+ s.currentUnit &&
1539
+ (unitResult.event?.messages?.length ?? 0) === 0 &&
1540
+ isSuspiciousGhostCompletion(ctx, unitResult.requestDispatchedAt ?? s.currentUnit.startedAt)) {
1541
+ const message = `${unitType} ${unitId} completed without assistant output or tool calls; treating as a stale ghost completion.`;
1542
+ debugLog("autoLoop", {
1543
+ phase: "ghost-completion",
1544
+ iteration: ic.iteration,
1545
+ unitType,
1546
+ unitId,
1547
+ elapsedMs: Date.now() - (unitResult.requestDispatchedAt ?? s.currentUnit.startedAt),
1548
+ });
1549
+ logWarning("engine", message);
1550
+ ctx.ui.notify(`${message} Pausing auto-mode before closeout side effects.`, "warning");
1551
+ await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, {
1552
+ message,
1553
+ category: "unknown",
1554
+ isTransient: true,
1555
+ });
1556
+ s.currentUnit = null;
1557
+ await deps.pauseAuto(ctx, pi);
1558
+ return { action: "break", reason: "ghost-completion" };
1559
+ }
1475
1560
  // Now that runUnit has called newSession(), the session file path is correct.
1476
1561
  const sessionFile = deps.getSessionFile(ctx);
1477
1562
  deps.updateSessionLock(deps.lockBase(), unitType, unitId, sessionFile);
@@ -1571,6 +1656,15 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
1571
1656
  await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
1572
1657
  return { action: "break", reason: "session-timeout" };
1573
1658
  }
1659
+ if (unitResult.errorContext?.isTransient &&
1660
+ errorCategory === "aborted") {
1661
+ ctx.ui.notify(`Unit ${unitType} ${unitId} was aborted by the user. Pausing auto-mode (recoverable).`, "warning");
1662
+ debugLog("autoLoop", { phase: "unit-aborted-transient-pause", unitType, unitId, category: errorCategory });
1663
+ await deps.pauseAuto(ctx, pi);
1664
+ await deps.autoCommitUnit?.(s.basePath, unitType, unitId, ctx);
1665
+ await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
1666
+ return { action: "break", reason: "unit-aborted-pause" };
1667
+ }
1574
1668
  // All other cancelled states (structural errors, non-transient failures): hard stop
1575
1669
  if (s.currentUnit) {
1576
1670
  await deps.closeoutUnit(ctx, s.basePath, unitType, unitId, s.currentUnit.startedAt, deps.buildSnapshotOpts(unitType, unitId));
@@ -1753,6 +1847,10 @@ export async function runFinalize(ic, iterData, loopState, sidecarItem) {
1753
1847
  attempt: retryInfo?.attempt,
1754
1848
  },
1755
1849
  });
1850
+ const retryPolicyResult = await applyVerificationRetryPolicy(ic, preUnitSnapshot?.type, "artifact-verification-retry");
1851
+ if (retryPolicyResult) {
1852
+ return retryPolicyResult;
1853
+ }
1756
1854
  // Continue the loop — next iteration will inject the retry context into the prompt.
1757
1855
  debugLog("autoLoop", { phase: "artifact-verification-retry", iteration: ic.iteration });
1758
1856
  return { action: "continue" };
@@ -1781,6 +1879,10 @@ export async function runFinalize(ic, iterData, loopState, sidecarItem) {
1781
1879
  }
1782
1880
  else {
1783
1881
  // s.pendingVerificationRetry was set by runPostUnitVerification.
1882
+ const retryPolicyResult = await applyVerificationRetryPolicy(ic, iterData.unitType, "verification-retry");
1883
+ if (retryPolicyResult) {
1884
+ return retryPolicyResult;
1885
+ }
1784
1886
  // Continue the loop — next iteration will inject the retry context into the prompt.
1785
1887
  debugLog("autoLoop", { phase: "verification-retry", iteration: ic.iteration });
1786
1888
  return { action: "continue" };
@@ -6,6 +6,31 @@ import { debugLog } from "../debug-logger.js";
6
6
  import { logWarning } from "../workflow-logger.js";
7
7
  import { resolveAutoSupervisorConfig } from "../preferences.js";
8
8
  import { formatAutoUnitWorkingMessage } from "../working-output-messages.js";
9
+ import { readUnitRuntimeRecord } from "../unit-runtime.js";
10
+ const UNIT_FAILSAFE_BUFFER_MS = 30_000;
11
+ const UNIT_FAILSAFE_RECHECK_MS = 30_000;
12
+ export function shouldDeferUnitFailsafeTimeout(runtime, opts) {
13
+ if (!runtime)
14
+ return false;
15
+ if (opts.currentUnitStartedAt === undefined)
16
+ return false;
17
+ if (runtime.startedAt !== opts.currentUnitStartedAt)
18
+ return false;
19
+ if (runtime.lastProgressAt <= 0)
20
+ return false;
21
+ const progressAgeMs = opts.nowMs - runtime.lastProgressAt;
22
+ if (progressAgeMs < 0)
23
+ return false;
24
+ if (progressAgeMs > opts.freshProgressMs)
25
+ return false;
26
+ if (runtime.phase === "recovered")
27
+ return true;
28
+ if (runtime.lastProgressKind.includes("recovery"))
29
+ return true;
30
+ if (runtime.recoveryAttempts && runtime.recoveryAttempts > 0)
31
+ return true;
32
+ return progressAgeMs >= 0 && progressAgeMs <= opts.freshProgressMs;
33
+ }
9
34
  // Tracks the latest session-switch attempt so a late timeout settlement from an
10
35
  // older runUnit() call cannot clear the guard for a newer one.
11
36
  let sessionSwitchGeneration = 0;
@@ -145,16 +170,54 @@ export async function runUnit(ctx, pi, s, unitType, unitId, prompt) {
145
170
  // If supervision fails to resolve unitPromise within 30s, treat as cancelled.
146
171
  // Without this, a crashed agent that never emits agent_end hangs the loop (#3161).
147
172
  const supervisor = resolveAutoSupervisorConfig();
148
- const UNIT_HARD_TIMEOUT_MS = Math.max(30_000, ((supervisor.hard_timeout_minutes ?? 30) * 60 * 1000) + 30_000);
173
+ const UNIT_HARD_TIMEOUT_MS = Math.max(UNIT_FAILSAFE_BUFFER_MS, ((supervisor.hard_timeout_minutes ?? 30) * 60 * 1000) + UNIT_FAILSAFE_BUFFER_MS);
174
+ const freshProgressMs = Math.max(UNIT_FAILSAFE_BUFFER_MS, ((supervisor.idle_timeout_minutes ?? 10) * 60 * 1000) + UNIT_FAILSAFE_BUFFER_MS);
149
175
  let unitTimeoutHandle;
150
176
  let result;
151
177
  try {
152
178
  pi.sendMessage({ customType: "gsd-auto", content: prompt, display: s.verbose }, { triggerTurn: true });
153
179
  debugLog("runUnit", { phase: "awaiting-agent-end", unitType, unitId });
154
180
  const timeoutResult = new Promise((resolve) => {
155
- unitTimeoutHandle = setTimeout(() => {
181
+ const settleOrDefer = () => {
182
+ let runtime;
183
+ try {
184
+ runtime = readUnitRuntimeRecord(s.basePath, unitType, unitId);
185
+ }
186
+ catch (error) {
187
+ debugLog("runUnit", {
188
+ phase: "unit-failsafe-runtime-read-failed",
189
+ unitType,
190
+ unitId,
191
+ error: error instanceof Error ? error.message : String(error),
192
+ });
193
+ resolve({
194
+ status: "cancelled",
195
+ errorContext: {
196
+ message: "Unit hard timeout — supervision may have failed; runtime progress could not be read",
197
+ category: "timeout",
198
+ isTransient: true,
199
+ },
200
+ });
201
+ return;
202
+ }
203
+ if (shouldDeferUnitFailsafeTimeout(runtime, {
204
+ nowMs: Date.now(),
205
+ currentUnitStartedAt: s.currentUnit?.startedAt,
206
+ freshProgressMs,
207
+ })) {
208
+ debugLog("runUnit", {
209
+ phase: "unit-failsafe-deferred",
210
+ unitType,
211
+ unitId,
212
+ runtimePhase: runtime?.phase,
213
+ lastProgressKind: runtime?.lastProgressKind,
214
+ });
215
+ unitTimeoutHandle = setTimeout(settleOrDefer, UNIT_FAILSAFE_RECHECK_MS);
216
+ return;
217
+ }
156
218
  resolve({ status: "cancelled", errorContext: { message: "Unit hard timeout — supervision may have failed", category: "timeout", isTransient: true } });
157
- }, UNIT_HARD_TIMEOUT_MS);
219
+ };
220
+ unitTimeoutHandle = setTimeout(settleOrDefer, UNIT_HARD_TIMEOUT_MS);
158
221
  });
159
222
  result = await runWithTurnGeneration(capturedTurnGen, () => Promise.race([unitPromise, timeoutResult]));
160
223
  }
@@ -25,6 +25,7 @@ export class AutoSession {
25
25
  // ── Lifecycle ────────────────────────────────────────────────────────────
26
26
  active = false;
27
27
  paused = false;
28
+ completionStopInProgress = false;
28
29
  stepMode = false;
29
30
  verbose = false;
30
31
  activeEngineId = null;
@@ -88,6 +89,7 @@ export class AutoSession {
88
89
  pendingCrashRecovery = null;
89
90
  pendingVerificationRetry = null;
90
91
  verificationRetryCount = new Map();
92
+ verificationRetryFailureHashes = new Map();
91
93
  pausedSessionFile = null;
92
94
  pausedUnitType = null;
93
95
  pausedUnitId = null;
@@ -207,6 +209,7 @@ export class AutoSession {
207
209
  // Lifecycle
208
210
  this.active = false;
209
211
  this.paused = false;
212
+ this.completionStopInProgress = false;
210
213
  this.stepMode = false;
211
214
  this.verbose = false;
212
215
  this.activeEngineId = null;
@@ -250,6 +253,7 @@ export class AutoSession {
250
253
  this.pendingCrashRecovery = null;
251
254
  this.pendingVerificationRetry = null;
252
255
  this.verificationRetryCount.clear();
256
+ this.verificationRetryFailureHashes.clear();
253
257
  this.pausedSessionFile = null;
254
258
  this.pausedUnitType = null;
255
259
  this.pausedUnitId = null;
@@ -282,6 +286,11 @@ export class AutoSession {
282
286
  this.orchestration = null;
283
287
  // Loop promise state lives in auto-loop.ts module scope
284
288
  }
289
+ resetAfterStop(options = {}) {
290
+ const completionStopInProgress = options.preserveCompletionSurface ? this.completionStopInProgress : false;
291
+ this.reset();
292
+ this.completionStopInProgress = completionStopInProgress;
293
+ }
285
294
  toJSON() {
286
295
  const orchestrationStatus = this.orchestration?.getStatus();
287
296
  return {
@@ -0,0 +1,43 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: Central retry policy for auto-mode verification redispatches.
3
+ import { createHash } from "node:crypto";
4
+ export const VERIFICATION_RETRY_BASE_DELAY_MS = 2_000;
5
+ export const VERIFICATION_RETRY_MAX_DELAY_MS = 30_000;
6
+ export const VERIFICATION_RETRY_JITTER_RATIO = 0.1;
7
+ export function verificationRetryKey(unitType, unitId) {
8
+ return `${unitType}:${unitId}`;
9
+ }
10
+ export function hashVerificationFailureContext(failureContext) {
11
+ const normalized = failureContext.replace(/\r\n/g, "\n").trim();
12
+ return createHash("sha256").update(normalized).digest("hex");
13
+ }
14
+ export function verificationRetryDelayMs(attempt, random = Math.random) {
15
+ const safeAttempt = Math.max(1, Math.floor(attempt));
16
+ const baseDelayMs = Math.min(VERIFICATION_RETRY_MAX_DELAY_MS, VERIFICATION_RETRY_BASE_DELAY_MS * 2 ** (safeAttempt - 1));
17
+ const jitterSpanMs = Math.round(baseDelayMs * VERIFICATION_RETRY_JITTER_RATIO);
18
+ const jitterMs = Math.round((random() - 0.5) * 2 * jitterSpanMs);
19
+ const delayMs = Math.min(VERIFICATION_RETRY_MAX_DELAY_MS, Math.max(0, baseDelayMs + jitterMs));
20
+ return { delayMs, baseDelayMs };
21
+ }
22
+ export function decideVerificationRetry(input) {
23
+ const { retryInfo, unitType } = input;
24
+ if (!retryInfo || !unitType) {
25
+ return { action: "pause", reason: "missing-retry-context" };
26
+ }
27
+ const key = verificationRetryKey(unitType, retryInfo.unitId);
28
+ const failureHash = hashVerificationFailureContext(retryInfo.failureContext);
29
+ if (input.previousFailureHash === failureHash) {
30
+ return {
31
+ action: "pause",
32
+ reason: "duplicate-failure-context",
33
+ key,
34
+ failureHash,
35
+ };
36
+ }
37
+ return {
38
+ action: "delay",
39
+ key,
40
+ failureHash,
41
+ ...verificationRetryDelayMs(retryInfo.attempt, input.random),
42
+ };
43
+ }