gsd-pi 2.81.0 → 2.82.0-dev.c22380fc3

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 (521) 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/orchestrator.js +113 -6
  7. package/dist/resources/extensions/gsd/auto/phases.js +199 -97
  8. package/dist/resources/extensions/gsd/auto/run-unit.js +66 -3
  9. package/dist/resources/extensions/gsd/auto/session.js +9 -0
  10. package/dist/resources/extensions/gsd/auto/verification-retry-policy.js +43 -0
  11. package/dist/resources/extensions/gsd/auto-dashboard.js +182 -178
  12. package/dist/resources/extensions/gsd/auto-dispatch.js +14 -11
  13. package/dist/resources/extensions/gsd/auto-post-unit.js +7 -1
  14. package/dist/resources/extensions/gsd/auto-prompts.js +11 -3
  15. package/dist/resources/extensions/gsd/auto-recovery.js +6 -181
  16. package/dist/resources/extensions/gsd/auto-runtime-state.js +5 -0
  17. package/dist/resources/extensions/gsd/auto-start.js +20 -23
  18. package/dist/resources/extensions/gsd/auto-unit-closeout.js +33 -5
  19. package/dist/resources/extensions/gsd/auto-verification.js +12 -6
  20. package/dist/resources/extensions/gsd/auto-worktree.js +8 -0
  21. package/dist/resources/extensions/gsd/auto.js +371 -106
  22. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +13 -6
  23. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +13 -2
  24. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +4 -8
  25. package/dist/resources/extensions/gsd/bootstrap/system-context.js +55 -12
  26. package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -1
  27. package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +4 -10
  28. package/dist/resources/extensions/gsd/commands/handlers/parallel.js +9 -0
  29. package/dist/resources/extensions/gsd/commands-handlers.js +15 -2
  30. package/dist/resources/extensions/gsd/context-store.js +112 -0
  31. package/dist/resources/extensions/gsd/db-writer.js +150 -84
  32. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  33. package/dist/resources/extensions/gsd/doctor-git-checks.js +41 -6
  34. package/dist/resources/extensions/gsd/git-service.js +2 -1
  35. package/dist/resources/extensions/gsd/gsd-db.js +7 -23
  36. package/dist/resources/extensions/gsd/health-widget-core.js +1 -1
  37. package/dist/resources/extensions/gsd/health-widget.js +4 -10
  38. package/dist/resources/extensions/gsd/knowledge-backfill.js +144 -0
  39. package/dist/resources/extensions/gsd/knowledge-capture.js +136 -0
  40. package/dist/resources/extensions/gsd/knowledge-parser.js +154 -0
  41. package/dist/resources/extensions/gsd/knowledge-projection.js +210 -0
  42. package/dist/resources/extensions/gsd/markdown-renderer.js +6 -96
  43. package/dist/resources/extensions/gsd/md-importer.js +1 -1
  44. package/dist/resources/extensions/gsd/memory-backfill.js +73 -17
  45. package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +222 -0
  46. package/dist/resources/extensions/gsd/migrate/command.js +5 -0
  47. package/dist/resources/extensions/gsd/migrate/preview.js +9 -0
  48. package/dist/resources/extensions/gsd/migrate/transformer.js +51 -4
  49. package/dist/resources/extensions/gsd/migrate/writer.js +11 -1
  50. package/dist/resources/extensions/gsd/native-git-bridge.js +14 -14
  51. package/dist/resources/extensions/gsd/notification-overlay.js +35 -40
  52. package/dist/resources/extensions/gsd/parallel-merge.js +53 -30
  53. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +25 -33
  54. package/dist/resources/extensions/gsd/prompts/complete-slice.md +14 -12
  55. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
  56. package/dist/resources/extensions/gsd/prompts/discuss.md +20 -2
  57. package/dist/resources/extensions/gsd/prompts/system.md +2 -2
  58. package/dist/resources/extensions/gsd/provider-switch-observer.js +146 -0
  59. package/dist/resources/extensions/gsd/recovery-classification.js +15 -1
  60. package/dist/resources/extensions/gsd/session-lock.js +40 -0
  61. package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +131 -0
  62. package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +247 -0
  63. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +50 -0
  64. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +87 -0
  65. package/dist/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.js +50 -0
  66. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +124 -0
  67. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-worker.js +32 -0
  68. package/dist/resources/extensions/gsd/state-reconciliation/errors.js +41 -0
  69. package/dist/resources/extensions/gsd/state-reconciliation/index.js +99 -0
  70. package/dist/resources/extensions/gsd/state-reconciliation/registry.js +24 -0
  71. package/dist/resources/extensions/gsd/state-reconciliation/spawn-gate.js +43 -0
  72. package/dist/resources/extensions/gsd/state-reconciliation/types.js +3 -0
  73. package/dist/resources/extensions/gsd/state-reconciliation.js +5 -26
  74. package/dist/resources/extensions/gsd/templates/knowledge.md +2 -2
  75. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +119 -0
  76. package/dist/resources/extensions/gsd/tui/render-kit.js +74 -0
  77. package/dist/resources/extensions/gsd/watch/header-renderer.js +92 -69
  78. package/dist/resources/extensions/gsd/watch/splash-palette.js +10 -0
  79. package/dist/resources/extensions/gsd/workflow-mcp.js +2 -2
  80. package/dist/resources/extensions/gsd/worktree-lifecycle.js +743 -318
  81. package/dist/resources/extensions/gsd/worktree-telemetry.js +3 -1
  82. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  83. package/dist/web/standalone/.next/BUILD_ID +1 -1
  84. package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
  85. package/dist/web/standalone/.next/build-manifest.json +3 -3
  86. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  87. package/dist/web/standalone/.next/required-server-files.json +3 -3
  88. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  89. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  90. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  91. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  99. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  103. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  105. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  115. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  127. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  147. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  157. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  163. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  179. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +2 -2
  183. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  185. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  186. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  187. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  188. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  189. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  190. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  191. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  192. package/dist/web/standalone/.next/server/app/index.html +1 -1
  193. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  194. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  195. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  196. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  197. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  198. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  199. package/dist/web/standalone/.next/server/app/page.js +2 -2
  200. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  201. package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
  202. package/dist/web/standalone/.next/server/chunks/63.js +3 -3
  203. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  204. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  205. package/dist/web/standalone/.next/server/middleware.js +2 -2
  206. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  207. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  208. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  209. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  210. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  211. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  212. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  213. package/dist/web/standalone/.next/static/chunks/app/page-752f1e2ebdaa3e45.js +1 -0
  214. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  215. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  216. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  217. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  218. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  219. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  220. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  221. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  222. package/dist/web/standalone/server.js +1 -1
  223. package/dist/welcome-screen.d.ts +0 -7
  224. package/dist/welcome-screen.js +60 -69
  225. package/package.json +3 -2
  226. package/packages/contracts/dist/rpc.test.js +7 -0
  227. package/packages/contracts/dist/rpc.test.js.map +1 -1
  228. package/packages/contracts/dist/workflow.d.ts +21 -0
  229. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  230. package/packages/contracts/dist/workflow.js +24 -0
  231. package/packages/contracts/dist/workflow.js.map +1 -1
  232. package/packages/contracts/src/rpc.test.ts +8 -0
  233. package/packages/contracts/src/workflow.ts +24 -0
  234. package/packages/daemon/package.json +2 -2
  235. package/packages/mcp-server/README.md +14 -3
  236. package/packages/mcp-server/dist/workflow-tools.d.ts +0 -3
  237. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  238. package/packages/mcp-server/dist/workflow-tools.js +80 -0
  239. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  240. package/packages/mcp-server/package.json +2 -2
  241. package/packages/mcp-server/src/workflow-tools-parity.test.ts +244 -0
  242. package/packages/mcp-server/src/workflow-tools.test.ts +22 -0
  243. package/packages/mcp-server/src/workflow-tools.ts +168 -0
  244. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  245. package/packages/native/package.json +1 -1
  246. package/packages/pi-agent-core/package.json +1 -1
  247. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  248. package/packages/pi-ai/dist/index.d.ts +2 -2
  249. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  250. package/packages/pi-ai/dist/index.js +1 -1
  251. package/packages/pi-ai/dist/index.js.map +1 -1
  252. package/packages/pi-ai/dist/providers/transform-messages.d.ts +11 -0
  253. package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
  254. package/packages/pi-ai/dist/providers/transform-messages.js +20 -0
  255. package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
  256. package/packages/pi-ai/package.json +1 -1
  257. package/packages/pi-ai/src/index.ts +7 -2
  258. package/packages/pi-ai/src/providers/transform-messages.ts +24 -0
  259. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  260. package/packages/pi-coding-agent/dist/core/system-prompt.js +4 -4
  261. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  262. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts +2 -0
  263. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts.map +1 -0
  264. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js +47 -0
  265. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js.map +1 -0
  266. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +76 -9
  267. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  268. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts +2 -0
  269. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts.map +1 -0
  270. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js +40 -0
  271. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js.map +1 -0
  272. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +0 -1
  273. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -1
  274. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +30 -29
  275. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -1
  276. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +10 -3
  277. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -1
  278. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  279. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +13 -13
  280. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  281. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +1 -3
  282. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  283. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +58 -3
  284. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
  285. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts +2 -2
  286. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts.map +1 -1
  287. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js +12 -6
  288. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js.map +1 -1
  289. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  290. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -41
  291. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  292. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +0 -1
  293. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  294. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +86 -82
  295. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  296. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts +35 -0
  297. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts.map +1 -0
  298. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js +152 -0
  299. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js.map +1 -0
  300. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts +16 -0
  301. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts.map +1 -0
  302. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js +73 -0
  303. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js.map +1 -0
  304. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +1 -1
  305. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  306. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +12 -8
  307. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  308. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
  309. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
  310. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
  311. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
  312. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  313. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +105 -1
  314. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  315. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  316. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +27 -26
  317. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  318. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +9 -6
  319. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -1
  320. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts +2 -0
  321. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts.map +1 -0
  322. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js +17 -0
  323. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js.map +1 -0
  324. package/packages/pi-coding-agent/package.json +1 -1
  325. package/packages/pi-coding-agent/src/core/system-prompt.ts +4 -4
  326. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/assistant-message-design.test.ts +56 -0
  327. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +113 -9
  328. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/user-message-design.test.ts +48 -0
  329. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +10 -3
  330. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +43 -42
  331. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +14 -14
  332. package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +64 -3
  333. package/packages/pi-coding-agent/src/modes/interactive/components/diff.ts +13 -7
  334. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +15 -42
  335. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +84 -104
  336. package/packages/pi-coding-agent/src/modes/interactive/components/transcript-design.ts +196 -0
  337. package/packages/pi-coding-agent/src/modes/interactive/components/tui-style-kit.ts +94 -0
  338. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +14 -9
  339. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-highlight.test.ts +23 -0
  340. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +106 -1
  341. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +27 -26
  342. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +9 -6
  343. package/packages/pi-coding-agent/src/tests/system-prompt-file-safety.test.ts +22 -0
  344. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  345. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +14 -1
  346. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  347. package/packages/pi-tui/dist/overlay-layout.d.ts.map +1 -1
  348. package/packages/pi-tui/dist/overlay-layout.js +9 -6
  349. package/packages/pi-tui/dist/overlay-layout.js.map +1 -1
  350. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  351. package/packages/pi-tui/dist/tui.js +5 -0
  352. package/packages/pi-tui/dist/tui.js.map +1 -1
  353. package/packages/pi-tui/package.json +1 -1
  354. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +20 -1
  355. package/packages/pi-tui/src/overlay-layout.ts +10 -7
  356. package/packages/pi-tui/src/tui.ts +6 -0
  357. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  358. package/packages/rpc-client/package.json +1 -1
  359. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  360. package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
  361. package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
  362. package/pkg/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
  363. package/pkg/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
  364. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  365. package/pkg/dist/modes/interactive/theme/theme.js +105 -1
  366. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  367. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  368. package/pkg/dist/modes/interactive/theme/themes.js +27 -26
  369. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  370. package/pkg/package.json +1 -1
  371. package/src/resources/extensions/browser-tools/tools/screenshot.ts +1 -0
  372. package/src/resources/extensions/browser-tools/tools/zoom.ts +1 -0
  373. package/src/resources/extensions/gsd/auto/contracts.ts +46 -11
  374. package/src/resources/extensions/gsd/auto/loop-deps.ts +9 -5
  375. package/src/resources/extensions/gsd/auto/loop.ts +113 -9
  376. package/src/resources/extensions/gsd/auto/orchestrator.ts +118 -6
  377. package/src/resources/extensions/gsd/auto/phases.ts +158 -19
  378. package/src/resources/extensions/gsd/auto/run-unit.ts +69 -4
  379. package/src/resources/extensions/gsd/auto/session.ts +10 -0
  380. package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +82 -0
  381. package/src/resources/extensions/gsd/auto-dashboard.ts +230 -183
  382. package/src/resources/extensions/gsd/auto-dispatch.ts +15 -1
  383. package/src/resources/extensions/gsd/auto-post-unit.ts +7 -1
  384. package/src/resources/extensions/gsd/auto-prompts.ts +11 -3
  385. package/src/resources/extensions/gsd/auto-recovery.ts +7 -209
  386. package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
  387. package/src/resources/extensions/gsd/auto-start.ts +22 -22
  388. package/src/resources/extensions/gsd/auto-unit-closeout.ts +51 -0
  389. package/src/resources/extensions/gsd/auto-verification.ts +12 -6
  390. package/src/resources/extensions/gsd/auto-worktree.ts +8 -0
  391. package/src/resources/extensions/gsd/auto.ts +411 -106
  392. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +21 -6
  393. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +12 -2
  394. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +5 -8
  395. package/src/resources/extensions/gsd/bootstrap/system-context.ts +58 -15
  396. package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -1
  397. package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +4 -10
  398. package/src/resources/extensions/gsd/commands/handlers/parallel.ts +12 -0
  399. package/src/resources/extensions/gsd/commands-handlers.ts +19 -2
  400. package/src/resources/extensions/gsd/context-store.ts +120 -1
  401. package/src/resources/extensions/gsd/db-writer.ts +167 -84
  402. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  403. package/src/resources/extensions/gsd/doctor-git-checks.ts +44 -6
  404. package/src/resources/extensions/gsd/doctor-types.ts +2 -0
  405. package/src/resources/extensions/gsd/git-service.ts +2 -0
  406. package/src/resources/extensions/gsd/gsd-db.ts +7 -23
  407. package/src/resources/extensions/gsd/health-widget-core.ts +1 -1
  408. package/src/resources/extensions/gsd/health-widget.ts +6 -10
  409. package/src/resources/extensions/gsd/journal.ts +2 -0
  410. package/src/resources/extensions/gsd/knowledge-backfill.ts +164 -0
  411. package/src/resources/extensions/gsd/knowledge-capture.ts +160 -0
  412. package/src/resources/extensions/gsd/knowledge-parser.ts +174 -0
  413. package/src/resources/extensions/gsd/knowledge-projection.ts +241 -0
  414. package/src/resources/extensions/gsd/markdown-renderer.ts +10 -96
  415. package/src/resources/extensions/gsd/md-importer.ts +1 -1
  416. package/src/resources/extensions/gsd/memory-backfill.ts +89 -17
  417. package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +277 -0
  418. package/src/resources/extensions/gsd/migrate/command.ts +5 -0
  419. package/src/resources/extensions/gsd/migrate/preview.ts +10 -0
  420. package/src/resources/extensions/gsd/migrate/transformer.ts +58 -4
  421. package/src/resources/extensions/gsd/migrate/writer.ts +14 -1
  422. package/src/resources/extensions/gsd/native-git-bridge.ts +14 -13
  423. package/src/resources/extensions/gsd/notification-overlay.ts +50 -46
  424. package/src/resources/extensions/gsd/parallel-merge.ts +61 -34
  425. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +33 -35
  426. package/src/resources/extensions/gsd/prompts/complete-slice.md +14 -12
  427. package/src/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
  428. package/src/resources/extensions/gsd/prompts/discuss.md +20 -2
  429. package/src/resources/extensions/gsd/prompts/system.md +2 -2
  430. package/src/resources/extensions/gsd/provider-switch-observer.ts +185 -0
  431. package/src/resources/extensions/gsd/recovery-classification.ts +18 -1
  432. package/src/resources/extensions/gsd/session-lock.ts +41 -0
  433. package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +172 -0
  434. package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +337 -0
  435. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +69 -0
  436. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +109 -0
  437. package/src/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.ts +68 -0
  438. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +185 -0
  439. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-worker.ts +46 -0
  440. package/src/resources/extensions/gsd/state-reconciliation/errors.ts +67 -0
  441. package/src/resources/extensions/gsd/state-reconciliation/index.ts +142 -0
  442. package/src/resources/extensions/gsd/state-reconciliation/registry.ts +27 -0
  443. package/src/resources/extensions/gsd/state-reconciliation/spawn-gate.ts +60 -0
  444. package/src/resources/extensions/gsd/state-reconciliation/types.ts +83 -0
  445. package/src/resources/extensions/gsd/state-reconciliation.ts +21 -53
  446. package/src/resources/extensions/gsd/templates/knowledge.md +2 -2
  447. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +1 -1
  448. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +99 -0
  449. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +729 -176
  450. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +408 -4
  451. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +292 -4
  452. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +20 -5
  453. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +18 -0
  454. package/src/resources/extensions/gsd/tests/auto-unit-closeout.test.ts +68 -0
  455. package/src/resources/extensions/gsd/tests/browser-tools-compatibility-declarations.test.ts +62 -0
  456. package/src/resources/extensions/gsd/tests/context-store-decisions-from-memories.test.ts +312 -0
  457. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +28 -1
  458. package/src/resources/extensions/gsd/tests/db-writer.test.ts +13 -8
  459. package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +453 -0
  460. package/src/resources/extensions/gsd/tests/decisions-stop-table-writes.test.ts +348 -0
  461. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +20 -2
  462. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +44 -0
  463. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +8 -4
  464. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +11 -7
  465. package/src/resources/extensions/gsd/tests/header-renderer.test.ts +40 -0
  466. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +10 -0
  467. package/src/resources/extensions/gsd/tests/health-widget.test.ts +14 -4
  468. package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +44 -0
  469. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +26 -0
  470. package/src/resources/extensions/gsd/tests/integration/integration-lifecycle.test.ts +13 -5
  471. package/src/resources/extensions/gsd/tests/integration/integration-proof.test.ts +1 -1
  472. package/src/resources/extensions/gsd/tests/integration/migrate-command.test.ts +48 -3
  473. package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +116 -24
  474. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -1
  475. package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +323 -0
  476. package/src/resources/extensions/gsd/tests/knowledge-capture.test.ts +242 -0
  477. package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -2
  478. package/src/resources/extensions/gsd/tests/load-knowledge-block-rules-only.test.ts +209 -0
  479. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +1 -1
  480. package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +316 -0
  481. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +46 -11
  482. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +5 -1
  483. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +6 -1
  484. package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +78 -41
  485. package/src/resources/extensions/gsd/tests/notifications-handler.test.ts +44 -0
  486. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +12 -217
  487. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +38 -6
  488. package/src/resources/extensions/gsd/tests/plan-milestone-sketch-render.test.ts +157 -0
  489. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +2 -2
  490. package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +1 -1
  491. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +32 -1
  492. package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +252 -0
  493. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +7 -3
  494. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +6 -3
  495. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +16 -4
  496. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +24 -0
  497. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +71 -58
  498. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +952 -0
  499. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +4 -0
  500. package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +121 -1
  501. package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +66 -0
  502. package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +83 -0
  503. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +6 -0
  504. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +158 -58
  505. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +597 -118
  506. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +59 -2
  507. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +18 -0
  508. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +135 -0
  509. package/src/resources/extensions/gsd/tui/render-kit.ts +109 -0
  510. package/src/resources/extensions/gsd/watch/header-renderer.ts +121 -79
  511. package/src/resources/extensions/gsd/watch/splash-palette.ts +11 -0
  512. package/src/resources/extensions/gsd/workflow-logger.ts +4 -0
  513. package/src/resources/extensions/gsd/workflow-mcp.ts +2 -2
  514. package/src/resources/extensions/gsd/worktree-lifecycle.ts +1171 -526
  515. package/src/resources/extensions/gsd/worktree-telemetry.ts +7 -2
  516. package/dist/web/standalone/.next/static/chunks/app/page-200592a7f3baf579.js +0 -1
  517. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  518. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  519. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +0 -1544
  520. /package/dist/web/standalone/.next/static/{drLMkgfHQ8lzS229_HWYR → Wop3A7KRGyR06H3rla_1-}/_buildManifest.js +0 -0
  521. /package/dist/web/standalone/.next/static/{drLMkgfHQ8lzS229_HWYR → Wop3A7KRGyR06H3rla_1-}/_ssgManifest.js +0 -0
