@duckmind/dm-darwin-x64 0.43.2 → 0.43.8

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 (256) hide show
  1. package/dm +0 -0
  2. package/extensions/.dm-extensions.json +242 -49
  3. package/extensions/dm-9router-ext/package.json +2 -19
  4. package/extensions/dm-9router-ext/src/index.js +5 -0
  5. package/extensions/dm-ask-user/index.js +10 -0
  6. package/extensions/dm-ask-user/package.json +1 -21
  7. package/extensions/dm-cli-anything/package.json +0 -6
  8. package/extensions/dm-context/package.json +2 -12
  9. package/extensions/dm-context/src/context.js +1 -0
  10. package/extensions/dm-context/src/index.js +7 -0
  11. package/extensions/dm-context/src/utils.js +1 -0
  12. package/extensions/dm-cua/package.json +0 -7
  13. package/extensions/dm-fff/package.json +1 -28
  14. package/extensions/dm-fff/src/index.js +15 -0
  15. package/extensions/dm-fff/src/query.js +1 -0
  16. package/extensions/dm-goal/package.json +2 -31
  17. package/extensions/dm-goal/src/goal.js +43 -0
  18. package/extensions/dm-grill-me/index.js +174 -0
  19. package/extensions/dm-grill-me/package.json +1 -26
  20. package/extensions/dm-image2/package.json +0 -7
  21. package/extensions/dm-subagents/package.json +1 -32
  22. package/extensions/dm-subagents/src/agents/agent-management.js +37 -0
  23. package/extensions/dm-subagents/src/agents/agent-memory.js +6 -0
  24. package/extensions/dm-subagents/src/agents/agent-scope.js +1 -0
  25. package/extensions/dm-subagents/src/agents/agent-selection.js +1 -0
  26. package/extensions/dm-subagents/src/agents/agent-serializer.js +7 -0
  27. package/extensions/dm-subagents/src/agents/agents.js +11 -0
  28. package/extensions/dm-subagents/src/agents/chain-serializer.js +12 -0
  29. package/extensions/dm-subagents/src/agents/frontmatter.js +6 -0
  30. package/extensions/dm-subagents/src/agents/identity.js +1 -0
  31. package/extensions/dm-subagents/src/agents/proactive-skills.js +1 -0
  32. package/extensions/dm-subagents/src/agents/skills.js +6 -0
  33. package/extensions/dm-subagents/src/extension/config.js +2 -0
  34. package/extensions/dm-subagents/src/extension/control-notices.js +4 -0
  35. package/extensions/dm-subagents/src/extension/doctor.js +16 -0
  36. package/extensions/dm-subagents/src/extension/fanout-child.js +231 -0
  37. package/extensions/dm-subagents/src/extension/index.js +367 -0
  38. package/extensions/dm-subagents/src/extension/rpc.js +8 -0
  39. package/extensions/dm-subagents/src/extension/schemas.js +1 -0
  40. package/extensions/dm-subagents/src/extension/{tool-description.ts → tool-description.js} +6 -126
  41. package/extensions/dm-subagents/src/intercom/intercom-bridge.js +13 -0
  42. package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +5 -0
  43. package/extensions/dm-subagents/src/intercom/result-intercom.js +3 -0
  44. package/extensions/dm-subagents/src/profiles/profiles.js +3 -0
  45. package/extensions/dm-subagents/src/runs/background/async-execution.js +46 -0
  46. package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +14 -0
  47. package/extensions/dm-subagents/src/runs/background/async-resume.js +8 -0
  48. package/extensions/dm-subagents/src/runs/background/async-status.js +12 -0
  49. package/extensions/dm-subagents/src/runs/background/chain-append.js +2 -0
  50. package/extensions/dm-subagents/src/runs/background/chain-root-attachment.js +1 -0
  51. package/extensions/dm-subagents/src/runs/background/completion-batcher.js +1 -0
  52. package/extensions/dm-subagents/src/runs/background/completion-dedupe.js +1 -0
  53. package/extensions/dm-subagents/src/runs/background/control-channel.js +1 -0
  54. package/extensions/dm-subagents/src/runs/background/fleet-view.js +17 -0
  55. package/extensions/dm-subagents/src/runs/background/notify.js +3 -0
  56. package/extensions/dm-subagents/src/runs/background/parallel-groups.js +1 -0
  57. package/extensions/dm-subagents/src/runs/background/result-watcher.js +8 -0
  58. package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +4 -0
  59. package/extensions/dm-subagents/src/runs/background/run-status.js +23 -0
  60. package/extensions/dm-subagents/src/runs/background/scheduled-runs.js +4 -0
  61. package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +11 -0
  62. package/extensions/dm-subagents/src/runs/background/subagent-runner.js +78 -0
  63. package/extensions/dm-subagents/src/runs/background/top-level-async.js +1 -0
  64. package/extensions/dm-subagents/src/runs/background/wait.js +11 -0
  65. package/extensions/dm-subagents/src/runs/foreground/chain-clarify.js +12 -0
  66. package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +102 -0
  67. package/extensions/dm-subagents/src/runs/foreground/execution.js +51 -0
  68. package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +228 -0
  69. package/extensions/dm-subagents/src/runs/shared/acceptance.js +3 -0
  70. package/extensions/dm-subagents/src/runs/shared/chain-outputs.js +1 -0
  71. package/extensions/dm-subagents/src/runs/shared/completion-guard.js +3 -0
  72. package/extensions/dm-subagents/src/runs/shared/dm-args.js +1 -0
  73. package/extensions/dm-subagents/src/runs/shared/dm-spawn.js +1 -0
  74. package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.js +1 -0
  75. package/extensions/dm-subagents/src/runs/shared/long-running-guard.js +1 -0
  76. package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.js +1 -0
  77. package/extensions/dm-subagents/src/runs/shared/model-fallback.js +1 -0
  78. package/extensions/dm-subagents/src/runs/shared/model-scope.js +1 -0
  79. package/extensions/dm-subagents/src/runs/shared/nested-events.js +8 -0
  80. package/extensions/dm-subagents/src/runs/shared/nested-path.js +1 -0
  81. package/extensions/dm-subagents/src/runs/shared/nested-render.js +1 -0
  82. package/extensions/dm-subagents/src/runs/shared/parallel-utils.js +5 -0
  83. package/extensions/dm-subagents/src/runs/shared/run-history.js +5 -0
  84. package/extensions/dm-subagents/src/runs/shared/single-output.js +14 -0
  85. package/extensions/dm-subagents/src/runs/shared/structured-output.js +1 -0
  86. package/extensions/dm-subagents/src/runs/shared/subagent-control.js +5 -0
  87. package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +22 -0
  88. package/extensions/dm-subagents/src/runs/shared/tool-budget.js +1 -0
  89. package/extensions/dm-subagents/src/runs/shared/turn-budget.js +7 -0
  90. package/extensions/dm-subagents/src/runs/shared/workflow-graph.js +1 -0
  91. package/extensions/dm-subagents/src/runs/shared/worktree.js +3 -0
  92. package/extensions/dm-subagents/src/shared/artifacts.js +2 -0
  93. package/extensions/dm-subagents/src/shared/atomic-json.js +1 -0
  94. package/extensions/dm-subagents/src/shared/child-transcript.js +5 -0
  95. package/extensions/dm-subagents/src/shared/file-coalescer.js +1 -0
  96. package/extensions/dm-subagents/src/shared/fork-context.js +6 -0
  97. package/extensions/dm-subagents/src/shared/formatters.js +9 -0
  98. package/extensions/dm-subagents/src/shared/jsonl-writer.js +2 -0
  99. package/extensions/dm-subagents/src/shared/model-info.js +1 -0
  100. package/extensions/dm-subagents/src/shared/post-exit-stdio-guard.js +1 -0
  101. package/extensions/dm-subagents/src/shared/session-identity.js +1 -0
  102. package/extensions/dm-subagents/src/shared/session-tokens.js +2 -0
  103. package/extensions/dm-subagents/src/shared/settings.js +23 -0
  104. package/extensions/dm-subagents/src/shared/status-format.js +1 -0
  105. package/extensions/dm-subagents/src/shared/types.js +8 -0
  106. package/extensions/dm-subagents/src/shared/utils.js +2 -0
  107. package/extensions/dm-subagents/src/slash/prompt-template-bridge.js +1 -0
  108. package/extensions/dm-subagents/src/slash/prompt-workflows.js +7 -0
  109. package/extensions/dm-subagents/src/slash/slash-bridge.js +1 -0
  110. package/extensions/dm-subagents/src/slash/slash-commands.js +38 -0
  111. package/extensions/dm-subagents/src/slash/slash-live-state.js +6 -0
  112. package/extensions/dm-subagents/src/tui/render-helpers.js +1 -0
  113. package/extensions/dm-subagents/src/tui/render.js +4 -0
  114. package/extensions/dm-tasks/package.json +1 -30
  115. package/extensions/dm-tasks/src/auto-clear.js +1 -0
  116. package/extensions/dm-tasks/src/index.js +212 -0
  117. package/extensions/dm-tasks/src/process-tracker.js +1 -0
  118. package/extensions/dm-tasks/src/task-store.js +1 -0
  119. package/extensions/dm-tasks/src/tasks-config.js +1 -0
  120. package/extensions/dm-tasks/src/types.js +0 -0
  121. package/extensions/dm-tasks/src/ui/settings-menu.js +1 -0
  122. package/extensions/dm-tasks/src/ui/task-widget.js +1 -0
  123. package/extensions/dm-usage/index.js +9 -0
  124. package/extensions/dm-usage/package.json +1 -18
  125. package/extensions/greedysearch-dm/bin/search.mjs +135 -135
  126. package/extensions/greedysearch-dm/index.js +20 -0
  127. package/extensions/greedysearch-dm/package.json +1 -22
  128. package/extensions/greedysearch-dm/src/formatters/results.js +8 -0
  129. package/extensions/greedysearch-dm/src/formatters/sources.js +1 -0
  130. package/extensions/greedysearch-dm/src/formatters/synthesis.js +1 -0
  131. package/extensions/greedysearch-dm/src/search/engines.mjs +9 -9
  132. package/extensions/greedysearch-dm/src/search/paths.mjs +1 -0
  133. package/extensions/greedysearch-dm/src/search/research.mjs +100 -100
  134. package/extensions/greedysearch-dm/src/search/synthesis-runner.mjs +10 -10
  135. package/extensions/greedysearch-dm/src/tools/greedy-search-handler.js +20 -0
  136. package/extensions/greedysearch-dm/src/tools/shared.js +9 -0
  137. package/extensions/greedysearch-dm/src/types.js +0 -0
  138. package/extensions/greedysearch-dm/src/utils/helpers.js +1 -0
  139. package/package.json +1 -1
  140. package/extensions/dm-9router-ext/src/index.ts +0 -541
  141. package/extensions/dm-ask-user/index.ts +0 -857
  142. package/extensions/dm-context/src/context.ts +0 -158
  143. package/extensions/dm-context/src/index.ts +0 -439
  144. package/extensions/dm-context/src/utils.ts +0 -6
  145. package/extensions/dm-fff/src/index.ts +0 -1023
  146. package/extensions/dm-fff/src/query.ts +0 -87
  147. package/extensions/dm-goal/src/goal.ts +0 -1073
  148. package/extensions/dm-grill-me/index.ts +0 -1085
  149. package/extensions/dm-subagents/src/agents/agent-management.ts +0 -1052
  150. package/extensions/dm-subagents/src/agents/agent-memory.ts +0 -254
  151. package/extensions/dm-subagents/src/agents/agent-scope.ts +0 -6
  152. package/extensions/dm-subagents/src/agents/agent-selection.ts +0 -25
  153. package/extensions/dm-subagents/src/agents/agent-serializer.ts +0 -121
  154. package/extensions/dm-subagents/src/agents/agents.ts +0 -1553
  155. package/extensions/dm-subagents/src/agents/chain-serializer.ts +0 -277
  156. package/extensions/dm-subagents/src/agents/frontmatter.ts +0 -93
  157. package/extensions/dm-subagents/src/agents/identity.ts +0 -30
  158. package/extensions/dm-subagents/src/agents/proactive-skills.ts +0 -191
  159. package/extensions/dm-subagents/src/agents/skills.ts +0 -729
  160. package/extensions/dm-subagents/src/extension/config.ts +0 -39
  161. package/extensions/dm-subagents/src/extension/control-notices.ts +0 -92
  162. package/extensions/dm-subagents/src/extension/doctor.ts +0 -214
  163. package/extensions/dm-subagents/src/extension/fanout-child.ts +0 -172
  164. package/extensions/dm-subagents/src/extension/index.ts +0 -656
  165. package/extensions/dm-subagents/src/extension/rpc.ts +0 -369
  166. package/extensions/dm-subagents/src/extension/schemas.ts +0 -309
  167. package/extensions/dm-subagents/src/intercom/intercom-bridge.ts +0 -180
  168. package/extensions/dm-subagents/src/intercom/native-supervisor-channel.ts +0 -519
  169. package/extensions/dm-subagents/src/intercom/result-intercom.ts +0 -377
  170. package/extensions/dm-subagents/src/profiles/profiles.ts +0 -637
  171. package/extensions/dm-subagents/src/runs/background/async-execution.ts +0 -1065
  172. package/extensions/dm-subagents/src/runs/background/async-job-tracker.ts +0 -441
  173. package/extensions/dm-subagents/src/runs/background/async-resume.ts +0 -391
  174. package/extensions/dm-subagents/src/runs/background/async-status.ts +0 -395
  175. package/extensions/dm-subagents/src/runs/background/chain-append.ts +0 -282
  176. package/extensions/dm-subagents/src/runs/background/chain-root-attachment.ts +0 -191
  177. package/extensions/dm-subagents/src/runs/background/completion-batcher.ts +0 -166
  178. package/extensions/dm-subagents/src/runs/background/completion-dedupe.ts +0 -63
  179. package/extensions/dm-subagents/src/runs/background/control-channel.ts +0 -332
  180. package/extensions/dm-subagents/src/runs/background/fleet-view.ts +0 -515
  181. package/extensions/dm-subagents/src/runs/background/notify.ts +0 -225
  182. package/extensions/dm-subagents/src/runs/background/parallel-groups.ts +0 -45
  183. package/extensions/dm-subagents/src/runs/background/result-watcher.ts +0 -315
  184. package/extensions/dm-subagents/src/runs/background/run-id-resolver.ts +0 -84
  185. package/extensions/dm-subagents/src/runs/background/run-status.ts +0 -434
  186. package/extensions/dm-subagents/src/runs/background/scheduled-runs.ts +0 -514
  187. package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.ts +0 -368
  188. package/extensions/dm-subagents/src/runs/background/subagent-runner.ts +0 -3171
  189. package/extensions/dm-subagents/src/runs/background/top-level-async.ts +0 -13
  190. package/extensions/dm-subagents/src/runs/background/wait.ts +0 -353
  191. package/extensions/dm-subagents/src/runs/foreground/chain-clarify.ts +0 -1333
  192. package/extensions/dm-subagents/src/runs/foreground/chain-execution.ts +0 -1313
  193. package/extensions/dm-subagents/src/runs/foreground/execution.ts +0 -1239
  194. package/extensions/dm-subagents/src/runs/foreground/subagent-executor.ts +0 -3613
  195. package/extensions/dm-subagents/src/runs/shared/acceptance.ts +0 -879
  196. package/extensions/dm-subagents/src/runs/shared/chain-outputs.ts +0 -116
  197. package/extensions/dm-subagents/src/runs/shared/completion-guard.ts +0 -147
  198. package/extensions/dm-subagents/src/runs/shared/dm-args.ts +0 -271
  199. package/extensions/dm-subagents/src/runs/shared/dm-spawn.ts +0 -147
  200. package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.ts +0 -295
  201. package/extensions/dm-subagents/src/runs/shared/long-running-guard.ts +0 -175
  202. package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +0 -365
  203. package/extensions/dm-subagents/src/runs/shared/model-fallback.ts +0 -292
  204. package/extensions/dm-subagents/src/runs/shared/model-scope.ts +0 -128
  205. package/extensions/dm-subagents/src/runs/shared/nested-events.ts +0 -908
  206. package/extensions/dm-subagents/src/runs/shared/nested-path.ts +0 -52
  207. package/extensions/dm-subagents/src/runs/shared/nested-render.ts +0 -115
  208. package/extensions/dm-subagents/src/runs/shared/parallel-utils.ts +0 -198
  209. package/extensions/dm-subagents/src/runs/shared/run-history.ts +0 -60
  210. package/extensions/dm-subagents/src/runs/shared/single-output.ts +0 -180
  211. package/extensions/dm-subagents/src/runs/shared/structured-output.ts +0 -77
  212. package/extensions/dm-subagents/src/runs/shared/subagent-control.ts +0 -223
  213. package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.ts +0 -342
  214. package/extensions/dm-subagents/src/runs/shared/tool-budget.ts +0 -74
  215. package/extensions/dm-subagents/src/runs/shared/turn-budget.ts +0 -52
  216. package/extensions/dm-subagents/src/runs/shared/workflow-graph.ts +0 -206
  217. package/extensions/dm-subagents/src/runs/shared/worktree.ts +0 -600
  218. package/extensions/dm-subagents/src/shared/artifacts.ts +0 -113
  219. package/extensions/dm-subagents/src/shared/atomic-json.ts +0 -86
  220. package/extensions/dm-subagents/src/shared/child-transcript.ts +0 -212
  221. package/extensions/dm-subagents/src/shared/file-coalescer.ts +0 -40
  222. package/extensions/dm-subagents/src/shared/fork-context.ts +0 -194
  223. package/extensions/dm-subagents/src/shared/formatters.ts +0 -133
  224. package/extensions/dm-subagents/src/shared/jsonl-writer.ts +0 -81
  225. package/extensions/dm-subagents/src/shared/model-info.ts +0 -78
  226. package/extensions/dm-subagents/src/shared/post-exit-stdio-guard.ts +0 -85
  227. package/extensions/dm-subagents/src/shared/session-identity.ts +0 -10
  228. package/extensions/dm-subagents/src/shared/session-tokens.ts +0 -44
  229. package/extensions/dm-subagents/src/shared/settings.ts +0 -450
  230. package/extensions/dm-subagents/src/shared/status-format.ts +0 -49
  231. package/extensions/dm-subagents/src/shared/types.ts +0 -1257
  232. package/extensions/dm-subagents/src/shared/utils.ts +0 -554
  233. package/extensions/dm-subagents/src/slash/prompt-template-bridge.ts +0 -420
  234. package/extensions/dm-subagents/src/slash/prompt-workflows.ts +0 -330
  235. package/extensions/dm-subagents/src/slash/slash-bridge.ts +0 -176
  236. package/extensions/dm-subagents/src/slash/slash-commands.ts +0 -1296
  237. package/extensions/dm-subagents/src/slash/slash-live-state.ts +0 -292
  238. package/extensions/dm-subagents/src/tui/render-helpers.ts +0 -80
  239. package/extensions/dm-subagents/src/tui/render.ts +0 -1748
  240. package/extensions/dm-tasks/src/auto-clear.ts +0 -91
  241. package/extensions/dm-tasks/src/index.ts +0 -1145
  242. package/extensions/dm-tasks/src/process-tracker.ts +0 -140
  243. package/extensions/dm-tasks/src/task-store.ts +0 -305
  244. package/extensions/dm-tasks/src/tasks-config.ts +0 -23
  245. package/extensions/dm-tasks/src/types.ts +0 -40
  246. package/extensions/dm-tasks/src/ui/settings-menu.ts +0 -100
  247. package/extensions/dm-tasks/src/ui/task-widget.ts +0 -265
  248. package/extensions/dm-usage/index.ts +0 -1718
  249. package/extensions/greedysearch-dm/index.ts +0 -177
  250. package/extensions/greedysearch-dm/src/formatters/results.ts +0 -163
  251. package/extensions/greedysearch-dm/src/formatters/sources.ts +0 -116
  252. package/extensions/greedysearch-dm/src/formatters/synthesis.ts +0 -87
  253. package/extensions/greedysearch-dm/src/tools/greedy-search-handler.ts +0 -370
  254. package/extensions/greedysearch-dm/src/tools/shared.ts +0 -187
  255. package/extensions/greedysearch-dm/src/types.ts +0 -110
  256. package/extensions/greedysearch-dm/src/utils/helpers.ts +0 -40
