gsd-pi 2.81.0 → 2.82.0-dev.ed17d078d

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 (503) 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 +386 -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/tui/render-kit.js +74 -0
  76. package/dist/resources/extensions/gsd/watch/header-renderer.js +92 -69
  77. package/dist/resources/extensions/gsd/watch/splash-palette.js +10 -0
  78. package/dist/resources/extensions/gsd/workflow-mcp.js +2 -2
  79. package/dist/resources/extensions/gsd/worktree-lifecycle.js +722 -316
  80. package/dist/resources/extensions/gsd/worktree-telemetry.js +3 -1
  81. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  82. package/dist/web/standalone/.next/BUILD_ID +1 -1
  83. package/dist/web/standalone/.next/app-path-routes-manifest.json +6 -6
  84. package/dist/web/standalone/.next/build-manifest.json +3 -3
  85. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  86. package/dist/web/standalone/.next/required-server-files.json +3 -3
  87. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  88. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  89. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  90. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  98. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  101. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  114. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  126. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  146. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  156. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  162. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  178. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +2 -2
  182. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  185. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  186. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  187. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  188. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  189. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  190. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  191. package/dist/web/standalone/.next/server/app/index.html +1 -1
  192. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  193. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  194. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  195. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  196. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  197. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  198. package/dist/web/standalone/.next/server/app/page.js +2 -2
  199. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  200. package/dist/web/standalone/.next/server/app-paths-manifest.json +6 -6
  201. package/dist/web/standalone/.next/server/chunks/63.js +3 -3
  202. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  203. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  204. package/dist/web/standalone/.next/server/middleware.js +2 -2
  205. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  206. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  207. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  208. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  209. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  210. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  211. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  212. package/dist/web/standalone/.next/static/chunks/app/page-752f1e2ebdaa3e45.js +1 -0
  213. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  214. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  215. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  216. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  217. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  218. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  219. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  220. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  221. package/dist/web/standalone/server.js +1 -1
  222. package/dist/welcome-screen.d.ts +0 -7
  223. package/dist/welcome-screen.js +60 -69
  224. package/package.json +3 -2
  225. package/packages/daemon/package.json +2 -2
  226. package/packages/mcp-server/README.md +2 -0
  227. package/packages/mcp-server/package.json +2 -2
  228. package/packages/mcp-server/src/workflow-tools-parity.test.ts +244 -0
  229. package/packages/native/package.json +1 -1
  230. package/packages/pi-agent-core/package.json +1 -1
  231. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  232. package/packages/pi-ai/dist/index.d.ts +2 -2
  233. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  234. package/packages/pi-ai/dist/index.js +1 -1
  235. package/packages/pi-ai/dist/index.js.map +1 -1
  236. package/packages/pi-ai/dist/providers/transform-messages.d.ts +11 -0
  237. package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
  238. package/packages/pi-ai/dist/providers/transform-messages.js +20 -0
  239. package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
  240. package/packages/pi-ai/package.json +1 -1
  241. package/packages/pi-ai/src/index.ts +7 -2
  242. package/packages/pi-ai/src/providers/transform-messages.ts +24 -0
  243. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  244. package/packages/pi-coding-agent/dist/core/system-prompt.js +4 -4
  245. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  246. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts +2 -0
  247. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts.map +1 -0
  248. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js +47 -0
  249. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js.map +1 -0
  250. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +76 -9
  251. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  252. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts +2 -0
  253. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts.map +1 -0
  254. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js +40 -0
  255. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js.map +1 -0
  256. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +0 -1
  257. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -1
  258. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +30 -29
  259. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -1
  260. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +10 -3
  261. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -1
  262. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  263. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +13 -13
  264. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  265. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +1 -3
  266. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  267. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +58 -3
  268. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
  269. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts +2 -2
  270. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts.map +1 -1
  271. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js +12 -6
  272. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js.map +1 -1
  273. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  274. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -41
  275. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  276. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +0 -1
  277. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  278. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +86 -82
  279. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  280. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts +35 -0
  281. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts.map +1 -0
  282. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js +152 -0
  283. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js.map +1 -0
  284. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts +16 -0
  285. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts.map +1 -0
  286. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js +73 -0
  287. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js.map +1 -0
  288. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +1 -1
  289. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  290. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +12 -8
  291. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  292. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
  293. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
  294. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
  295. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
  296. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  297. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +105 -1
  298. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  299. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  300. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +27 -26
  301. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  302. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +9 -6
  303. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -1
  304. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts +2 -0
  305. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts.map +1 -0
  306. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js +17 -0
  307. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js.map +1 -0
  308. package/packages/pi-coding-agent/package.json +1 -1
  309. package/packages/pi-coding-agent/src/core/system-prompt.ts +4 -4
  310. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/assistant-message-design.test.ts +56 -0
  311. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +113 -9
  312. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/user-message-design.test.ts +48 -0
  313. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +10 -3
  314. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +43 -42
  315. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +14 -14
  316. package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +64 -3
  317. package/packages/pi-coding-agent/src/modes/interactive/components/diff.ts +13 -7
  318. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +15 -42
  319. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +84 -104
  320. package/packages/pi-coding-agent/src/modes/interactive/components/transcript-design.ts +196 -0
  321. package/packages/pi-coding-agent/src/modes/interactive/components/tui-style-kit.ts +94 -0
  322. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +14 -9
  323. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-highlight.test.ts +23 -0
  324. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +106 -1
  325. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +27 -26
  326. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +9 -6
  327. package/packages/pi-coding-agent/src/tests/system-prompt-file-safety.test.ts +22 -0
  328. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  329. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +14 -1
  330. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  331. package/packages/pi-tui/dist/overlay-layout.d.ts.map +1 -1
  332. package/packages/pi-tui/dist/overlay-layout.js +9 -6
  333. package/packages/pi-tui/dist/overlay-layout.js.map +1 -1
  334. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  335. package/packages/pi-tui/dist/tui.js +5 -0
  336. package/packages/pi-tui/dist/tui.js.map +1 -1
  337. package/packages/pi-tui/package.json +1 -1
  338. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +20 -1
  339. package/packages/pi-tui/src/overlay-layout.ts +10 -7
  340. package/packages/pi-tui/src/tui.ts +6 -0
  341. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  342. package/packages/rpc-client/package.json +1 -1
  343. package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
  344. package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
  345. package/pkg/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
  346. package/pkg/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
  347. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  348. package/pkg/dist/modes/interactive/theme/theme.js +105 -1
  349. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  350. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  351. package/pkg/dist/modes/interactive/theme/themes.js +27 -26
  352. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  353. package/pkg/package.json +1 -1
  354. package/src/resources/extensions/browser-tools/tools/screenshot.ts +1 -0
  355. package/src/resources/extensions/browser-tools/tools/zoom.ts +1 -0
  356. package/src/resources/extensions/gsd/auto/contracts.ts +46 -11
  357. package/src/resources/extensions/gsd/auto/loop-deps.ts +9 -5
  358. package/src/resources/extensions/gsd/auto/loop.ts +113 -9
  359. package/src/resources/extensions/gsd/auto/orchestrator.ts +118 -6
  360. package/src/resources/extensions/gsd/auto/phases.ts +158 -19
  361. package/src/resources/extensions/gsd/auto/run-unit.ts +69 -4
  362. package/src/resources/extensions/gsd/auto/session.ts +10 -0
  363. package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +82 -0
  364. package/src/resources/extensions/gsd/auto-dashboard.ts +230 -183
  365. package/src/resources/extensions/gsd/auto-dispatch.ts +15 -1
  366. package/src/resources/extensions/gsd/auto-post-unit.ts +7 -1
  367. package/src/resources/extensions/gsd/auto-prompts.ts +11 -3
  368. package/src/resources/extensions/gsd/auto-recovery.ts +7 -209
  369. package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
  370. package/src/resources/extensions/gsd/auto-start.ts +22 -22
  371. package/src/resources/extensions/gsd/auto-unit-closeout.ts +51 -0
  372. package/src/resources/extensions/gsd/auto-verification.ts +12 -6
  373. package/src/resources/extensions/gsd/auto-worktree.ts +8 -0
  374. package/src/resources/extensions/gsd/auto.ts +424 -106
  375. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +21 -6
  376. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +12 -2
  377. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +5 -8
  378. package/src/resources/extensions/gsd/bootstrap/system-context.ts +58 -15
  379. package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -1
  380. package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +4 -10
  381. package/src/resources/extensions/gsd/commands/handlers/parallel.ts +12 -0
  382. package/src/resources/extensions/gsd/commands-handlers.ts +19 -2
  383. package/src/resources/extensions/gsd/context-store.ts +120 -1
  384. package/src/resources/extensions/gsd/db-writer.ts +167 -84
  385. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  386. package/src/resources/extensions/gsd/doctor-git-checks.ts +44 -6
  387. package/src/resources/extensions/gsd/doctor-types.ts +2 -0
  388. package/src/resources/extensions/gsd/git-service.ts +2 -0
  389. package/src/resources/extensions/gsd/gsd-db.ts +7 -23
  390. package/src/resources/extensions/gsd/health-widget-core.ts +1 -1
  391. package/src/resources/extensions/gsd/health-widget.ts +6 -10
  392. package/src/resources/extensions/gsd/journal.ts +2 -0
  393. package/src/resources/extensions/gsd/knowledge-backfill.ts +164 -0
  394. package/src/resources/extensions/gsd/knowledge-capture.ts +160 -0
  395. package/src/resources/extensions/gsd/knowledge-parser.ts +174 -0
  396. package/src/resources/extensions/gsd/knowledge-projection.ts +241 -0
  397. package/src/resources/extensions/gsd/markdown-renderer.ts +10 -96
  398. package/src/resources/extensions/gsd/md-importer.ts +1 -1
  399. package/src/resources/extensions/gsd/memory-backfill.ts +89 -17
  400. package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +277 -0
  401. package/src/resources/extensions/gsd/migrate/command.ts +5 -0
  402. package/src/resources/extensions/gsd/migrate/preview.ts +10 -0
  403. package/src/resources/extensions/gsd/migrate/transformer.ts +58 -4
  404. package/src/resources/extensions/gsd/migrate/writer.ts +14 -1
  405. package/src/resources/extensions/gsd/native-git-bridge.ts +14 -13
  406. package/src/resources/extensions/gsd/notification-overlay.ts +50 -46
  407. package/src/resources/extensions/gsd/parallel-merge.ts +61 -34
  408. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +33 -35
  409. package/src/resources/extensions/gsd/prompts/complete-slice.md +14 -12
  410. package/src/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
  411. package/src/resources/extensions/gsd/prompts/discuss.md +20 -2
  412. package/src/resources/extensions/gsd/prompts/system.md +2 -2
  413. package/src/resources/extensions/gsd/provider-switch-observer.ts +185 -0
  414. package/src/resources/extensions/gsd/recovery-classification.ts +18 -1
  415. package/src/resources/extensions/gsd/session-lock.ts +41 -0
  416. package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +172 -0
  417. package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +337 -0
  418. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +69 -0
  419. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +109 -0
  420. package/src/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.ts +68 -0
  421. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +185 -0
  422. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-worker.ts +46 -0
  423. package/src/resources/extensions/gsd/state-reconciliation/errors.ts +67 -0
  424. package/src/resources/extensions/gsd/state-reconciliation/index.ts +142 -0
  425. package/src/resources/extensions/gsd/state-reconciliation/registry.ts +27 -0
  426. package/src/resources/extensions/gsd/state-reconciliation/spawn-gate.ts +60 -0
  427. package/src/resources/extensions/gsd/state-reconciliation/types.ts +83 -0
  428. package/src/resources/extensions/gsd/state-reconciliation.ts +21 -53
  429. package/src/resources/extensions/gsd/templates/knowledge.md +2 -2
  430. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +1 -1
  431. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +99 -0
  432. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +729 -176
  433. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +408 -4
  434. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +291 -4
  435. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +20 -5
  436. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +18 -0
  437. package/src/resources/extensions/gsd/tests/auto-unit-closeout.test.ts +68 -0
  438. package/src/resources/extensions/gsd/tests/browser-tools-compatibility-declarations.test.ts +62 -0
  439. package/src/resources/extensions/gsd/tests/context-store-decisions-from-memories.test.ts +312 -0
  440. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +28 -1
  441. package/src/resources/extensions/gsd/tests/db-writer.test.ts +13 -8
  442. package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +453 -0
  443. package/src/resources/extensions/gsd/tests/decisions-stop-table-writes.test.ts +348 -0
  444. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +20 -2
  445. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +44 -0
  446. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +8 -4
  447. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +11 -7
  448. package/src/resources/extensions/gsd/tests/header-renderer.test.ts +40 -0
  449. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +10 -0
  450. package/src/resources/extensions/gsd/tests/health-widget.test.ts +14 -4
  451. package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +44 -0
  452. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +26 -0
  453. package/src/resources/extensions/gsd/tests/integration/integration-lifecycle.test.ts +13 -5
  454. package/src/resources/extensions/gsd/tests/integration/integration-proof.test.ts +1 -1
  455. package/src/resources/extensions/gsd/tests/integration/migrate-command.test.ts +48 -3
  456. package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +116 -24
  457. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -1
  458. package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +323 -0
  459. package/src/resources/extensions/gsd/tests/knowledge-capture.test.ts +242 -0
  460. package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -2
  461. package/src/resources/extensions/gsd/tests/load-knowledge-block-rules-only.test.ts +209 -0
  462. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +1 -1
  463. package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +316 -0
  464. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +46 -11
  465. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +5 -1
  466. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +6 -1
  467. package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +78 -41
  468. package/src/resources/extensions/gsd/tests/notifications-handler.test.ts +44 -0
  469. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +12 -217
  470. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +38 -6
  471. package/src/resources/extensions/gsd/tests/plan-milestone-sketch-render.test.ts +157 -0
  472. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +2 -2
  473. package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +1 -1
  474. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +32 -1
  475. package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +252 -0
  476. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +7 -3
  477. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +6 -3
  478. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +16 -4
  479. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +24 -0
  480. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +65 -58
  481. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +952 -0
  482. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +4 -0
  483. package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +121 -1
  484. package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +66 -0
  485. package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +83 -0
  486. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +6 -0
  487. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +158 -58
  488. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +572 -118
  489. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +59 -2
  490. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +18 -0
  491. package/src/resources/extensions/gsd/tui/render-kit.ts +109 -0
  492. package/src/resources/extensions/gsd/watch/header-renderer.ts +121 -79
  493. package/src/resources/extensions/gsd/watch/splash-palette.ts +11 -0
  494. package/src/resources/extensions/gsd/workflow-logger.ts +4 -0
  495. package/src/resources/extensions/gsd/workflow-mcp.ts +2 -2
  496. package/src/resources/extensions/gsd/worktree-lifecycle.ts +1151 -524
  497. package/src/resources/extensions/gsd/worktree-telemetry.ts +7 -2
  498. package/dist/web/standalone/.next/static/chunks/app/page-200592a7f3baf579.js +0 -1
  499. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  500. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  501. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +0 -1544
  502. /package/dist/web/standalone/.next/static/{drLMkgfHQ8lzS229_HWYR → YEvjuT-fsFfYQhDSWtueS}/_buildManifest.js +0 -0
  503. /package/dist/web/standalone/.next/static/{drLMkgfHQ8lzS229_HWYR → YEvjuT-fsFfYQhDSWtueS}/_ssgManifest.js +0 -0
