@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
@@ -0,0 +1,31 @@
1
+ import {
2
+ projectAsyncStatusSnapshot
3
+ } from "../shared/async-status-projection.js";
4
+ export {
5
+ ASYNC_STATUS_SNAPSHOT_KIND,
6
+ ASYNC_STATUS_SNAPSHOT_VERSION
7
+ } from "../shared/async-status-projection.js";
8
+ export const ASYNC_STATUS_SNAPSHOT_WIDGET_PREFIX = "DM_SUBAGENT_ASYNC_JSON:";
9
+ export function buildAsyncStatusSnapshot(jobs, options = {}) {
10
+ return projectAsyncStatusSnapshot(jobs, options);
11
+ }
12
+ export function asyncStatusSnapshotJobsForState(state, sessionId) {
13
+ if (!state || !sessionId || state.currentSessionId !== sessionId)
14
+ return [];
15
+ const jobs = new Map;
16
+ for (const job of state.asyncJobs.values()) {
17
+ if (job.sessionId === sessionId)
18
+ jobs.set(job.asyncId, job);
19
+ }
20
+ for (const job of state.fleetJobs?.values() ?? []) {
21
+ if (job.sessionId === sessionId && !jobs.has(job.asyncId))
22
+ jobs.set(job.asyncId, job);
23
+ }
24
+ return [...jobs.values()];
25
+ }
26
+ export function buildAsyncStatusSnapshotForState(state, sessionId, options = {}) {
27
+ return buildAsyncStatusSnapshot(asyncStatusSnapshotJobsForState(state, sessionId), options);
28
+ }
29
+ export function encodeAsyncStatusSnapshotWidget(jobs, options = {}) {
30
+ return [`${ASYNC_STATUS_SNAPSHOT_WIDGET_PREFIX}${JSON.stringify(buildAsyncStatusSnapshot(jobs, options))}`];
31
+ }
@@ -1,12 +1,27 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
3
  import { formatDuration, formatModelThinking, formatTokens, shortenPath } from "../../shared/formatters.js";
4
+ import { previewDisplayText } from "../../shared/display-text.js";
4
5
  import { formatActivityLabel, formatParallelOutcome } from "../../shared/status-format.js";
5
6
  import { readStatus } from "../../shared/utils.js";
6
- import { attachRootChildrenToSteps, buildNestedRouteIndex, projectNestedEvents } from "../shared/nested-events.js";
7
+ import { attachRootChildrenToSteps, buildNestedRouteIndex, findNestedRouteForRootId, projectNestedEvents } from "../shared/nested-events.js";
7
8
  import { formatNestedRunStatusLines } from "../shared/nested-render.js";
9
+ import { formatRunFanoutBudget, getRunFanoutBudgetSnapshot, readRunFanoutBudgetDescriptor } from "../shared/run-fanout-budget.js";
8
10
  import { flatToLogicalStepIndex, normalizeParallelGroups } from "./parallel-groups.js";
11
+ import { contextModeLabel, summarizeContextModes } from "../shared/context-mode.js";
9
12
  import { reconcileAsyncRun, reconcileNestedAsyncDescendants } from "./stale-run-reconciler.js";
13
+ import { readProcessTerminal, sanitizeProcessTerminal } from "./process-terminal.js";
14
+ import { ACTIVE_RUN_INDEX_DIR, DEFAULT_STALE_TERMINAL_ACTIVE_MARKER_MS, activeRunMarkerAgeMs, isActiveAsyncState, readActiveRunIndex, releaseActiveRunIndex, updateActiveRunIndex } from "./active-run-index.js";
15
+ import { readRecentTerminalRunIndex, TERMINAL_RUN_INDEX_DIR } from "./terminal-run-index.js";
16
+ import { canScanAsyncRunPrefix } from "./run-id-query.js";
17
+ import { asyncStatusChildIdentity } from "../shared/child-identity.js";
18
+ import { parseWorkflowChildSummary } from "../../workflows/workflow-child-summary.js";
19
+ import { assertWorkflowGraphHostSteps, hostStepReportName, hostStepVerdictLabel, validHostStepNodes } from "../shared/host-step-status.js";
20
+ import { projectAsyncWorkflowRows } from "../shared/async-status-projection.js";
21
+ import { validateAsyncStatusLaneMetadata } from "../shared/lane-metadata.js";
22
+ import { formatWorkflowPreflightPlanSummary, formatWorkflowPreflightWarningSummary } from "../../workflows/workflow-preflight.js";
23
+ import { workflowGraphStageNodes } from "../shared/workflow-graph.js";
24
+ import { formatTimeoutRecoveryLines, projectTimeoutRecovery } from "../shared/mutation-evidence.js";
10
25
  function getErrorMessage(error) {
11
26
  return error instanceof Error ? error.message : String(error);
12
27
  }
@@ -25,6 +40,41 @@ function isAsyncRunDir(root, entry) {
25
40
  });
26
41
  }
