@bastani/atomic 0.9.5-alpha.8 → 0.9.5

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 (530) hide show
  1. package/CHANGELOG.md +122 -0
  2. package/README.md +2 -2
  3. package/dist/builtin/cursor/CHANGELOG.md +12 -0
  4. package/dist/builtin/cursor/package.json +3 -3
  5. package/dist/builtin/cursor/src/model-mapper.ts +6 -3
  6. package/dist/builtin/intercom/CHANGELOG.md +37 -0
  7. package/dist/builtin/intercom/README.md +4 -2
  8. package/dist/builtin/intercom/broker/broker.ts +6 -114
  9. package/dist/builtin/intercom/broker/client.ts +29 -54
  10. package/dist/builtin/intercom/broker/delivered-message-cache.ts +44 -0
  11. package/dist/builtin/intercom/broker/pending-send-registry.ts +142 -0
  12. package/dist/builtin/intercom/broker/send-handler.ts +106 -0
  13. package/dist/builtin/intercom/broker/send-signature.ts +37 -0
  14. package/dist/builtin/intercom/foreground-detach-handoff.ts +136 -0
  15. package/dist/builtin/intercom/index-heavy.ts +49 -53
  16. package/dist/builtin/intercom/index.ts +278 -262
  17. package/dist/builtin/intercom/lazy-heavy-proxy.ts +114 -0
  18. package/dist/builtin/intercom/lazy-subagent-ack.ts +20 -0
  19. package/dist/builtin/intercom/lazy-tool-execution.ts +39 -0
  20. package/dist/builtin/intercom/lifecycle-lease.ts +51 -0
  21. package/dist/builtin/intercom/lifecycle.ts +37 -20
  22. package/dist/builtin/intercom/package.json +3 -6
  23. package/dist/builtin/intercom/reply-routing.ts +17 -0
  24. package/dist/builtin/intercom/subagent-relay.ts +58 -12
  25. package/dist/builtin/intercom/types.ts +3 -3
  26. package/dist/builtin/mcp/CHANGELOG.md +38 -0
  27. package/dist/builtin/mcp/OAUTH.md +1 -0
  28. package/dist/builtin/mcp/README.md +10 -6
  29. package/dist/builtin/mcp/apps-cancellation.ts +32 -0
  30. package/dist/builtin/mcp/call-tool-result.ts +9 -0
  31. package/dist/builtin/mcp/caller-wait.ts +50 -0
  32. package/dist/builtin/mcp/command-registration.ts +82 -0
  33. package/dist/builtin/mcp/direct-tool-executor.ts +279 -0
  34. package/dist/builtin/mcp/direct-tools.ts +40 -255
  35. package/dist/builtin/mcp/host-html-template.ts +4 -2
  36. package/dist/builtin/mcp/index.ts +274 -239
  37. package/dist/builtin/mcp/init.ts +96 -126
  38. package/dist/builtin/mcp/mcp-auth-flow.ts +247 -237
  39. package/dist/builtin/mcp/mcp-callback-server.ts +89 -68
  40. package/dist/builtin/mcp/mcp-oauth-provider.ts +23 -1
  41. package/dist/builtin/mcp/metadata-hydration.ts +52 -0
  42. package/dist/builtin/mcp/package.json +3 -3
  43. package/dist/builtin/mcp/proxy-auth.ts +4 -4
  44. package/dist/builtin/mcp/proxy-call.ts +111 -40
  45. package/dist/builtin/mcp/proxy-connect.ts +35 -15
  46. package/dist/builtin/mcp/proxy-info-modes.ts +106 -23
  47. package/dist/builtin/mcp/proxy-modes.ts +3 -3
  48. package/dist/builtin/mcp/session-cleanup-barrier.ts +43 -0
  49. package/dist/builtin/mcp/startup-warmup.ts +98 -0
  50. package/dist/builtin/mcp/state-lease.ts +12 -0
  51. package/dist/builtin/mcp/tool-result-renderer.ts +3 -3
  52. package/dist/builtin/mcp/ui-server.ts +8 -8
  53. package/dist/builtin/mcp/ui-session.ts +9 -18
  54. package/dist/builtin/subagents/CHANGELOG.md +78 -0
  55. package/dist/builtin/subagents/README.md +30 -29
  56. package/dist/builtin/subagents/agents/code-simplifier.md +2 -2
  57. package/dist/builtin/subagents/agents/codebase-analyzer.md +2 -2
  58. package/dist/builtin/subagents/agents/codebase-locator.md +2 -2
  59. package/dist/builtin/subagents/agents/codebase-online-researcher.md +2 -2
  60. package/dist/builtin/subagents/agents/codebase-pattern-finder.md +2 -2
  61. package/dist/builtin/subagents/agents/codebase-research-analyzer.md +2 -2
  62. package/dist/builtin/subagents/agents/codebase-research-locator.md +2 -2
  63. package/dist/builtin/subagents/agents/debugger.md +2 -2
  64. package/dist/builtin/subagents/agents/worker.md +2 -2
  65. package/dist/builtin/subagents/package.json +5 -5
  66. package/dist/builtin/subagents/prompts/review-loop.md +1 -1
  67. package/dist/builtin/subagents/skills/subagent/SKILL.md +37 -36
  68. package/dist/builtin/subagents/src/extension/api-lifecycle.ts +64 -0
  69. package/dist/builtin/subagents/src/extension/fanout-child.ts +44 -51
  70. package/dist/builtin/subagents/src/extension/index.ts +289 -320
  71. package/dist/builtin/subagents/src/extension/prompt-guidance.ts +7 -10
  72. package/dist/builtin/subagents/src/extension/schemas.ts +22 -5
  73. package/dist/builtin/subagents/src/extension/startup-maintenance.ts +89 -0
  74. package/dist/builtin/subagents/src/extension/tool-description.ts +29 -0
  75. package/dist/builtin/subagents/src/intercom/intercom-bridge.ts +13 -2
  76. package/dist/builtin/subagents/src/intercom/result-intercom.ts +4 -4
  77. package/dist/builtin/subagents/src/runs/background/async-event-journal.ts +106 -0
  78. package/dist/builtin/subagents/src/runs/background/async-execution-common.ts +26 -20
  79. package/dist/builtin/subagents/src/runs/background/async-execution-single.ts +13 -2
  80. package/dist/builtin/subagents/src/runs/background/async-execution-types.ts +3 -0
  81. package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +1 -1
  82. package/dist/builtin/subagents/src/runs/background/completion-claims.ts +189 -0
  83. package/dist/builtin/subagents/src/runs/background/completion-dedupe.ts +44 -7
  84. package/dist/builtin/subagents/src/runs/background/completion-notification.ts +34 -0
  85. package/dist/builtin/subagents/src/runs/background/notify.ts +72 -22
  86. package/dist/builtin/subagents/src/runs/background/result-delivery-processor.ts +232 -0
  87. package/dist/builtin/subagents/src/runs/background/result-file-claims.ts +151 -0
  88. package/dist/builtin/subagents/src/runs/background/result-quarantine.ts +72 -0
  89. package/dist/builtin/subagents/src/runs/background/result-retry-scheduler.ts +48 -0
  90. package/dist/builtin/subagents/src/runs/background/result-status.ts +81 -0
  91. package/dist/builtin/subagents/src/runs/background/result-watcher-data.ts +59 -0
  92. package/dist/builtin/subagents/src/runs/background/result-watcher.ts +177 -233
  93. package/dist/builtin/subagents/src/runs/background/run-id-resolver.ts +3 -2
  94. package/dist/builtin/subagents/src/runs/background/stale-run-reconciler.ts +73 -14
  95. package/dist/builtin/subagents/src/runs/background/subagent-runner-streaming.ts +29 -15
  96. package/dist/builtin/subagents/src/runs/background/top-level-async.ts +1 -2
  97. package/dist/builtin/subagents/src/runs/foreground/chain-execution-dynamic-step.ts +1 -0
  98. package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-runner.ts +1 -0
  99. package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-step.ts +1 -0
  100. package/dist/builtin/subagents/src/runs/foreground/chain-execution-sequential-step.ts +7 -9
  101. package/dist/builtin/subagents/src/runs/foreground/chain-execution-types.ts +3 -13
  102. package/dist/builtin/subagents/src/runs/foreground/chain-execution.ts +2 -15
  103. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-finalize.ts +2 -2
  104. package/dist/builtin/subagents/src/runs/foreground/execution-attempt.ts +63 -46
  105. package/dist/builtin/subagents/src/runs/foreground/execution-detach-reservations.ts +48 -0
  106. package/dist/builtin/subagents/src/runs/foreground/execution-detach-route.ts +17 -0
  107. package/dist/builtin/subagents/src/runs/foreground/execution-run-sync.ts +39 -26
  108. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-async.ts +3 -1
  109. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-chain.ts +3 -51
  110. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-context.ts +6 -11
  111. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-input.ts +11 -2
  112. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +2 -0
  113. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel.ts +5 -112
  114. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-resume.ts +2 -0
  115. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +68 -118
  116. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-status.ts +79 -7
  117. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-types.ts +2 -2
  118. package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +3 -0
  119. package/dist/builtin/subagents/src/runs/shared/pi-args.ts +2 -2
  120. package/dist/builtin/subagents/src/runs/shared/pi-spawn.ts +55 -12
  121. package/dist/builtin/subagents/src/shared/artifacts.ts +22 -11
  122. package/dist/builtin/subagents/src/shared/event-jsonl-writer.ts +294 -0
  123. package/dist/builtin/subagents/src/shared/exclusive-file-publication.ts +44 -0
  124. package/dist/builtin/subagents/src/shared/jsonl-writer.ts +1 -0
  125. package/dist/builtin/subagents/src/shared/model-info.ts +2 -2
  126. package/dist/builtin/subagents/src/shared/settings.ts +20 -10
  127. package/dist/builtin/subagents/src/shared/types-async.ts +3 -1
  128. package/dist/builtin/subagents/src/shared/types-config.ts +2 -0
  129. package/dist/builtin/subagents/src/shared/types-runtime.ts +3 -2
  130. package/dist/builtin/subagents/src/slash/slash-commands.ts +9 -12
  131. package/dist/builtin/subagents/src/slash/slash-live-state.ts +63 -32
  132. package/dist/builtin/subagents/src/tui/render-result.ts +7 -0
  133. package/dist/builtin/subagents/src/tui/render-stable-output.ts +1 -0
  134. package/dist/builtin/subagents/src/tui/render-widget.ts +157 -89
  135. package/dist/builtin/web-access/CHANGELOG.md +28 -0
  136. package/dist/builtin/web-access/README.md +4 -0
  137. package/dist/builtin/web-access/content-tools.ts +8 -3
  138. package/dist/builtin/web-access/index-heavy.ts +1 -1
  139. package/dist/builtin/web-access/index.ts +190 -46
  140. package/dist/builtin/web-access/lifecycle-lease.ts +38 -0
  141. package/dist/builtin/web-access/package.json +2 -2
  142. package/dist/builtin/web-access/result-renderers.ts +1 -1
  143. package/dist/builtin/web-access/summary-review.ts +1 -1
  144. package/dist/builtin/web-access/web-search-activity.ts +1 -1
  145. package/dist/builtin/web-access/web-search-return.ts +7 -0
  146. package/dist/builtin/web-access/web-search-summary.ts +1 -1
  147. package/dist/builtin/web-access/web-search-tool.ts +4 -2
  148. package/dist/builtin/workflows/CHANGELOG.md +86 -0
  149. package/dist/builtin/workflows/README.md +5 -5
  150. package/dist/builtin/workflows/builtin/deep-research-codebase-utils.ts +27 -4
  151. package/dist/builtin/workflows/builtin/goal-runner.ts +86 -27
  152. package/dist/builtin/workflows/builtin/open-claude-design-runner.ts +10 -0
  153. package/dist/builtin/workflows/builtin/ralph-core.ts +9 -9
  154. package/dist/builtin/workflows/builtin/ralph-models.ts +71 -36
  155. package/dist/builtin/workflows/builtin/ralph-runner.ts +20 -31
  156. package/dist/builtin/workflows/package.json +2 -2
  157. package/dist/builtin/workflows/skills/impeccable/SKILL.md +16 -13
  158. package/dist/builtin/workflows/skills/impeccable/reference/adapt.md +1 -0
  159. package/dist/builtin/workflows/skills/impeccable/reference/adapt.native.md +58 -0
  160. package/dist/builtin/workflows/skills/impeccable/reference/android.md +40 -0
  161. package/dist/builtin/workflows/skills/impeccable/reference/animate.md +2 -0
  162. package/dist/builtin/workflows/skills/impeccable/reference/audit.md +2 -0
  163. package/dist/builtin/workflows/skills/impeccable/reference/audit.native.md +139 -0
  164. package/dist/builtin/workflows/skills/impeccable/reference/bolder.md +69 -62
  165. package/dist/builtin/workflows/skills/impeccable/reference/critique.md +21 -7
  166. package/dist/builtin/workflows/skills/impeccable/reference/document.md +1 -1
  167. package/dist/builtin/workflows/skills/impeccable/reference/hooks.md +92 -0
  168. package/dist/builtin/workflows/skills/impeccable/reference/init.md +29 -7
  169. package/dist/builtin/workflows/skills/impeccable/reference/ios.md +45 -0
  170. package/dist/builtin/workflows/skills/impeccable/reference/layout.md +25 -1
  171. package/dist/builtin/workflows/skills/impeccable/reference/typeset.md +23 -1
  172. package/dist/builtin/workflows/skills/impeccable/scripts/context-signals.mjs +2 -1
  173. package/dist/builtin/workflows/skills/impeccable/scripts/context.mjs +75 -14
  174. package/dist/builtin/workflows/skills/impeccable/scripts/detector/browser/injected/index.mjs +1 -1
  175. package/dist/builtin/workflows/skills/impeccable/scripts/detector/cli/main.mjs +31 -0
  176. package/dist/builtin/workflows/skills/impeccable/scripts/detector/design-system.mjs +64 -0
  177. package/dist/builtin/workflows/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +118 -11
  178. package/dist/builtin/workflows/skills/impeccable/scripts/detector/engines/regex/detect-text.mjs +16 -11
  179. package/dist/builtin/workflows/skills/impeccable/scripts/detector/registry/antipatterns.mjs +66 -0
  180. package/dist/builtin/workflows/skills/impeccable/scripts/detector/rules/checks.mjs +42 -10
  181. package/dist/builtin/workflows/skills/impeccable/scripts/detector/shared/fonts.mjs +30 -0
  182. package/dist/builtin/workflows/skills/impeccable/scripts/detector/shared/page.mjs +4 -6
  183. package/dist/builtin/workflows/skills/impeccable/scripts/hook-admin.mjs +660 -0
  184. package/dist/builtin/workflows/skills/impeccable/scripts/hook-before-edit.mjs +516 -0
  185. package/dist/builtin/workflows/skills/impeccable/scripts/hook-lib.mjs +1764 -0
  186. package/dist/builtin/workflows/skills/impeccable/scripts/hook.mjs +61 -0
  187. package/dist/builtin/workflows/skills/impeccable/scripts/lib/impeccable-config.mjs +4 -2
  188. package/dist/builtin/workflows/skills/impeccable/scripts/lib/is-generated.mjs +2 -2
  189. package/dist/builtin/workflows/skills/impeccable/scripts/live/svelte-component.mjs +13 -16
  190. package/dist/builtin/workflows/skills/impeccable/scripts/live-accept.mjs +17 -11
  191. package/dist/builtin/workflows/skills/impeccable/scripts/live-browser.js +104 -37
  192. package/dist/builtin/workflows/skills/impeccable/scripts/live-wrap.mjs +9 -0
  193. package/dist/builtin/workflows/src/durable/backend.ts +12 -0
  194. package/dist/builtin/workflows/src/durable/dbos-backend.ts +17 -1
  195. package/dist/builtin/workflows/src/durable/resume-catalog.ts +12 -0
  196. package/dist/builtin/workflows/src/durable/resume-runtime.ts +5 -2
  197. package/dist/builtin/workflows/src/durable/stage-primitive.ts +2 -1
  198. package/dist/builtin/workflows/src/durable/types.ts +16 -0
  199. package/dist/builtin/workflows/src/engine/primitives/task.ts +3 -1
  200. package/dist/builtin/workflows/src/engine/run-durable-finalize.ts +1 -2
  201. package/dist/builtin/workflows/src/engine/run-returned-status.ts +50 -16
  202. package/dist/builtin/workflows/src/engine/run.ts +20 -19
  203. package/dist/builtin/workflows/src/engine/runtime.ts +5 -0
  204. package/dist/builtin/workflows/src/extension/extension-factory.ts +3 -0
  205. package/dist/builtin/workflows/src/extension/extension-lifecycle.ts +9 -2
  206. package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +137 -27
  207. package/dist/builtin/workflows/src/extension/lifecycle-notifications.ts +22 -6
  208. package/dist/builtin/workflows/src/extension/public-types.ts +1 -1
  209. package/dist/builtin/workflows/src/extension/workflow-command-completions.ts +13 -1
  210. package/dist/builtin/workflows/src/extension/workflow-command-registration.ts +19 -4
  211. package/dist/builtin/workflows/src/extension/workflow-command-surfaces.ts +9 -0
  212. package/dist/builtin/workflows/src/extension/workflow-prompts.ts +17 -22
  213. package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +48 -23
  214. package/dist/builtin/workflows/src/extension/workflow-schema.ts +15 -2
  215. package/dist/builtin/workflows/src/extension/workflow-tool-control.ts +20 -8
  216. package/dist/builtin/workflows/src/extension/workflow-tool.ts +24 -8
  217. package/dist/builtin/workflows/src/runs/background/status.ts +4 -3
  218. package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +29 -8
  219. package/dist/builtin/workflows/src/runs/foreground/executor-hil.ts +1 -1
  220. package/dist/builtin/workflows/src/runs/foreground/executor-stage-factory.ts +3 -2
  221. package/dist/builtin/workflows/src/runs/shared/model-fallback-candidates.ts +1 -1
  222. package/dist/builtin/workflows/src/runs/shared/worktree-git.ts +155 -20
  223. package/dist/builtin/workflows/src/runs/shared/worktree-types.ts +6 -0
  224. package/dist/builtin/workflows/src/runs/shared/worktree.ts +2 -1
  225. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +2 -2
  226. package/dist/builtin/workflows/src/shared/authoring-contract-stage.ts +2 -2
  227. package/dist/builtin/workflows/src/shared/resume-continuation.ts +2 -0
  228. package/dist/builtin/workflows/src/shared/returned-run-status.ts +116 -0
  229. package/dist/builtin/workflows/src/shared/workflow-failures-decisions.ts +2 -0
  230. package/dist/builtin/workflows/src/tui/graph-view-render-helpers.ts +21 -3
  231. package/dist/builtin/workflows/src/tui/graph-view-state.ts +3 -0
  232. package/dist/builtin/workflows/src/tui/graph-view-types.ts +3 -0
  233. package/dist/builtin/workflows/src/tui/stage-chat-view-archive-history.ts +1 -23
  234. package/dist/builtin/workflows/src/tui/stage-chat-view-footer-status.ts +54 -9
  235. package/dist/builtin/workflows/src/tui/stage-chat-view.ts +5 -2
  236. package/dist/builtin/workflows/src/tui/status-list.ts +22 -15
  237. package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +4 -4
  238. package/dist/cli/args.d.ts.map +1 -1
  239. package/dist/cli/args.js +2 -2
  240. package/dist/cli/args.js.map +1 -1
  241. package/dist/core/agent-session-auto-compaction.d.ts +23 -3
  242. package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
  243. package/dist/core/agent-session-auto-compaction.js +129 -17
  244. package/dist/core/agent-session-auto-compaction.js.map +1 -1
  245. package/dist/core/agent-session-events.d.ts.map +1 -1
  246. package/dist/core/agent-session-events.js +9 -1
  247. package/dist/core/agent-session-events.js.map +1 -1
  248. package/dist/core/agent-session-message-queue.d.ts.map +1 -1
  249. package/dist/core/agent-session-message-queue.js +1 -1
  250. package/dist/core/agent-session-message-queue.js.map +1 -1
  251. package/dist/core/agent-session-methods.d.ts +6 -3
  252. package/dist/core/agent-session-methods.d.ts.map +1 -1
  253. package/dist/core/agent-session-methods.js.map +1 -1
  254. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  255. package/dist/core/agent-session-prompt.js +2 -2
  256. package/dist/core/agent-session-prompt.js.map +1 -1
  257. package/dist/core/agent-session-retry.d.ts.map +1 -1
  258. package/dist/core/agent-session-retry.js +1 -1
  259. package/dist/core/agent-session-retry.js.map +1 -1
  260. package/dist/core/agent-session-services.d.ts.map +1 -1
  261. package/dist/core/agent-session-services.js +3 -2
  262. package/dist/core/agent-session-services.js.map +1 -1
  263. package/dist/core/agent-session-types.d.ts.map +1 -1
  264. package/dist/core/agent-session-types.js +1 -1
  265. package/dist/core/agent-session-types.js.map +1 -1
  266. package/dist/core/agent-session.d.ts +4 -2
  267. package/dist/core/agent-session.d.ts.map +1 -1
  268. package/dist/core/agent-session.js +4 -2
  269. package/dist/core/agent-session.js.map +1 -1
  270. package/dist/core/anthropic-thinking-guard.d.ts +5 -5
  271. package/dist/core/anthropic-thinking-guard.d.ts.map +1 -1
  272. package/dist/core/anthropic-thinking-guard.js +42 -32
  273. package/dist/core/anthropic-thinking-guard.js.map +1 -1
  274. package/dist/core/atomic-guide-command.d.ts.map +1 -1
  275. package/dist/core/atomic-guide-command.js +15 -15
  276. package/dist/core/atomic-guide-command.js.map +1 -1
  277. package/dist/core/auth-storage.d.ts.map +1 -1
  278. package/dist/core/auth-storage.js +14 -9
  279. package/dist/core/auth-storage.js.map +1 -1
  280. package/dist/core/compaction/compaction.d.ts +2 -0
  281. package/dist/core/compaction/compaction.d.ts.map +1 -1
  282. package/dist/core/compaction/compaction.js +79 -46
  283. package/dist/core/compaction/compaction.js.map +1 -1
  284. package/dist/core/compaction/context-assistant-turns.d.ts +42 -0
  285. package/dist/core/compaction/context-assistant-turns.d.ts.map +1 -0
  286. package/dist/core/compaction/context-assistant-turns.js +87 -0
  287. package/dist/core/compaction/context-assistant-turns.js.map +1 -0
  288. package/dist/core/compaction/context-compaction-critical.d.ts +1 -1
  289. package/dist/core/compaction/context-compaction-critical.d.ts.map +1 -1
  290. package/dist/core/compaction/context-compaction-critical.js +2 -2
  291. package/dist/core/compaction/context-compaction-critical.js.map +1 -1
  292. package/dist/core/compaction/context-compaction-eviction-alternates.d.ts +18 -0
  293. package/dist/core/compaction/context-compaction-eviction-alternates.d.ts.map +1 -0
  294. package/dist/core/compaction/context-compaction-eviction-alternates.js +186 -0
  295. package/dist/core/compaction/context-compaction-eviction-alternates.js.map +1 -0
  296. package/dist/core/compaction/context-compaction-eviction.d.ts +10 -2
  297. package/dist/core/compaction/context-compaction-eviction.d.ts.map +1 -1
  298. package/dist/core/compaction/context-compaction-eviction.js +196 -146
  299. package/dist/core/compaction/context-compaction-eviction.js.map +1 -1
  300. package/dist/core/compaction/context-compaction-prompt.d.ts.map +1 -1
  301. package/dist/core/compaction/context-compaction-prompt.js +1 -1
  302. package/dist/core/compaction/context-compaction-prompt.js.map +1 -1
  303. package/dist/core/compaction/context-compaction-types.d.ts +2 -0
  304. package/dist/core/compaction/context-compaction-types.d.ts.map +1 -1
  305. package/dist/core/compaction/context-compaction-types.js.map +1 -1
  306. package/dist/core/compaction/context-deletion-application.d.ts +5 -4
  307. package/dist/core/compaction/context-deletion-application.d.ts.map +1 -1
  308. package/dist/core/compaction/context-deletion-application.js +17 -15
  309. package/dist/core/compaction/context-deletion-application.js.map +1 -1
  310. package/dist/core/compaction/context-deletion-store.d.ts.map +1 -1
  311. package/dist/core/compaction/context-deletion-store.js +1 -1
  312. package/dist/core/compaction/context-deletion-store.js.map +1 -1
  313. package/dist/core/compaction/context-deletion-targets.d.ts +2 -1
  314. package/dist/core/compaction/context-deletion-targets.d.ts.map +1 -1
  315. package/dist/core/compaction/context-deletion-targets.js +36 -31
  316. package/dist/core/compaction/context-deletion-targets.js.map +1 -1
  317. package/dist/core/compaction/context-deletion-tool-helpers.d.ts.map +1 -1
  318. package/dist/core/compaction/context-deletion-tool-helpers.js +116 -43
  319. package/dist/core/compaction/context-deletion-tool-helpers.js.map +1 -1
  320. package/dist/core/compaction/context-transcript-analysis.d.ts +1 -2
  321. package/dist/core/compaction/context-transcript-analysis.d.ts.map +1 -1
  322. package/dist/core/compaction/context-transcript-analysis.js +33 -37
  323. package/dist/core/compaction/context-transcript-analysis.js.map +1 -1
  324. package/dist/core/copilot-model-synthesis.d.ts.map +1 -1
  325. package/dist/core/copilot-model-synthesis.js +3 -1
  326. package/dist/core/copilot-model-synthesis.js.map +1 -1
  327. package/dist/core/extensions/loader-virtual-modules.d.ts +8 -1
  328. package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
  329. package/dist/core/extensions/loader-virtual-modules.js +2 -1
  330. package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
  331. package/dist/core/extensions/provider-types.d.ts +2 -7
  332. package/dist/core/extensions/provider-types.d.ts.map +1 -1
  333. package/dist/core/extensions/provider-types.js.map +1 -1
  334. package/dist/core/footer-data-provider.d.ts +6 -0
  335. package/dist/core/footer-data-provider.d.ts.map +1 -1
  336. package/dist/core/footer-data-provider.js +72 -29
  337. package/dist/core/footer-data-provider.js.map +1 -1
  338. package/dist/core/messages.d.ts +9 -0
  339. package/dist/core/messages.d.ts.map +1 -1
  340. package/dist/core/messages.js +100 -18
  341. package/dist/core/messages.js.map +1 -1
  342. package/dist/core/model-registry-builtins.d.ts.map +1 -1
  343. package/dist/core/model-registry-builtins.js +5 -0
  344. package/dist/core/model-registry-builtins.js.map +1 -1
  345. package/dist/core/model-registry-custom-loader.d.ts.map +1 -1
  346. package/dist/core/model-registry-custom-loader.js +49 -8
  347. package/dist/core/model-registry-custom-loader.js.map +1 -1
  348. package/dist/core/model-registry-dynamic.d.ts.map +1 -1
  349. package/dist/core/model-registry-dynamic.js +11 -5
  350. package/dist/core/model-registry-dynamic.js.map +1 -1
  351. package/dist/core/model-registry-loader.d.ts.map +1 -1
  352. package/dist/core/model-registry-loader.js +8 -0
  353. package/dist/core/model-registry-loader.js.map +1 -1
  354. package/dist/core/model-registry-schemas.d.ts +93 -8
  355. package/dist/core/model-registry-schemas.d.ts.map +1 -1
  356. package/dist/core/model-registry-schemas.js +24 -12
  357. package/dist/core/model-registry-schemas.js.map +1 -1
  358. package/dist/core/model-registry-types.d.ts +7 -6
  359. package/dist/core/model-registry-types.d.ts.map +1 -1
  360. package/dist/core/model-registry-types.js.map +1 -1
  361. package/dist/core/model-registry.d.ts +5 -0
  362. package/dist/core/model-registry.d.ts.map +1 -1
  363. package/dist/core/model-registry.js +23 -0
  364. package/dist/core/model-registry.js.map +1 -1
  365. package/dist/core/model-resolver-cli.d.ts.map +1 -1
  366. package/dist/core/model-resolver-cli.js +33 -5
  367. package/dist/core/model-resolver-cli.js.map +1 -1
  368. package/dist/core/model-resolver-initial.d.ts +6 -1
  369. package/dist/core/model-resolver-initial.d.ts.map +1 -1
  370. package/dist/core/model-resolver-initial.js +12 -7
  371. package/dist/core/model-resolver-initial.js.map +1 -1
  372. package/dist/core/model-resolver.d.ts +1 -1
  373. package/dist/core/model-resolver.d.ts.map +1 -1
  374. package/dist/core/model-resolver.js +1 -1
  375. package/dist/core/model-resolver.js.map +1 -1
  376. package/dist/core/openai-responses-payload-sanitizer.d.ts +1 -0
  377. package/dist/core/openai-responses-payload-sanitizer.d.ts.map +1 -1
  378. package/dist/core/openai-responses-payload-sanitizer.js +24 -9
  379. package/dist/core/openai-responses-payload-sanitizer.js.map +1 -1
  380. package/dist/core/resource-loader-context-files.d.ts +1 -0
  381. package/dist/core/resource-loader-context-files.d.ts.map +1 -1
  382. package/dist/core/resource-loader-context-files.js +13 -10
  383. package/dist/core/resource-loader-context-files.js.map +1 -1
  384. package/dist/core/sdk.d.ts.map +1 -1
  385. package/dist/core/sdk.js +2 -2
  386. package/dist/core/sdk.js.map +1 -1
  387. package/dist/core/session-entry-normalization.d.ts +7 -0
  388. package/dist/core/session-entry-normalization.d.ts.map +1 -0
  389. package/dist/core/session-entry-normalization.js +14 -0
  390. package/dist/core/session-entry-normalization.js.map +1 -0
  391. package/dist/core/session-manager-core.d.ts.map +1 -1
  392. package/dist/core/session-manager-core.js +1 -0
  393. package/dist/core/session-manager-core.js.map +1 -1
  394. package/dist/core/session-manager-history.d.ts +2 -2
  395. package/dist/core/session-manager-history.d.ts.map +1 -1
  396. package/dist/core/session-manager-history.js +127 -108
  397. package/dist/core/session-manager-history.js.map +1 -1
  398. package/dist/core/settings-manager-basic-accessors.d.ts +2 -2
  399. package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
  400. package/dist/core/settings-manager-basic-accessors.js.map +1 -1
  401. package/dist/core/settings-types.d.ts +1 -1
  402. package/dist/core/settings-types.d.ts.map +1 -1
  403. package/dist/core/settings-types.js.map +1 -1
  404. package/dist/core/slash-commands.d.ts +2 -0
  405. package/dist/core/slash-commands.d.ts.map +1 -1
  406. package/dist/core/slash-commands.js +141 -0
  407. package/dist/core/slash-commands.js.map +1 -1
  408. package/dist/core/tools/bash.d.ts.map +1 -1
  409. package/dist/core/tools/bash.js +11 -8
  410. package/dist/core/tools/bash.js.map +1 -1
  411. package/dist/index.d.ts +1 -0
  412. package/dist/index.d.ts.map +1 -1
  413. package/dist/index.js +1 -0
  414. package/dist/index.js.map +1 -1
  415. package/dist/main-deferred-startup.d.ts.map +1 -1
  416. package/dist/main-deferred-startup.js +2 -2
  417. package/dist/main-deferred-startup.js.map +1 -1
  418. package/dist/main-early-input.d.ts.map +1 -1
  419. package/dist/main-early-input.js +7 -0
  420. package/dist/main-early-input.js.map +1 -1
  421. package/dist/main-session.d.ts.map +1 -1
  422. package/dist/main-session.js +1 -0
  423. package/dist/main-session.js.map +1 -1
  424. package/dist/main.d.ts.map +1 -1
  425. package/dist/main.js +1 -1
  426. package/dist/main.js.map +1 -1
  427. package/dist/modes/interactive/components/chat-session-host-actions.d.ts.map +1 -1
  428. package/dist/modes/interactive/components/chat-session-host-actions.js +0 -1
  429. package/dist/modes/interactive/components/chat-session-host-actions.js.map +1 -1
  430. package/dist/modes/interactive/components/settings-selector-options.d.ts.map +1 -1
  431. package/dist/modes/interactive/components/settings-selector-options.js +3 -1
  432. package/dist/modes/interactive/components/settings-selector-options.js.map +1 -1
  433. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  434. package/dist/modes/interactive/components/thinking-selector.js +2 -1
  435. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  436. package/dist/modes/interactive/interactive-agent-events.d.ts.map +1 -1
  437. package/dist/modes/interactive/interactive-agent-events.js +3 -1
  438. package/dist/modes/interactive/interactive-agent-events.js.map +1 -1
  439. package/dist/modes/interactive/interactive-autocomplete.d.ts.map +1 -1
  440. package/dist/modes/interactive/interactive-autocomplete.js +21 -9
  441. package/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
  442. package/dist/modes/interactive/interactive-child-ordering.d.ts +7 -0
  443. package/dist/modes/interactive/interactive-child-ordering.d.ts.map +1 -0
  444. package/dist/modes/interactive/interactive-child-ordering.js +26 -0
  445. package/dist/modes/interactive/interactive-child-ordering.js.map +1 -0
  446. package/dist/modes/interactive/interactive-deferred-startup.d.ts.map +1 -1
  447. package/dist/modes/interactive/interactive-deferred-startup.js +43 -30
  448. package/dist/modes/interactive/interactive-deferred-startup.js.map +1 -1
  449. package/dist/modes/interactive/interactive-hotkeys-debug.d.ts.map +1 -1
  450. package/dist/modes/interactive/interactive-hotkeys-debug.js +1 -0
  451. package/dist/modes/interactive/interactive-hotkeys-debug.js.map +1 -1
  452. package/dist/modes/interactive/interactive-input-handling.d.ts.map +1 -1
  453. package/dist/modes/interactive/interactive-input-handling.js +41 -6
  454. package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
  455. package/dist/modes/interactive/interactive-mode-base.d.ts +3 -0
  456. package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
  457. package/dist/modes/interactive/interactive-mode-base.js +3 -0
  458. package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
  459. package/dist/modes/interactive/interactive-mode-deps.d.ts +2 -2
  460. package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -1
  461. package/dist/modes/interactive/interactive-mode-deps.js +2 -2
  462. package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
  463. package/dist/modes/interactive/interactive-mode-surface.d.ts +2 -2
  464. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  465. package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
  466. package/dist/modes/interactive/interactive-model-routing.d.ts.map +1 -1
  467. package/dist/modes/interactive/interactive-model-routing.js +11 -4
  468. package/dist/modes/interactive/interactive-model-routing.js.map +1 -1
  469. package/dist/modes/interactive/interactive-process-lifecycle.d.ts.map +1 -1
  470. package/dist/modes/interactive/interactive-process-lifecycle.js +0 -3
  471. package/dist/modes/interactive/interactive-process-lifecycle.js.map +1 -1
  472. package/dist/modes/interactive/interactive-render-chat.d.ts.map +1 -1
  473. package/dist/modes/interactive/interactive-render-chat.js +15 -1
  474. package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
  475. package/dist/modes/interactive/interactive-session-routing.d.ts.map +1 -1
  476. package/dist/modes/interactive/interactive-session-routing.js +5 -1
  477. package/dist/modes/interactive/interactive-session-routing.js.map +1 -1
  478. package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
  479. package/dist/modes/interactive/interactive-startup.js +20 -21
  480. package/dist/modes/interactive/interactive-startup.js.map +1 -1
  481. package/dist/modes/interactive/theme/global-theme.d.ts.map +1 -1
  482. package/dist/modes/interactive/theme/global-theme.js +26 -2
  483. package/dist/modes/interactive/theme/global-theme.js.map +1 -1
  484. package/dist/modes/interactive/theme/theme-class.d.ts +1 -1
  485. package/dist/modes/interactive/theme/theme-class.d.ts.map +1 -1
  486. package/dist/modes/interactive/theme/theme-class.js +2 -0
  487. package/dist/modes/interactive/theme/theme-class.js.map +1 -1
  488. package/dist/utils/clipboard-image.d.ts.map +1 -1
  489. package/dist/utils/clipboard-image.js +3 -0
  490. package/dist/utils/clipboard-image.js.map +1 -1
  491. package/dist/utils/fs-watch.d.ts +24 -1
  492. package/dist/utils/fs-watch.d.ts.map +1 -1
  493. package/dist/utils/fs-watch.js +60 -5
  494. package/dist/utils/fs-watch.js.map +1 -1
  495. package/docs/changelog.mdx +19 -0
  496. package/docs/compaction.md +60 -49
  497. package/docs/custom-provider.md +18 -5
  498. package/docs/development.md +4 -0
  499. package/docs/extensions.md +11 -2
  500. package/docs/json.md +1 -1
  501. package/docs/models.md +69 -10
  502. package/docs/providers.md +1 -1
  503. package/docs/quickstart.md +12 -8
  504. package/docs/rpc.md +2 -2
  505. package/docs/sdk.md +1 -1
  506. package/docs/settings.md +4 -4
  507. package/docs/subagents.md +40 -5
  508. package/docs/tools.md +1 -1
  509. package/docs/usage.md +4 -2
  510. package/docs/windows.md +4 -0
  511. package/docs/workflows.md +33 -48
  512. package/examples/extensions/preset.ts +2 -2
  513. package/examples/extensions/subagent/README.md +2 -2
  514. package/examples/extensions/subagent/index.ts +1 -2
  515. package/examples/extensions/subagent/schemas.ts +4 -1
  516. package/examples/sdk/12-full-control.ts +1 -1
  517. package/npm-shrinkwrap.json +48 -51
  518. package/package.json +7 -7
  519. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-behavior.ts +0 -75
  520. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-component.ts +0 -202
  521. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-edit.ts +0 -97
  522. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-editor.ts +0 -160
  523. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-frame.ts +0 -72
  524. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-render-modes.ts +0 -161
  525. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-render-selectors.ts +0 -203
  526. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-selectors.ts +0 -234
  527. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-state.ts +0 -103
  528. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-types.ts +0 -29
  529. package/dist/builtin/subagents/src/runs/foreground/chain-clarify.ts +0 -9
  530. package/dist/builtin/subagents/src/runs/foreground/chain-execution-clarify.ts +0 -117
