@duckmind/dm-windows-x64 0.61.4 → 0.61.9

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 (279) hide show
  1. package/dm.exe +0 -0
  2. package/extensions/.dm-extensions.json +211 -67
  3. package/extensions/dm-subagents/agents/claude-code-writer.md +15 -0
  4. package/extensions/dm-subagents/agents/claude-code.md +15 -0
  5. package/extensions/dm-subagents/agents/codex-exec-writer.md +15 -0
  6. package/extensions/dm-subagents/agents/codex-exec.md +15 -0
  7. package/extensions/dm-subagents/agents/cursor-agent-writer.md +14 -0
  8. package/extensions/dm-subagents/agents/cursor-agent.md +14 -0
  9. package/extensions/dm-subagents/agents/delegate.md +3 -2
  10. package/extensions/dm-subagents/agents/oracle.md +10 -5
  11. package/extensions/dm-subagents/agents/researcher.md +2 -2
  12. package/extensions/dm-subagents/agents/reviewer.md +17 -7
  13. package/extensions/dm-subagents/agents/scout.md +5 -5
  14. package/extensions/dm-subagents/agents/worker.md +6 -2
  15. package/extensions/dm-subagents/async-retention-discovery-worker.mjs +167 -0
  16. package/extensions/dm-subagents/index.js +4 -0
  17. package/extensions/dm-subagents/inspector-runner.mjs +10 -0
  18. package/extensions/dm-subagents/install.mjs +3 -2
  19. package/extensions/dm-subagents/package.json +2 -2
  20. package/extensions/dm-subagents/prompts/council.md +60 -0
  21. package/extensions/dm-subagents/prompts/parallel-review.md +5 -1
  22. package/extensions/dm-subagents/prompts/review-loop.md +13 -7
  23. package/extensions/dm-subagents/skills/council-mode/SKILL.md +59 -0
  24. package/extensions/dm-subagents/skills/council-mode/references/pass-contracts.md +150 -0
  25. package/extensions/dm-subagents/skills/dm-subagents/SKILL.md +96 -911
  26. package/extensions/dm-subagents/skills/dm-subagents/references/constraints-and-recipes.md +70 -0
  27. package/extensions/dm-subagents/skills/dm-subagents/references/execution-controls.md +539 -0
  28. package/extensions/dm-subagents/skills/dm-subagents/references/management-authoring-rpc.md +161 -0
  29. package/extensions/dm-subagents/skills/dm-subagents/references/multi-lane-orchestration.md +51 -0
  30. package/extensions/dm-subagents/skills/dm-subagents/references/prompting-and-roles.md +295 -0
  31. package/extensions/dm-subagents/skills/dm-subagents/references/review-and-validation.md +73 -0
  32. package/extensions/dm-subagents/src/agents/agent-management.js +716 -484
  33. package/extensions/dm-subagents/src/agents/agent-refinements.js +563 -0
  34. package/extensions/dm-subagents/src/agents/agent-serializer.js +70 -5
  35. package/extensions/dm-subagents/src/agents/agents.js +1447 -299
  36. package/extensions/dm-subagents/src/agents/builtin-names.js +15 -0
  37. package/extensions/dm-subagents/src/agents/chain-serializer.js +12 -7
  38. package/extensions/dm-subagents/src/agents/frontmatter.js +64 -14
  39. package/extensions/dm-subagents/src/agents/identity.js +1 -1
  40. package/extensions/dm-subagents/src/agents/proactive-skills.js +14 -11
  41. package/extensions/dm-subagents/src/agents/runtime-agent-events.js +49 -0
  42. package/extensions/dm-subagents/src/agents/runtime-agent-registry.js +412 -0
  43. package/extensions/dm-subagents/src/agents/skills.js +52 -35
  44. package/extensions/dm-subagents/src/api/agents.js +6 -0
  45. package/extensions/dm-subagents/src/api/background-work.js +151 -0
  46. package/extensions/dm-subagents/src/api/capability-ceiling.js +12 -0
  47. package/extensions/dm-subagents/src/api/control-channel.js +3 -0
  48. package/extensions/dm-subagents/src/api/delegation.js +5 -0
  49. package/extensions/dm-subagents/src/api/dm-args.js +3 -0
  50. package/extensions/dm-subagents/src/api/external-job-provider.js +137 -0
  51. package/extensions/dm-subagents/src/api/external-runs.js +233 -0
  52. package/extensions/dm-subagents/src/api/intercom-bridge.js +3 -0
  53. package/extensions/dm-subagents/src/api/preflight.js +322 -0
  54. package/extensions/dm-subagents/src/api/project-panes.js +11 -0
  55. package/extensions/dm-subagents/src/api/shared-types.js +4 -0
  56. package/extensions/dm-subagents/src/extension/config.js +175 -0
  57. package/extensions/dm-subagents/src/extension/control-notices.js +4 -43
  58. package/extensions/dm-subagents/src/extension/doctor.js +71 -17
  59. package/extensions/dm-subagents/src/extension/fanout-child.js +49 -32
  60. package/extensions/dm-subagents/src/extension/index.js +711 -265
  61. package/extensions/dm-subagents/src/extension/public-execution.js +114 -0
  62. package/extensions/dm-subagents/src/extension/rpc.js +427 -22
  63. package/extensions/dm-subagents/src/extension/schemas.js +158 -65
  64. package/extensions/dm-subagents/src/extension/steering-notices.js +23 -0
  65. package/extensions/dm-subagents/src/extension/subagent-guide.js +31 -0
  66. package/extensions/dm-subagents/src/extension/tool-description.js +92 -74
  67. package/extensions/dm-subagents/src/extension/tool-result.js +7 -0
  68. package/extensions/dm-subagents/src/inspectors/herdr/actions.js +218 -0
  69. package/extensions/dm-subagents/src/inspectors/herdr/client.js +123 -0
  70. package/extensions/dm-subagents/src/inspectors/herdr/focus.js +47 -0
  71. package/extensions/dm-subagents/src/inspectors/herdr/inspector-runner.js +160 -0
  72. package/extensions/dm-subagents/src/inspectors/herdr/project-panes.js +618 -0
  73. package/extensions/dm-subagents/src/inspectors/herdr/session-roots-codec.js +21 -0
  74. package/extensions/dm-subagents/src/inspectors/herdr/shell-command.js +15 -0
  75. package/extensions/dm-subagents/src/integrations/herdr-status.js +377 -0
  76. package/extensions/dm-subagents/src/intercom/intercom-bridge.js +17 -13
  77. package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +371 -79
  78. package/extensions/dm-subagents/src/intercom/result-intercom.js +47 -7
  79. package/extensions/dm-subagents/src/missions/actions.js +394 -0
  80. package/extensions/dm-subagents/src/missions/goal-driver.js +149 -0
  81. package/extensions/dm-subagents/src/missions/lifecycle.js +331 -0
  82. package/extensions/dm-subagents/src/missions/store.js +548 -0
  83. package/extensions/dm-subagents/src/missions/types.js +9 -0
  84. package/extensions/dm-subagents/src/missions/workflow-state.js +245 -0
  85. package/extensions/dm-subagents/src/policy/authority.js +37 -0
  86. package/extensions/dm-subagents/src/profiles/profiles.js +36 -18
  87. package/extensions/dm-subagents/src/runs/background/active-async-capacity.js +427 -0
  88. package/extensions/dm-subagents/src/runs/background/active-run-index.js +122 -0
  89. package/extensions/dm-subagents/src/runs/background/async-execution.js +925 -137
  90. package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +515 -148
  91. package/extensions/dm-subagents/src/runs/background/async-resume.js +378 -51
  92. package/extensions/dm-subagents/src/runs/background/async-retention.js +828 -0
  93. package/extensions/dm-subagents/src/runs/background/async-status-snapshot.js +31 -0
  94. package/extensions/dm-subagents/src/runs/background/async-status.js +259 -22
  95. package/extensions/dm-subagents/src/runs/background/auto-drain.js +46 -0
  96. package/extensions/dm-subagents/src/runs/background/chain-append.js +50 -15
  97. package/extensions/dm-subagents/src/runs/background/chain-root-attachment.js +67 -12
  98. package/extensions/dm-subagents/src/runs/background/completion-batcher.js +5 -1
  99. package/extensions/dm-subagents/src/runs/background/completion-dedupe.js +3 -11
  100. package/extensions/dm-subagents/src/runs/background/completion-replay.js +245 -0
  101. package/extensions/dm-subagents/src/runs/background/control-channel.js +423 -36
  102. package/extensions/dm-subagents/src/runs/background/fleet-view.js +132 -59
  103. package/extensions/dm-subagents/src/runs/background/index-segment.js +38 -0
  104. package/extensions/dm-subagents/src/runs/background/inspect-rpc.js +373 -0
  105. package/extensions/dm-subagents/src/runs/background/notify.js +357 -57
  106. package/extensions/dm-subagents/src/runs/background/owned-process-tree.js +86 -0
  107. package/extensions/dm-subagents/src/runs/background/process-terminal.js +269 -0
  108. package/extensions/dm-subagents/src/runs/background/result-delivery-ownership.js +34 -0
  109. package/extensions/dm-subagents/src/runs/background/result-files.js +469 -0
  110. package/extensions/dm-subagents/src/runs/background/result-watcher.js +540 -75
  111. package/extensions/dm-subagents/src/runs/background/resume-guidance.js +44 -0
  112. package/extensions/dm-subagents/src/runs/background/retained-children.js +119 -0
  113. package/extensions/dm-subagents/src/runs/background/run-id-query.js +5 -0
  114. package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +93 -9
  115. package/extensions/dm-subagents/src/runs/background/run-status.js +303 -32
  116. package/extensions/dm-subagents/src/runs/background/scheduled-runs.js +784 -376
  117. package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +75 -34
  118. package/extensions/dm-subagents/src/runs/background/steering.js +221 -0
  119. package/extensions/dm-subagents/src/runs/background/subagent-runner.js +3106 -844
  120. package/extensions/dm-subagents/src/runs/background/subagent-wait.js +529 -0
  121. package/extensions/dm-subagents/src/runs/background/terminal-run-index.js +106 -0
  122. package/extensions/dm-subagents/src/runs/background/top-level-async.js +1 -1
  123. package/extensions/dm-subagents/src/runs/background/wait-completions.js +155 -0
  124. package/extensions/dm-subagents/src/runs/background/wait-config.js +46 -0
  125. package/extensions/dm-subagents/src/runs/background/wait-subscriptions.js +278 -0
  126. package/extensions/dm-subagents/src/runs/background/wait-tool.js +47 -0
  127. package/extensions/dm-subagents/src/runs/foreground/async-dismiss-action.js +81 -0
  128. package/extensions/dm-subagents/src/runs/foreground/async-steering-action.js +245 -0
  129. package/extensions/dm-subagents/src/runs/foreground/async-stop-action.js +74 -0
  130. package/extensions/dm-subagents/src/runs/foreground/execution.js +1401 -342
  131. package/extensions/dm-subagents/src/runs/foreground/foreground-control.js +133 -0
  132. package/extensions/dm-subagents/src/runs/foreground/foreground-history.js +148 -0
  133. package/extensions/dm-subagents/src/runs/foreground/prompt-audit.js +139 -0
  134. package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +4278 -1441
  135. package/extensions/dm-subagents/src/runs/foreground/workflow-detach-reconcile.js +278 -0
  136. package/extensions/dm-subagents/src/runs/foreground/workflow-foreground-steering.js +155 -0
  137. package/extensions/dm-subagents/src/runs/shared/abort-recovery.js +97 -0
  138. package/extensions/dm-subagents/src/runs/shared/acceptance.js +597 -148
  139. package/extensions/dm-subagents/src/runs/shared/agent-contract.js +35 -0
  140. package/extensions/dm-subagents/src/runs/shared/async-status-projection.js +472 -0
  141. package/extensions/dm-subagents/src/runs/shared/background-process-options.js +6 -0
  142. package/extensions/dm-subagents/src/runs/shared/capability-ceiling.js +175 -0
  143. package/extensions/dm-subagents/src/runs/shared/child-identity.js +32 -0
  144. package/extensions/dm-subagents/src/runs/shared/child-launch-plan.js +65 -0
  145. package/extensions/dm-subagents/src/runs/shared/child-protocol.js +447 -0
  146. package/extensions/dm-subagents/src/runs/shared/claude-code-adapter.js +120 -0
  147. package/extensions/dm-subagents/src/runs/shared/codex-exec-adapter.js +129 -0
  148. package/extensions/dm-subagents/src/runs/shared/completion-evidence.js +40 -0
  149. package/extensions/dm-subagents/src/runs/shared/completion-guard.js +140 -83
  150. package/extensions/dm-subagents/src/runs/shared/context-mode.js +38 -0
  151. package/extensions/dm-subagents/src/runs/shared/cursor-agent-adapter.js +101 -0
  152. package/extensions/dm-subagents/src/runs/shared/dm-args.js +445 -72
  153. package/extensions/dm-subagents/src/runs/shared/dm-spawn.js +27 -16
  154. package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.js +19 -6
  155. package/extensions/dm-subagents/src/runs/shared/extension-bindings.js +81 -0
  156. package/extensions/dm-subagents/src/runs/shared/external-cli-contract.js +134 -0
  157. package/extensions/dm-subagents/src/runs/shared/external-cli-preflight.js +98 -0
  158. package/extensions/dm-subagents/src/runs/shared/external-cli-runner.js +419 -0
  159. package/extensions/dm-subagents/src/runs/shared/external-job-bridge.js +404 -0
  160. package/extensions/dm-subagents/src/runs/shared/external-job-runner.js +334 -0
  161. package/extensions/dm-subagents/src/runs/shared/fast-mode-extension.js +8 -0
  162. package/extensions/dm-subagents/src/runs/shared/host-step-status.js +228 -0
  163. package/extensions/dm-subagents/src/runs/shared/lane-metadata.js +104 -0
  164. package/extensions/dm-subagents/src/runs/shared/launch-cwd.js +17 -0
  165. package/extensions/dm-subagents/src/runs/shared/llm-intent-arbiter.js +190 -0
  166. package/extensions/dm-subagents/src/runs/shared/long-running-guard.js +48 -3
  167. package/extensions/dm-subagents/src/runs/shared/mcp-config-sources.js +387 -0
  168. package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.js +212 -137
  169. package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-grant.js +131 -0
  170. package/extensions/dm-subagents/src/runs/shared/model-exclusions.js +207 -0
  171. package/extensions/dm-subagents/src/runs/shared/model-fallback.js +225 -55
  172. package/extensions/dm-subagents/src/runs/shared/model-scope.js +85 -28
  173. package/extensions/dm-subagents/src/runs/shared/mutation-evidence.js +182 -0
  174. package/extensions/dm-subagents/src/runs/shared/nested-events.js +264 -102
  175. package/extensions/dm-subagents/src/runs/shared/nested-render.js +15 -5
  176. package/extensions/dm-subagents/src/runs/shared/orca-progress-tabs.js +505 -0
  177. package/extensions/dm-subagents/src/runs/shared/parallel-handoff.js +653 -0
  178. package/extensions/dm-subagents/src/runs/shared/parallel-utils.js +29 -12
  179. package/extensions/dm-subagents/src/runs/shared/permissions.js +108 -0
  180. package/extensions/dm-subagents/src/runs/shared/process-signal.js +13 -0
  181. package/extensions/dm-subagents/src/runs/shared/run-fanout-budget.js +257 -0
  182. package/extensions/dm-subagents/src/runs/shared/run-history.js +133 -13
  183. package/extensions/dm-subagents/src/runs/shared/runtime-acknowledged-extensions.js +62 -0
  184. package/extensions/dm-subagents/src/runs/shared/session-lease.js +225 -0
  185. package/extensions/dm-subagents/src/runs/shared/single-output.js +129 -27
  186. package/extensions/dm-subagents/src/runs/shared/spawn-budget.js +95 -0
  187. package/extensions/dm-subagents/src/runs/shared/structured-output.js +129 -10
  188. package/extensions/dm-subagents/src/runs/shared/subagent-control.js +66 -11
  189. package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +548 -70
  190. package/extensions/dm-subagents/src/runs/shared/subagent-startup-retry.js +50 -0
  191. package/extensions/dm-subagents/src/runs/shared/task-intent.js +130 -0
  192. package/extensions/dm-subagents/src/runs/shared/tool-availability.js +59 -0
  193. package/extensions/dm-subagents/src/runs/shared/tool-budget.js +7 -5
  194. package/extensions/dm-subagents/src/runs/shared/tool-timeout.js +64 -0
  195. package/extensions/dm-subagents/src/runs/shared/usage-budget.js +74 -0
  196. package/extensions/dm-subagents/src/runs/shared/workflow-graph.js +22 -0
  197. package/extensions/dm-subagents/src/runs/shared/worktree-cleanup-plan.js +721 -0
  198. package/extensions/dm-subagents/src/runs/shared/worktree.js +168 -19
  199. package/extensions/dm-subagents/src/shared/accessible-dir.js +35 -0
  200. package/extensions/dm-subagents/src/shared/agent-stream-options.js +3 -0
  201. package/extensions/dm-subagents/src/shared/artifacts.js +170 -11
  202. package/extensions/dm-subagents/src/shared/atomic-json.js +36 -38
  203. package/extensions/dm-subagents/src/shared/capacity-resilient-json.js +77 -0
  204. package/extensions/dm-subagents/src/shared/child-session-name.js +15 -0
  205. package/extensions/dm-subagents/src/shared/child-transcript.js +57 -2
  206. package/extensions/dm-subagents/src/shared/completion-owner.js +7 -0
  207. package/extensions/dm-subagents/src/shared/display-text.js +142 -0
  208. package/extensions/dm-subagents/src/shared/extension-context.js +17 -0
  209. package/extensions/dm-subagents/src/shared/file-coalescer.js +9 -0
  210. package/extensions/dm-subagents/src/shared/file-system-retry.js +56 -0
  211. package/extensions/dm-subagents/src/shared/fork-context.js +96 -33
  212. package/extensions/dm-subagents/src/shared/formatters.js +21 -7
  213. package/extensions/dm-subagents/src/shared/launch-contract.js +94 -0
  214. package/extensions/dm-subagents/src/shared/model-info.js +10 -5
  215. package/extensions/dm-subagents/src/shared/node-executable.js +19 -0
  216. package/extensions/dm-subagents/src/shared/prompt-resources.js +10 -0
  217. package/extensions/dm-subagents/src/shared/pruned-fork.js +427 -0
  218. package/extensions/dm-subagents/src/shared/session-file-trust.js +19 -0
  219. package/extensions/dm-subagents/src/shared/session-tokens.js +14 -3
  220. package/extensions/dm-subagents/src/shared/settings.js +39 -47
  221. package/extensions/dm-subagents/src/shared/shortcuts.js +16 -0
  222. package/extensions/dm-subagents/src/shared/status-format.js +9 -2
  223. package/extensions/dm-subagents/src/shared/thinking-ceiling.js +41 -0
  224. package/extensions/dm-subagents/src/shared/types.js +47 -7
  225. package/extensions/dm-subagents/src/shared/utf8.js +12 -0
  226. package/extensions/dm-subagents/src/shared/utils.js +151 -131
  227. package/extensions/dm-subagents/src/shared/watch-strategy.js +3 -0
  228. package/extensions/dm-subagents/src/shared/workflow-child-permit.js +84 -0
  229. package/extensions/dm-subagents/src/slash/delegation-adapters.js +274 -0
  230. package/extensions/dm-subagents/src/slash/delegation-json.js +113 -0
  231. package/extensions/dm-subagents/src/slash/delegation-request.js +152 -0
  232. package/extensions/dm-subagents/src/slash/prompt-template-bridge.js +294 -243
  233. package/extensions/dm-subagents/src/slash/prompt-workflows.js +35 -73
  234. package/extensions/dm-subagents/src/slash/selector.js +101 -0
  235. package/extensions/dm-subagents/src/slash/slash-bridge.js +17 -1
  236. package/extensions/dm-subagents/src/slash/slash-commands.js +722 -732
  237. package/extensions/dm-subagents/src/slash/slash-live-state.js +37 -19
  238. package/extensions/dm-subagents/src/slash/subagents-admin.js +410 -0
  239. package/extensions/dm-subagents/src/tui/fleet-status.js +824 -0
  240. package/extensions/dm-subagents/src/tui/fleet-transcript.js +479 -0
  241. package/extensions/dm-subagents/src/tui/fleet.js +1326 -0
  242. package/extensions/dm-subagents/src/tui/render-helpers.js +22 -0
  243. package/extensions/dm-subagents/src/tui/render.js +1511 -261
  244. package/extensions/dm-subagents/src/watchdog/change-signature.js +220 -0
  245. package/extensions/dm-subagents/src/watchdog/child-status.js +151 -0
  246. package/extensions/dm-subagents/src/watchdog/emission-guard.js +90 -0
  247. package/extensions/dm-subagents/src/watchdog/lsp-diagnostics.js +484 -0
  248. package/extensions/dm-subagents/src/watchdog/model-selection.js +154 -0
  249. package/extensions/dm-subagents/src/watchdog/permission-arbiter.js +138 -0
  250. package/extensions/dm-subagents/src/watchdog/register-child.js +112 -0
  251. package/extensions/dm-subagents/src/watchdog/register-main.js +419 -0
  252. package/extensions/dm-subagents/src/watchdog/render.js +54 -0
  253. package/extensions/dm-subagents/src/watchdog/review.js +251 -0
  254. package/extensions/dm-subagents/src/watchdog/runtime.js +803 -0
  255. package/extensions/dm-subagents/src/watchdog/scope.js +56 -0
  256. package/extensions/dm-subagents/src/watchdog/settings.js +515 -0
  257. package/extensions/dm-subagents/src/watchdog/tool-actions.js +151 -0
  258. package/extensions/dm-subagents/src/watchdog/turn-delta.js +169 -0
  259. package/extensions/dm-subagents/src/watchdog/types.js +29 -0
  260. package/extensions/dm-subagents/src/watchdog/warning-format.js +58 -0
  261. package/extensions/dm-subagents/src/workflows/chat-progress.js +116 -0
  262. package/extensions/dm-subagents/src/workflows/host-command.js +227 -0
  263. package/extensions/dm-subagents/src/workflows/scripted-workflow.js +2011 -0
  264. package/extensions/dm-subagents/src/workflows/workflow-child-summary.js +116 -0
  265. package/extensions/dm-subagents/src/workflows/workflow-preflight.js +243 -0
  266. package/extensions/dm-subagents/src/workflows/workflow-receipt.js +387 -0
  267. package/extensions/dm-subagents/src/workflows/workflow-settlement.js +189 -0
  268. package/package.json +4 -3
  269. package/extensions/dm-fff/package.json +0 -21
  270. package/extensions/dm-fff/src/index.js +0 -691
  271. package/extensions/dm-fff/src/query.js +0 -60
  272. package/extensions/dm-subagents/agents/context-builder.md +0 -46
  273. package/extensions/dm-subagents/agents/planner.md +0 -55
  274. package/extensions/dm-subagents/prompts/parallel-context-build.md +0 -55
  275. package/extensions/dm-subagents/prompts/parallel-handoff-plan.md +0 -61
  276. package/extensions/dm-subagents/src/runs/background/wait.js +0 -206
  277. package/extensions/dm-subagents/src/runs/foreground/chain-clarify.js +0 -1013
  278. package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +0 -981
  279. package/extensions/dm-subagents/src/runs/shared/turn-budget.js +0 -50