27
42
  }
43
+ export function resolveTargetedAsyncRun(asyncDirRoot, id, sessionId) {
44
+ if (!id || id === "." || id === ".." || id === ACTIVE_RUN_INDEX_DIR || id === TERMINAL_RUN_INDEX_DIR || path.basename(id) !== id)
45
+ return { kind: "reject" };
46
+ const asyncDir = path.join(asyncDirRoot, id);
47
+ let entryStat;
48
+ try {
49
+ entryStat = fs.lstatSync(asyncDir);
50
+ } catch (error) {
51
+ if (isNotFoundError(error))
52
+ return canScanAsyncRunPrefix(id) ? { kind: "prefix" } : { kind: "reject" };
53
+ throw new Error(`Failed to inspect async run path '${asyncDir}': ${getErrorMessage(error)}`, {
54
+ cause: error instanceof Error ? error : undefined
55
+ });
56
+ }
57
+ if (!entryStat.isDirectory() || entryStat.isSymbolicLink())
58
+ return { kind: "reject" };
59
+ try {
60
+ const canonicalRoot = fs.realpathSync(asyncDirRoot);
61
+ const canonicalDir = fs.realpathSync(asyncDir);
62
+ if (canonicalDir !== canonicalRoot && !canonicalDir.startsWith(`${canonicalRoot}${path.sep}`))
63
+ return { kind: "reject" };
64
+ } catch (error) {
65
+ if (isNotFoundError(error))
66
+ return { kind: "reject" };
67
+ throw new Error(`Failed to resolve async run path '${asyncDir}': ${getErrorMessage(error)}`, {
68
+ cause: error instanceof Error ? error : undefined
69
+ });
70
+ }
71
+ if (sessionId !== undefined) {
72
+ const status = readStatus(asyncDir);
73
+ if (status?.sessionId !== sessionId)
74
+ return canScanAsyncRunPrefix(id) ? { kind: "prefix" } : { kind: "reject" };
75
+ }
76
+ return { kind: "exact", id };
77
+ }
28
78
  function outputFileMtime(outputFile) {
29
79
  if (!outputFile)
30
80
  return;
@@ -45,19 +95,35 @@ function deriveAsyncActivityState(asyncDir, status) {
45
95
  const currentStep = typeof status.currentStep === "number" ? status.steps?.[status.currentStep] : undefined;
46
96
  return {
47
97
  activityState: status.activityState,
48
- lastActivityAt: status.lastActivityAt ?? outputFileMtime(outputPath) ?? currentStep?.lastActivityAt ?? currentStep?.startedAt ?? status.startedAt
98
+ lastActivityAt: status.lastActivityAt ?? outputFileMtime(outputPath) ?? currentStep?.lastActivityAt ?? (status.mode === "workflow" ? undefined : currentStep?.startedAt ?? status.startedAt)
49
99
  };
50
100
  }
51
101
  function statusToSummary(asyncDir, status, nestedWarnings = [], nestedRoute) {
102
+ validateAsyncStatusLaneMetadata(status, `Invalid async status '${path.join(asyncDir, "status.json")}'`);
103
+ const workflowChildren = parseWorkflowChildSummary(status.workflowChildren);
104
+ if (workflowChildren && workflowChildren.workflowRunId !== status.runId)
105
+ throw new Error(`Invalid async status '${path.join(asyncDir, "status.json")}': workflowChildren.workflowRunId does not match.`);
106
+ assertWorkflowGraphHostSteps(status.workflowGraph, path.join(asyncDir, "status.json"), status.runId);
107
+ const hostSteps = validHostStepNodes(status.workflowGraph);
52
108
  if (status.sessionId !== undefined && typeof status.sessionId !== "string") {
53
109
  throw new Error(`Invalid async status '${path.join(asyncDir, "status.json")}': sessionId must be a string.`);
54
110
  }
55
111
  const { activityState, lastActivityAt } = deriveAsyncActivityState(asyncDir, status);
112
+ const processTerminal = readProcessTerminal(asyncDir, { runId: status.runId, runnerProcessInstanceId: status.processTerminal?.runnerProcessInstanceId }) ?? sanitizeProcessTerminal(status.processTerminal, { runId: status.runId, runnerProcessInstanceId: status.processTerminal?.runnerProcessInstanceId }, path.join(asyncDir, "status.json"));
113
+ const nestedProjectionAllowed = nestedWarnings.length === 0;
114
+ let runFanoutBudget = status.runFanoutBudget;
115
+ try {
116
+ const runFanoutBudgetDescriptor = readRunFanoutBudgetDescriptor(asyncDir);
117
+ if (runFanoutBudgetDescriptor)
118
+ runFanoutBudget = getRunFanoutBudgetSnapshot(runFanoutBudgetDescriptor);
119
+ } catch (error) {
120
+ nestedWarnings.push(`Run fan-out status unavailable: ${getErrorMessage(error)}`);
121
+ }
56
122
  const steps = status.steps ?? [];
57
123
  const chainStepCount = status.chainStepCount ?? steps.length;
58
124
  const parallelGroups = normalizeParallelGroups(status.parallelGroups, steps.length, chainStepCount);
59
125
  let nestedChildren = [];
60
- if (nestedWarnings.length === 0 && nestedRoute) {
126
+ if (nestedProjectionAllowed && nestedRoute) {
61
127
  try {
62
128
  nestedChildren = projectNestedEvents(nestedRoute)?.children ?? [];
63
129
  } catch (error) {
@@ -67,14 +133,25 @@ function statusToSummary(asyncDir, status, nestedWarnings = [], nestedRoute) {
67
133
  const summarizedSteps = steps.map((step, index) => {
68
134
  const stepActivityState = step.activityState;
69
135
  const stepLastActivityAt = step.lastActivityAt;
136
+ const timeoutRecovery = projectTimeoutRecovery(step.timeoutRecovery);
70
137
  return {
71
138
  index,
139
+ childId: asyncStatusChildIdentity(step, index),
72
140
  agent: step.agent,
141
+ ...step.sessionName ? { sessionName: step.sessionName } : {},
142
+ ...step.context ? { context: step.context } : {},
73
143
  ...step.label ? { label: step.label } : {},
144
+ ...step.description ? { description: step.description } : {},
74
145
  ...step.phase ? { phase: step.phase } : {},
146
+ ...step.workflowKey ? { workflowKey: step.workflowKey } : {},
147
+ ...step.lane ? { lane: step.lane } : {},
148
+ ...step.worktreePath ? { worktreePath: step.worktreePath } : {},
149
+ ...step.branch ? { branch: step.branch } : {},
150
+ ...step.runId ? { runId: step.runId } : {},
75
151
  ...step.outputName ? { outputName: step.outputName } : {},
76
152
  ...step.structured ? { structured: step.structured } : {},
77
153
  status: step.status,
154
+ ...step.runner ? { runner: step.runner } : {},
78
155
  ...stepActivityState ? { activityState: stepActivityState } : {},
79
156
  ...stepLastActivityAt ? { lastActivityAt: stepLastActivityAt } : {},
80
157
  ...step.currentTool ? { currentTool: step.currentTool } : {},
@@ -85,20 +162,40 @@ function statusToSummary(asyncDir, status, nestedWarnings = [], nestedRoute) {
85
162
  ...step.recentOutput ? { recentOutput: [...step.recentOutput] } : {},
86
163
  ...step.turnCount !== undefined ? { turnCount: step.turnCount } : {},
87
164
  ...step.toolCount !== undefined ? { toolCount: step.toolCount } : {},
88
- ...step.steerCount !== undefined ? { steerCount: step.steerCount } : {},
89
- ...step.lastSteerAt !== undefined ? { lastSteerAt: step.lastSteerAt } : {},
165
+ ...step.steering ? { steering: step.steering } : {},
90
166
  ...step.durationMs !== undefined ? { durationMs: step.durationMs } : {},
91
167
  ...step.tokens ? { tokens: step.tokens } : {},
92
168
  ...step.totalCost ? { totalCost: step.totalCost } : {},
93
169
  ...step.skills ? { skills: step.skills } : {},
94
170
  ...step.model ? { model: step.model } : {},
171
+ ...step.contextLimit !== undefined ? { contextLimit: step.contextLimit } : {},
95
172
  ...step.thinking ? { thinking: step.thinking } : {},
173
+ ...step.thinkingCeiling ? { thinkingCeiling: step.thinkingCeiling } : {},
96
174
  ...step.attemptedModels ? { attemptedModels: step.attemptedModels } : {},
175
+ ...step.sessionFile ? { sessionFile: step.sessionFile } : {},
176
+ ...step.transcriptPath ? { transcriptPath: step.transcriptPath } : {},
97
177
  ...step.error ? { error: step.error } : {},
98
178
  ...step.timedOut !== undefined ? { timedOut: step.timedOut } : {},
179
+ ...step.stopped !== undefined ? { stopped: step.stopped } : {},
180
+ ...step.stopRequested !== undefined ? { stopRequested: step.stopRequested } : {},
181
+ ...step.stopRequestedAt !== undefined ? { stopRequestedAt: step.stopRequestedAt } : {},
99
182
  ...step.turnBudget ? { turnBudget: step.turnBudget } : {},
100
183
  ...step.turnBudgetExceeded !== undefined ? { turnBudgetExceeded: step.turnBudgetExceeded } : {},
184
+ ...step.toolBudgetBlocked !== undefined ? { toolBudgetBlocked: step.toolBudgetBlocked } : {},
101
185
  ...step.wrapUpRequested !== undefined ? { wrapUpRequested: step.wrapUpRequested } : {},
186
+ ...step.acceptance ? { acceptance: step.acceptance } : {},
187
+ ...step.agentContract ? { agentContract: step.agentContract } : {},
188
+ ...step.launchContractDigest ? { launchContractDigest: step.launchContractDigest } : {},
189
+ ...step.launchResolvedExtensions ? { launchResolvedExtensions: step.launchResolvedExtensions } : {},
190
+ ...step.runtimeAcknowledgedExtensions ? { runtimeAcknowledgedExtensions: step.runtimeAcknowledgedExtensions } : {},
191
+ ...step.execution ? { execution: step.execution } : {},
192
+ ...step.review ? { review: step.review } : {},
193
+ ...step.effects ? { effects: step.effects } : {},
194
+ ...step.watchdog ? { watchdog: step.watchdog } : {},
195
+ ...step.processTerminal ? { processTerminal: sanitizeProcessTerminal(step.processTerminal, { runId: status.runId, runnerProcessInstanceId: step.processTerminal.runnerProcessInstanceId }, `${path.join(asyncDir, "status.json")} step ${index}`) } : {},
196
+ ...timeoutRecovery ? { timeoutRecovery } : {},
197
+ ...step.capabilityCeiling ? { capabilityCeiling: step.capabilityCeiling } : {},
198
+ ...step.capabilityAudit ? { capabilityAudit: step.capabilityAudit } : {},
102
199
  ...step.children?.length ? { children: step.children } : {}
103
200
  };
104
201
  });
@@ -106,6 +203,7 @@ function statusToSummary(asyncDir, status, nestedWarnings = [], nestedRoute) {
106
203
  return {
107
204
  id: status.runId || path.basename(asyncDir),
108
205
  asyncDir,
206
+ ...status.toolCallId ? { toolCallId: status.toolCallId } : {},
109
207
  ...status.sessionId ? { sessionId: status.sessionId } : {},
110
208
  state: status.state,
111
209
  ...status.error ? { error: status.error } : {},
@@ -116,16 +214,18 @@ function statusToSummary(asyncDir, status, nestedWarnings = [], nestedRoute) {
116
214
  currentPath: status.currentPath,
117
215
  turnCount: status.turnCount,
118
216
  toolCount: status.toolCount,
119
- steerCount: status.steerCount,
120
- lastSteerAt: status.lastSteerAt,
217
+ steering: status.steering,
121
218
  mode: status.mode,
219
+ ...summarizeContextModes(summarizedSteps.map((step) => step.context)) ? { context: summarizeContextModes(summarizedSteps.map((step) => step.context)) } : {},
122
220
  cwd: status.cwd,
221
+ ...status.sessionRoot ? { sessionRoot: status.sessionRoot } : {},
123
222
  startedAt: status.startedAt,
124
223
  lastUpdate: status.lastUpdate,
125
224
  endedAt: status.endedAt,
126
225
  ...status.timeoutMs !== undefined ? { timeoutMs: status.timeoutMs } : {},
127
226
  ...status.deadlineAt !== undefined ? { deadlineAt: status.deadlineAt } : {},
128
227
  ...status.timedOut !== undefined ? { timedOut: status.timedOut } : {},
228
+ ...status.stopped !== undefined ? { stopped: status.stopped } : {},
129
229
  ...status.turnBudget ? { turnBudget: status.turnBudget } : {},
130
230
  ...status.turnBudgetExceeded !== undefined ? { turnBudgetExceeded: status.turnBudgetExceeded } : {},
131
231
  ...status.wrapUpRequested !== undefined ? { wrapUpRequested: status.wrapUpRequested } : {},
@@ -133,16 +233,35 @@ function statusToSummary(asyncDir, status, nestedWarnings = [], nestedRoute) {
133
233
  ...status.chainStepCount !== undefined ? { chainStepCount: status.chainStepCount } : {},
134
234
  ...status.pendingAppends !== undefined ? { pendingAppends: status.pendingAppends } : {},
135
235
  ...parallelGroups.length ? { parallelGroups } : {},
236
+ ...hostSteps.length ? { hostSteps } : {},
237
+ ...status.mode === "workflow" && status.workflowGraph ? { workflowGraph: status.workflowGraph } : {},
136
238
  steps: summarizedSteps,
137
239
  ...nestedChildren.length ? { nestedChildren } : {},
138
240
  ...nestedWarnings.length ? { nestedWarnings } : {},
241
+ ...processTerminal ? { processTerminal } : {},
242
+ ...runFanoutBudget ? { runFanoutBudget } : {},
243
+ ...status.launchContractDigest ? { launchContractDigest: status.launchContractDigest } : {},
244
+ ...status.launchResolvedExtensions ? { launchResolvedExtensions: status.launchResolvedExtensions } : {},
245
+ ...status.runtimeAcknowledgedExtensions ? { runtimeAcknowledgedExtensions: status.runtimeAcknowledgedExtensions } : {},
246
+ ...status.capabilityCeiling ? { capabilityCeiling: status.capabilityCeiling } : {},
247
+ ...status.capabilityAudit ? { capabilityAudit: status.capabilityAudit } : {},
248
+ ...status.parentWorkflowRunId ? { parentWorkflowRunId: status.parentWorkflowRunId } : {},
249
+ ...status.workflowKey ? { workflowKey: status.workflowKey } : {},
250
+ ...status.lane ? { lane: status.lane } : {},
251
+ ...status.workflow ? { workflow: status.workflow } : {},
252
+ ...workflowChildren ? { workflowChildren } : {},
253
+ ...status.preflight ? { preflight: status.preflight } : {},
139
254
  ...status.sessionDir ? { sessionDir: status.sessionDir } : {},
140
255
  ...status.outputFile ? { outputFile: status.outputFile } : {},
141
256
  ...status.totalTokens ? { totalTokens: status.totalTokens } : {},
142
257
  ...status.totalCost ? { totalCost: status.totalCost } : {},
258
+ ...status.usageBudget ? { usageBudget: status.usageBudget } : {},
143
259
  ...status.sessionFile ? { sessionFile: status.sessionFile } : {}
144
260
  };
145
261
  }
262
+ export function summarizeAsyncStatus(asyncDir, status) {
263
+ return statusToSummary(asyncDir, status);
264
+ }
146
265
  function sortRuns(runs) {
147
266
  const rank = (state) => {
148
267
  switch (state) {
@@ -152,10 +271,16 @@ function sortRuns(runs) {
152
271
  return 1;
153
272
  case "failed":
154
273
  return 2;
274
+ case "partial":
275
+ return 2;
276
+ case "stopped":
277
+ return 2;
155
278
  case "paused":
156
279
  return 2;
157
280
  case "complete":
158
281
  return 3;
282
+ default:
283
+ return 4;
159
284
  }
160
285
  };
161
286
  return [...runs].sort((a, b) => {
@@ -169,8 +294,34 @@ function sortRuns(runs) {
169
294
  }
170
295
  export function listAsyncRuns(asyncDirRoot, options = {}) {
171
296
  let entries;
297
+ const activeEntries = new Set;
298
+ const wantsActive = options.states === undefined || options.states.some(isActiveAsyncState);
299
+ const wantsTerminal = options.states === undefined || options.states.some((state) => !isActiveAsyncState(state));
300
+ const includeNested = options.includeNested !== false;
172
301
  try {
173
- entries = fs.readdirSync(asyncDirRoot).filter((entry) => isAsyncRunDir(asyncDirRoot, entry));
302
+ if (options.runId !== undefined) {
303
+ const resolution = resolveTargetedAsyncRun(asyncDirRoot, options.runId, options.sessionId);
304
+ entries = resolution.kind === "exact" ? [resolution.id] : resolution.kind === "prefix" && options.exactRunId !== true ? fs.readdirSync(asyncDirRoot).filter((entry) => (entry === options.runId || entry.startsWith(options.runId)) && resolveTargetedAsyncRun(asyncDirRoot, entry, options.sessionId).kind === "exact") : [];
305
+ } else if (options.repairScan === true) {
306
+ entries = fs.readdirSync(asyncDirRoot).filter((entry) => entry !== ACTIVE_RUN_INDEX_DIR && entry !== TERMINAL_RUN_INDEX_DIR && isAsyncRunDir(asyncDirRoot, entry));
307
+ } else {
308
+ const indexed = new Set;
309
+ if (wantsActive) {
310
+ for (const entry of readActiveRunIndex(asyncDirRoot) ?? []) {
311
+ if (resolveTargetedAsyncRun(asyncDirRoot, entry).kind === "exact") {
312
+ indexed.add(entry);
313
+ activeEntries.add(entry);
314
+ } else {
315
+ updateActiveRunIndex(path.join(asyncDirRoot, entry), "failed");
316
+ }
317
+ }
318
+ }
319
+ if (wantsTerminal) {
320
+ for (const entry of readRecentTerminalRunIndex(asyncDirRoot, { sessionId: options.sessionId, ...options.entryLimit !== undefined ? { limit: options.entryLimit } : {} }))
321
+ indexed.add(entry);
322
+ }
323
+ entries = [...indexed];
324
+ }
174
325
  } catch (error) {
175
326
  if (isNotFoundError(error))
176
327
  return [];
@@ -182,6 +333,10 @@ export function listAsyncRuns(asyncDirRoot, options = {}) {
182
333
  const runs = [];
183
334
  let nestedRouteIndex;
184
335
  const resolveNestedRoute = (rootRunId) => {
336
+ if (!includeNested)
337
+ return;
338
+ if (activeEntries.has(rootRunId))
339
+ return findNestedRouteForRootId(rootRunId);
185
340
  if (!nestedRouteIndex)
186
341
  nestedRouteIndex = buildNestedRouteIndex();
187
342
  return nestedRouteIndex.get(rootRunId);
@@ -190,7 +345,17 @@ export function listAsyncRuns(asyncDirRoot, options = {}) {
190
345
  const asyncDir = path.join(asyncDirRoot, entry);
191
346
  const reconciliation = options.reconcile === false ? undefined : reconcileAsyncRun(asyncDir, { resultsDir: options.resultsDir, kill: options.kill, now: options.now });
192
347
  const status = reconciliation?.status ?? readStatus(asyncDir);
193
- if (!status)
348
+ if (!status) {
349
+ if (activeEntries.has(entry))
350
+ updateActiveRunIndex(asyncDir, "failed");
351
+ continue;
352
+ }
353
+ if (activeEntries.has(entry) && !isActiveAsyncState(status.state)) {
354
+ const processTerminal = readProcessTerminal(asyncDir, { runId: status.runId, runnerProcessInstanceId: status.processTerminal?.runnerProcessInstanceId });
355
+ if (processTerminal?.state === "observed" || (activeRunMarkerAgeMs(asyncDir, options.now?.()) ?? 0) > DEFAULT_STALE_TERMINAL_ACTIVE_MARKER_MS)
356
+ releaseActiveRunIndex(asyncDir);
357
+ }
358
+ if (status.displayDismissedAt !== undefined)
194
359
  continue;
195
360
  if (allowedStates && !allowedStates.has(status.state))
196
361
  continue;
@@ -198,12 +363,14 @@ export function listAsyncRuns(asyncDirRoot, options = {}) {
198
363
  continue;
199
364
  const nestedWarnings = [];
200
365
  let nestedRoute;
201
- try {
202
- nestedRoute = resolveNestedRoute(status.runId || path.basename(asyncDir));
203
- if (nestedRoute)
204
- reconcileNestedAsyncDescendants(nestedRoute, { resultsDir: options.resultsDir, kill: options.kill, now: options.now });
205
- } catch (error) {
206
- nestedWarnings.push(`Nested status unavailable: ${getErrorMessage(error)}`);
366
+ if (options.reconcile !== false && includeNested) {
367
+ try {
368
+ nestedRoute = resolveNestedRoute(status.runId || path.basename(asyncDir));
369
+ if (nestedRoute)
370
+ reconcileNestedAsyncDescendants(nestedRoute, { resultsDir: options.resultsDir, kill: options.kill, now: options.now });
371
+ } catch (error) {
372
+ nestedWarnings.push(`Nested status unavailable: ${getErrorMessage(error)}`);
373
+ }
207
374
  }
208
375
  const summary = statusToSummary(asyncDir, status, nestedWarnings, nestedRoute);
209
376
  runs.push(summary);
@@ -223,23 +390,24 @@ function formatActivityFacts(input) {
223
390
  facts.push(`${input.turnCount} turns`);
224
391
  if (input.turnBudgetExceeded && input.turnBudget)
225
392
  facts.push(`turn budget exceeded ${input.turnBudget.turnCount}/${input.turnBudget.maxTurns}+${input.turnBudget.graceTurns}`);
393
+ else if (input.turnBudget?.outcome === "termination-deferred")
394
+ facts.push(`turn-budget termination deferred ${input.turnBudget.turnCount}/${input.turnBudget.maxTurns}+${input.turnBudget.graceTurns}`);
226
395
  else if (input.wrapUpRequested && input.turnBudget)
227
396
  facts.push(`wrap-up requested ${input.turnBudget.turnCount}/${input.turnBudget.maxTurns}`);
228
397
  else if (input.turnBudget)
229
398
  facts.push(`turn budget ${input.turnBudget.turnCount}/${input.turnBudget.maxTurns}+${input.turnBudget.graceTurns}`);
230
399
  if (input.toolCount !== undefined)
231
400
  facts.push(`${input.toolCount} tools`);
232
- if (input.steerCount !== undefined)
233
- facts.push(`${input.steerCount} steers`);
234
- if (typeof input.lastSteerAt === "number" && Number.isFinite(input.lastSteerAt))
235
- facts.push(`last steer ${new Date(input.lastSteerAt).toISOString()}`);
401
+ if (input.steering)
402
+ facts.push(`steering ${input.steering.scheduled} scheduled, ${input.steering.pending} pending, ${input.steering.delivered} delivered, ${input.steering.failed} failed, ${input.steering.recovered} recovered`);
236
403
  const activity = formatActivityLabel(input.lastActivityAt, input.activityState);
237
404
  return activity || facts.length ? [activity, ...facts].filter(Boolean).join(" | ") : undefined;
238
405
  }
239
406
  function formatStepLine(step) {
240
- const display = step.label ? `${step.label} (${step.agent})` : step.agent;
407
+ const display = step.sessionName?.trim() || (step.label ? `${step.label} (${step.agent})` : step.agent);
408
+ const context = contextModeLabel(step.context);
241
409
  const phase = step.phase ? `[${step.phase}] ` : "";
242
- const parts = [`${step.index + 1}. ${phase}${display}`, step.status];
410
+ const parts = [`${step.index + 1}. ${phase}${display}${context ? ` ${context}` : ""}`, step.status];
243
411
  const activity = formatActivityFacts(step);
244
412
  if (activity)
245
413
  parts.push(activity);
@@ -250,14 +418,62 @@ function formatStepLine(step) {
250
418
  parts.push(formatDuration(step.durationMs));
251
419
  if (step.tokens)
252
420
  parts.push(`${formatTokens(step.tokens.total)} tok`);
421
+ if (step.lane)
422
+ parts.push(`lane ${step.lane.key}`);
423
+ if (step.worktreePath)
424
+ parts.push(`worktree ${shortenPath(step.worktreePath)} · branch ${step.branch ?? "unknown"}`);
253
425
  return parts.join(" | ");
254
426
  }
427
+ function formatHostStepLine(row) {
428
+ if (!row.kind)
429
+ return "";
430
+ const state = hostStepVerdictLabel(row.state, row.verdict);
431
+ const details = [
432
+ row.provider ? `provider:${row.provider}` : undefined,
433
+ row.role ? `role:${row.role}` : undefined,
434
+ row.target,
435
+ row.detail,
436
+ row.reasonCode ? `reason:${row.reasonCode}` : undefined,
437
+ row.freshness?.stale ? "stale" : row.freshness?.observedRef ? `ref:${row.freshness.observedRef}` : undefined,
438
+ row.reportPath ? `out:${hostStepReportName(row.reportPath)}` : undefined
439
+ ].filter((value) => Boolean(value));
440
+ return `host ${row.kind}: ${row.name} | ${state}${details.length ? ` | ${details.join(" | ")}` : ""}`;
441
+ }
442
+ function workflowStageStateLabel(status) {
443
+ switch (status) {
444
+ case "completed":
445
+ return "complete";
446
+ case "detached":
447
+ return "paused";
448
+ default:
449
+ return status;
450
+ }
451
+ }
452
+ export function formatWorkflowStageLine(node, index, total) {
453
+ const state = workflowStageStateLabel(node.status);
454
+ const id = previewDisplayText(node.id, 160);
455
+ const label = node.label ? previewDisplayText(node.label, 160) : "";
456
+ const display = label && label !== id ? ` | ${label}` : "";
457
+ const agent = node.agent ? ` | ${previewDisplayText(node.agent, 80)}` : "";
458
+ const error = node.error ? ` | ${previewDisplayText(node.error, 240)}` : "";
459
+ return `stage ${index + 1}/${total}: ${id}${display}${agent} | ${state}${error}`;
460
+ }
255
461
  export function formatAsyncRunOutputPath(run) {
256
462
  if (!run.outputFile)
257
463
  return;
258
464
  return path.isAbsolute(run.outputFile) ? run.outputFile : path.join(run.asyncDir, run.outputFile);
259
465
  }
260
466
  export function formatAsyncRunProgressLabel(run) {
467
+ const graphStages = run.mode === "workflow" ? workflowGraphStageNodes(run.workflowGraph) : [];
468
+ if (graphStages.length > 0) {
469
+ const currentNode = graphStages.find((node) => node.id === run.workflowGraph?.currentNodeId);
470
+ if (currentNode && currentNode.status !== "completed")
471
+ return `stage ${graphStages.indexOf(currentNode) + 1}/${graphStages.length}`;
472
+ const activeNode = graphStages.find((node) => node.status === "running") ?? graphStages.find((node) => node.status !== "completed");
473
+ if (activeNode)
474
+ return `stage ${graphStages.indexOf(activeNode) + 1}/${graphStages.length}`;
475
+ return `stage ${graphStages.length}/${graphStages.length}`;
476
+ }
261
477
  const stepCount = run.steps.length || 1;
262
478
  const chainStepCount = run.chainStepCount ?? stepCount;
263
479
  const groups = normalizeParallelGroups(run.parallelGroups, run.steps.length, chainStepCount);
@@ -282,7 +498,9 @@ function formatRunHeader(run) {
282
498
  const cwd = run.cwd ? shortenPath(run.cwd) : shortenPath(run.asyncDir);
283
499
  const activity = formatActivityFacts(run);
284
500
  const pending = run.pendingAppends ? ` | ${run.pendingAppends} pending append${run.pendingAppends === 1 ? "" : "s"}` : "";
285
- return `${run.id} | ${run.state}${activity ? ` | ${activity}` : ""} | ${run.mode} | ${stepLabel}${pending} | ${cwd}`;
501
+ const context = contextModeLabel(run.context);
502
+ const lane = run.lane ? ` | lane ${run.lane.key}` : "";
503
+ return `${run.id} | ${run.state}${activity ? ` | ${activity}` : ""} | ${run.mode}${context ? ` ${context}` : ""} | ${stepLabel}${pending}${lane} | ${cwd}`;
286
504
  }
287
505
  export function formatAsyncRunList(runs, heading = "Active async runs") {
288
506
  if (runs.length === 0)
@@ -290,13 +508,32 @@ export function formatAsyncRunList(runs, heading = "Active async runs") {
290
508
  const lines = [`${heading}: ${runs.length}`, ""];
291
509
  for (const run of runs) {
292
510
  lines.push(`- ${formatRunHeader(run)}`);
511
+ if (run.preflight)
512
+ lines.push(formatWorkflowPreflightPlanSummary(run.preflight, { indent: " " }));
513
+ const preflightWarning = formatWorkflowPreflightWarningSummary(run.workflow?.preflightWarnings, { indent: " " });
514
+ if (preflightWarning)
515
+ lines.push(preflightWarning);
293
516
  for (const step of run.steps) {
294
517
  lines.push(` ${formatStepLine(step)}`);
518
+ lines.push(...formatTimeoutRecoveryLines(step.timeoutRecovery, " "));
295
519
  lines.push(...formatNestedRunStatusLines(step.children, { indent: " ", maxLines: 12 }));
296
520
  }
521
+ const loadedWorkflowKeys = new Set(run.steps.flatMap((step) => step.workflowKey ? [step.workflowKey] : []));
522
+ const graphStages = run.mode === "workflow" ? workflowGraphStageNodes(run.workflowGraph) : [];
523
+ for (const [index, node] of graphStages.entries()) {
524
+ if (!loadedWorkflowKeys.has(node.id))
525
+ lines.push(` ${formatWorkflowStageLine(node, index, graphStages.length)}`);
526
+ }
527
+ for (const row of projectAsyncWorkflowRows([], run.hostSteps)) {
528
+ const line = formatHostStepLine(row);
529
+ if (line)
530
+ lines.push(` ${line}`);
531
+ }
297
532
  const attached = new Set(run.steps.flatMap((step) => step.children?.map((child) => child.id) ?? []));
298
533
  const unattached = run.nestedChildren?.filter((child) => !attached.has(child.id)) ?? [];
299
534
  lines.push(...formatNestedRunStatusLines(unattached, { indent: " ", maxLines: 12 }));
535
+ if (run.runFanoutBudget)
536
+ lines.push(` ${formatRunFanoutBudget(run.runFanoutBudget)}`);
300
537
  if (run.error)
301
538
  lines.push(` Error: ${run.error}`);
302
539
  for (const warning of run.nestedWarnings ?? [])
@@ -0,0 +1,46 @@
1
+ import { snapshotBackgroundWork } from "../../api/background-work.js";
2
+ import { DIRS } from "../../shared/types.js";
3
+ import { listAsyncRuns } from "./async-status.js";
4
+ import { waitForSubagents } from "./subagent-wait.js";
5
+ export const DEFAULT_AUTO_DRAIN_TIMEOUT_MS = 30 * 60 * 1000;
6
+ function resultText(value) {
7
+ return value.content.map((part) => part.type === "text" ? part.text : "").join(" ").trim();
8
+ }
9
+ function hasOutstandingWork(sessionId, nowMs) {
10
+ const asyncRuns = listAsyncRuns(DIRS.async, {
11
+ states: ["queued", "running"],
12
+ sessionId,
13
+ resultsDir: DIRS.results,
14
+ now: () => nowMs
15
+ });
16
+ return asyncRuns.length > 0 || snapshotBackgroundWork(sessionId, nowMs).items.length > 0;
17
+ }
18
+ export async function drainOutstandingWork(deps) {
19
+ const sessionId = deps.state.currentSessionId;
20
+ if (!sessionId)
21
+ throw new Error("Cannot auto-drain background work without an active session identity.");
22
+ const now = deps.now ?? Date.now;
23
+ const timeoutMs = deps.timeoutMs ?? DEFAULT_AUTO_DRAIN_TIMEOUT_MS;
24
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0)
25
+ throw new Error("Auto-drain timeoutMs must be a positive finite number.");
26
+ const deadlineAt = now() + timeoutMs;
27
+ const hasWork = deps.hasWork ?? hasOutstandingWork;
28
+ const wait = deps.wait ?? waitForSubagents;
29
+ while (hasWork(sessionId, now())) {
30
+ const remainingMs = deadlineAt - now();
31
+ if (remainingMs <= 0) {
32
+ throw new Error(`Auto-drain timed out after ${timeoutMs}ms with background work still active in session '${sessionId}'.`);
33
+ }
34
+ const waitResult = await wait({ all: true, timeoutMs: remainingMs }, undefined, {
35
+ state: deps.state,
36
+ events: deps.events,
37
+ now,
38
+ stopOnAttention: false,
39
+ failOnFailedRuns: true,
40
+ failOnAttention: true
41
+ });
42
+ if (waitResult.isError) {
43
+ throw new Error(`Auto-drain failed for session '${sessionId}': ${resultText(waitResult) || "bg_wait returned an error without details"}.`);
44
+ }
45
+ }
46
+ }