@@ -7,6 +7,16 @@ function now(): number {
7
7
  return Date.now();
8
8
  }
9
9
 
10
+ /**
11
+ * Size of the dispatch-decision ring buffer used by the Auto Orchestration
12
+ * module's stuck-loop detector. When the same `${unitType}:${unitId}` key
13
+ * fills the window, advance() blocks with `action: "stop"`.
14
+ *
15
+ * Mirrors the legacy `STUCK_WINDOW_SIZE` in auto/phases.ts so behaviour is
16
+ * preserved across the eventual cutover (issue #5791).
17
+ */
18
+ export const STUCK_WINDOW_SIZE = 6;
19
+
10
20
  export class AutoOrchestrator implements AutoOrchestrationModule {
11
21
  private status: AutoStatus = {
12
22
  phase: "idle",
@@ -14,6 +24,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
14
24
  };
15
25
  private readonly deps: AutoOrchestratorDeps;
16
26
  private lastAdvanceKey: string | null = null;
27
+ private dispatchKeyWindow: string[] = [];
17
28
 
18
29
  public constructor(deps: AutoOrchestratorDeps) {
19
30
  this.deps = deps;
@@ -21,6 +32,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
21
32
 
22
33
  public async start(_sessionContext: AutoSessionContext): Promise<AutoAdvanceResult> {
23
34
  this.lastAdvanceKey = null;
35
+ this.dispatchKeyWindow = [];
24
36
  this.status.phase = "running";
25
37
  this.bumpTransition();
26
38
  await this.deps.runtime.journalTransition({ name: "start" });
@@ -31,19 +43,72 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
31
43
  public async advance(): Promise<AutoAdvanceResult> {
32
44
  try {
33
45
  await this.deps.runtime.ensureLockOwnership();
46
+
47
+ const staleMsg = this.deps.health.checkResourcesStale();
48
+ if (staleMsg) {
49
+ await this.deps.uokGate.emit({
50
+ gateId: "resource-version-guard",
51
+ gateType: "policy",
52
+ outcome: "fail",
53
+ failureClass: "policy",
54
+ rationale: "resource version guard blocked dispatch",
55
+ findings: staleMsg,
56
+ });
57
+ const blocked: AutoAdvanceResult = { kind: "blocked", reason: staleMsg, action: "stop" };
58
+ await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
59
+ await this.deps.health.postAdvanceRecord(blocked);
60
+ return blocked;
61
+ }
62
+ await this.deps.uokGate.emit({
63
+ gateId: "resource-version-guard",
64
+ gateType: "policy",
65
+ outcome: "pass",
66
+ failureClass: "none",
67
+ rationale: "resource version guard passed",
68
+ });
69
+
34
70
  const gate = await this.deps.health.preAdvanceGate();
35
- if (!gate.allow) {
36
- const blocked: AutoAdvanceResult = { kind: "blocked", reason: gate.reason ?? "health gate blocked" };
71
+ if (gate.kind === "fail") {
72
+ await this.deps.uokGate.emit({
73
+ gateId: "pre-dispatch-health-gate",
74
+ gateType: "execution",
75
+ outcome: "manual-attention",
76
+ failureClass: "manual-attention",
77
+ rationale: "pre-dispatch health gate blocked dispatch",
78
+ findings: gate.reason,
79
+ });
80
+ const blocked: AutoAdvanceResult = { kind: "blocked", reason: gate.reason, action: "pause" };
37
81
  await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
38
82
  await this.deps.health.postAdvanceRecord(blocked);
39
83
  return blocked;
40
84
  }
85
+ if (gate.kind === "threw") {
86
+ await this.deps.uokGate.emit({
87
+ gateId: "pre-dispatch-health-gate",
88
+ gateType: "execution",
89
+ outcome: "manual-attention",
90
+ failureClass: "manual-attention",
91
+ rationale: "pre-dispatch health gate threw unexpectedly",
92
+ findings: String(gate.error),
93
+ });
94
+ // intentional fall-through: matches runPreDispatch behaviour
95
+ } else {
96
+ await this.deps.uokGate.emit({
97
+ gateId: "pre-dispatch-health-gate",
98
+ gateType: "execution",
99
+ outcome: "pass",
100
+ failureClass: "none",
101
+ rationale: "pre-dispatch health gate passed",
102
+ findings: gate.fixesApplied?.join(", ") ?? "",
103
+ });
104
+ }
41
105
 
42
106
  const reconciliation = await this.deps.stateReconciliation.reconcileBeforeDispatch();
43
107
  if (!reconciliation.ok || !reconciliation.stateSnapshot) {
44
108
  const blocked: AutoAdvanceResult = {
45
109
  kind: "blocked",
46
- reason: reconciliation.reason,
110
+ reason: reconciliation.reason ?? "state reconciliation produced no snapshot",
111
+ action: "pause",
47
112
  stateSnapshot: reconciliation.stateSnapshot,
48
113
  };
49
114
  await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
@@ -57,6 +122,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
57
122
  this.status.phase = "stopped";
58
123
  this.status.activeUnit = undefined;
59
124
  this.lastAdvanceKey = null;
125
+ this.dispatchKeyWindow = [];
60
126
  this.bumpTransition();
61
127
  await this.deps.runtime.journalTransition({ name: "advance-stopped", reason: stopped.reason });
62
128
  await this.deps.health.postAdvanceRecord(stopped);
@@ -64,8 +130,45 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
64
130
  }
65
131
 
66
132
  const nextKey = `${decision.unitType}:${decision.unitId}`;
67
- if (this.lastAdvanceKey === nextKey) {
68
- const blocked: AutoAdvanceResult = { kind: "blocked", reason: "idempotent advance: unit already active" };
133
+
134
+ // Record every dispatch decision in the ring buffer before pre-flight
135
+ // checks so the stuck-loop detector observes the full decision history
136
+ // (including decisions that idempotency would otherwise short-circuit).
137
+ // The ring is capped at STUCK_WINDOW_SIZE and evicts oldest-first.
138
+ this.dispatchKeyWindow.push(nextKey);
139
+ if (this.dispatchKeyWindow.length > STUCK_WINDOW_SIZE) {
140
+ this.dispatchKeyWindow.shift();
141
+ }
142
+
143
+ // Idempotency: same key as immediately previous successful advance.
144
+ // This is the soft, fast-path block kept from #5786. It only fires when
145
+ // the ring is NOT yet saturated for this key — once the ring is full of
146
+ // `nextKey`, the stuck-loop verdict takes precedence (see below). Both
147
+ // checks coexist: idempotency for the common immediate-repeat case,
148
+ // stuck-loop for the saturated-window case.
149
+ const matchingCount = this.dispatchKeyWindow.filter((k) => k === nextKey).length;
150
+ if (this.lastAdvanceKey === nextKey && matchingCount < STUCK_WINDOW_SIZE) {
151
+ const blocked: AutoAdvanceResult = { kind: "blocked", reason: "idempotent advance: unit already active", action: "stop" };
152
+ await this.deps.runtime.journalTransition({
153
+ name: "advance-blocked",
154
+ reason: blocked.reason,
155
+ unitType: decision.unitType,
156
+ unitId: decision.unitId,
157
+ });
158
+ await this.deps.health.postAdvanceRecord(blocked);
159
+ return blocked;
160
+ }
161
+
162
+ // Stuck-loop detection: when the ring is saturated with copies of
163
+ // `nextKey` (count >= STUCK_WINDOW_SIZE), the orchestrator has been
164
+ // picking the same unit across the whole window and must hard-stop with
165
+ // a diagnosable reason.
166
+ if (matchingCount >= STUCK_WINDOW_SIZE) {
167
+ const blocked: AutoAdvanceResult = {
168
+ kind: "blocked",
169
+ reason: `stuck-loop: ${nextKey} picked ${matchingCount} times`,
170
+ action: "stop",
171
+ };
69
172
  await this.deps.runtime.journalTransition({
70
173
  name: "advance-blocked",
71
174
  reason: blocked.reason,
@@ -81,6 +184,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
81
184
  const blocked: AutoAdvanceResult = {
82
185
  kind: "blocked",
83
186
  reason: contract.reason,
187
+ action: "pause",
84
188
  stateSnapshot: reconciliation.stateSnapshot,
85
189
  };
86
190
  await this.deps.runtime.journalTransition({
@@ -98,6 +202,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
98
202
  const blocked: AutoAdvanceResult = {
99
203
  kind: "blocked",
100
204
  reason: worktree.reason,
205
+ action: "pause",
101
206
  stateSnapshot: reconciliation.stateSnapshot,
102
207
  };
103
208
  await this.deps.runtime.journalTransition({
@@ -123,7 +228,11 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
123
228
  });
124
229
  await this.deps.worktree.syncAfterUnit(decision.unitType, decision.unitId);
125
230
 
126
- const advanced: AutoAdvanceResult = { kind: "advanced", stateSnapshot: reconciliation.stateSnapshot };
231
+ const advanced: AutoAdvanceResult = {
232
+ kind: "advanced",
233
+ unit: { unitType: decision.unitType, unitId: decision.unitId },
234
+ stateSnapshot: reconciliation.stateSnapshot,
235
+ };
127
236
  await this.deps.health.postAdvanceRecord(advanced);
128
237
  return advanced;
129
238
  } catch (error) {
@@ -148,6 +257,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
148
257
 
149
258
  if (result.kind === "stopped") {
150
259
  this.lastAdvanceKey = null;
260
+ this.dispatchKeyWindow = [];
151
261
  this.status.activeUnit = undefined;
152
262
  }
153
263
  this.bumpTransition();
@@ -173,6 +283,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
173
283
 
174
284
  public async resume(): Promise<AutoAdvanceResult> {
175
285
  this.lastAdvanceKey = null;
286
+ this.dispatchKeyWindow = [];
176
287
  this.status.phase = "running";
177
288
  this.bumpTransition();
178
289
  await this.deps.runtime.journalTransition({ name: "resume" });
@@ -188,6 +299,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
188
299
  this.status.phase = "stopped";
189
300
  this.status.activeUnit = undefined;
190
301
  this.lastAdvanceKey = null;
302
+ this.dispatchKeyWindow = [];
191
303
  this.bumpTransition();
192
304
  await this.deps.runtime.journalTransition({ name: "stop", reason });
193
305
  await this.deps.notifications.notifyLifecycle({ name: "stop", detail: reason });
@@ -58,6 +58,7 @@ import { withTimeout, FINALIZE_PRE_TIMEOUT_MS, FINALIZE_POST_TIMEOUT_MS } from "
58
58
  import { getEligibleSlices } from "../slice-parallel-eligibility.js";
59
59
  import { startSliceParallel } from "../slice-parallel-orchestrator.js";
60
60
  import { isDbAvailable, getMilestoneSlices } from "../gsd-db.js";
61
+ import { reconcileBeforeSpawn } from "../state-reconciliation.js";
61
62
  import type { MinimalModelRegistry } from "../context-budget.js";
62
63
  import type { PostflightResult, PreflightResult } from "../clean-root-preflight.js";
63
64
  import { ensurePlanV2Graph, isEmptyPlanV2GraphResult, isMissingFinalizedContextResult } from "../uok/plan-v2.js";
@@ -74,6 +75,8 @@ import {
74
75
  } from "../workflow-mcp.js";
75
76
  import { resolveManifest } from "../unit-context-manifest.js";
76
77
  import { createWorktreeSafetyModule, type WorktreeSafetyResult } from "../worktree-safety.js";
78
+ import { isSuspiciousGhostCompletion } from "../auto-unit-closeout.js";
79
+ import { decideVerificationRetry, verificationRetryKey } from "./verification-retry-policy.js";
77
80
 
78
81
  // ─── Path Comparison Helper ───────────────────────────────────────────────
79
82
  /** Compare two paths for physical identity, tolerating trailing slashes and symlinks. */
@@ -81,6 +84,56 @@ function isSamePathLocal(a: string, b: string): boolean {
81
84
  return normalizeWorktreePathForCompare(a) === normalizeWorktreePathForCompare(b);
82
85
  }
83
86
 
87
+ async function applyVerificationRetryPolicy(
88
+ ic: IterationContext,
89
+ unitType: string | undefined,
90
+ phase: "artifact-verification-retry" | "verification-retry",
91
+ ): Promise<PhaseResult | null> {
92
+ const { ctx, pi, s, deps } = ic;
93
+ const retryInfo = s.pendingVerificationRetry;
94
+ const key = unitType && retryInfo
95
+ ? verificationRetryKey(unitType, retryInfo.unitId)
96
+ : undefined;
97
+ const decision = decideVerificationRetry({
98
+ unitType,
99
+ retryInfo,
100
+ previousFailureHash: key ? s.verificationRetryFailureHashes.get(key) : undefined,
101
+ });
102
+
103
+ if (decision.action === "pause") {
104
+ s.pendingVerificationRetry = null;
105
+ debugLog("autoLoop", {
106
+ phase: `${phase}-paused`,
107
+ reason: decision.reason,
108
+ unitType,
109
+ unitId: retryInfo?.unitId,
110
+ failureHash: decision.failureHash,
111
+ });
112
+ ctx.ui.notify(
113
+ decision.reason === "duplicate-failure-context"
114
+ ? `Verification retry for ${unitType ?? "unit"} ${retryInfo?.unitId ?? "unknown"} produced the same failure context. Pausing auto-mode instead of re-dispatching.`
115
+ : "Verification retry requested without retry context. Pausing auto-mode instead of re-dispatching.",
116
+ "warning",
117
+ );
118
+ await deps.pauseAuto(ctx, pi);
119
+ return { action: "break", reason: decision.reason };
120
+ }
121
+
122
+ s.verificationRetryFailureHashes.set(decision.key, decision.failureHash);
123
+ debugLog("autoLoop", {
124
+ phase: `${phase}-backoff`,
125
+ iteration: ic.iteration,
126
+ unitType,
127
+ unitId: retryInfo?.unitId,
128
+ attempt: retryInfo?.attempt,
129
+ delayMs: decision.delayMs,
130
+ baseDelayMs: decision.baseDelayMs,
131
+ failureHash: decision.failureHash,
132
+ });
133
+ await new Promise<void>((resolve) => setTimeout(resolve, decision.delayMs));
134
+ return null;
135
+ }
136
+
84
137
  export function shouldDegradeEmptyWorktreeToProjectRoot(
85
138
  worktreeClassification: ReturnType<typeof classifyProject>,
86
139
  projectRootClassification: ReturnType<typeof classifyProject>,
@@ -826,6 +879,16 @@ export async function runPreDispatch(
826
879
  `Slice-parallel: dispatching ${eligible.length} eligible slices for ${mid}.`,
827
880
  "info",
828
881
  );
882
+ // ADR-017 #5707: reconcile before spawning so each worker doesn't
883
+ // independently race on the same drift. Failure aborts the spawn.
884
+ const spawnGate = await reconcileBeforeSpawn(s.basePath);
885
+ if (!spawnGate.ok) {
886
+ ctx.ui.notify(
887
+ `Slice-parallel: aborting spawn — ${spawnGate.reason}`,
888
+ "error",
889
+ );
890
+ return { action: "break", reason: `slice-parallel-reconciliation-failed: ${spawnGate.reason}` };
891
+ }
829
892
  const result = await startSliceParallel(
830
893
  s.basePath,
831
894
  mid,
@@ -1008,7 +1071,13 @@ export async function runPreDispatch(
1008
1071
  "All milestones complete.",
1009
1072
  "success",
1010
1073
  );
1011
- await deps.stopAuto(ctx, pi, "All milestones complete");
1074
+ await deps.stopAuto(ctx, pi, "All milestones complete", {
1075
+ completionWidget: {
1076
+ milestoneId: s.currentMilestoneId,
1077
+ milestoneTitle: midTitle,
1078
+ allMilestonesComplete: true,
1079
+ },
1080
+ });
1012
1081
  } else if (incomplete.length === 0 && state.registry.length === 0) {
1013
1082
  // Empty registry — no milestones visible, likely a path resolution bug
1014
1083
  const diag = `basePath=${s.basePath}, phase=${state.phase}`;
@@ -1103,7 +1172,23 @@ export async function runPreDispatch(
1103
1172
  `Milestone ${mid} complete.`,
1104
1173
  "success",
1105
1174
  );
1106
- await closeoutAndStop(ctx, pi, s, deps, `Milestone ${mid} complete`);
1175
+ if (s.currentUnit) {
1176
+ await deps.closeoutUnit(
1177
+ ctx,
1178
+ s.basePath,
1179
+ s.currentUnit.type,
1180
+ s.currentUnit.id,
1181
+ s.currentUnit.startedAt,
1182
+ deps.buildSnapshotOpts(s.currentUnit.type, s.currentUnit.id),
1183
+ );
1184
+ s.currentUnit = null;
1185
+ }
1186
+ await deps.stopAuto(ctx, pi, `Milestone ${mid} complete`, {
1187
+ completionWidget: {
1188
+ milestoneId: mid,
1189
+ milestoneTitle: midTitle,
1190
+ },
1191
+ });
1107
1192
  debugLog("autoLoop", { phase: "exit", reason: "milestone-complete" });
1108
1193
  deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "terminal", data: { reason: "milestone-complete", milestoneId: mid } });
1109
1194
  return { action: "break", reason: "milestone-complete" };
@@ -1266,16 +1351,14 @@ export async function runDispatch(
1266
1351
  // ── Sliding-window stuck detection with graduated recovery ──
1267
1352
  const derivedKey = `${unitType}/${unitId}`;
1268
1353
 
1269
- // Always record this dispatch in the sliding window so detectStuck() has
1270
- // accurate history. Skipping the push when pendingVerificationRetry is set
1271
- // caused infinite artifact-retry loops to be invisible to stuck detection
1272
- // (#2007). Only the *response* to a stuck signal is suppressed during retries.
1354
+ // Always record this dispatch in the sliding window and run detection so
1355
+ // Rules 1/3/4 can catch retry loops with repeated failure content (#5719).
1356
+ // Rules 2/2b suppress legitimate retry backoff through the dispatch ledger.
1273
1357
  loopState.recentUnits.push({ key: derivedKey });
1274
1358
  if (loopState.recentUnits.length > STUCK_WINDOW_SIZE) loopState.recentUnits.shift();
1275
1359
 
1276
- if (!s.pendingVerificationRetry) {
1277
- const stuckSignal = detectStuck(loopState.recentUnits);
1278
- if (stuckSignal) {
1360
+ const stuckSignal = detectStuck(loopState.recentUnits);
1361
+ if (stuckSignal) {
1279
1362
  debugLog("autoLoop", {
1280
1363
  phase: "stuck-check",
1281
1364
  unitType,
@@ -1391,16 +1474,15 @@ export async function runDispatch(
1391
1474
  );
1392
1475
  return { action: "break", reason: "stuck-detected" };
1393
1476
  }
1394
- } else {
1395
- // Progress detected — reset recovery counter
1396
- if (loopState.stuckRecoveryAttempts > 0) {
1397
- debugLog("autoLoop", {
1398
- phase: "stuck-counter-reset",
1399
- from: loopState.recentUnits[loopState.recentUnits.length - 2]?.key ?? "",
1400
- to: derivedKey,
1401
- });
1402
- loopState.stuckRecoveryAttempts = 0;
1403
- }
1477
+ } else {
1478
+ // Progress detected — reset recovery counter
1479
+ if (loopState.stuckRecoveryAttempts > 0) {
1480
+ debugLog("autoLoop", {
1481
+ phase: "stuck-counter-reset",
1482
+ from: loopState.recentUnits[loopState.recentUnits.length - 2]?.key ?? "",
1483
+ to: derivedKey,
1484
+ });
1485
+ loopState.stuckRecoveryAttempts = 0;
1404
1486
  }
1405
1487
  }
1406
1488
 
@@ -1984,6 +2066,33 @@ export async function runUnitPhase(
1984
2066
  status: unitResult.status,
1985
2067
  });
1986
2068
 
2069
+ if (
2070
+ unitResult.status === "completed" &&
2071
+ s.currentUnit &&
2072
+ (unitResult.event?.messages?.length ?? 0) === 0 &&
2073
+ isSuspiciousGhostCompletion(ctx, unitResult.requestDispatchedAt ?? s.currentUnit.startedAt)
2074
+ ) {
2075
+ const message =
2076
+ `${unitType} ${unitId} completed without assistant output or tool calls; treating as a stale ghost completion.`;
2077
+ debugLog("autoLoop", {
2078
+ phase: "ghost-completion",
2079
+ iteration: ic.iteration,
2080
+ unitType,
2081
+ unitId,
2082
+ elapsedMs: Date.now() - (unitResult.requestDispatchedAt ?? s.currentUnit.startedAt),
2083
+ });
2084
+ logWarning("engine", message);
2085
+ ctx.ui.notify(`${message} Pausing auto-mode before closeout side effects.`, "warning");
2086
+ await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, {
2087
+ message,
2088
+ category: "unknown",
2089
+ isTransient: true,
2090
+ });
2091
+ s.currentUnit = null;
2092
+ await deps.pauseAuto(ctx, pi);
2093
+ return { action: "break", reason: "ghost-completion" };
2094
+ }
2095
+
1987
2096
  // Now that runUnit has called newSession(), the session file path is correct.
1988
2097
  const sessionFile = deps.getSessionFile(ctx);
1989
2098
  deps.updateSessionLock(
@@ -2124,6 +2233,20 @@ export async function runUnitPhase(
2124
2233
  await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
2125
2234
  return { action: "break", reason: "session-timeout" };
2126
2235
  }
2236
+ if (
2237
+ unitResult.errorContext?.isTransient &&
2238
+ errorCategory === "aborted"
2239
+ ) {
2240
+ ctx.ui.notify(
2241
+ `Unit ${unitType} ${unitId} was aborted by the user. Pausing auto-mode (recoverable).`,
2242
+ "warning",
2243
+ );
2244
+ debugLog("autoLoop", { phase: "unit-aborted-transient-pause", unitType, unitId, category: errorCategory });
2245
+ await deps.pauseAuto(ctx, pi);
2246
+ await deps.autoCommitUnit?.(s.basePath, unitType, unitId, ctx);
2247
+ await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
2248
+ return { action: "break", reason: "unit-aborted-pause" };
2249
+ }
2127
2250
  // All other cancelled states (structural errors, non-transient failures): hard stop
2128
2251
  if (s.currentUnit) {
2129
2252
  await deps.closeoutUnit(
@@ -2364,6 +2487,14 @@ export async function runFinalize(
2364
2487
  attempt: retryInfo?.attempt,
2365
2488
  },
2366
2489
  });
2490
+ const retryPolicyResult = await applyVerificationRetryPolicy(
2491
+ ic,
2492
+ preUnitSnapshot?.type,
2493
+ "artifact-verification-retry",
2494
+ );
2495
+ if (retryPolicyResult) {
2496
+ return retryPolicyResult;
2497
+ }
2367
2498
  // Continue the loop — next iteration will inject the retry context into the prompt.
2368
2499
  debugLog("autoLoop", { phase: "artifact-verification-retry", iteration: ic.iteration });
2369
2500
  return { action: "continue" };
@@ -2401,6 +2532,14 @@ export async function runFinalize(
2401
2532
  debugLog("autoLoop", { phase: "sidecar-verification-retry-skipped", iteration: ic.iteration });
2402
2533
  } else {
2403
2534
  // s.pendingVerificationRetry was set by runPostUnitVerification.
2535
+ const retryPolicyResult = await applyVerificationRetryPolicy(
2536
+ ic,
2537
+ iterData.unitType,
2538
+ "verification-retry",
2539
+ );
2540
+ if (retryPolicyResult) {
2541
+ return retryPolicyResult;
2542
+ }
2404
2543
  // Continue the loop — next iteration will inject the retry context into the prompt.
2405
2544
  debugLog("autoLoop", { phase: "verification-retry", iteration: ic.iteration });
2406
2545
  return { action: "continue" };
@@ -26,6 +26,31 @@ import { debugLog } from "../debug-logger.js";
26
26
  import { logWarning, logError } from "../workflow-logger.js";
27
27
  import { resolveAutoSupervisorConfig } from "../preferences.js";
28
28
  import { formatAutoUnitWorkingMessage } from "../working-output-messages.js";
29
+ import { readUnitRuntimeRecord, type AutoUnitRuntimeRecord } from "../unit-runtime.js";
30
+
31
+ const UNIT_FAILSAFE_BUFFER_MS = 30_000;
32
+ const UNIT_FAILSAFE_RECHECK_MS = 30_000;
33
+
34
+ export function shouldDeferUnitFailsafeTimeout(
35
+ runtime: AutoUnitRuntimeRecord | null,
36
+ opts: {
37
+ nowMs: number;
38
+ currentUnitStartedAt?: number;
39
+ freshProgressMs: number;
40
+ },
41
+ ): boolean {
42
+ if (!runtime) return false;
43
+ if (opts.currentUnitStartedAt === undefined) return false;
44
+ if (runtime.startedAt !== opts.currentUnitStartedAt) return false;
45
+ if (runtime.lastProgressAt <= 0) return false;
46
+ const progressAgeMs = opts.nowMs - runtime.lastProgressAt;
47
+ if (progressAgeMs < 0) return false;
48
+ if (progressAgeMs > opts.freshProgressMs) return false;
49
+ if (runtime.phase === "recovered") return true;
50
+ if (runtime.lastProgressKind.includes("recovery")) return true;
51
+ if (runtime.recoveryAttempts && runtime.recoveryAttempts > 0) return true;
52
+ return progressAgeMs >= 0 && progressAgeMs <= opts.freshProgressMs;
53
+ }
29
54
 
30
55
  // Tracks the latest session-switch attempt so a late timeout settlement from an
31
56
  // older runUnit() call cannot clear the guard for a newer one.
@@ -192,8 +217,12 @@ export async function runUnit(
192
217
  // Without this, a crashed agent that never emits agent_end hangs the loop (#3161).
193
218
  const supervisor = resolveAutoSupervisorConfig();
194
219
  const UNIT_HARD_TIMEOUT_MS = Math.max(
195
- 30_000,
196
- ((supervisor.hard_timeout_minutes ?? 30) * 60 * 1000) + 30_000,
220
+ UNIT_FAILSAFE_BUFFER_MS,
221
+ ((supervisor.hard_timeout_minutes ?? 30) * 60 * 1000) + UNIT_FAILSAFE_BUFFER_MS,
222
+ );
223
+ const freshProgressMs = Math.max(
224
+ UNIT_FAILSAFE_BUFFER_MS,
225
+ ((supervisor.idle_timeout_minutes ?? 10) * 60 * 1000) + UNIT_FAILSAFE_BUFFER_MS,
197
226
  );
198
227
  let unitTimeoutHandle: ReturnType<typeof setTimeout> | undefined;
199
228
  let result: UnitResult;
@@ -205,9 +234,45 @@ export async function runUnit(
205
234
 
206
235
  debugLog("runUnit", { phase: "awaiting-agent-end", unitType, unitId });
207
236
  const timeoutResult = new Promise<UnitResult>((resolve) => {
208
- unitTimeoutHandle = setTimeout(() => {
237
+ const settleOrDefer = () => {
238
+ let runtime: AutoUnitRuntimeRecord | null;
239
+ try {
240
+ runtime = readUnitRuntimeRecord(s.basePath, unitType, unitId);
241
+ } catch (error) {
242
+ debugLog("runUnit", {
243
+ phase: "unit-failsafe-runtime-read-failed",
244
+ unitType,
245
+ unitId,
246
+ error: error instanceof Error ? error.message : String(error),
247
+ });
248
+ resolve({
249
+ status: "cancelled",
250
+ errorContext: {
251
+ message: "Unit hard timeout — supervision may have failed; runtime progress could not be read",
252
+ category: "timeout",
253
+ isTransient: true,
254
+ },
255
+ });
256
+ return;
257
+ }
258
+ if (shouldDeferUnitFailsafeTimeout(runtime, {
259
+ nowMs: Date.now(),
260
+ currentUnitStartedAt: s.currentUnit?.startedAt,
261
+ freshProgressMs,
262
+ })) {
263
+ debugLog("runUnit", {
264
+ phase: "unit-failsafe-deferred",
265
+ unitType,
266
+ unitId,
267
+ runtimePhase: runtime?.phase,
268
+ lastProgressKind: runtime?.lastProgressKind,
269
+ });
270
+ unitTimeoutHandle = setTimeout(settleOrDefer, UNIT_FAILSAFE_RECHECK_MS);
271
+ return;
272
+ }
209
273
  resolve({ status: "cancelled", errorContext: { message: "Unit hard timeout — supervision may have failed", category: "timeout", isTransient: true } });
210
- }, UNIT_HARD_TIMEOUT_MS);
274
+ };
275
+ unitTimeoutHandle = setTimeout(settleOrDefer, UNIT_HARD_TIMEOUT_MS);
211
276
  });
212
277
  result = await runWithTurnGeneration(capturedTurnGen, () =>
213
278
  Promise.race([unitPromise, timeoutResult]),
@@ -88,6 +88,7 @@ export class AutoSession {
88
88
  // ── Lifecycle ────────────────────────────────────────────────────────────
89
89
  active = false;
90
90
  paused = false;
91
+ completionStopInProgress = false;
91
92
  stepMode = false;
92
93
  verbose = false;
93
94
  activeEngineId: string | null = null;
@@ -158,6 +159,7 @@ export class AutoSession {
158
159
  pendingCrashRecovery: string | null = null;
159
160
  pendingVerificationRetry: PendingVerificationRetry | null = null;
160
161
  readonly verificationRetryCount = new Map<string, number>();
162
+ readonly verificationRetryFailureHashes = new Map<string, string>();
161
163
  pausedSessionFile: string | null = null;
162
164
  pausedUnitType: string | null = null;
163
165
  pausedUnitId: string | null = null;
@@ -286,6 +288,7 @@ export class AutoSession {
286
288
  // Lifecycle
287
289
  this.active = false;
288
290
  this.paused = false;
291
+ this.completionStopInProgress = false;
289
292
  this.stepMode = false;
290
293
  this.verbose = false;
291
294
  this.activeEngineId = null;
@@ -334,6 +337,7 @@ export class AutoSession {
334
337
  this.pendingCrashRecovery = null;
335
338
  this.pendingVerificationRetry = null;
336
339
  this.verificationRetryCount.clear();
340
+ this.verificationRetryFailureHashes.clear();
337
341
  this.pausedSessionFile = null;
338
342
  this.pausedUnitType = null;
339
343
  this.pausedUnitId = null;
@@ -372,6 +376,12 @@ export class AutoSession {
372
376
  // Loop promise state lives in auto-loop.ts module scope
373
377
  }
374
378
 
379
+ resetAfterStop(options: { preserveCompletionSurface?: boolean } = {}): void {
380
+ const completionStopInProgress = options.preserveCompletionSurface ? this.completionStopInProgress : false;
381
+ this.reset();
382
+ this.completionStopInProgress = completionStopInProgress;
383
+ }
384
+
375
385
  toJSON(): Record<string, unknown> {
376
386
  const orchestrationStatus = this.orchestration?.getStatus();
377
387
  return {