@@ -2,6 +2,7 @@ import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
3
  import { buildCompletionKey, markSeenWithTtl } from "./completion-dedupe.js";
4
4
  import { createFileCoalescer } from "../../shared/file-coalescer.js";
5
+ import { shouldUseNativeFsWatch } from "../../shared/watch-strategy.js";
5
6
  import {
6
7
  SUBAGENT_ASYNC_COMPLETE_EVENT
7
8
  } from "../../shared/types.js";
@@ -13,8 +14,37 @@ import {
13
14
  resolveSubagentResultStatus
14
15
  } from "../../intercom/result-intercom.js";
15
16
  import { projectNestedRegistryForRoot, sanitizeSummary } from "../shared/nested-events.js";
17
+ import { resolveWatchPath } from "../../shared/utils.js";
18
+ import { recordWaitCompletion } from "./wait-completions.js";
19
+ import { MISSION_BINDING_FILE, syncMissionFromAsyncCompletion } from "../../missions/lifecycle.js";
20
+ import { missionObserverResultCandidateFiles, promotePendingResultFile, removeMissionObserverIndex, removeResultIndex, resultCandidateFilesForSession, resultPayloadPathForIndexedRun, resultPayloadPathForMissionObserverRun, resultPayloadPathForSessionRun, writeAsyncResultFile, writeResultIndexForData } from "./result-files.js";
16
21
  const WATCHER_RESTART_DELAY_MS = 3000;