@@ -1,85 +1,47 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
- import { buildCompletionKey, markSeenWithTtl } from "./completion-dedupe.ts";
4
- import { createFileCoalescer } from "../../shared/file-coalescer.ts";
5
- import {
6
- SUBAGENT_ASYNC_COMPLETE_EVENT,
7
- type IntercomEventBus,
8
- type NestedRunSummary,
9
- type SubagentResultIntercomChild,
10
- type SubagentState,
11
- } from "../../shared/types.ts";
12
- import {
13
- attachNestedChildrenToResultChildren,
14
- buildSubagentResultIntercomPayload,
15
- compactNestedResultChildren,
16
- deliverSubagentResultIntercomEvent,
17
- resolveSubagentResultStatus,
18
- } from "../../intercom/result-intercom.ts";
19
- import { projectNestedRegistryForRoot, sanitizeSummary } from "../shared/nested-events.ts";
3
+ import { isSafeFsWatchPathError, watchWithErrorHandler } from "@bastani/atomic";
4
+ import { createFileCoalescer } from "../../shared/file-coalescer.js";
5
+ import type { IntercomEventBus, SubagentState } from "../../shared/types.js";
6
+ import { processResultEntry, type ResultProcessorFs } from "./result-delivery-processor.js";
7
+ import { claimIdFromScheduleKey, claimScheduleKey, listResultClaims } from "./result-file-claims.js";
8
+ import { createRetryScheduler } from "./result-retry-scheduler.js";
9
+ import type { ResultFileData } from "./result-watcher-data.js";
20
10
 
