@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
@@ -3,7 +3,8 @@ import * as fs from "node:fs";
3
3
  import * as path from "node:path";
4
4
  import { writeAtomicJson } from "../../shared/atomic-json.js";
5
5
  import { appendJsonl } from "../../shared/artifacts.js";
6
- import { readStatus } from "../../shared/utils.js";
6
+ import { PROMPT_REDACTED, readStatus } from "../../shared/utils.js";
7
+ import { deriveChildSessionName } from "../../shared/child-session-name.js";
7
8
  import { isDynamicRunnerGroup, isParallelGroup } from "../shared/parallel-utils.js";
8
9
  const APPEND_REQUESTS_DIR = "append-requests";
9
10
  function appendDir(asyncDir) {
@@ -60,30 +61,49 @@ export function enqueueChainAppendRequest(input) {
60
61
  steps: input.steps
61
62
  };
62
63
  fs.mkdirSync(appendDir(input.asyncDir), { recursive: true });
63
- writeAtomicJson(appendRequestPath(input.asyncDir, request), request);
64
- const pendingCount = countPendingChainAppendRequests(input.asyncDir);
64
+ const persist = () => writeAtomicJson(appendRequestPath(input.asyncDir, request), request);
65
+ if (input.admit)
66
+ input.admit(persist);
67
+ else
68
+ persist();
69
+ let pendingCount = 1;
70
+ const bookkeepingErrors = [];
71
+ try {
72
+ pendingCount = countPendingChainAppendRequests(input.asyncDir);
73
+ } catch (error) {
74
+ bookkeepingErrors.push(`pending append count failed: ${error instanceof Error ? error.message : String(error)}`);
75
+ }
65
76
  const statusPath = path.join(input.asyncDir, "status.json");
66
77
  const updatedStatus = { ...status, pendingAppends: pendingCount, lastUpdate: request.createdAt };
67
- writeAtomicJson(statusPath, updatedStatus);
68
- appendJsonl(path.join(input.asyncDir, "events.jsonl"), JSON.stringify({
69
- type: "subagent.chain.append.requested",
70
- ts: request.createdAt,
71
- runId: input.runId,
72
- requestId: request.id,
73
- stepCount: input.steps.length,
74
- pendingAppends: pendingCount
75
- }));
76
- return { request, pendingCount };
78
+ try {
79
+ writeAtomicJson(statusPath, updatedStatus);
80
+ } catch (error) {
81
+ bookkeepingErrors.push(`status update failed: ${error instanceof Error ? error.message : String(error)}`);
82
+ }
83
+ try {
84
+ appendJsonl(path.join(input.asyncDir, "events.jsonl"), JSON.stringify({
85
+ type: "subagent.chain.append.requested",
86
+ ts: request.createdAt,
87
+ runId: input.runId,
88
+ requestId: request.id,
89
+ stepCount: input.steps.length,
90
+ pendingAppends: pendingCount
91
+ }));
92
+ } catch (error) {
93
+ bookkeepingErrors.push(`event append failed: ${error instanceof Error ? error.message : String(error)}`);
94
+ }
95
+ return { request, pendingCount, ...bookkeepingErrors.length > 0 ? { bookkeepingError: bookkeepingErrors.join("; ") } : {} };
77
96
  }
78
97
  function readAppendRequest(filePath) {
79
98
  const raw = JSON.parse(fs.readFileSync(filePath, "utf-8"));
80
99
  if (!raw.id || typeof raw.id !== "string")
81
100
  return;
82
- if (!Number.isFinite(raw.createdAt))
101
+ const createdAt = raw.createdAt;
102
+ if (typeof createdAt !== "number" || !Number.isFinite(createdAt))
83
103
  return;
84
104
  if (!Array.isArray(raw.steps) || raw.steps.length === 0)
85
105
  return;
86
- return { id: raw.id, createdAt: raw.createdAt, steps: raw.steps };
106
+ return { id: raw.id, createdAt, steps: raw.steps };
87
107
  }