17
22
  const POLL_INTERVAL_MS = 3000;
23
+ const HEALTHY_SCAN_INTERVAL_MS = 60000;
24
+ const RETRY_DELAY_MS = 100;
25
+ const SLOW_RESULT_SCAN_MS = 500;
26
+ function jsonStringProperty(raw, property) {
27
+ const matches = raw.matchAll(new RegExp(`"${property}"\\s*:\\s*("(?:\\\\.|[^"\\\\])*")`, "g"));
28
+ let encoded;
29
+ for (const match of matches)
30
+ encoded = match[1];
31
+ if (!encoded)
32
+ return;
33
+ try {
34
+ const value = JSON.parse(encoded);
35
+ return typeof value === "string" && value ? value : undefined;
36
+ } catch {
37
+ return;
38
+ }
39
+ }
40
+ function resultFileIdentity(raw, file) {
41
+ return {
42
+ sessionId: jsonStringProperty(raw, "sessionId"),
43
+ completionOwnerId: jsonStringProperty(raw, "completionOwnerId"),
44
+ runId: file.replace(/\.json$/i, ""),
45
+ asyncDir: jsonStringProperty(raw, "asyncDir")
46
+ };
47
+ }
18
48
  function sanitizeNestedResultChildren(value, resultPath, label) {
19
49
  if (value === undefined)
20
50
  return;
@@ -28,35 +58,282 @@ function sanitizeNestedResultChildren(value, resultPath, label) {
28
58
  }
29
59
  return children.length ? children : undefined;
30
60
  }