21
11
  const WATCHER_RESTART_DELAY_MS = 3000;
22
12
  const POLL_INTERVAL_MS = 3000;
13
+ const DIRECTORY_RESCAN_DELAY_MS = 50;
14
+ const STATUS_RECHECK_BASE_MS = 250;
15
+ const STATUS_RECHECK_MAX_MS = 30_000;
16
+ const DELIVERY_RETRY_BASE_MS = 1000;
17
+ const DELIVERY_RETRY_MAX_MS = 30_000;
23
18
 
24
- type ResultWatcherFs = Pick<typeof fs, "existsSync" | "readFileSync" | "unlinkSync" | "readdirSync" | "mkdirSync" | "watch">;
25
-
19
+ type ResultWatcherFs = ResultProcessorFs & Pick<typeof fs, "existsSync" | "readdirSync" | "mkdirSync" | "watch">;
26
20
  type ResultWatcherTimers = {
27
21
  setTimeout: typeof setTimeout;
28
22
  clearTimeout: typeof clearTimeout;
29
23
  setInterval: typeof setInterval;
30
24
  clearInterval: typeof clearInterval;
31
25
  };
26
+ type ResultWatcherSafeWatch = typeof watchWithErrorHandler;
32
27
 
33
28
  type ResultWatcherDeps = {
34
29
  fs?: ResultWatcherFs;
35
30
  timers?: ResultWatcherTimers;
31
+ safeWatch?: ResultWatcherSafeWatch;
32
+ statusRecheckBaseMs?: number;
33
+ statusRecheckMaxMs?: number;
34
+ deliveryRetryBaseMs?: number;
35
+ deliveryRetryMaxMs?: number;
36
+ maxNoProgressFailures?: number;
37
+ intercomTimeoutMs?: number | false;
38
+ allowedStatusRoots?: string[];
39
+ maxStatusBytes?: number;
36
40
  };