88
108
  export function readPendingChainAppendRequests(asyncDir) {
89
109
  return listAppendRequestFiles(asyncDir).map((filePath) => readAppendRequest(filePath)).filter((request) => Boolean(request)).sort((left, right) => left.createdAt - right.createdAt || left.id.localeCompare(right.id));
@@ -100,9 +120,21 @@ export function consumeChainAppendRequests(asyncDir) {
100
120
  }
101
121
  return requests.sort((left, right) => left.createdAt - right.createdAt || left.id.localeCompare(right.id));
102
122
  }
123
+ const MAX_STATUS_STEP_DESCRIPTION_CHARS = 160;
124
+ export function statusStepDescription(task) {
125
+ if (!task?.trim())
126
+ return;
127
+ const description = PROMPT_REDACTED;
128
+ return description.length > MAX_STATUS_STEP_DESCRIPTION_CHARS ? `${description.slice(0, MAX_STATUS_STEP_DESCRIPTION_CHARS - 1)}…` : description;
129
+ }
103
130
  function statusStepForTask(task) {
131
+ const description = statusStepDescription(task.task);
132
+ const sessionName = task.sessionName ?? deriveChildSessionName({ agent: task.agent, task: task.task, label: task.label });
104
133
  return {
105
134
  agent: task.agent,
135
+ ...sessionName ? { sessionName } : {},
136
+ ...description ? { description } : {},
137
+ ...task.context ? { context: task.context } : {},
106
138
  phase: task.phase,
107
139
  label: task.label,
108
140
  outputName: task.outputName,
@@ -111,6 +143,7 @@ function statusStepForTask(task) {
111
143
  ...task.sessionFile ? { sessionFile: task.sessionFile } : {},
112
144
  skills: task.skills,
113
145
  model: task.model,
146
+ ...task.contextLimit !== undefined ? { contextLimit: task.contextLimit } : {},
114
147
  thinking: task.thinking,
115
148
  attemptedModels: task.modelCandidates && task.modelCandidates.length > 0 ? task.modelCandidates : task.model ? [task.model] : undefined,
116
149
  recentTools: [],
@@ -123,10 +156,12 @@ function statusStepsForRunnerStep(step) {
123
156
  if (isDynamicRunnerGroup(step)) {
124
157
  return [{
125
158
  agent: `expand:${step.parallel.agent}`,
159
+ ...step.parallel.context ? { context: step.parallel.context } : {},
126
160
  phase: step.phase ?? step.parallel.phase,
127
161
  label: step.label ?? step.parallel.label ?? `Dynamic fanout (${step.collect.as})`,
128
162
  outputName: step.collect.as,
129
163
  structured: Boolean(step.collect.outputSchema),
164
+ ...step.parallel.contextLimit !== undefined ? { contextLimit: step.parallel.contextLimit } : {},
130
165
  status: "pending",
131
166
  recentTools: [],
132
167
  recentOutput: []
@@ -1,8 +1,25 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
+ import { resultFilePath, resultPayloadPathForSessionRun } from "./result-files.js";
3
4
  import { readStatus } from "../../shared/utils.js";
4
- const TERMINAL_STATES = new Set(["complete", "failed", "paused"]);
5
- const TERMINAL_STEP_STATUSES = new Set(["complete", "completed", "failed", "paused"]);
5
+ const TERMINAL_STATES = new Set(["complete", "failed", "partial", "paused", "stopped"]);
6
+ const TERMINAL_STEP_STATUSES = new Set(["complete", "completed", "failed", "partial", "paused", "stopped"]);
7
+ function usageFromAttempts(attempts) {
8
+ if (!attempts?.length)
9
+ return;
10
+ const usage = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, turns: 0 };
11
+ for (const attempt of attempts) {
12
+ if (!attempt.usage)
13
+ continue;
14
+ usage.input += attempt.usage.input;
15
+ usage.output += attempt.usage.output;
16
+ usage.cacheRead += attempt.usage.cacheRead;
17
+ usage.cacheWrite += attempt.usage.cacheWrite;
18
+ usage.cost += attempt.usage.cost;
19
+ usage.turns += attempt.usage.turns;
20
+ }
21
+ return usage.input !== 0 || usage.output !== 0 || usage.cacheRead !== 0 || usage.cacheWrite !== 0 || usage.cost !== 0 || usage.turns !== 0 ? usage : undefined;
22
+ }
6
23
  function readResultFile(resultPath) {
7
24
  try {
8
25
  return JSON.parse(fs.readFileSync(resultPath, "utf-8"));
@@ -13,6 +30,13 @@ function readResultFile(resultPath) {
13
30
  throw error;
14
31
  }
15
32
  }
33
+ function readImportedResultFile(root, status) {
34
+ const direct = readResultFile(root.resultPath);
35
+ if (direct || !status?.sessionId)
36
+ return direct;
37
+ const indexedPath = resultPayloadPathForSessionRun(path.dirname(root.resultPath), status.sessionId, root.runId);
38
+ return indexedPath ? readResultFile(indexedPath) : undefined;
39
+ }
16
40
  function selectedStatusStep(status, index) {
17
41
  return status?.steps?.[index];
18
42
  }
@@ -27,11 +51,13 @@ function isTerminalStatus(status, index) {
27
51
  function resultState(result, child) {
28
52
  if (!result)
29
53
  return;
54
+ if (child?.stopped === true)
55
+ return "stopped";
30
56
  if (child?.success === true)
31
57
  return "complete";
32
58
  if (child?.success === false)
33
- return result.state === "paused" ? "paused" : "failed";
34
- if (result.state === "complete" || result.state === "failed" || result.state === "paused")
59
+ return result.state === "stopped" ? "stopped" : result.state === "paused" ? "paused" : result.state === "partial" ? "partial" : "failed";
60
+ if (result.state === "complete" || result.state === "failed" || result.state === "partial" || result.state === "paused" || result.state === "stopped")
35
61
  return result.state;
36
62
  if (result.success === true)
37
63
  return "complete";
@@ -42,7 +68,11 @@ function resultState(result, child) {
42
68
  function outputFromTerminalStatus(root, status, step) {
43
69
  const agent = step?.agent ?? status.steps?.[root.index]?.agent ?? "subagent";
44
70
  const timedOut = step?.timedOut === true || status.timedOut === true;
45
- const message = step?.error ?? status.error ?? `Attached async root ${root.runId} ended without a result file at ${root.resultPath}.`;
71
+ const stopped = step?.stopped === true || status.stopped === true || status.state === "stopped";
72
+ const message = step?.error ?? status.error ?? (stopped ? "Subagent stopped by user." : `Attached async root ${root.runId} ended without a result file at ${root.resultPath}.`);
73
+ const partialStatus = status.state === "partial" || step?.status === "partial";
74
+ const execution = step?.execution ?? (partialStatus ? { status: "partial", success: false, exitCode: 1, error: message } : undefined);
75
+ const usage = usageFromAttempts(step?.modelAttempts);
46
76
  return {
47
77
  agent,
48
78
  output: message,
@@ -50,19 +80,27 @@ function outputFromTerminalStatus(root, status, step) {
50
80
  exitCode: 1,
51
81
  error: message,
52
82
  ...timedOut ? { timedOut: true } : {},
83
+ ...stopped ? { stopped: true } : {},
84
+ ...step?.sessionName ? { sessionName: step.sessionName } : {},
53
85
  ...step?.sessionFile ?? status.sessionFile ? { sessionFile: step?.sessionFile ?? status.sessionFile } : {},
54
86
  ...step?.model ? { model: step.model } : {},
55
87
  ...step?.attemptedModels ? { attemptedModels: step.attemptedModels } : {},
56
88
  ...step?.modelAttempts ? { modelAttempts: step.modelAttempts } : {},
89
+ ...step?.contextOverflow ? { contextOverflow: true } : {},
57
90
  ...step?.totalCost ? { totalCost: step.totalCost } : {},
91
+ ...usage ? { usage } : {},
58
92
  ...step?.structuredOutput !== undefined ? { structuredOutput: step.structuredOutput } : {},
59
93
  ...step?.structuredOutputPath ? { structuredOutputPath: step.structuredOutputPath } : {},
60
94
  ...step?.structuredOutputSchemaPath ? { structuredOutputSchemaPath: step.structuredOutputSchemaPath } : {},
61
- ...step?.acceptance ? { acceptance: step.acceptance } : {}
95
+ ...step?.acceptance ? { acceptance: step.acceptance } : {},
96
+ ...execution ? { execution } : {},
97
+ ...step?.effects ? { effects: step.effects } : {},
98
+ ...step?.transcriptPath ? { transcriptPath: step.transcriptPath } : {}
62
99
  };
63
100
  }
64
101
  function outputFromTimeout(root, status, message) {
65
102
  const step = selectedStatusStep(status, root.index);
103
+ const usage = usageFromAttempts(step?.modelAttempts);
66
104
  return {
67
105
  agent: step?.agent ?? status?.steps?.[root.index]?.agent ?? "subagent",
68
106
  output: message,
@@ -70,11 +108,15 @@ function outputFromTimeout(root, status, message) {
70
108
  exitCode: 1,
71
109
  error: message,
72
110
  timedOut: true,
111
+ ...step?.sessionName ? { sessionName: step.sessionName } : {},
73
112
  ...step?.sessionFile ?? status?.sessionFile ? { sessionFile: step?.sessionFile ?? status?.sessionFile } : {},
74
113
  ...step?.model ? { model: step.model } : {},
75
114
  ...step?.attemptedModels ? { attemptedModels: step.attemptedModels } : {},
76
115
  ...step?.modelAttempts ? { modelAttempts: step.modelAttempts } : {},
77
- ...step?.totalCost ? { totalCost: step.totalCost } : {}
116
+ ...step?.contextOverflow ? { contextOverflow: true } : {},
117
+ ...step?.totalCost ? { totalCost: step.totalCost } : {},
118
+ ...usage ? { usage } : {},
119
+ ...step?.transcriptPath ? { transcriptPath: step.transcriptPath } : {}
78
120
  };
79
121
  }
80
122
  function buildImportedResult(root, status, result) {
@@ -84,8 +126,11 @@ function buildImportedResult(root, status, result) {
84
126
  const agent = child?.agent ?? step?.agent ?? status?.steps?.[root.index]?.agent ?? "subagent";
85
127
  const output = child?.output ?? result.summary ?? "";
86
128
  const timedOut = child?.timedOut === true || step?.timedOut === true || result.timedOut === true || status?.timedOut === true;
87
- const success = state === "complete" && !timedOut;
88
- const error = child?.error ?? (success ? undefined : result.error ?? result.summary ?? status?.error ?? `Attached async root ${root.runId} did not complete successfully.`);
129
+ const stopped = child?.stopped === true || step?.stopped === true || result.stopped === true || status?.stopped === true || state === "stopped";
130
+ const success = state === "complete" && !timedOut && !stopped;
131
+ const error = child?.error ?? (success ? undefined : stopped ? "Subagent stopped by user." : result.error ?? result.summary ?? status?.error ?? `Attached async root ${root.runId} did not complete successfully.`);
132
+ const execution = state ? { status: state === "complete" ? "completed" : state, success, exitCode: success ? 0 : 1, ...error ? { error } : {} } : undefined;
133
+ const usage = child?.usage ?? usageFromAttempts(step?.modelAttempts);
89
134
  return {
90
135
  agent,
91
136
  output: success ? output : output || error || "",
@@ -93,16 +138,26 @@ function buildImportedResult(root, status, result) {
93
138
  exitCode: success ? 0 : 1,
94
139
  ...error ? { error } : {},
95
140
  ...timedOut ? { timedOut: true } : {},
141
+ ...stopped ? { stopped: true } : {},
142
+ ...child?.sessionName ?? step?.sessionName ? { sessionName: child?.sessionName ?? step?.sessionName } : {},
96
143
  ...child?.sessionFile ?? step?.sessionFile ?? status?.sessionFile ? { sessionFile: child?.sessionFile ?? step?.sessionFile ?? status?.sessionFile } : {},
97
144
  ...child?.intercomTarget ? { intercomTarget: child.intercomTarget } : {},
98
145
  ...child?.model ?? step?.model ? { model: child?.model ?? step?.model } : {},
99
146
  ...child?.attemptedModels ?? step?.attemptedModels ? { attemptedModels: child?.attemptedModels ?? step?.attemptedModels } : {},
100
147
  ...child?.modelAttempts ?? step?.modelAttempts ? { modelAttempts: child?.modelAttempts ?? step?.modelAttempts } : {},
148
+ ...child?.contextOverflow || step?.contextOverflow ? { contextOverflow: true } : {},
101
149
  ...child?.totalCost ?? step?.totalCost ? { totalCost: child?.totalCost ?? step?.totalCost } : {},
150
+ ...usage ? { usage } : {},
102
151
  ...child?.structuredOutput !== undefined ? { structuredOutput: child.structuredOutput } : step?.structuredOutput !== undefined ? { structuredOutput: step.structuredOutput } : {},
103
152
  ...child?.structuredOutputPath ?? step?.structuredOutputPath ? { structuredOutputPath: child?.structuredOutputPath ?? step?.structuredOutputPath } : {},
104
153
  ...child?.structuredOutputSchemaPath ?? step?.structuredOutputSchemaPath ? { structuredOutputSchemaPath: child?.structuredOutputSchemaPath ?? step?.structuredOutputSchemaPath } : {},
105
- ...child?.acceptance ?? step?.acceptance ? { acceptance: child?.acceptance ?? step?.acceptance } : {}
154
+ ...child?.acceptance ?? step?.acceptance ? { acceptance: child?.acceptance ?? step?.acceptance } : {},
155
+ ...child?.artifactPaths ? { artifactPaths: child.artifactPaths } : {},
156
+ ...child?.outputSaveError ? { outputSaveError: child.outputSaveError } : {},
157
+ ...child?.transcriptPath ?? step?.transcriptPath ? { transcriptPath: child?.transcriptPath ?? step?.transcriptPath } : {},
158
+ ...child?.transcriptError ? { transcriptError: child.transcriptError } : {},
159
+ ...execution ? { execution } : {},
160
+ ...child?.effects ?? step?.effects ? { effects: child?.effects ?? step?.effects } : {}
106
161
  };
107
162
  }
108
163
  export async function waitForImportedAsyncRoot(root, options = {}) {
@@ -114,7 +169,7 @@ export async function waitForImportedAsyncRoot(root, options = {}) {
114
169
  const status = readStatus(root.asyncDir);
115
170
  if (options.shouldAbort?.())
116
171
  return outputFromTimeout(root, status, options.timeoutMessage ?? "Subagent timed out.");
117
- const result = readResultFile(root.resultPath);
172
+ const result = readImportedResultFile(root, status);
118
173
  if (result)
119
174
  return buildImportedResult(root, status, result);
120
175
  if (isTerminalStatus(status, root.index)) {
@@ -132,5 +187,5 @@ export async function waitForImportedAsyncRoot(root, options = {}) {
132
187
  }
133
188
  }
134
189
  export function resolveAsyncRootResultPath(resultsDir, runId) {
135
- return path.join(resultsDir, `${runId}.json`);
190
+ return resultFilePath(resultsDir, runId);
136
191
  }
@@ -41,7 +41,9 @@ export function createCompletionBatcher(options) {
41
41
  options.emit([item]);
42
42
  },
43
43
  flush() {},
44
- dispose() {}
44
+ dispose() {
45
+ return [];
46
+ }
45
47
  };
46
48
  }
47
49
  let pending = [];
@@ -88,7 +90,9 @@ export function createCompletionBatcher(options) {
88
90
  flush: emitGroup,
89
91
  dispose() {
90
92
  clearTimers();
93
+ const abandoned = pending;
91
94
  pending = [];
95
+ return abandoned;
92
96
  }
93
97
  };
94
98
  }
@@ -10,10 +10,11 @@ function asFiniteNumber(value) {
10
10
  return Number.isFinite(value) ? value : undefined;
11
11
  }
12
12
  export function buildCompletionKey(data, fallback) {
13
+ const sessionId = asNonEmptyString(data.sessionId) ?? "no-session";
13
14
  const id = asNonEmptyString(data.id);
15
+ const state = asNonEmptyString(data.state);
14
16
  if (id)
15
- return `id:${id}`;
16
- const sessionId = asNonEmptyString(data.sessionId) ?? "no-session";
17
+ return state ? `session:${sessionId}:id:${id}:state:${state}` : `session:${sessionId}:id:${id}`;
17
18
  const agent = asNonEmptyString(data.agent) ?? "unknown";
18
19
  const timestamp = asFiniteNumber(data.timestamp);
19
20
  const taskIndex = asFiniteNumber(data.taskIndex);
@@ -43,12 +44,3 @@ export function markSeenWithTtl(seen, key, now, ttlMs) {
43
44
  seen.set(key, now);
44
45
  return false;
45
46
  }
46
- export function getGlobalSeenMap(storeKey) {
47
- const globalStore = globalThis;
48
- const existing = globalStore[storeKey];
49
- if (existing instanceof Map)
50
- return existing;
51
- const map = new Map;
52
- globalStore[storeKey] = map;
53
- return map;
54
- }
@@ -0,0 +1,245 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { writePrivateAtomicJson } from "../../shared/atomic-json.js";
4
+ import { utf8Tail } from "../../shared/utf8.js";
5
+ const REPLAY_VERSION = 1;
6
+ const ARCHIVE_VERSION = 1;
7
+ const ARCHIVE_TEXT_LIMIT_BYTES = 64 * 1024;
8
+ const REPLAY_DIR_NAME = "completion-replay";
9
+ const ARCHIVE_DIR_NAME = "output-archives";
10
+ const CLEANUP_INTERVAL_MS = 60000;
11
+ const lastCleanupByResultsDir = new Map;
12
+ function safeRunFile(runId) {
13
+ return `${encodeURIComponent(runId)}.json`;
14
+ }
15
+ export function completionReplayPath(resultsDir, runId) {
16
+ return path.join(resultsDir, REPLAY_DIR_NAME, safeRunFile(runId));
17
+ }
18
+ export function completionArchivePath(resultsDir, runId) {
19
+ return path.join(resultsDir, ARCHIVE_DIR_NAME, safeRunFile(runId));
20
+ }
21
+ function nonEmptyString(value) {
22
+ return typeof value === "string" && value.length > 0 ? value : undefined;
23
+ }
24
+ function existingFile(value) {
25
+ const filePath = nonEmptyString(value);
26
+ if (!filePath)
27
+ return;
28
+ try {
29
+ return fs.statSync(filePath).isFile() ? filePath : undefined;
30
+ } catch {
31
+ return;
32
+ }
33
+ }
34
+ function outputArtifactPath(child) {
35
+ if (!child.artifactPaths || typeof child.artifactPaths !== "object" || Array.isArray(child.artifactPaths))
36
+ return;
37
+ return existingFile(child.artifactPaths.outputPath);
38
+ }
39
+ export function writeCompletionArchive(resultsDir, runId, data, createdAt) {
40
+ const entries = [];
41
+ const results = Array.isArray(data.results) ? data.results : [];
42
+ for (let resultIndex = 0;resultIndex < results.length; resultIndex++) {
43
+ const value = results[resultIndex];
44
+ if (!value || typeof value !== "object" || Array.isArray(value))
45
+ continue;
46
+ const child = value;
47
+ const agent = nonEmptyString(child.agent);
48
+ const artifactPath = outputArtifactPath(child);
49
+ if (artifactPath) {
50
+ entries.push({ ...agent ? { agent } : {}, resultIndex, source: "output-artifact", path: artifactPath });
51
+ continue;
52
+ }
53
+ const sessionPath = existingFile(child.sessionFile);
54
+ if (sessionPath) {
55
+ entries.push({ ...agent ? { agent } : {}, resultIndex, source: "session", path: sessionPath });
56
+ continue;
57
+ }
58
+ const output = nonEmptyString(child.output);
59
+ const error = nonEmptyString(child.error);
60
+ if (output || error) {
61
+ const bounded = utf8Tail([error ? `Error: ${error}` : undefined, output].filter(Boolean).join(`
62
+ `), ARCHIVE_TEXT_LIMIT_BYTES);
63
+ entries.push({
64
+ ...agent ? { agent } : {},
65
+ resultIndex,
66
+ source: "result-tail",
67
+ text: bounded.text,
68
+ ...bounded.truncated ? { truncated: true } : {}
69
+ });
70
+ }
71
+ }
72
+ if (results.length === 0) {
73
+ const sessionPath = existingFile(data.sessionFile);
74
+ if (sessionPath)
75
+ entries.push({ source: "session", path: sessionPath });
76
+ }
77
+ if (entries.length === 0) {
78
+ const summary = nonEmptyString(data.summary);
79
+ if (summary) {
80
+ const bounded = utf8Tail(summary, ARCHIVE_TEXT_LIMIT_BYTES);
81
+ entries.push({ source: "result-tail", text: bounded.text, ...bounded.truncated ? { truncated: true } : {} });
82
+ }
83
+ }
84
+ const archive = { version: ARCHIVE_VERSION, runId, createdAt, entries };
85
+ const archivePath = completionArchivePath(resultsDir, runId);
86
+ writePrivateAtomicJson(archivePath, archive);
87
+ return archivePath;
88
+ }
89
+ function parseCompletion(value, runId) {
90
+ if (!value || typeof value !== "object" || Array.isArray(value))
91
+ return;
92
+ const completion = value;
93
+ if (completion.runId !== runId)
94
+ return;
95
+ return completion;
96
+ }
97
+ function parseReplay(value) {
98
+ if (!value || typeof value !== "object" || Array.isArray(value))
99
+ return;
100
+ const record = value;
101
+ if (record.version !== REPLAY_VERSION || typeof record.runId !== "string" || typeof record.sessionId !== "string" || typeof record.completedAt !== "number" || typeof record.expiresAt !== "number" || typeof record.archivePath !== "string")
102
+ return;
103
+ const completion = parseCompletion(record.completion, record.runId);
104
+ return completion ? { ...record, completion } : undefined;
105
+ }
106
+ function validateReplayRecord(resultsDir, runId, record) {
107
+ if (record.runId !== runId)
108
+ return;
109
+ const archivePath = completionArchivePath(resultsDir, runId);
110
+ return path.resolve(record.archivePath) === path.resolve(archivePath) ? { ...record, archivePath, completion: { ...record.completion, archivePath } } : undefined;
111
+ }
112
+ function runIdFromReplayFile(file) {
113
+ if (!file.endsWith(".json"))
114
+ return;
115
+ try {
116
+ const runId = decodeURIComponent(file.slice(0, -".json".length));
117
+ return safeRunFile(runId) === file ? runId : undefined;
118
+ } catch {
119
+ return;
120
+ }
121
+ }
122
+ function removeBestEffort(filePath) {
123
+ try {
124
+ fs.rmSync(filePath, { force: true });
125
+ } catch {}
126
+ }
127
+ function parseArchive(value) {
128
+ if (!value || typeof value !== "object" || Array.isArray(value))
129
+ return;
130
+ const archive = value;
131
+ if (archive.version !== ARCHIVE_VERSION || typeof archive.runId !== "string" || typeof archive.createdAt !== "number" || !Array.isArray(archive.entries))
132
+ return;
133
+ const entries = archive.entries.flatMap((value) => {
134
+ if (!value || typeof value !== "object" || Array.isArray(value))
135
+ return [];
136
+ const entry = value;
137
+ if (entry.source !== "output-artifact" && entry.source !== "session" && entry.source !== "result-tail")
138
+ return [];
139
+ return [{
140
+ ...typeof entry.agent === "string" ? { agent: entry.agent } : {},
141
+ ...typeof entry.resultIndex === "number" && Number.isSafeInteger(entry.resultIndex) && entry.resultIndex >= 0 ? { resultIndex: entry.resultIndex } : {},
142
+ source: entry.source,
143
+ ...typeof entry.path === "string" ? { path: entry.path } : {},
144
+ ...typeof entry.text === "string" ? { text: entry.text } : {},
145
+ ...entry.truncated === true ? { truncated: true } : {}
146
+ }];
147
+ });
148
+ return { version: ARCHIVE_VERSION, runId: archive.runId, createdAt: archive.createdAt, entries };
149
+ }
150
+ export function writeCompletionReplay(input) {
151
+ const archivePath = writeCompletionArchive(input.resultsDir, input.runId, input.data, input.now);
152
+ const completion = { ...input.completion, archivePath };
153
+ const record = {
154
+ version: REPLAY_VERSION,
155
+ runId: input.runId,
156
+ sessionId: input.sessionId,
157
+ completedAt: input.now,
158
+ expiresAt: input.now + input.ttlMs,
159
+ completion,
160
+ archivePath
161
+ };
162
+ writePrivateAtomicJson(completionReplayPath(input.resultsDir, input.runId), record);
163
+ cleanupCompletionReplayIfDue(input.resultsDir, input.now, input.ttlMs);
164
+ return record;
165
+ }
166
+ export function readCompletionReplay(resultsDir, runId, options = {}) {
167
+ const replayPath = completionReplayPath(resultsDir, runId);
168
+ let parsed;
169
+ try {
170
+ parsed = parseReplay(JSON.parse(fs.readFileSync(replayPath, "utf-8")));
171
+ } catch (error) {
172
+ if (error.code === "ENOENT")
173
+ return;
174
+ throw error;
175
+ }
176
+ if (!parsed)
177
+ return;
178
+ const safeRecord = validateReplayRecord(resultsDir, runId, parsed);
179
+ if (!safeRecord) {
180
+ removeBestEffort(replayPath);
181
+ return;
182
+ }
183
+ parsed = safeRecord;
184
+ if (options.sessionId !== undefined && parsed.sessionId !== options.sessionId)
185
+ return;
186
+ if (parsed.expiresAt <= (options.now ?? Date.now())) {
187
+ removeBestEffort(replayPath);
188
+ removeBestEffort(parsed.archivePath);
189
+ return;
190
+ }
191
+ return parsed;
192
+ }
193
+ export function readCompletionArchive(archivePath) {
194
+ try {
195
+ const archive = parseArchive(JSON.parse(fs.readFileSync(archivePath, "utf-8")));
196
+ if (!archive)
197
+ throw new Error("Completion archive is malformed.");
198
+ return archive;
199
+ } catch (error) {
200
+ if (error.code === "ENOENT")
201
+ return;
202
+ throw error;
203
+ }
204
+ }
205
+ export function cleanupCompletionReplayIfDue(resultsDir, now, maxAgeMs, intervalMs = CLEANUP_INTERVAL_MS) {
206
+ const last = lastCleanupByResultsDir.get(resultsDir);
207
+ if (last !== undefined && now - last < intervalMs)
208
+ return false;
209
+ lastCleanupByResultsDir.set(resultsDir, now);
210
+ cleanupCompletionReplay(resultsDir, now, maxAgeMs);
211
+ return true;
212
+ }
213
+ export function cleanupCompletionReplay(resultsDir, now, maxAgeMs) {
214
+ const replayDir = path.join(resultsDir, REPLAY_DIR_NAME);
215
+ try {
216
+ for (const file of fs.readdirSync(replayDir)) {
217
+ const runId = runIdFromReplayFile(file);
218
+ if (!runId)
219
+ continue;
220
+ const filePath = path.join(replayDir, file);
221
+ try {
222
+ const record = parseReplay(JSON.parse(fs.readFileSync(filePath, "utf-8")));
223
+ const safeRecord = record ? validateReplayRecord(resultsDir, runId, record) : undefined;
224
+ if (record && !safeRecord) {
225
+ fs.rmSync(filePath, { force: true });
226
+ } else if (safeRecord && safeRecord.expiresAt <= now) {
227
+ fs.rmSync(filePath, { force: true });
228
+ fs.rmSync(safeRecord.archivePath, { force: true });
229
+ } else if (!record && now - fs.statSync(filePath).mtimeMs > maxAgeMs) {
230
+ fs.rmSync(filePath, { force: true });
231
+ }
232
+ } catch {}
233
+ }
234
+ } catch {}
235
+ const archiveDir = path.join(resultsDir, ARCHIVE_DIR_NAME);
236
+ try {
237
+ for (const file of fs.readdirSync(archiveDir)) {
238
+ const filePath = path.join(archiveDir, file);
239
+ try {
240
+ if (now - fs.statSync(filePath).mtimeMs > maxAgeMs)
241
+ fs.rmSync(filePath, { force: true });
242
+ } catch {}
243
+ }
244
+ } catch {}
245
+ }