@@ -1,441 +0,0 @@
1
- import type { ExtensionAPI, ExtensionContext } from "@duckmind/dm-coding-agent";
2
- import * as fs from "node:fs";
3
- import * as path from "node:path";
4
- import { renderWidget, widgetRenderKey } from "../../tui/render.ts";
5
- import { formatControlNoticeMessage } from "../shared/subagent-control.ts";
6
- import {
7
- type AsyncJobState,
8
- type AsyncStartedEvent,
9
- type ControlEvent,
10
- type SubagentState,
11
- POLL_INTERVAL_MS,
12
- RESULTS_DIR,
13
- SUBAGENT_CONTROL_EVENT,
14
- SUBAGENT_CONTROL_INTERCOM_EVENT,
15
- } from "../../shared/types.ts";
16
- import { readStatus } from "../../shared/utils.ts";
17
- import { normalizeParallelGroups } from "./parallel-groups.ts";
18
- import { reconcileAsyncRun, reconcileNestedAsyncDescendants } from "./stale-run-reconciler.ts";
19
- import { hasLiveNestedDescendants, updateAsyncJobNestedProjection } from "../shared/nested-events.ts";
20
- import { listAsyncRuns, type AsyncRunSummary } from "./async-status.ts";
21
-
22
- interface AsyncJobTrackerOptions {
23
- completionRetentionMs?: number;
24
- pollIntervalMs?: number;
25
- resultsDir?: string;
26
- kill?: (pid: number, signal?: NodeJS.Signals | 0) => boolean;
27
- now?: () => number;
28
- }
29
-
30
- const CONTROL_EVENT_READ_CHUNK_BYTES = 64 * 1024;
31
- const MAX_CONTROL_EVENT_LINE_BYTES = 1024 * 1024;
32
- const CONTROL_EVENT_SCAN_WINDOW_BYTES = 2 * 1024 * 1024;
33
-
34
- export function createAsyncJobTracker(pi: Pick<ExtensionAPI, "events">, state: SubagentState, asyncDirRoot: string, options: AsyncJobTrackerOptions = {}): {
35
- ensurePoller: () => void;
36
- handleStarted: (data: unknown) => void;
37
- handleComplete: (data: unknown) => void;
38
- resetJobs: (ctx?: ExtensionContext) => void;
39
- restoreActiveJobs: (ctx?: ExtensionContext) => void;
40
- } {
41
- const completionRetentionMs = options.completionRetentionMs ?? 10000;
42
- const pollIntervalMs = options.pollIntervalMs ?? POLL_INTERVAL_MS;
43
- const resultsDir = options.resultsDir ?? RESULTS_DIR;
44
- const rerenderWidget = (ctx: ExtensionContext, jobs = Array.from(state.asyncJobs.values())) => {
45
- renderWidget(ctx, jobs);
46
- ctx.ui.requestRender?.();
47
- };
48
- const restoredControlEventCursor = (asyncDir: string) => {
49
- try {
50
- return fs.statSync(path.join(asyncDir, "events.jsonl")).size;
51
- } catch (error) {
52
- if ((error as NodeJS.ErrnoException).code === "ENOENT") return 0;
53
- throw error;
54
- }
55
- };
56
- const summaryToJob = (run: AsyncRunSummary): AsyncJobState => {
57
- const groups = normalizeParallelGroups(run.parallelGroups, run.steps.length, run.chainStepCount ?? run.steps.length);
58
- const activeGroup = run.currentStep !== undefined
59
- ? groups.find((group) => run.currentStep! >= group.start && run.currentStep! < group.start + group.count)
60
- : undefined;
61
- const visibleSteps = activeGroup
62
- ? run.steps.slice(activeGroup.start, activeGroup.start + activeGroup.count).map((step, index) => ({ ...step, index: activeGroup.start + index }))
63
- : run.steps.map((step, index) => ({ ...step, index }));
64
- return {
65
- asyncId: run.id,
66
- asyncDir: run.asyncDir,
67
- status: run.state,
68
- sessionId: run.sessionId,
69
- activityState: run.activityState,
70
- lastActivityAt: run.lastActivityAt,
71
- currentTool: run.currentTool,
72
- currentToolStartedAt: run.currentToolStartedAt,
73
- currentPath: run.currentPath,
74
- turnCount: run.turnCount,
75
- toolCount: run.toolCount,
76
- mode: run.mode,
77
- agents: visibleSteps.map((step) => step.agent),
78
- currentStep: run.currentStep,
79
- chainStepCount: run.chainStepCount,
80
- parallelGroups: groups,
81
- steps: visibleSteps,
82
- stepsTotal: visibleSteps.length,
83
- runningSteps: visibleSteps.filter((step) => step.status === "running").length,
84
- completedSteps: visibleSteps.filter((step) => step.status === "complete" || step.status === "completed").length,
85
- hasParallelGroups: groups.length > 0,
86
- activeParallelGroup: Boolean(activeGroup),
87
- startedAt: run.startedAt,
88
- updatedAt: run.lastUpdate ?? run.startedAt,
89
- timeoutMs: run.timeoutMs,
90
- deadlineAt: run.deadlineAt,
91
- timedOut: run.timedOut,
92
- turnBudget: run.turnBudget,
93
- turnBudgetExceeded: run.turnBudgetExceeded,
94
- wrapUpRequested: run.wrapUpRequested,
95
- sessionDir: run.sessionDir,
96
- outputFile: run.outputFile,
97
- totalTokens: run.totalTokens,
98
- sessionFile: run.sessionFile,
99
- controlEventCursor: restoredControlEventCursor(run.asyncDir),
100
- nestedChildren: run.nestedChildren,
101
- };
102
- };
103
- const cancelCleanup = (asyncId: string) => {
104
- const existingTimer = state.cleanupTimers.get(asyncId);
105
- if (!existingTimer) return;
106
- clearTimeout(existingTimer);
107
- state.cleanupTimers.delete(asyncId);
108
- };
109
- const scheduleCleanup = (asyncId: string) => {
110
- cancelCleanup(asyncId);
111
- const timer = setTimeout(() => {
112
- state.cleanupTimers.delete(asyncId);
113
- state.asyncJobs.delete(asyncId);
114
- if (state.lastUiContext) {
115
- rerenderWidget(state.lastUiContext);
116
- }
117
- }, completionRetentionMs);
118
- state.cleanupTimers.set(asyncId, timer);
119
- };
120
- const emitNewControlEvents = (job: AsyncJobState) => {
121
- const eventsPath = path.join(job.asyncDir, "events.jsonl");
122
- let fd: number;
123
- try {
124
- fd = fs.openSync(eventsPath, "r");
125
- } catch (error) {
126
- if ((error as NodeJS.ErrnoException).code === "ENOENT") return;
127
- console.error(`Failed to open async control events for '${job.asyncDir}':`, error);
128
- return;
129
- }
130
- try {
131
- const stat = fs.fstatSync(fd);
132
- const savedCursor = job.controlEventCursor;
133
- let cursor = stat.size < (savedCursor ?? 0) ? 0 : (savedCursor ?? 0);
134
- const startedFromTail = savedCursor === undefined && stat.size > CONTROL_EVENT_SCAN_WINDOW_BYTES;
135
- if (startedFromTail) cursor = stat.size - CONTROL_EVENT_SCAN_WINDOW_BYTES;
136
- if (stat.size <= cursor) return;
137
- const scanEnd = Math.min(stat.size, cursor + CONTROL_EVENT_SCAN_WINDOW_BYTES);
138
- const handleLine = (line: string) => {
139
- if (!line.trim()) return;
140
- let parsed: unknown;
141
- try {
142
- parsed = JSON.parse(line);
143
- } catch (error) {
144
- console.error(`Ignoring malformed async control event in '${eventsPath}':`, error);
145
- return;
146
- }
147
- if (!parsed || typeof parsed !== "object" || (parsed as { type?: unknown }).type !== "subagent.control") return;
148
- const record = parsed as { event?: ControlEvent; channels?: string[]; childIntercomTarget?: string; noticeText?: string; intercom?: { to?: string; message?: string } };
149
- if (!record.event || !Array.isArray(record.channels)) return;
150
- const payload = {
151
- event: record.event,
152
- source: "async" as const,
153
- asyncDir: job.asyncDir,
154
- childIntercomTarget: record.childIntercomTarget,
155
- noticeText: record.noticeText ?? formatControlNoticeMessage(record.event, record.childIntercomTarget),
156
- };
157
- if (record.channels.includes("event")) {
158
- pi.events.emit(SUBAGENT_CONTROL_EVENT, payload);
159
- }
160
- if (record.event.type !== "active_long_running" && record.channels.includes("intercom") && record.intercom?.to && record.intercom.message) {
161
- pi.events.emit(SUBAGENT_CONTROL_INTERCOM_EVENT, {
162
- ...payload,
163
- to: record.intercom.to,
164
- message: record.intercom.message,
165
- });
166
- }
167
- };
168
- let readCursor = cursor;
169
- let lastCompleteCursor = cursor;
170
- let lineParts: Buffer[] = [];
171
- let lineBytes = 0;
172
- let skippingOversizedLine = startedFromTail;
173
- const appendLineSegment = (segment: Buffer) => {
174
- if (segment.length === 0 || skippingOversizedLine) return;
175
- if (lineBytes + segment.length > MAX_CONTROL_EVENT_LINE_BYTES) {
176
- lineParts = [];
177
- lineBytes = 0;
178
- skippingOversizedLine = true;
179
- return;
180
- }
181
- lineParts.push(segment);
182
- lineBytes += segment.length;
183
- };
184
- while (readCursor < scanEnd) {
185
- const toRead = Math.min(CONTROL_EVENT_READ_CHUNK_BYTES, scanEnd - readCursor);
186
- const buffer = Buffer.alloc(toRead);
187
- const bytesRead = fs.readSync(fd, buffer, 0, toRead, readCursor);
188
- if (bytesRead <= 0) break;
189
- const chunk = bytesRead === buffer.length ? buffer : buffer.subarray(0, bytesRead);
190
- let lineStart = 0;
191
- for (let index = 0; index < chunk.length; index++) {
192
- if (chunk[index] !== 0x0a) continue;
193
- appendLineSegment(chunk.subarray(lineStart, index));
194
- if (!skippingOversizedLine && lineBytes > 0) {
195
- handleLine(Buffer.concat(lineParts, lineBytes).toString("utf-8"));
196
- }
197
- lineParts = [];
198
- lineBytes = 0;
199
- skippingOversizedLine = false;
200
- lastCompleteCursor = readCursor + index + 1;
201
- lineStart = index + 1;
202
- }
203
- appendLineSegment(chunk.subarray(lineStart));
204
- readCursor += bytesRead;
205
- if (skippingOversizedLine) job.controlEventCursor = readCursor;
206
- }
207
- if (lastCompleteCursor > cursor) job.controlEventCursor = lastCompleteCursor;
208
- else if (scanEnd < stat.size || startedFromTail) job.controlEventCursor = scanEnd;
209
- } catch (error) {
210
- console.error(`Failed to read async control events for '${job.asyncDir}':`, error);
211
- } finally {
212
- fs.closeSync(fd);
213
- }
214
- };
215
-
216
- const ensurePoller = () => {
217
- if (state.poller) return;
218
- state.poller = setInterval(() => {
219
- if (state.asyncJobs.size === 0) {
220
- if (state.lastUiContext?.hasUI) rerenderWidget(state.lastUiContext, []);
221
- if (state.poller) {
222
- clearInterval(state.poller);
223
- state.poller = null;
224
- }
225
- return;
226
- }
227
-
228
- let widgetChanged = false;
229
- for (const job of state.asyncJobs.values()) {
230
- const widgetStateBefore = widgetRenderKey(job);
231
- let nestedRefreshFailed = false;
232
- const refreshNestedProjection = () => {
233
- try {
234
- updateAsyncJobNestedProjection(job);
235
- } catch (error) {
236
- nestedRefreshFailed = true;
237
- console.error(`Failed to refresh nested async descendants for '${job.asyncDir}':`, error);
238
- }
239
- };
240
- const reconcileNestedDescendants = () => {
241
- try {
242
- if (job.nestedRoute) reconcileNestedAsyncDescendants(job.nestedRoute, { resultsDir, kill: options.kill, now: options.now });
243
- } catch (error) {
244
- nestedRefreshFailed = true;
245
- console.error(`Failed to refresh nested async descendants for '${job.asyncDir}':`, error);
246
- }
247
- refreshNestedProjection();
248
- };
249
- try {
250
- emitNewControlEvents(job);
251
- reconcileNestedDescendants();
252
- const reconciliation = reconcileAsyncRun(job.asyncDir, {
253
- resultsDir,
254
- kill: options.kill,
255
- now: options.now,
256
- startedRun: {
257
- runId: job.asyncId,
258
- pid: job.pid,
259
- sessionId: job.sessionId,
260
- mode: job.mode,
261
- agents: job.agents,
262
- chainStepCount: job.chainStepCount,
263
- parallelGroups: job.parallelGroups,
264
- startedAt: job.startedAt,
265
- sessionFile: job.sessionFile,
266
- },
267
- });
268
- const status = reconciliation.status ?? readStatus(job.asyncDir);
269
- if (status) {
270
- const previousStatus = job.status;
271
- job.status = status.state;
272
- if (job.status !== "complete" && job.status !== "failed" && job.status !== "paused") cancelCleanup(job.asyncId);
273
- job.sessionId = status.sessionId ?? job.sessionId;
274
- job.activityState = status.activityState;
275
- job.lastActivityAt = status.lastActivityAt ?? job.lastActivityAt;
276
- job.currentTool = status.currentTool;
277
- job.currentToolStartedAt = status.currentToolStartedAt;
278
- job.currentPath = status.currentPath;
279
- job.turnCount = status.turnCount ?? job.turnCount;
280
- job.toolCount = status.toolCount ?? job.toolCount;
281
- job.mode = status.mode;
282
- job.currentStep = status.currentStep ?? job.currentStep;
283
- job.chainStepCount = status.chainStepCount ?? job.chainStepCount;
284
- job.startedAt = status.startedAt ?? job.startedAt;
285
- if (status.lastUpdate !== undefined) job.updatedAt = status.lastUpdate;
286
- if (status.steps?.length) {
287
- const groups = normalizeParallelGroups(status.parallelGroups, status.steps.length, status.chainStepCount ?? status.steps.length);
288
- job.parallelGroups = groups.length ? groups : job.parallelGroups;
289
- job.hasParallelGroups = groups.length > 0 || job.hasParallelGroups;
290
- const activeGroup = status.currentStep !== undefined
291
- ? groups.find((group) => status.currentStep! >= group.start && status.currentStep! < group.start + group.count)
292
- : undefined;
293
- const visibleSteps = activeGroup
294
- ? status.steps.slice(activeGroup.start, activeGroup.start + activeGroup.count).map((step, index) => ({ ...step, index: activeGroup.start + index }))
295
- : status.steps.map((step, index) => ({ ...step, index }));
296
- job.activeParallelGroup = Boolean(activeGroup);
297
- job.agents = visibleSteps.map((step) => step.agent);
298
- job.steps = visibleSteps;
299
- refreshNestedProjection();
300
- job.stepsTotal = visibleSteps.length;
301
- job.runningSteps = visibleSteps.filter((step) => step.status === "running").length;
302
- job.completedSteps = visibleSteps.filter((step) => step.status === "complete" || step.status === "completed").length;
303
- if (status.state === "complete") job.completedSteps = visibleSteps.length;
304
- }
305
- job.sessionDir = status.sessionDir ?? job.sessionDir;
306
- job.outputFile = status.outputFile ?? job.outputFile;
307
- job.totalTokens = status.totalTokens ?? job.totalTokens;
308
- job.timeoutMs = status.timeoutMs ?? job.timeoutMs;
309
- job.deadlineAt = status.deadlineAt ?? job.deadlineAt;
310
- job.timedOut = status.timedOut ?? job.timedOut;
311
- job.turnBudget = status.turnBudget ?? job.turnBudget;
312
- job.turnBudgetExceeded = status.turnBudgetExceeded ?? job.turnBudgetExceeded;
313
- job.wrapUpRequested = status.wrapUpRequested ?? job.wrapUpRequested;
314
- job.sessionFile = status.sessionFile ?? job.sessionFile;
315
- if ((job.status === "complete" || job.status === "failed" || job.status === "paused") && !nestedRefreshFailed && !hasLiveNestedDescendants(job.nestedChildren) && (previousStatus !== job.status || !state.cleanupTimers.has(job.asyncId))) {
316
- scheduleCleanup(job.asyncId);
317
- }
318
- if (widgetRenderKey(job) !== widgetStateBefore) widgetChanged = true;
319
- continue;
320
- }
321
- if (job.status === "queued") {
322
- job.status = "running";
323
- job.updatedAt = Date.now();
324
- }
325
- } catch (error) {
326
- if (job.status !== "failed") {
327
- console.error(`Failed to read async status for '${job.asyncDir}':`, error);
328
- job.status = "failed";
329
- job.updatedAt = Date.now();
330
- }
331
- if (!hasLiveNestedDescendants(job.nestedChildren) && !state.cleanupTimers.has(job.asyncId)) {
332
- scheduleCleanup(job.asyncId);
333
- }
334
- }
335
- if (widgetRenderKey(job) !== widgetStateBefore) widgetChanged = true;
336
- }
337
-
338
- if (widgetChanged && state.lastUiContext?.hasUI) rerenderWidget(state.lastUiContext);
339
- }, pollIntervalMs);
340
- state.poller.unref?.();
341
- };
342
-
343
- const handleStarted = (data: unknown) => {
344
- const info = data as AsyncStartedEvent;
345
- if (!info.id) return;
346
- if (typeof state.currentSessionId === "string" && info.sessionId !== state.currentSessionId) return;
347
- const now = Date.now();
348
- const asyncDir = info.asyncDir ?? path.join(asyncDirRoot, info.id);
349
- const rawAgents = info.agents?.length ? info.agents : info.chain && info.chain.length > 0 ? info.chain : info.agent ? [info.agent] : undefined;
350
- const validParallelGroups = normalizeParallelGroups(info.parallelGroups, Number.MAX_SAFE_INTEGER, info.chainStepCount ?? Number.MAX_SAFE_INTEGER);
351
- const firstGroup = validParallelGroups.find((group) => group.start === 0);
352
- const firstGroupCount = firstGroup?.count;
353
- const agents = firstGroupCount && firstGroupCount > 0
354
- ? rawAgents?.slice(0, firstGroupCount)
355
- : rawAgents;
356
- state.asyncJobs.set(info.id, {
357
- asyncId: info.id,
358
- asyncDir,
359
- status: "queued",
360
- pid: typeof info.pid === "number" ? info.pid : undefined,
361
- ...(typeof info.sessionId === "string" ? { sessionId: info.sessionId } : {}),
362
- mode: info.mode ?? (info.chain ? "chain" : "single"),
363
- agents,
364
- chainStepCount: info.chainStepCount,
365
- parallelGroups: validParallelGroups,
366
- nestedRoute: info.nestedRoute,
367
- stepsTotal: firstGroupCount ?? agents?.length,
368
- hasParallelGroups: validParallelGroups.length > 0,
369
- activeParallelGroup: Boolean(firstGroupCount && firstGroupCount > 0),
370
- startedAt: now,
371
- updatedAt: now,
372
- timeoutMs: info.timeoutMs,
373
- deadlineAt: info.deadlineAt,
374
- turnBudget: info.turnBudget,
375
- controlEventCursor: 0,
376
- });
377
- ensurePoller();
378
- if (state.lastUiContext) {
379
- rerenderWidget(state.lastUiContext);
380
- }
381
- };
382
-
383
- const handleComplete = (data: unknown) => {
384
- const result = data as { id?: string; success?: boolean; asyncDir?: string; sessionId?: string };
385
- if (typeof state.currentSessionId === "string" && result.sessionId !== state.currentSessionId) return;
386
- const asyncId = result.id;
387
- if (!asyncId) return;
388
- const job = state.asyncJobs.get(asyncId);
389
- let nestedRefreshFailed = false;
390
- if (job) {
391
- job.status = result.success ? "complete" : "failed";
392
- job.updatedAt = Date.now();
393
- if (result.asyncDir) job.asyncDir = result.asyncDir;
394
- try {
395
- updateAsyncJobNestedProjection(job);
396
- } catch (error) {
397
- nestedRefreshFailed = true;
398
- console.error(`Failed to refresh nested async descendants for '${job.asyncDir}':`, error);
399
- }
400
- }
401
- if (state.lastUiContext) {
402
- rerenderWidget(state.lastUiContext);
403
- }
404
- if (!nestedRefreshFailed && !hasLiveNestedDescendants(job?.nestedChildren)) scheduleCleanup(asyncId);
405
- };
406
-
407
- const resetJobs = (ctx?: ExtensionContext) => {
408
- for (const timer of state.cleanupTimers.values()) {
409
- clearTimeout(timer);
410
- }
411
- state.cleanupTimers.clear();
412
- state.asyncJobs.clear();
413
- state.foregroundControls?.clear();
414
- state.lastForegroundControlId = null;
415
- state.resultFileCoalescer.clear();
416
- if (ctx?.hasUI) {
417
- state.lastUiContext = ctx;
418
- rerenderWidget(ctx, []);
419
- }
420
- };
421
-
422
- const restoreActiveJobs = (ctx?: ExtensionContext) => {
423
- if (ctx?.hasUI) state.lastUiContext = ctx;
424
- if (!state.currentSessionId) return;
425
- let runs: AsyncRunSummary[];
426
- try {
427
- runs = listAsyncRuns(asyncDirRoot, { states: ["queued", "running"], sessionId: state.currentSessionId, resultsDir, kill: options.kill, now: options.now });
428
- } catch (error) {
429
- console.error(`Failed to restore active async jobs from '${asyncDirRoot}':`, error);
430
- return;
431
- }
432
- for (const run of runs) {
433
- state.asyncJobs.set(run.id, summaryToJob(run));
434
- }
435
- if (runs.length === 0) return;
436
- ensurePoller();
437
- if (state.lastUiContext?.hasUI) rerenderWidget(state.lastUiContext);
438
- };
439
-
440
- return { ensurePoller, handleStarted, handleComplete, resetJobs, restoreActiveJobs };
441
- }