37
41
 
38
- type ResultFileChild = {
39
- agent?: string;
40
- output?: string;
41
- error?: string;
42
- success?: boolean;
43
- sessionFile?: string;
44
- artifactPaths?: { outputPath?: string };
45
- intercomTarget?: string;
46
- children?: unknown;
47
- };
48
-
49
- type ResultFileData = {
50
- id?: string;
51
- runId?: string;
52
- agent?: string;
53
- success?: boolean;
54
- state?: string;
55
- mode?: string;
56
- summary?: string;
57
- results?: ResultFileChild[];
58
- nestedChildren?: unknown;
59
- sessionId?: string;
60
- cwd?: string;
61
- sessionFile?: string;
62
- asyncDir?: string;
63
- intercomTarget?: string;
64
- };
65
-
66
- function sanitizeNestedResultChildren(value: unknown, resultPath: string, label: string): NestedRunSummary[] | undefined {
67
- if (value === undefined) return undefined;
68
- if (!Array.isArray(value)) {
69
- console.error(`Ignoring invalid nested children in subagent result file '${resultPath}' at ${label}: expected an array.`);
70
- return undefined;
71
- }
72
- const children = value.map((child) => sanitizeSummary(child)).filter((child): child is NestedRunSummary => Boolean(child));
73
- if (children.length !== value.length) {
74
- console.error(`Ignoring ${value.length - children.length} invalid nested child record(s) in subagent result file '${resultPath}' at ${label}.`);
75
- }
76
- return children.length ? children : undefined;
77
- }
78
-
79
42
  function getErrorCode(error: unknown): string | undefined {
80
43
  return typeof error === "object" && error !== null && "code" in error
81
- ? (error as NodeJS.ErrnoException).code
82
- : undefined;
44
+ ? (error as NodeJS.ErrnoException).code : undefined;
83
45
  }