31
- function getErrorCode(error) {
61
+ function errorCode(error) {
32
62
  return typeof error === "object" && error !== null && "code" in error ? error.code : undefined;
33
63
  }
34
- function isNotFoundError(error) {
35
- return getErrorCode(error) === "ENOENT";
64
+ function isNotFound(error) {
65
+ return errorCode(error) === "ENOENT";
66
+ }
67
+ function isAbsentResultCandidate(error) {
68
+ return isNotFound(error) || errorCode(error) === "ENAMETOOLONG";
36
69
  }
37
- function shouldFallBackToPolling(error) {
38
- const code = getErrorCode(error);
70
+ function isAccessDenied(error) {
71
+ const code = errorCode(error);
72
+ return code === "EPERM" || code === "EACCES";
73
+ }
74
+ function shouldPoll(error) {
75
+ const code = errorCode(error);
39
76
  return code === "EMFILE" || code === "ENOSPC";
40
77
  }
41
- function resolveNativeWatchDir(fsApi, resultsDir) {
42
- try {
43
- return fsApi.realpathSync.native(resultsDir);
44
- } catch {
45
- return resultsDir;
46
- }
78
+ function hasDeliveredNotification(data) {
79
+ return typeof data.notificationDeliveredAt === "number" && Number.isFinite(data.notificationDeliveredAt);
80
+ }
81
+ function resultPayloadWasReplaced(delivered, disk) {
82
+ if (!disk)
83
+ return false;
84
+ const deliveredState = typeof delivered.state === "string" ? delivered.state : undefined;
85
+ if (disk.state && deliveredState && disk.state !== deliveredState)
86
+ return true;
87
+ const deliveredTimestamp = typeof delivered.timestamp === "number" && Number.isFinite(delivered.timestamp) ? delivered.timestamp : undefined;
88
+ return disk.timestamp !== undefined && deliveredTimestamp !== undefined && disk.timestamp !== deliveredTimestamp;
47
89
  }
48
- export function createResultWatcher(pi, state, resultsDir, completionTtlMs, deps = {}) {
90
+ function markDeliveredNotification(resultPath, data, runId, now) {
91
+ const marked = { ...data, runId, notificationDeliveredAt: now };
92
+ writeAsyncResultFile(resultPath, marked);
93
+ return marked;
94
+ }
95
+ export function createResultWatcher(dm, state, resultsDir, completionTtlMs, deps = {}) {
49
96
  const fsApi = deps.fs ?? fs;
50
97
  const timers = deps.timers ?? { setTimeout, clearTimeout, setInterval, clearInterval };
51
- const handleResult = async (file) => {
52
- const resultPath = path.join(resultsDir, file);
53
- if (!fsApi.existsSync(resultPath))
98
+ const notifier = deps.notifier ?? { deliver: async () => true };
99
+ const parseResult = deps.parseResult ?? ((raw) => JSON.parse(raw));
100
+ const deliverIntercomResults = deps.deliverIntercomResults !== false;
101
+ const pendingTriggerTurn = new Map;
102
+ const processing = new Set;
103
+ const identityCache = new Map;
104
+ let deliveryActive = true;
105
+ let deliveryEpoch = 0;
106
+ let resultScanTimer = null;
107
+ let activeSessionId = null;
108
+ const ownsResult = deps.ownership?.owns ?? ((sessionId, completionOwnerId) => sessionId === state.currentSessionId && typeof completionOwnerId === "string" && completionOwnerId === state.completionOwnerId);
109
+ const claimedSessionIds = () => deps.ownership?.claimedSessionIds() ?? [];
110
+ const ownsCompletion = (sessionId, completionOwnerId, epoch) => {
111
+ if (!deliveryActive || epoch !== deliveryEpoch)
112
+ return false;
113
+ if (!activeSessionId && state.currentSessionId)
114
+ activeSessionId = state.currentSessionId;
115
+ return activeSessionId === state.currentSessionId && ownsResult(sessionId, completionOwnerId);
116
+ };
117
+ const scheduleResult = (file, triggerTurn, delayMs = 0) => {
118
+ const pendingMode = pendingTriggerTurn.get(file);
119
+ pendingTriggerTurn.set(file, pendingMode === false || !triggerTurn ? false : true);
120
+ state.resultFileCoalescer.schedule(file, delayMs);
121
+ };
122
+ const publicResultPath = (file) => path.join(resultsDir, file);
123
+ const publicResultFileExists = (file) => {
124
+ try {
125
+ return fsApi.statSync(publicResultPath(file)).isFile();
126
+ } catch (error) {
127
+ if (!isAbsentResultCandidate(error))
128
+ console.error(`Failed to inspect subagent result file '${publicResultPath(file)}':`, error);
129
+ return false;
130
+ }
131
+ };
132
+ const resultPayloadPath = (file, observed) => {
133
+ if (file !== path.basename(file) || !file.endsWith(".json"))
134
+ return;
135
+ const runId = file.replace(/\.json$/i, "");
136
+ for (const sessionId of [state.currentSessionId, ...claimedSessionIds()]) {
137
+ if (!sessionId)
138
+ continue;
139
+ const sessionResult = resultPayloadPathForSessionRun(resultsDir, sessionId, runId);
140
+ if (sessionResult)
141
+ return sessionResult;
142
+ }
143
+ const observerResult = resultPayloadPathForMissionObserverRun(resultsDir, runId);
144
+ if (observerResult)
145
+ return observerResult;
146
+ if (observed?.has(runId)) {
147
+ const indexedResult = resultPayloadPathForIndexedRun(resultsDir, runId);
148
+ if (indexedResult)
149
+ return indexedResult;
150
+ }
151
+ return publicResultFileExists(file) ? publicResultPath(file) : undefined;
152
+ };
153
+ const resultSignature = (file, observed) => {
154
+ const resultPath = resultPayloadPath(file, observed);
155
+ if (!resultPath) {
156
+ identityCache.delete(file);
157
+ return;
158
+ }
159
+ try {
160
+ const stat = fsApi.statSync(resultPath);
161
+ if (!stat.isFile())
162
+ return;
163
+ return `${resultPath}:${stat.size}:${stat.mtimeMs}`;
164
+ } catch (error) {
165
+ identityCache.delete(file);
166
+ if (isAccessDenied(error))
167
+ throw error;
168
+ if (!isAbsentResultCandidate(error))
169
+ console.error(`Failed to inspect subagent result file '${resultPath}':`, error);
170
+ return;
171
+ }
172
+ };
173
+ const inspectResult = (file, knownSignature, observed) => {
174
+ const resultPath = resultPayloadPath(file, observed);
175
+ if (!resultPath)
54
176
  return;
55
177
  try {
56
- const data = JSON.parse(fsApi.readFileSync(resultPath, "utf-8"));
57
- if (typeof data.sessionId !== "string" || data.sessionId !== state.currentSessionId)
178
+ const signature = knownSignature ?? resultSignature(file, observed);
179
+ if (!signature)
58
180
  return;
181
+ const cached = identityCache.get(file);
182
+ if (cached?.signature === signature)
183
+ return { identity: cached.identity, signature };
184
+ const identity = resultFileIdentity(fsApi.readFileSync(resultPath, "utf-8"), file);
185
+ identityCache.set(file, { signature, identity });
186
+ return { identity, signature };
187
+ } catch (error) {
188
+ identityCache.delete(file);
189
+ if (isAccessDenied(error))
190
+ throw error;
191
+ if (!isAbsentResultCandidate(error))
192
+ console.error(`Failed to inspect subagent result file '${resultPath}':`, error);
193
+ return;
194
+ }
195
+ };
196
+ const observedRunIds = () => {
197
+ try {
198
+ return new Set(deps.observedCompletionRunIds?.() ?? []);
199
+ } catch (error) {
200
+ console.error("Failed to inspect observed subagent completion ids:", error);
201
+ return new Set;
202
+ }
203
+ };
204
+ const shouldProcessResult = (file, observed, knownSignature) => {
205
+ const inspected = inspectResult(file, knownSignature, observed);
206
+ if (!inspected)
207
+ return false;
208
+ const { identity } = inspected;
209
+ if (!identity.sessionId)
210
+ return true;
211
+ if (ownsResult(identity.sessionId, identity.completionOwnerId))
212
+ return true;
213
+ if (identity.asyncDir && fsApi.existsSync(path.join(identity.asyncDir, MISSION_BINDING_FILE)))
214
+ return true;
215
+ if (identity.runId && (observed ?? observedRunIds()).has(identity.runId))
216
+ return true;
217
+ return Boolean(deps.observeCompletion && !deps.observedCompletionRunIds);
218
+ };
219
+ const removeDeliveredResult = (file, sessionId, runId, toolCallId) => {
220
+ try {
221
+ if (publicResultFileExists(file))
222
+ fsApi.unlinkSync(publicResultPath(file));
223
+ identityCache.delete(file);
224
+ removeResultIndex(resultsDir, sessionId, runId, toolCallId);
225
+ return true;
226
+ } catch (error) {
227
+ if (!isAbsentResultCandidate(error)) {
228
+ console.error(`Failed to remove delivered subagent result '${publicResultPath(file)}'; will retry:`, error);
229
+ return false;
230
+ }
231
+ return true;
232
+ }
233
+ };
234
+ const handleResult = async (file, triggerTurn) => {
235
+ if (processing.has(file))
236
+ return;
237
+ let observed;
238
+ try {
239
+ if (!shouldProcessResult(file)) {
240
+ const runId = file === path.basename(file) && file.endsWith(".json") ? file.replace(/\.json$/i, "") : undefined;
241
+ observed = observedRunIds();
242
+ if (!runId || !observed.has(runId) || !shouldProcessResult(file, observed))
243
+ return;
244
+ }
245
+ } catch (error) {
246
+ if (!isAccessDenied(error))
247
+ throw error;
248
+ console.error(`Failed to inspect subagent result file '${publicResultPath(file)}'; will retry:`, error);
249
+ scheduleResult(file, triggerTurn, RETRY_DELAY_MS);
250
+ return;
251
+ }
252
+ processing.add(file);
253
+ let rereadReplacedPayload = false;
254
+ let resultPath = publicResultPath(file);
255
+ const readPublicResultIdentity = () => {
256
+ if (!publicResultFileExists(file))
257
+ return;
258
+ const parsed = JSON.parse(fsApi.readFileSync(publicResultPath(file), "utf-8"));
259
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
260
+ return;
261
+ const record = parsed;
262
+ const state = typeof record.state === "string" && record.state ? record.state : undefined;
263
+ const timestamp = typeof record.timestamp === "number" && Number.isFinite(record.timestamp) ? record.timestamp : undefined;
264
+ if (!state && timestamp === undefined)
265
+ return;
266
+ return { state, timestamp };
267
+ };
268
+ try {
269
+ const payloadPath = resultPayloadPath(file, observed);
270
+ if (!payloadPath)
271
+ return;
272
+ resultPath = payloadPath;
273
+ let raw = fsApi.readFileSync(resultPath, "utf-8");
274
+ let identity = resultFileIdentity(raw, file);
275
+ if (identity.sessionId && identity.runId) {
276
+ const pendingState = promotePendingResultFile(resultsDir, identity.sessionId, identity.runId, file);
277
+ if (pendingState === "promoted") {
278
+ identityCache.delete(file);
279
+ resultPath = publicResultPath(file);
280
+ raw = fsApi.readFileSync(resultPath, "utf-8");
281
+ identity = resultFileIdentity(raw, file);
282
+ } else if (pendingState === "pending") {
283
+ const pendingPath = resultPayloadPathForSessionRun(resultsDir, identity.sessionId, identity.runId);
284
+ if (!pendingPath) {
285
+ scheduleResult(file, triggerTurn, RETRY_DELAY_MS);
286
+ return;
287
+ }
288
+ resultPath = pendingPath;
289
+ raw = fsApi.readFileSync(resultPath, "utf-8");
290
+ identity = resultFileIdentity(raw, file);
291
+ }
292
+ }
293
+ let data = parseResult(raw);
294
+ const markReplacedPayload = () => {
295
+ try {
296
+ if (!resultPayloadWasReplaced(data, readPublicResultIdentity()))
297
+ return false;
298
+ } catch (error) {
299
+ if (isAccessDenied(error))
300
+ throw error;
301
+ if (isAbsentResultCandidate(error))
302
+ return false;
303
+ console.error(`Failed to re-read subagent result file '${publicResultPath(file)}':`, error);
304
+ }
305
+ identityCache.delete(file);
306
+ rereadReplacedPayload = true;
307
+ return true;
308
+ };
309
+ if (typeof data.sessionId !== "string" || !data.sessionId)
310
+ return;
311
+ const sessionId = data.sessionId;
312
+ const completionOwnerId = data.completionOwnerId;
59
313
  const runId = data.runId ?? data.id ?? file.replace(/\.json$/i, "");
314
+ const toolCallId = typeof data.toolCallId === "string" ? data.toolCallId : undefined;
315
+ let observerSucceeded = true;
316
+ try {
317
+ syncMissionFromAsyncCompletion({ ...data, runId });
318
+ } catch (error) {
319
+ observerSucceeded = false;
320
+ console.error(`Mission completion sync failed for '${resultPath}':`, error);
321
+ }
322
+ try {
323
+ deps.observeCompletion?.({ ...data, runId });
324
+ } catch (error) {
325
+ observerSucceeded = false;
326
+ console.error(`Completion observer failed for '${resultPath}':`, error);
327
+ }
328
+ if (observerSucceeded)
329
+ removeMissionObserverIndex(resultsDir, runId);
330
+ const epoch = deliveryEpoch;
331
+ if (!ownsCompletion(sessionId, completionOwnerId, epoch))
332
+ return;
333
+ recordWaitCompletion(state, runId, data, Date.now(), completionTtlMs, {
334
+ resultsDir,
335
+ sessionId
336
+ });
60
337
  const hasExplicitNestedChildren = data.nestedChildren !== undefined;
61
338
  let nestedChildren = compactNestedResultChildren(sanitizeNestedResultChildren(data.nestedChildren, resultPath, "nestedChildren"));
62
339
  if (!nestedChildren?.length && !hasExplicitNestedChildren) {
@@ -64,37 +341,56 @@ export function createResultWatcher(pi, state, resultsDir, completionTtlMs, deps
64
341
  nestedChildren = compactNestedResultChildren(projectNestedRegistryForRoot(runId)?.children);
65
342
  } catch (error) {
66
343
  console.error(`Failed to enrich subagent result file '${resultPath}' with nested registry children; will retry later:`, error);
344
+ scheduleResult(file, triggerTurn, RETRY_DELAY_MS);
67
345
  return;
68
346
  }
69
347
  }
70
- const now = Date.now();
71
348
  const completionKey = buildCompletionKey(data, `result:${file}`);
72
- if (markSeenWithTtl(state.completionSeen, completionKey, now, completionTtlMs)) {
73
- fsApi.unlinkSync(resultPath);
349
+ const alreadyDelivered = hasDeliveredNotification(data);
350
+ const lastSeenAt = state.completionSeen.get(completionKey);
351
+ if (lastSeenAt !== undefined && Date.now() - lastSeenAt > completionTtlMs) {
352
+ state.completionSeen.delete(completionKey);
353
+ } else if (lastSeenAt !== undefined) {
354
+ if (!observerSucceeded) {
355
+ scheduleResult(file, triggerTurn, RETRY_DELAY_MS);
356
+ return;
357
+ }
358
+ if (!ownsCompletion(sessionId, completionOwnerId, epoch))
359
+ return;
360
+ if (markReplacedPayload())
361
+ return;
362
+ if (!removeDeliveredResult(file, sessionId, runId, toolCallId))
363
+ scheduleResult(file, triggerTurn, RETRY_DELAY_MS);
74
364
  return;
75
365
  }
76
366
  const hasResultChildren = Array.isArray(data.results) && data.results.length > 0;
77
- const resultChildren = hasResultChildren ? data.results : [{
78
- agent: data.agent,
79
- output: data.summary,
80
- success: data.success
81
- }];
367
+ const resultChildren = hasResultChildren ? data.results : [{ agent: data.agent ?? undefined, output: data.summary, outputState: "unknown", success: data.success }];
82
368
  const normalizedChildren = attachNestedChildrenToResultChildren(runId, resultChildren.map((result = {}, index) => {
83
- const baseOutput = result.output ?? data.summary;
369
+ const baseOutput = hasResultChildren ? result.output : result.output ?? data.summary;
84
370
  const hasRealOutput = typeof baseOutput === "string" && baseOutput.trim().length > 0;
85
- const output = hasRealOutput ? baseOutput : "(no output)";
371
+ const structuredPreview = result.structuredOutput === undefined ? undefined : JSON.stringify(result.structuredOutput, null, 2).slice(0, 4000);
372
+ const output = hasRealOutput ? baseOutput : structuredPreview ? `Structured output:
373
+ ${structuredPreview}` : "(no output)";
86
374
  const summary = result.success === false && result.error ? `${result.error}${hasRealOutput ? `
87
375
 
88
376
  Output:
89
377
  ${baseOutput}` : ""}` : output;
90
378
  const sessionPath = result.sessionFile ?? (resultChildren.length === 1 ? data.sessionFile : undefined);
91
379
  const childNestedChildren = sanitizeNestedResultChildren(result.children, resultPath, `results[${index}].children`);
380
+ const childState = result.state === "paused" || result.state === "stopped" ? result.state : result.stopped === true ? "stopped" : data.state === "paused" || !hasResultChildren && (data.state === "stopped" || typeof result.success !== "boolean") ? data.state : undefined;
92
381
  return {
93
382
  agent: result.agent ?? data.agent ?? `step-${index + 1}`,
383
+ ...result.sessionName ? { sessionName: result.sessionName } : {},
94
384
  status: resolveSubagentResultStatus({
95
385
  success: result.success,
96
- state: data.state === "paused" || typeof result.success !== "boolean" ? data.state : undefined
386
+ state: childState,
387
+ interrupted: result.interrupted,
388
+ timedOut: result.timedOut,
389
+ stopped: result.stopped,
390
+ turnBudgetExceeded: result.turnBudgetExceeded,
391
+ processSignal: result.processSignal
97
392
  }),
393
+ outputState: result.outputState === "present" || result.outputState === "absent" || result.outputState === "unknown" ? result.outputState : "unknown",
98
394
  summary,
99
395
  index,
100
396
  artifactPath: result.artifactPaths?.outputPath,
@@ -103,26 +399,45 @@ ${baseOutput}` : ""}` : output;
103
399
  ...childNestedChildren ? { children: childNestedChildren } : {}
104
400
  };
105
401
  }), nestedChildren);
402
+ if (alreadyDelivered) {
403
+ markSeenWithTtl(state.completionSeen, completionKey, Date.now(), completionTtlMs);
404
+ if (!observerSucceeded) {
405
+ scheduleResult(file, triggerTurn, RETRY_DELAY_MS);
406
+ return;
407
+ }
408
+ if (!ownsCompletion(sessionId, completionOwnerId, epoch))
409
+ return;
410
+ if (markReplacedPayload())
411
+ return;
412
+ if (!removeDeliveredResult(file, sessionId, runId, toolCallId))
413
+ scheduleResult(file, triggerTurn, RETRY_DELAY_MS);
414
+ return;
415
+ }
106
416
  const intercomTarget = data.intercomTarget?.trim();
107
- if (intercomTarget) {
108
- const mode = data.mode === "single" || data.mode === "parallel" || data.mode === "chain" ? data.mode : resultChildren.length > 1 ? "chain" : "single";
109
- const payload = buildSubagentResultIntercomPayload({
417
+ let intercomDelivered = false;
418
+ if (deliverIntercomResults && intercomTarget && triggerTurn) {
419
+ const mode = data.mode === "single" || data.mode === "parallel" || data.mode === "chain" || data.mode === "workflow" ? data.mode : resultChildren.length > 1 ? "chain" : "single";
420
+ intercomDelivered = await deliverSubagentResultIntercomEvent(dm.events, buildSubagentResultIntercomPayload({
110
421
  to: intercomTarget,
111
422
  runId,
112
423
  mode,
113
424
  source: "async",
114
425
  children: normalizedChildren,
115
- asyncId: data.id,
116
- asyncDir: data.asyncDir
117
- });
118
- const delivered = await deliverSubagentResultIntercomEvent(pi.events, payload);
119
- if (!delivered) {
426
+ asyncId: data.id ?? undefined,
427
+ asyncDir: data.asyncDir,
428
+ ...data.parallelHandoff ? { parallelHandoff: data.parallelHandoff } : {}
429
+ }));
430
+ if (!ownsCompletion(sessionId, completionOwnerId, epoch))
431
+ return;
432
+ if (!intercomDelivered)
120
433
  console.error(`Subagent async grouped result intercom delivery was not acknowledged for '${resultPath}'.`);
121
- }
122
434
  }
123
- pi.events.emit(SUBAGENT_ASYNC_COMPLETE_EVENT, {
435
+ const accepted = await notifier.deliver({
124
436
  ...data,
437
+ id: data.id ?? runId,
125
438
  runId,
439
+ triggerTurn,
440
+ intercomDelivered,
126
441
  ...nestedChildren?.length ? { nestedChildren } : {},
127
442
  ...Array.isArray(data.results) ? {
128
443
  results: hasResultChildren ? normalizedChildren.map((child, index) => ({
@@ -137,36 +452,165 @@ ${baseOutput}` : ""}` : output;
137
452
  })) : []
138
453
  } : {}
139
454
  });
140
- fsApi.unlinkSync(resultPath);
141
- } catch (error) {
142
- if (isNotFoundError(error))
455
+ if (!ownsCompletion(sessionId, completionOwnerId, epoch))
143
456
  return;
144
- console.error(`Failed to process subagent result file '${resultPath}':`, error);
457
+ if (!accepted) {
458
+ scheduleResult(file, triggerTurn, RETRY_DELAY_MS);
459
+ return;
460
+ }
461
+ if (markReplacedPayload())
462
+ return;
463
+ try {
464
+ data = markDeliveredNotification(publicResultPath(file), data, runId, Date.now());
465
+ identityCache.delete(file);
466
+ } catch (error) {
467
+ console.error(`Failed to mark subagent result notification delivered for '${resultPath}'; will retry:`, error);
468
+ scheduleResult(file, triggerTurn, RETRY_DELAY_MS);
469
+ return;
470
+ }
471
+ markSeenWithTtl(state.completionSeen, completionKey, Date.now(), completionTtlMs);
472
+ try {
473
+ dm.events.emit(SUBAGENT_ASYNC_COMPLETE_EVENT, {
474
+ ...data,
475
+ runId,
476
+ triggerTurn,
477
+ intercomDelivered,
478
+ ...nestedChildren?.length ? { nestedChildren } : {},
479
+ ...Array.isArray(data.results) ? {
480
+ results: hasResultChildren ? normalizedChildren.map((child, index) => ({
481
+ ...data.results[index],
482
+ agent: child.agent,
483
+ status: child.status,
484
+ summary: child.summary,
485
+ index: child.index,
486
+ artifactPath: child.artifactPath,
487
+ sessionPath: child.sessionPath,
488
+ children: child.children
489
+ })) : []
490
+ } : {}
491
+ });
492
+ } catch (error) {
493
+ console.error(`Completion observer failed for '${resultPath}':`, error);
494
+ }
495
+ if (!observerSucceeded) {
496
+ scheduleResult(file, triggerTurn, RETRY_DELAY_MS);
497
+ return;
498
+ }
499
+ if (!ownsCompletion(sessionId, completionOwnerId, epoch))
500
+ return;
501
+ if (!removeDeliveredResult(file, sessionId, runId, toolCallId))
502
+ scheduleResult(file, triggerTurn, RETRY_DELAY_MS);
503
+ } catch (error) {
504
+ if (isAccessDenied(error)) {
505
+ console.error(`Failed to process subagent result file '${resultPath}'; will retry:`, error);
506
+ scheduleResult(file, triggerTurn, RETRY_DELAY_MS);
507
+ } else if (!isNotFound(error))
508
+ console.error(`Failed to process subagent result file '${resultPath}':`, error);
509
+ } finally {
510
+ processing.delete(file);
511
+ if (rereadReplacedPayload)
512
+ scheduleResult(file, triggerTurn);
145
513
  }
146
514
  };
147
515
  state.resultFileCoalescer = createFileCoalescer((file) => {
148
- handleResult(file);
149
- }, 50);
150
- const primeExistingResults = () => {
516
+ const triggerTurn = pendingTriggerTurn.get(file) !== false;
517
+ pendingTriggerTurn.delete(file);
518
+ handleResult(file, triggerTurn);
519
+ }, deps.coalesceDelayMs ?? 50);
520
+ const logScanStats = (stats) => {
521
+ const elapsed = Date.now() - stats.startedAt;
522
+ if (elapsed < SLOW_RESULT_SCAN_MS)
523
+ return;
524
+ const resultScanLogging = deps.resultScanLogging ?? "activity";
525
+ if (resultScanLogging === "off")
526
+ return;
527
+ if (resultScanLogging === "activity" && stats.files === 0 && stats.scheduled === 0)
528
+ return;
529
+ console.error(`Subagent result scan inspected ${stats.files} indexed result file(s), scheduled ${stats.scheduled} in ${elapsed}ms (${resultsDir}).`);
530
+ };
531
+ const indexedResultCandidates = (observed) => {
532
+ const files = new Set;
533
+ for (const sessionId of [state.currentSessionId, ...claimedSessionIds()]) {
534
+ if (!sessionId)
535
+ continue;
536
+ for (const file of resultCandidateFilesForSession(resultsDir, sessionId))
537
+ files.add(file);
538
+ }
539
+ for (const runId of state.asyncJobs.keys())
540
+ files.add(`${runId}.json`);
541
+ for (const file of missionObserverResultCandidateFiles(resultsDir))
542
+ files.add(file);
543
+ for (const runId of observed)
544
+ files.add(`${runId}.json`);
545
+ return [...files];
546
+ };
547
+ const primeExistingResults = (options = {}) => {
151
548
  try {
152
- fsApi.readdirSync(resultsDir).filter((f) => f.endsWith(".json")).forEach((file) => state.resultFileCoalescer.schedule(file, 0));
549
+ const triggerTurn = options.triggerTurn !== false;
550
+ const stats = { files: 0, scheduled: 0, startedAt: Date.now() };
551
+ const observed = observedRunIds();
552
+ for (const file of indexedResultCandidates(observed)) {
553
+ stats.files += 1;
554
+ const signature = resultSignature(file, observed);
555
+ if (!signature)
556
+ continue;
557
+ if (!shouldProcessResult(file, observed, signature))
558
+ continue;
559
+ stats.scheduled += 1;
560
+ scheduleResult(file, triggerTurn);
561
+ }
562
+ logScanStats(stats);
153
563
  } catch (error) {
154
- if (isNotFoundError(error))
155
- return;
156
- console.error(`Failed to scan subagent result directory '${resultsDir}':`, error);
564
+ if (!isNotFound(error))
565
+ console.error(`Failed to scan subagent result index in '${resultsDir}':`, error);
566
+ }
567
+ };
568
+ const clearResultScan = () => {
569
+ if (resultScanTimer)
570
+ timers.clearInterval(resultScanTimer);
571
+ resultScanTimer = null;
572
+ };
573
+ const useNativeWatcher = () => shouldUseNativeFsWatch("result-delivery", deps.platform);
574
+ const hasDeliveryDemand = () => {
575
+ try {
576
+ return deps.hasDeliveryDemand?.() === true;
577
+ } catch (error) {
578
+ console.error("Failed to inspect subagent result delivery demand:", error);
579
+ return false;
157
580
  }
158
581
  };
159
- const startPollingFallback = (reason) => {
582
+ const clearResultPoller = () => {
583
+ if (!state.watcherRestartTimer)
584
+ return;
585
+ timers.clearTimeout(state.watcherRestartTimer);
586
+ timers.clearInterval(state.watcherRestartTimer);
587
+ state.watcherRestartTimer = null;
588
+ };
589
+ const startDemandPolling = () => {
590
+ if (!deliveryActive || useNativeWatcher() || state.watcherRestartTimer)
591
+ return;
592
+ if (!hasDeliveryDemand())
593
+ return;
594
+ state.watcherRestartTimer = timers.setInterval(() => {
595
+ primeExistingResults();
596
+ if (!hasDeliveryDemand())
597
+ clearResultPoller();
598
+ }, POLL_INTERVAL_MS);
599
+ state.watcherRestartTimer.unref?.();
600
+ };
601
+ const startPolling = (reason) => {
160
602
  state.watcher?.close();
161
603
  state.watcher = null;
604
+ clearResultScan();
162
605
  if (state.watcherRestartTimer)
163
606
  return;
164
- console.error(`Subagent result watcher for '${resultsDir}' fell back to polling because native fs.watch is unavailable (${getErrorCode(reason) ?? "unknown error"}).`);
607
+ console.error(`Subagent result watcher for '${resultsDir}' fell back to polling because native fs.watch is unavailable (${errorCode(reason) ?? "unknown error"}).`);
165
608
  primeExistingResults();
166
609
  state.watcherRestartTimer = timers.setInterval(primeExistingResults, POLL_INTERVAL_MS);
167
610
  state.watcherRestartTimer.unref?.();
168
611
  };
169
612
  const scheduleRestart = () => {
613
+ clearResultScan();
170
614
  if (state.watcherRestartTimer)
171
615
  return;
172
616
  state.watcherRestartTimer = timers.setTimeout(() => {
@@ -175,10 +619,8 @@ ${baseOutput}` : ""}` : output;
175
619
  fsApi.mkdirSync(resultsDir, { recursive: true });
176
620
  startResultWatcher();
177
621
  } catch (error) {
178
- if (shouldFallBackToPolling(error)) {
179
- startPollingFallback(error);
180
- return;
181
- }
622
+ if (shouldPoll(error))
623
+ return startPolling(error);
182
624
  console.error(`Failed to restart subagent result watcher for '${resultsDir}':`, error);
183
625
  scheduleRestart();
184
626
  }
@@ -188,51 +630,74 @@ ${baseOutput}` : ""}` : output;
188
630
  const startResultWatcher = () => {
189
631
  if (state.watcher)
190
632
  return;
633
+ activeSessionId = state.currentSessionId;
634
+ deliveryActive = true;
635
+ deliveryEpoch += 1;
191
636
  if (state.watcherRestartTimer) {
192
637
  timers.clearTimeout(state.watcherRestartTimer);
193
638
  timers.clearInterval(state.watcherRestartTimer);
194
639
  state.watcherRestartTimer = null;
195
640
  }
641
+ if (!useNativeWatcher()) {
642
+ startDemandPolling();
643
+ return;
644
+ }
196
645
  try {
197
- const watchDir = resolveNativeWatchDir(fsApi, resultsDir);
198
- state.watcher = fsApi.watch(watchDir, (ev, file) => {
199
- if (ev !== "rename" || !file)
646
+ const watchDir = resolveWatchPath(resultsDir, fsApi.realpathSync.native);
647
+ state.watcher = fsApi.watch(watchDir, (_event, file) => {
648
+ if (!file) {
649
+ primeExistingResults();
200
650
  return;
651
+ }
201
652
  const fileName = file.toString();
202
- if (!fileName.endsWith(".json"))
203
- return;
204
- state.resultFileCoalescer.schedule(fileName);
653
+ if (fileName.endsWith(".json")) {
654
+ identityCache.delete(fileName);
655
+ try {
656
+ writeResultIndexForData(path.join(resultsDir, fileName), JSON.parse(fsApi.readFileSync(path.join(resultsDir, fileName), "utf-8")));
657
+ } catch {}
658
+ scheduleResult(fileName, true);
659
+ }
205
660
  });
206
661
  state.watcher.on("error", (error) => {
207
- if (shouldFallBackToPolling(error)) {
208
- startPollingFallback(error);
209
- return;
210
- }
662
+ if (shouldPoll(error))
663
+ return startPolling(error);
211
664
  console.error(`Subagent result watcher failed for '${resultsDir}':`, error);
212
665
  state.watcher?.close();
213
666
  state.watcher = null;
214
667
  scheduleRestart();
215
668
  });
216
669
  state.watcher.unref?.();
670
+ resultScanTimer = timers.setInterval(primeExistingResults, HEALTHY_SCAN_INTERVAL_MS);
671
+ resultScanTimer.unref?.();
217
672
  } catch (error) {
218
- if (shouldFallBackToPolling(error)) {
219
- startPollingFallback(error);
220
- return;
221
- }
673
+ if (shouldPoll(error))
674
+ return startPolling(error);
222
675
  console.error(`Failed to start subagent result watcher for '${resultsDir}':`, error);
223
676
  state.watcher = null;
224
677
  scheduleRestart();
225
678
  }
226
679
  };
680
+ const transitionResultDelivery = () => {
681
+ deliveryActive = true;
682
+ activeSessionId = state.currentSessionId;
683
+ deliveryEpoch += 1;
684
+ identityCache.clear();
685
+ };
227
686
  const stopResultWatcher = () => {
687
+ deliveryActive = false;
688
+ activeSessionId = null;
689
+ deliveryEpoch += 1;
228
690
  state.watcher?.close();
229
691
  state.watcher = null;
230
- if (state.watcherRestartTimer) {
231
- timers.clearTimeout(state.watcherRestartTimer);
232
- timers.clearInterval(state.watcherRestartTimer);
233
- }
234
- state.watcherRestartTimer = null;
692
+ clearResultPoller();
693
+ clearResultScan();
235
694
  state.resultFileCoalescer.clear();
695
+ pendingTriggerTurn.clear();
696
+ processing.clear();
697
+ identityCache.clear();
236
698
  };
237
- return { startResultWatcher, primeExistingResults, stopResultWatcher };
699
+ return { startResultWatcher, transitionResultDelivery, primeExistingResults, stopResultWatcher, refreshResultDelivery: () => {
700
+ primeExistingResults();
701
+ startDemandPolling();
702
+ } };
238
703
  }