@@ -3,6 +3,15 @@
3
3
  function now() {
4
4
  return Date.now();
5
5
  }
6
+ /**
7
+ * Size of the dispatch-decision ring buffer used by the Auto Orchestration
8
+ * module's stuck-loop detector. When the same `${unitType}:${unitId}` key
9
+ * fills the window, advance() blocks with `action: "stop"`.
10
+ *
11
+ * Mirrors the legacy `STUCK_WINDOW_SIZE` in auto/phases.ts so behaviour is
12
+ * preserved across the eventual cutover (issue #5791).
13
+ */
14
+ export const STUCK_WINDOW_SIZE = 6;
6
15
  export class AutoOrchestrator {
7
16
  status = {
8
17
  phase: "idle",
@@ -10,11 +19,13 @@ export class AutoOrchestrator {
10
19
  };
11
20
  deps;
12
21
  lastAdvanceKey = null;
22
+ dispatchKeyWindow = [];
13
23
  constructor(deps) {
14
24
  this.deps = deps;
15
25
  }
16
26
  async start(_sessionContext) {
17
27
  this.lastAdvanceKey = null;
28
+ this.dispatchKeyWindow = [];
18
29
  this.status.phase = "running";
19
30
  this.bumpTransition();
20
31
  await this.deps.runtime.journalTransition({ name: "start" });
@@ -24,18 +35,70 @@ export class AutoOrchestrator {
24
35
  async advance() {
25
36
  try {
26
37
  await this.deps.runtime.ensureLockOwnership();
38
+ const staleMsg = this.deps.health.checkResourcesStale();
39
+ if (staleMsg) {
40
+ await this.deps.uokGate.emit({
41
+ gateId: "resource-version-guard",
42
+ gateType: "policy",
43
+ outcome: "fail",
44
+ failureClass: "policy",
45
+ rationale: "resource version guard blocked dispatch",
46
+ findings: staleMsg,
47
+ });
48
+ const blocked = { kind: "blocked", reason: staleMsg, action: "stop" };
49
+ await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
50
+ await this.deps.health.postAdvanceRecord(blocked);
51
+ return blocked;
52
+ }
53
+ await this.deps.uokGate.emit({
54
+ gateId: "resource-version-guard",
55
+ gateType: "policy",
56
+ outcome: "pass",
57
+ failureClass: "none",
58
+ rationale: "resource version guard passed",
59
+ });
27
60
  const gate = await this.deps.health.preAdvanceGate();
28
- if (!gate.allow) {
29
- const blocked = { kind: "blocked", reason: gate.reason ?? "health gate blocked" };
61
+ if (gate.kind === "fail") {
62
+ await this.deps.uokGate.emit({
63
+ gateId: "pre-dispatch-health-gate",
64
+ gateType: "execution",
65
+ outcome: "manual-attention",
66
+ failureClass: "manual-attention",
67
+ rationale: "pre-dispatch health gate blocked dispatch",
68
+ findings: gate.reason,
69
+ });
70
+ const blocked = { kind: "blocked", reason: gate.reason, action: "pause" };
30
71
  await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
31
72
  await this.deps.health.postAdvanceRecord(blocked);
32
73
  return blocked;
33
74
  }
75
+ if (gate.kind === "threw") {
76
+ await this.deps.uokGate.emit({
77
+ gateId: "pre-dispatch-health-gate",
78
+ gateType: "execution",
79
+ outcome: "manual-attention",
80
+ failureClass: "manual-attention",
81
+ rationale: "pre-dispatch health gate threw unexpectedly",
82
+ findings: String(gate.error),
83
+ });
84
+ // intentional fall-through: matches runPreDispatch behaviour
85
+ }
86
+ else {
87
+ await this.deps.uokGate.emit({
88
+ gateId: "pre-dispatch-health-gate",
89
+ gateType: "execution",
90
+ outcome: "pass",
91
+ failureClass: "none",
92
+ rationale: "pre-dispatch health gate passed",
93
+ findings: gate.fixesApplied?.join(", ") ?? "",
94
+ });
95
+ }
34
96
  const reconciliation = await this.deps.stateReconciliation.reconcileBeforeDispatch();
35
97
  if (!reconciliation.ok || !reconciliation.stateSnapshot) {
36
98
  const blocked = {
37
99
  kind: "blocked",
38
- reason: reconciliation.reason,
100
+ reason: reconciliation.reason ?? "state reconciliation produced no snapshot",
101
+ action: "pause",
39
102
  stateSnapshot: reconciliation.stateSnapshot,
40
103
  };
41
104
  await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
@@ -48,14 +111,49 @@ export class AutoOrchestrator {
48
111
  this.status.phase = "stopped";
49
112
  this.status.activeUnit = undefined;
50
113
  this.lastAdvanceKey = null;
114
+ this.dispatchKeyWindow = [];
51
115
  this.bumpTransition();
52
116
  await this.deps.runtime.journalTransition({ name: "advance-stopped", reason: stopped.reason });
53
117
  await this.deps.health.postAdvanceRecord(stopped);
54
118
  return stopped;
55
119
  }
56
120
  const nextKey = `${decision.unitType}:${decision.unitId}`;
57
- if (this.lastAdvanceKey === nextKey) {
58
- const blocked = { kind: "blocked", reason: "idempotent advance: unit already active" };
121
+ // Record every dispatch decision in the ring buffer before pre-flight
122
+ // checks so the stuck-loop detector observes the full decision history
123
+ // (including decisions that idempotency would otherwise short-circuit).
124
+ // The ring is capped at STUCK_WINDOW_SIZE and evicts oldest-first.
125
+ this.dispatchKeyWindow.push(nextKey);
126
+ if (this.dispatchKeyWindow.length > STUCK_WINDOW_SIZE) {
127
+ this.dispatchKeyWindow.shift();
128
+ }
129
+ // Idempotency: same key as immediately previous successful advance.
130
+ // This is the soft, fast-path block kept from #5786. It only fires when
131
+ // the ring is NOT yet saturated for this key — once the ring is full of
132
+ // `nextKey`, the stuck-loop verdict takes precedence (see below). Both
133
+ // checks coexist: idempotency for the common immediate-repeat case,
134
+ // stuck-loop for the saturated-window case.
135
+ const matchingCount = this.dispatchKeyWindow.filter((k) => k === nextKey).length;
136
+ if (this.lastAdvanceKey === nextKey && matchingCount < STUCK_WINDOW_SIZE) {
137
+ const blocked = { kind: "blocked", reason: "idempotent advance: unit already active", action: "stop" };
138
+ await this.deps.runtime.journalTransition({
139
+ name: "advance-blocked",
140
+ reason: blocked.reason,
141
+ unitType: decision.unitType,
142
+ unitId: decision.unitId,
143
+ });
144
+ await this.deps.health.postAdvanceRecord(blocked);
145
+ return blocked;
146
+ }
147
+ // Stuck-loop detection: when the ring is saturated with copies of
148
+ // `nextKey` (count >= STUCK_WINDOW_SIZE), the orchestrator has been
149
+ // picking the same unit across the whole window and must hard-stop with
150
+ // a diagnosable reason.
151
+ if (matchingCount >= STUCK_WINDOW_SIZE) {
152
+ const blocked = {
153
+ kind: "blocked",
154
+ reason: `stuck-loop: ${nextKey} picked ${matchingCount} times`,
155
+ action: "stop",
156
+ };
59
157
  await this.deps.runtime.journalTransition({
60
158
  name: "advance-blocked",
61
159
  reason: blocked.reason,
@@ -70,6 +168,7 @@ export class AutoOrchestrator {
70
168
  const blocked = {
71
169
  kind: "blocked",
72
170
  reason: contract.reason,
171
+ action: "pause",
73
172
  stateSnapshot: reconciliation.stateSnapshot,
74
173
  };
75
174
  await this.deps.runtime.journalTransition({
@@ -86,6 +185,7 @@ export class AutoOrchestrator {
86
185
  const blocked = {
87
186
  kind: "blocked",
88
187
  reason: worktree.reason,
188
+ action: "pause",
89
189
  stateSnapshot: reconciliation.stateSnapshot,
90
190
  };
91
191
  await this.deps.runtime.journalTransition({
@@ -108,7 +208,11 @@ export class AutoOrchestrator {
108
208
  unitId: decision.unitId,
109
209
  });
110
210
  await this.deps.worktree.syncAfterUnit(decision.unitType, decision.unitId);
111
- const advanced = { kind: "advanced", stateSnapshot: reconciliation.stateSnapshot };
211
+ const advanced = {
212
+ kind: "advanced",
213
+ unit: { unitType: decision.unitType, unitId: decision.unitId },
214
+ stateSnapshot: reconciliation.stateSnapshot,
215
+ };
112
216
  await this.deps.health.postAdvanceRecord(advanced);
113
217
  return advanced;
114
218
  }
@@ -134,6 +238,7 @@ export class AutoOrchestrator {
134
238
  }
135
239
  if (result.kind === "stopped") {
136
240
  this.lastAdvanceKey = null;
241
+ this.dispatchKeyWindow = [];
137
242
  this.status.activeUnit = undefined;
138
243
  }
139
244
  this.bumpTransition();
@@ -158,6 +263,7 @@ export class AutoOrchestrator {
158
263
  }
159
264
  async resume() {
160
265
  this.lastAdvanceKey = null;
266
+ this.dispatchKeyWindow = [];
161
267
  this.status.phase = "running";
162
268
  this.bumpTransition();
163
269
  await this.deps.runtime.journalTransition({ name: "resume" });
@@ -172,6 +278,7 @@ export class AutoOrchestrator {
172
278
  this.status.phase = "stopped";
173
279
  this.status.activeUnit = undefined;
174
280
  this.lastAdvanceKey = null;
281
+ this.dispatchKeyWindow = [];
175
282
  this.bumpTransition();
176
283
  await this.deps.runtime.journalTransition({ name: "stop", reason });
177
284
  await this.deps.notifications.notifyLifecycle({ name: "stop", detail: reason });
@@ -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" };