84
46
 
85
47
  function isNotFoundError(error: unknown): boolean {
@@ -88,7 +50,7 @@ function isNotFoundError(error: unknown): boolean {
88
50
 
89
51
  function shouldFallBackToPolling(error: unknown): boolean {
90
52
  const code = getErrorCode(error);
91
- return code === "EMFILE" || code === "ENOSPC";
53
+ return code === "EMFILE" || code === "ENOSPC" || isSafeFsWatchPathError(error);
92
54
  }
93
55
 
94
56
  export function createResultWatcher(
@@ -97,211 +59,193 @@ export function createResultWatcher(
97
59
  resultsDir: string,
98
60
  completionTtlMs: number,
99
61
  deps: ResultWatcherDeps = {},
100
- ): {
101
- startResultWatcher: () => void;
102
- primeExistingResults: () => void;
103
- stopResultWatcher: () => void;
104
- } {
62
+ ): { startResultWatcher: () => void; primeExistingResults: () => void; stopResultWatcher: () => void } {
105
63
  const fsApi = deps.fs ?? fs;
106
64
  const timers = deps.timers ?? { setTimeout, clearTimeout, setInterval, clearInterval };
65
+ const safeWatch = deps.safeWatch ?? watchWithErrorHandler;
66
+ let directoryRescanTimer: ReturnType<typeof setTimeout> | null = null;
67
+ let stopped = false;
68
+ let processingEpoch = 0;
69
+ let watcherInstallation = 0;
70
+ let activeWatcherInstallation = 0;
71
+ const inFlight = new Set<string>();
72
+ const rerunAfterFlight = new Set<string>();
73
+ const statusRetries = createRetryScheduler(timers, deps.statusRecheckBaseMs ?? STATUS_RECHECK_BASE_MS, deps.statusRecheckMaxMs ?? STATUS_RECHECK_MAX_MS);
74
+ const deliveryRetries = createRetryScheduler(timers, deps.deliveryRetryBaseMs ?? DELIVERY_RETRY_BASE_MS, deps.deliveryRetryMaxMs ?? DELIVERY_RETRY_MAX_MS);
75
+ const isEpochActive = (epoch: number): boolean => !stopped && epoch === processingEpoch;
76
+ const entryExists = (entry: string): boolean => {
77
+ const claimId = claimIdFromScheduleKey(entry);
78
+ return claimId ? Boolean(listResultClaims(resultsDir, fsApi).some((claim) => claim.id === claimId))
79
+ : fsApi.existsSync(path.join(resultsDir, entry));
80
+ };
81
+ const ownsResult = (data: ResultFileData): boolean => !stopped
82
+ && (!data.sessionId || data.sessionId === state.currentSessionId)
83
+ && Boolean(data.sessionId || !data.cwd || (state.baseCwd && data.cwd === state.baseCwd));
84
+
85
+ const coalescerKey = (entry: string, epoch: number): string => `${epoch}\0${entry}`;
86
+ const parseCoalescerKey = (key: string): { epoch: number; entry: string } => {
87
+ const split = key.indexOf("\0");
88
+ return { epoch: Number(key.slice(0, split)), entry: key.slice(split + 1) };
89
+ };
90
+ const scheduleResultEntry = (entry: string, delay = 0, epoch = processingEpoch): boolean => {
91
+ if (!isEpochActive(epoch) || statusRetries.has(entry) || deliveryRetries.has(entry)) return false;
92
+ return state.resultFileCoalescer.schedule(coalescerKey(entry, epoch), delay);
93
+ };
94
+ const scheduleStatusRecheck = (entry: string, epoch: number) => {
95
+ if (!isEpochActive(epoch)) return;
96
+ statusRetries.schedule(entry, () => {
97
+ if (!isEpochActive(epoch) || !entryExists(entry)) { statusRetries.clear(entry); return; }
98
+ scheduleResultEntry(entry, 0, epoch);
99
+ });
100
+ };
101
+ const scheduleDeliveryRetry = (entry: string, epoch: number) => {
102
+ if (!isEpochActive(epoch)) return;
103
+ deliveryRetries.schedule(entry, () => {
104
+ if (!isEpochActive(epoch) || !entryExists(entry)) { deliveryRetries.clear(entry); return; }
105
+ scheduleResultEntry(entry, 0, epoch);
106
+ });
107
+ };
107
108
 
108
- const handleResult = async (file: string) => {
109
- const resultPath = path.join(resultsDir, file);
110
- if (!fsApi.existsSync(resultPath)) return;
109
+ const handleResult = async (entry: string, epoch: number) => {
110
+ if (!isEpochActive(epoch)) return;
111
+ const flightKey = coalescerKey(entry, epoch);
112
+ if (inFlight.has(flightKey)) { rerunAfterFlight.add(flightKey); return; }
113
+ inFlight.add(flightKey);
111
114
  try {
112
- const data = JSON.parse(fsApi.readFileSync(resultPath, "utf-8")) as ResultFileData;
113
- if (data.sessionId && data.sessionId !== state.currentSessionId) return;
114
- if (!data.sessionId && data.cwd && (!state.baseCwd || data.cwd !== state.baseCwd)) return;
115
-
116
- const runId = data.runId ?? data.id ?? file.replace(/\.json$/i, "");
117
- const hasExplicitNestedChildren = data.nestedChildren !== undefined;
118
- let nestedChildren = compactNestedResultChildren(sanitizeNestedResultChildren(data.nestedChildren, resultPath, "nestedChildren"));
119
- if (!nestedChildren?.length && !hasExplicitNestedChildren) {
120
- try {
121
- nestedChildren = compactNestedResultChildren(projectNestedRegistryForRoot(runId)?.children);
122
- } catch (error) {
123
- console.error(`Failed to enrich subagent result file '${resultPath}' with nested registry children; will retry later:`, error);
124
- return;
125
- }
126
- }
127
- const now = Date.now();
128
- const completionKey = buildCompletionKey(data, `result:${file}`);
129
- if (markSeenWithTtl(state.completionSeen, completionKey, now, completionTtlMs)) {
130
- fsApi.unlinkSync(resultPath);
131
- return;
132
- }
133
-
134
- const hasResultChildren = Array.isArray(data.results) && data.results.length > 0;
135
- const resultChildren = hasResultChildren
136
- ? data.results!
137
- : [{
138
- agent: data.agent,
139
- output: data.summary,
140
- success: data.success,
141
- }];
142
- const normalizedChildren = attachNestedChildrenToResultChildren(runId, resultChildren.map((result = {}, index): SubagentResultIntercomChild => {
143
- const baseOutput = result.output ?? data.summary;
144
- const hasRealOutput = typeof baseOutput === "string" && baseOutput.trim().length > 0;
145
- const output = hasRealOutput ? baseOutput : "(no output)";
146
- const summary = result.success === false && result.error
147
- ? `${result.error}${hasRealOutput ? `\n\nOutput:\n${baseOutput}` : ""}`
148
- : output;
149
- const sessionPath = result.sessionFile ?? (resultChildren.length === 1 ? data.sessionFile : undefined);
150
- const childNestedChildren = sanitizeNestedResultChildren(result.children, resultPath, `results[${index}].children`);
151
- return {
152
- agent: result.agent ?? data.agent ?? `step-${index + 1}`,
153
- status: resolveSubagentResultStatus({
154
- success: result.success,
155
- state: data.state === "paused" || typeof result.success !== "boolean" ? data.state : undefined,
156
- }),
157
- summary,
158
- index,
159
- artifactPath: result.artifactPaths?.outputPath,
160
- ...(typeof sessionPath === "string" && fsApi.existsSync(sessionPath) ? { sessionPath } : {}),
161
- ...(result.intercomTarget ? { intercomTarget: result.intercomTarget } : {}),
162
- ...(childNestedChildren ? { children: childNestedChildren } : {}),
163
- };
164
- }), nestedChildren);
165
-
166
- const intercomTarget = data.intercomTarget?.trim();
167
- if (intercomTarget) {
168
- const mode = data.mode === "single" || data.mode === "parallel" || data.mode === "chain"
169
- ? data.mode
170
- : resultChildren.length > 1 ? "chain" : "single";
171
- const payload = buildSubagentResultIntercomPayload({
172
- to: intercomTarget,
173
- runId,
174
- mode,
175
- source: "async",
176
- children: normalizedChildren,
177
- asyncId: data.id,
178
- asyncDir: data.asyncDir,
179
- });
180
- const delivered = await deliverSubagentResultIntercomEvent(pi.events, payload);
181
- if (!delivered) {
182
- console.error(`Subagent async grouped result intercom delivery was not acknowledged for '${resultPath}'.`);
183
- }
184
- }
185
-
186
- pi.events.emit(SUBAGENT_ASYNC_COMPLETE_EVENT, {
187
- ...data,
188
- runId,
189
- ...(nestedChildren?.length ? { nestedChildren } : {}),
190
- ...(Array.isArray(data.results) ? {
191
- results: hasResultChildren
192
- ? normalizedChildren.map((child, index) => ({
193
- ...data.results![index],
194
- agent: child.agent,
195
- status: child.status,
196
- summary: child.summary,
197
- index: child.index,
198
- artifactPath: child.artifactPath,
199
- sessionPath: child.sessionPath,
200
- children: child.children,
201
- }))
202
- : [],
203
- } : {}),
115
+ const outcome = await processResultEntry(entry, {
116
+ pi, state, resultsDir, completionTtlMs, fsApi,
117
+ allowedStatusRoots: deps.allowedStatusRoots,
118
+ maxStatusBytes: deps.maxStatusBytes,
119
+ maxNoProgressFailures: deps.maxNoProgressFailures,
120
+ intercomTimeoutMs: deps.intercomTimeoutMs,
121
+ isActive: () => isEpochActive(epoch),
122
+ ownsResult: (data) => isEpochActive(epoch) && ownsResult(data),
204
123
  });
205
- fsApi.unlinkSync(resultPath);
124
+ const nextEntry = outcome.entry ?? entry;
125
+ if (outcome.status === "status-pending") scheduleStatusRecheck(nextEntry, epoch);
126
+ else if (outcome.status === "delivery-retry") scheduleDeliveryRetry(nextEntry, epoch);
127
+ else { statusRetries.clear(entry); deliveryRetries.clear(entry); }
206
128
  } catch (error) {
207
- if (isNotFoundError(error)) return;
208
- console.error(`Failed to process subagent result file '${resultPath}':`, error);
129
+ if (!isNotFoundError(error)) {
130
+ console.error(`Failed to process subagent result entry '${entry}':`, error);
131
+ if (isEpochActive(epoch) && entryExists(entry)) scheduleDeliveryRetry(entry, epoch);
132
+ }
133
+ } finally {
134
+ inFlight.delete(flightKey);
135
+ if (rerunAfterFlight.delete(flightKey) && entryExists(entry)) scheduleResultEntry(entry, 0, epoch);
209
136
  }
210
137
  };
211
138
 
212
- state.resultFileCoalescer = createFileCoalescer((file) => {
213
- void handleResult(file);
214
- }, 50);
139
+ state.resultFileCoalescer = createFileCoalescer((key) => {
140
+ const { epoch, entry } = parseCoalescerKey(key);
141
+ void handleResult(entry, epoch);
142
+ }, 50, { setTimeout: timers.setTimeout, clearTimeout: timers.clearTimeout });
215
143
 
216
144
  const primeExistingResults = () => {
145
+ if (stopped) return;
146
+ const epoch = processingEpoch;
217
147
  try {
218
- fsApi.readdirSync(resultsDir)
219
- .filter((f) => f.endsWith(".json"))
220
- .forEach((file) => state.resultFileCoalescer.schedule(file, 0));
148
+ for (const file of fsApi.readdirSync(resultsDir)) if (file.endsWith(".json")) scheduleResultEntry(file, 0, epoch);
149
+ for (const claim of listResultClaims(resultsDir, fsApi)) scheduleResultEntry(claimScheduleKey(claim.id), 0, epoch);
221
150
  } catch (error) {
222
- if (isNotFoundError(error)) return;
223
- console.error(`Failed to scan subagent result directory '${resultsDir}':`, error);
151
+ if (!isNotFoundError(error)) console.error(`Failed to scan subagent result directory '${resultsDir}':`, error);
224
152
  }
225
153
  };
154
+ const scheduleDirectoryRescan = (epoch: number) => {
155
+ if (!isEpochActive(epoch)) return;
156
+ if (directoryRescanTimer) timers.clearTimeout(directoryRescanTimer);
157
+ directoryRescanTimer = timers.setTimeout(() => {
158
+ directoryRescanTimer = null;
159
+ if (isEpochActive(epoch)) primeExistingResults();
160
+ }, DIRECTORY_RESCAN_DELAY_MS);
161
+ directoryRescanTimer.unref?.();
162
+ };
226
163
 
227
- const startPollingFallback = (reason: unknown) => {
164
+ const startPollingFallback = (reason: unknown, epoch: number, installation?: number) => {
165
+ if (!isEpochActive(epoch) || (installation !== undefined && installation !== activeWatcherInstallation)) return;
228
166
  state.watcher?.close();
229
167
  state.watcher = null;
168
+ activeWatcherInstallation = 0;
230
169
  if (state.watcherRestartTimer) return;
231
-
232
- console.error(
233
- `Subagent result watcher for '${resultsDir}' fell back to polling because native fs.watch is unavailable (${getErrorCode(reason) ?? "unknown error"}).`,
234
- );
170
+ console.error(`Subagent result watcher for '${resultsDir}' fell back to polling because native fs.watch is unavailable (${getErrorCode(reason) ?? "unknown error"}).`);
235
171
  primeExistingResults();
236
- state.watcherRestartTimer = timers.setInterval(primeExistingResults, POLL_INTERVAL_MS);
172
+ state.watcherRestartTimer = timers.setInterval(() => { if (isEpochActive(epoch)) primeExistingResults(); }, POLL_INTERVAL_MS);
237
173
  state.watcherRestartTimer.unref?.();
238
174
  };
239
175
 
240
- const scheduleRestart = () => {
241
- if (state.watcherRestartTimer) return;
242
- state.watcherRestartTimer = timers.setTimeout(() => {
176
+ function scheduleRestart(epoch: number): void {
177
+ if (!isEpochActive(epoch) || state.watcherRestartTimer) return;
178
+ let timer!: ReturnType<typeof setTimeout>;
179
+ timer = timers.setTimeout(() => {
180
+ if (state.watcherRestartTimer !== timer || !isEpochActive(epoch)) return;
243
181
  state.watcherRestartTimer = null;
244
- try {
245
- fsApi.mkdirSync(resultsDir, { recursive: true });
246
- startResultWatcher();
247
- } catch (error) {
248
- if (shouldFallBackToPolling(error)) {
249
- startPollingFallback(error);
250
- return;
251
- }
252
- console.error(`Failed to restart subagent result watcher for '${resultsDir}':`, error);
253
- scheduleRestart();
182
+ try { fsApi.mkdirSync(resultsDir, { recursive: true }); openResultWatcher(epoch); }
183
+ catch (error) {
184
+ if (!isEpochActive(epoch)) return;
185
+ if (shouldFallBackToPolling(error)) startPollingFallback(error, epoch);
186
+ else { console.error(`Failed to restart subagent result watcher for '${resultsDir}':`, error); scheduleRestart(epoch); }
254
187
  }
255
188
  }, WATCHER_RESTART_DELAY_MS);
256
- state.watcherRestartTimer.unref?.();
257
- };
189
+ state.watcherRestartTimer = timer;
190
+ timer.unref?.();
191
+ }
258
192
 
259
- const startResultWatcher = () => {
260
- if (state.watcher) return;
261
- if (state.watcherRestartTimer) {
262
- timers.clearTimeout(state.watcherRestartTimer);
263
- timers.clearInterval(state.watcherRestartTimer);
264
- state.watcherRestartTimer = null;
265
- }
193
+ function openResultWatcher(epoch: number): void {
194
+ if (!isEpochActive(epoch) || state.watcher) return;
195
+ const installation = ++watcherInstallation;
196
+ let handle: fs.FSWatcher | null = null;
197
+ let pendingSynchronousError: Error | undefined;
198
+ const handleWatcherError = (error: Error) => {
199
+ if (!handle) { pendingSynchronousError = error; return; }
200
+ if (!isEpochActive(epoch) || installation !== activeWatcherInstallation || state.watcher !== handle) return;
201
+ if (shouldFallBackToPolling(error)) { startPollingFallback(error, epoch, installation); return; }
202
+ console.error(`Subagent result watcher failed for '${resultsDir}':`, error);
203
+ handle.close();
204
+ if (state.watcher === handle) state.watcher = null;
205
+ activeWatcherInstallation = 0;
206
+ scheduleRestart(epoch);
207
+ };
266
208
  try {
267
- state.watcher = fsApi.watch(resultsDir, (ev, file) => {
268
- if (ev !== "rename" || !file) return;
269
- const fileName = file.toString();
270
- if (!fileName.endsWith(".json")) return;
271
- state.resultFileCoalescer.schedule(fileName);
272
- });
273
- state.watcher.on("error", (error) => {
274
- if (shouldFallBackToPolling(error)) {
275
- startPollingFallback(error);
276
- return;
277
- }
278
- console.error(`Subagent result watcher failed for '${resultsDir}':`, error);
279
- state.watcher?.close();
280
- state.watcher = null;
281
- scheduleRestart();
282
- });
283
- state.watcher.unref?.();
209
+ handle = safeWatch(resultsDir, (_event, file) => {
210
+ if (!isEpochActive(epoch) || installation !== activeWatcherInstallation) return;
211
+ if (file) { const name = file.toString(); if (name.endsWith(".json")) scheduleResultEntry(name, 50, epoch); }
212
+ scheduleDirectoryRescan(epoch);
213
+ }, handleWatcherError, { watch: fsApi.watch, realpathSyncNative: fsApi.realpathSync?.native });
214
+ if (!handle) throw pendingSynchronousError ?? new Error("Result watcher installation returned no handle");
215
+ if (!isEpochActive(epoch)) { handle.close(); return; }
216
+ state.watcher = handle;
217
+ activeWatcherInstallation = installation;
218
+ handle.unref?.();
219
+ if (pendingSynchronousError) handleWatcherError(pendingSynchronousError);
284
220
  } catch (error) {
285
- if (shouldFallBackToPolling(error)) {
286
- startPollingFallback(error);
287
- return;
288
- }
289
- console.error(`Failed to start subagent result watcher for '${resultsDir}':`, error);
290
- state.watcher = null;
291
- scheduleRestart();
221
+ handle?.close();
222
+ if (state.watcher === handle) state.watcher = null;
223
+ activeWatcherInstallation = 0;
224
+ if (!isEpochActive(epoch)) return;
225
+ if (shouldFallBackToPolling(error)) startPollingFallback(error, epoch);
226
+ else { console.error(`Failed to start subagent result watcher for '${resultsDir}':`, error); scheduleRestart(epoch); }
292
227
  }
293
- };
228
+ }
294
229
 
230
+ const startResultWatcher = () => {
231
+ stopped = false;
232
+ processingEpoch += 1;
233
+ if (state.watcherRestartTimer) {
234
+ timers.clearTimeout(state.watcherRestartTimer); timers.clearInterval(state.watcherRestartTimer); state.watcherRestartTimer = null;
235
+ }
236
+ openResultWatcher(processingEpoch);
237
+ };
295
238
  const stopResultWatcher = () => {
239
+ stopped = true;
240
+ processingEpoch += 1;
296
241
  state.watcher?.close();
297
242
  state.watcher = null;
298
- if (state.watcherRestartTimer) {
299
- timers.clearTimeout(state.watcherRestartTimer);
300
- timers.clearInterval(state.watcherRestartTimer);
301
- }
243
+ activeWatcherInstallation = 0;
244
+ if (state.watcherRestartTimer) { timers.clearTimeout(state.watcherRestartTimer); timers.clearInterval(state.watcherRestartTimer); }
302
245
  state.watcherRestartTimer = null;
303
- state.resultFileCoalescer.clear();
246
+ if (directoryRescanTimer) timers.clearTimeout(directoryRescanTimer);
247
+ directoryRescanTimer = null;
248
+ statusRetries.clearAll(); deliveryRetries.clearAll(); state.resultFileCoalescer.clear();
304
249
  };
305
-
306
250
  return { startResultWatcher, primeExistingResults, stopResultWatcher };
307
251
  }
@@ -28,7 +28,8 @@ function exactAsyncLocation(id: string, asyncDirRoot: string, resultsDir: string
28
28
  }
29
29
 
30
30
  function foregroundIds(state: SubagentState | undefined): string[] {
31
- return state ? [...state.foregroundControls.keys()] : [];
31
+ if (!state) return [];
32
+ return [...new Set([...state.foregroundControls.keys(), ...(state.foregroundRuns?.keys() ?? [])])];
32
33
  }
33
34
 
34
35
  export function nestedScopeFromState(state: SubagentState | undefined): NestedRunResolutionScope | undefined {
@@ -57,7 +58,7 @@ export function resolveSubagentRunId(id: string, deps: ResolveSubagentRunIdDeps
57
58
  const resultsDir = deps.resultsDir ?? RESULTS_DIR;
58
59
 
59
60
  const nestedScope = deps.nested ?? nestedScopeFromState(deps.state);
60
- if (deps.state?.foregroundControls.has(id)) return { kind: "foreground", id };
61
+ if (deps.state?.foregroundControls.has(id) || deps.state?.foregroundRuns?.has(id)) return { kind: "foreground", id };
61
62
  const exactAsync = exactAsyncLocation(id, asyncDirRoot, resultsDir);
62
63
  if (exactAsync) return { kind: "async", id, location: exactAsync };
63
64
  const exactNested = findNestedRunMatchesById(id, nestedScope ? { scope: nestedScope } : {});
@@ -1,6 +1,7 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
3
  import { writeAtomicJson } from "../../shared/atomic-json.ts";
4
+ import { publishFileExclusive, unlinkIfPresent } from "../../shared/exclusive-file-publication.js";
4
5
  import { RESULTS_DIR, type AsyncParallelGroupStatus, type AsyncStatus, type NestedRunSummary, type SubagentRunMode } from "../../shared/types.ts";
5
6
  import { normalizeParallelGroups } from "./parallel-groups.ts";
6
7
  import { nestedSummaryFromAsyncStatus, projectNestedEvents, resolveNestedAsyncDir, writeNestedEvent, type NestedRoute } from "../shared/nested-events.ts";
@@ -28,6 +29,7 @@ interface ReconcileAsyncRunOptions {
28
29
  startedRun?: StartedRunMetadata;
29
30
  missingStatusGraceMs?: number;
30
31
  staleAlivePidMs?: number;
32
+ publish?: (source: string, destination: string) => "published" | "exists";
31
33
  }
32
34
 
33
35
  interface ReconcileAsyncRunResult {
@@ -53,6 +55,52 @@ function appendJsonl(filePath: string, payload: object): void {
53
55
  fs.appendFileSync(filePath, `${JSON.stringify(payload)}\n`, "utf-8");
54
56
  }
55
57
 
58
+ function repairStagePath(resultPath: string): string {
59
+ return path.join(path.dirname(resultPath), `.${path.basename(resultPath)}.stale-repair-stage`);
60
+ }
61
+
62
+ function readStagedRepair(resultPath: string): object | undefined {
63
+ try {
64
+ return JSON.parse(fs.readFileSync(repairStagePath(resultPath), "utf-8")) as object;
65
+ } catch (error) {
66
+ if (isNotFoundError(error)) return undefined;
67
+ throw error;
68
+ }
69
+ }
70
+
71
+ function stagedRepairMessage(staged: object): string | undefined {
72
+ const summary = (staged as { summary?: unknown }).summary;
73
+ return typeof summary === "string" ? summary : undefined;
74
+ }
75
+
76
+ function retireObsoleteStage(resultPath: string): void {
77
+ const stagePath = repairStagePath(resultPath);
78
+ const retiredPath = `${stagePath}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.retired`;
79
+ try {
80
+ fs.renameSync(stagePath, retiredPath);
81
+ try { fs.unlinkSync(retiredPath); } catch (error) { if (!isNotFoundError(error)) console.error(error); }
82
+ } catch (error) {
83
+ if (!isNotFoundError(error)) console.error(error);
84
+ }
85
+ }
86
+
87
+ function publishStagedRepair(
88
+ resultPath: string,
89
+ status: AsyncStatus,
90
+ staged: object,
91
+ publish: (source: string, destination: string) => "published" | "exists" = publishFileExclusive,
92
+ ): ReconcileAsyncRunResult {
93
+ const stagePath = repairStagePath(resultPath);
94
+ const outcome = publish(stagePath, resultPath);
95
+ unlinkIfPresent(stagePath);
96
+ return {
97
+ status,
98
+ repaired: outcome === "published",
99
+ resultPath,
100
+ message: outcome === "published" ? stagedRepairMessage(staged) : "A concurrently published result was preserved.",
101
+ };
102
+ }
103
+
56
104
  function readStatusFile(asyncDir: string): AsyncStatus | null {
57
105
  const statusPath = path.join(asyncDir, "status.json");
58
106
  let content: string;
@@ -222,19 +270,25 @@ function buildFailedRepair(status: AsyncStatus, asyncDir: string, now: number, r
222
270
  };
223
271
  }
224
272
 
225
- function writeFailedRepair(asyncDir: string, status: AsyncStatus, resultPath: string, now: number, reason?: string): ReconcileAsyncRunResult {
273
+ function writeFailedRepair(asyncDir: string, status: AsyncStatus, resultPath: string, now: number, reason?: string, publish?: ReconcileAsyncRunOptions["publish"]): ReconcileAsyncRunResult {
226
274
  const repair = buildFailedRepair(status, asyncDir, now, reason);
227
- writeAtomicJson(resultPath, repair.result);
275
+ // Stage the exact public payload beside its destination. Publication consumes
276
+ // the hidden stage with one atomic rename after terminal status is durable.
277
+ writeAtomicJson(repairStagePath(resultPath), repair.result);
228
278
  writeAtomicJson(path.join(asyncDir, "status.json"), repair.status);
229
- appendJsonl(path.join(asyncDir, "events.jsonl"), {
230
- type: "subagent.run.repaired_stale",
231
- ts: now,
232
- runId: repair.status.runId,
233
- pid: status.pid,
234
- resultPath,
235
- message: repair.message,
236
- });
237
- return { status: repair.status, repaired: true, resultPath, message: repair.message };
279
+ try {
280
+ appendJsonl(path.join(asyncDir, "events.jsonl"), {
281
+ type: "subagent.run.repaired_stale",
282
+ ts: now,
283
+ runId: repair.status.runId,
284
+ pid: status.pid,
285
+ resultPath,
286
+ message: repair.message,
287
+ });
288
+ } catch (error) {
289
+ console.error(`Failed to append stale-repair event for '${asyncDir}'; publishing the recoverable result:`, error);
290
+ }
291
+ return publishStagedRepair(resultPath, repair.status, repair.result, publish);
238
292
  }
239
293
 
240
294
  function terminal(state: AsyncStatus["state"]): boolean {
@@ -305,6 +359,7 @@ export function reconcileAsyncRun(asyncDir: string, options: ReconcileAsyncRunOp
305
359
  const runId = effectiveStatus.runId || path.basename(asyncDir);
306
360
  const resultPath = path.join(options.resultsDir ?? RESULTS_DIR, `${runId}.json`);
307
361
  if (fs.existsSync(resultPath)) {
362
+ retireObsoleteStage(resultPath);
308
363
  const terminalStatus = effectiveStatus.state === "running" || effectiveStatus.state === "queued"
309
364
  ? terminalStatusFromResult(effectiveStatus, resultPath, now)
310
365
  : undefined;
@@ -315,6 +370,11 @@ export function reconcileAsyncRun(asyncDir: string, options: ReconcileAsyncRunOp
315
370
  return { status: effectiveStatus, repaired: false, resultPath };
316
371
  }
317
372
 
373
+ const stagedRepair = readStagedRepair(resultPath);
374
+ if (stagedRepair && terminal(effectiveStatus.state)) {
375
+ return publishStagedRepair(resultPath, effectiveStatus, stagedRepair, options.publish);
376
+ }
377
+
318
378
  if (effectiveStatus.state !== "running" || typeof effectiveStatus.pid !== "number") {
319
379
  return { status: status ?? null, repaired: false, resultPath };
320
380
  }
@@ -332,8 +392,7 @@ export function reconcileAsyncRun(asyncDir: string, options: ReconcileAsyncRunOp
332
392
  const lastUpdate = effectiveStatus.lastUpdate ?? effectiveStatus.startedAt;
333
393
  if (now - lastUpdate <= staleAfterMs) return { status: status ?? null, repaired: false, resultPath };
334
394
  const message = `Async runner process ${effectiveStatus.pid} still has a live PID, but status has not updated for ${now - lastUpdate}ms. Marked run failed by stale-run reconciliation because PID ownership cannot be verified.`;
335
- return writeFailedRepair(asyncDir, effectiveStatus, resultPath, now, message);
395
+ return writeFailedRepair(asyncDir, effectiveStatus, resultPath, now, message, options.publish);
336
396
  }
337
-
338
- return writeFailedRepair(asyncDir, effectiveStatus, resultPath, now);
397
+ return writeFailedRepair(asyncDir, effectiveStatus, resultPath, now, undefined, options.publish);
339
398
  }