@duckmind/dm-windows-x64 0.60.6 → 0.60.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.
- package/dm.exe +0 -0
- package/extensions/.dm-extensions.json +70 -123
- package/extensions/dm-9router-ext/src/index.js +410 -5
- package/extensions/dm-caveman/extensions/caveman.js +283 -12
- package/extensions/dm-cliproxy/index.js +182 -2
- package/extensions/dm-cliproxy/scripts/check-config-migration.js +66 -8
- package/extensions/dm-cliproxy/src/apply.js +228 -1
- package/extensions/dm-cliproxy/src/cache.js +42 -1
- package/extensions/dm-cliproxy/src/commands.js +50 -2
- package/extensions/dm-cliproxy/src/compat.js +81 -1
- package/extensions/dm-cliproxy/src/config.js +192 -2
- package/extensions/dm-cliproxy/src/conflicts.js +46 -1
- package/extensions/dm-cliproxy/src/fetch-models.js +190 -1
- package/extensions/dm-cliproxy/src/fetch-usage.js +41 -1
- package/extensions/dm-cliproxy/src/log.js +23 -1
- package/extensions/dm-cliproxy/src/status-quota.js +77 -1
- package/extensions/dm-cliproxy/src/ui-frame.js +50 -1
- package/extensions/dm-cliproxy/src/ui-hub/hub.js +199 -2
- package/extensions/dm-cliproxy/src/ui-hub/index.js +26 -2
- package/extensions/dm-cliproxy/src/ui-hub/shell.js +46 -1
- package/extensions/dm-cliproxy/src/ui-hub/view-diagnostics.js +69 -1
- package/extensions/dm-cliproxy/src/ui-hub/view-models.js +379 -1
- package/extensions/dm-cliproxy/src/ui-hub/view-usage.js +106 -1
- package/extensions/dm-cliproxy/src/ui-picker/catalog.js +41 -1
- package/extensions/dm-cliproxy/src/ui-picker/mutate.js +115 -1
- package/extensions/dm-cliproxy/src/ui-picker/prompt-confirm.js +35 -1
- package/extensions/dm-cliproxy/src/ui-picker/prompt-name.js +62 -1
- package/extensions/dm-cliproxy/src/ui-picker/providers.js +45 -1
- package/extensions/dm-cliproxy/src/ui-picker/render-text.js +34 -1
- package/extensions/dm-cliproxy/src/ui-picker/rows.js +57 -1
- package/extensions/dm-cliproxy/src/ui-setup.js +260 -2
- package/extensions/dm-cliproxy/src/ui-usage.js +151 -1
- package/extensions/dm-cliproxy/src/usage-shared-cache.js +97 -1
- package/extensions/dm-context/src/context.js +144 -1
- package/extensions/dm-context/src/index.js +339 -7
- package/extensions/dm-context/src/utils.js +9 -1
- package/extensions/dm-cua/bin/browser-cua.mjs +73 -8
- package/extensions/dm-cua/index.js +75 -6
- package/extensions/dm-cua/src/browser-cua-lib.mjs +490 -6
- package/extensions/dm-cua/src/browser-install.mjs +331 -2
- package/extensions/dm-fff/src/index.js +688 -12
- package/extensions/dm-fff/src/query.js +60 -1
- package/extensions/dm-goal/src/goal.js +894 -23
- package/extensions/dm-image2/index.js +103 -9
- package/extensions/dm-image2/src/image-lib.mjs +1275 -8
- package/extensions/dm-subagents/install.mjs +62 -8
- package/extensions/dm-subagents/src/agents/agent-management.js +1190 -36
- package/extensions/dm-subagents/src/agents/agent-memory.js +216 -6
- package/extensions/dm-subagents/src/agents/agent-scope.js +5 -1
- package/extensions/dm-subagents/src/agents/agent-selection.js +20 -1
- package/extensions/dm-subagents/src/agents/agent-serializer.js +120 -5
- package/extensions/dm-subagents/src/agents/agents.js +1139 -11
- package/extensions/dm-subagents/src/agents/chain-serializer.js +299 -11
- package/extensions/dm-subagents/src/agents/frontmatter.js +65 -6
- package/extensions/dm-subagents/src/agents/identity.js +29 -1
- package/extensions/dm-subagents/src/agents/proactive-skills.js +141 -1
- package/extensions/dm-subagents/src/agents/skills.js +614 -6
- package/extensions/dm-subagents/src/extension/config.js +35 -2
- package/extensions/dm-subagents/src/extension/control-notices.js +69 -4
- package/extensions/dm-subagents/src/extension/doctor.js +172 -15
- package/extensions/dm-subagents/src/extension/fanout-child.js +158 -231
- package/extensions/dm-subagents/src/extension/index.js +521 -359
- package/extensions/dm-subagents/src/extension/rpc.js +266 -7
- package/extensions/dm-subagents/src/extension/schemas.js +275 -1
- package/extensions/dm-subagents/src/extension/tool-description.js +111 -6
- package/extensions/dm-subagents/src/intercom/intercom-bridge.js +126 -4
- package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +452 -5
- package/extensions/dm-subagents/src/intercom/result-intercom.js +319 -3
- package/extensions/dm-subagents/src/profiles/profiles.js +458 -3
- package/extensions/dm-subagents/src/runs/background/async-execution.js +834 -40
- package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +435 -14
- package/extensions/dm-subagents/src/runs/background/async-resume.js +334 -8
- package/extensions/dm-subagents/src/runs/background/async-status.js +313 -12
- package/extensions/dm-subagents/src/runs/background/chain-append.js +245 -2
- package/extensions/dm-subagents/src/runs/background/chain-root-attachment.js +136 -1
- package/extensions/dm-subagents/src/runs/background/completion-batcher.js +94 -1
- package/extensions/dm-subagents/src/runs/background/completion-dedupe.js +54 -1
- package/extensions/dm-subagents/src/runs/background/control-channel.js +190 -1
- package/extensions/dm-subagents/src/runs/background/fleet-view.js +483 -17
- package/extensions/dm-subagents/src/runs/background/notify.js +129 -3
- package/extensions/dm-subagents/src/runs/background/parallel-groups.js +34 -1
- package/extensions/dm-subagents/src/runs/background/result-watcher.js +236 -6
- package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +76 -4
- package/extensions/dm-subagents/src/runs/background/run-status.js +427 -23
- package/extensions/dm-subagents/src/runs/background/scheduled-runs.js +487 -4
- package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +306 -9
- package/extensions/dm-subagents/src/runs/background/subagent-runner.js +2849 -73
- package/extensions/dm-subagents/src/runs/background/top-level-async.js +5 -1
- package/extensions/dm-subagents/src/runs/background/wait.js +206 -11
- package/extensions/dm-subagents/src/runs/foreground/chain-clarify.js +1013 -12
- package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +980 -101
- package/extensions/dm-subagents/src/runs/foreground/execution.js +1165 -45
- package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +3157 -222
- package/extensions/dm-subagents/src/runs/shared/acceptance.js +835 -3
- package/extensions/dm-subagents/src/runs/shared/chain-outputs.js +104 -1
- package/extensions/dm-subagents/src/runs/shared/completion-guard.js +116 -3
- package/extensions/dm-subagents/src/runs/shared/dm-args.js +208 -1
- package/extensions/dm-subagents/src/runs/shared/dm-spawn.js +90 -1
- package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.js +282 -1
- package/extensions/dm-subagents/src/runs/shared/long-running-guard.js +148 -1
- package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.js +305 -1
- package/extensions/dm-subagents/src/runs/shared/model-fallback.js +194 -1
- package/extensions/dm-subagents/src/runs/shared/model-scope.js +65 -1
- package/extensions/dm-subagents/src/runs/shared/nested-events.js +851 -8
- package/extensions/dm-subagents/src/runs/shared/nested-path.js +41 -1
- package/extensions/dm-subagents/src/runs/shared/nested-render.js +105 -1
- package/extensions/dm-subagents/src/runs/shared/parallel-utils.js +81 -4
- package/extensions/dm-subagents/src/runs/shared/run-history.js +51 -4
- package/extensions/dm-subagents/src/runs/shared/single-output.js +149 -8
- package/extensions/dm-subagents/src/runs/shared/structured-output.js +58 -1
- package/extensions/dm-subagents/src/runs/shared/subagent-control.js +166 -5
- package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +329 -13
- package/extensions/dm-subagents/src/runs/shared/tool-budget.js +73 -1
- package/extensions/dm-subagents/src/runs/shared/turn-budget.js +47 -4
- package/extensions/dm-subagents/src/runs/shared/workflow-graph.js +196 -1
- package/extensions/dm-subagents/src/runs/shared/worktree.js +435 -3
- package/extensions/dm-subagents/src/shared/artifacts.js +92 -2
- package/extensions/dm-subagents/src/shared/atomic-json.js +55 -1
- package/extensions/dm-subagents/src/shared/child-transcript.js +167 -5
- package/extensions/dm-subagents/src/shared/file-coalescer.js +25 -1
- package/extensions/dm-subagents/src/shared/fork-context.js +147 -4
- package/extensions/dm-subagents/src/shared/formatters.js +98 -7
- package/extensions/dm-subagents/src/shared/jsonl-writer.js +56 -2
- package/extensions/dm-subagents/src/shared/model-info.js +62 -1
- package/extensions/dm-subagents/src/shared/post-exit-stdio-guard.js +68 -1
- package/extensions/dm-subagents/src/shared/session-identity.js +6 -1
- package/extensions/dm-subagents/src/shared/session-tokens.js +39 -2
- package/extensions/dm-subagents/src/shared/settings.js +198 -11
- package/extensions/dm-subagents/src/shared/status-format.js +53 -1
- package/extensions/dm-subagents/src/shared/types.js +184 -6
- package/extensions/dm-subagents/src/shared/utils.js +462 -2
- package/extensions/dm-subagents/src/slash/prompt-template-bridge.js +288 -1
- package/extensions/dm-subagents/src/slash/prompt-workflows.js +297 -7
- package/extensions/dm-subagents/src/slash/slash-bridge.js +118 -1
- package/extensions/dm-subagents/src/slash/slash-commands.js +1287 -31
- package/extensions/dm-subagents/src/slash/slash-live-state.js +240 -4
- package/extensions/dm-subagents/src/tui/render-helpers.js +64 -1
- package/extensions/dm-subagents/src/tui/render.js +1542 -4
- package/extensions/dm-usage/index.js +1294 -9
- package/extensions/greedysearch-dm/bin/cdp-greedy.mjs +40 -9
- package/extensions/greedysearch-dm/bin/cdp-headless.mjs +5 -2
- package/extensions/greedysearch-dm/bin/cdp-visible.mjs +5 -2
- package/extensions/greedysearch-dm/bin/cdp.mjs +896 -30
- package/extensions/greedysearch-dm/bin/gschrome.mjs +30 -2
- package/extensions/greedysearch-dm/bin/kill-visible.mjs +7 -2
- package/extensions/greedysearch-dm/bin/launch-visible.mjs +13 -2
- package/extensions/greedysearch-dm/bin/launch.mjs +282 -10
- package/extensions/greedysearch-dm/bin/mcp.mjs +386 -361
- package/extensions/greedysearch-dm/bin/search.mjs +620 -540
- package/extensions/greedysearch-dm/bin/visible.mjs +22 -2
- package/extensions/greedysearch-dm/extractors/bing-copilot.mjs +329 -579
- package/extensions/greedysearch-dm/extractors/chatgpt.mjs +301 -583
- package/extensions/greedysearch-dm/extractors/common.mjs +408 -32
- package/extensions/greedysearch-dm/extractors/consensus.mjs +376 -365
- package/extensions/greedysearch-dm/extractors/consent.mjs +303 -14
- package/extensions/greedysearch-dm/extractors/gemini.mjs +228 -592
- package/extensions/greedysearch-dm/extractors/google-ai.mjs +78 -499
- package/extensions/greedysearch-dm/extractors/logically.mjs +270 -347
- package/extensions/greedysearch-dm/extractors/perplexity.mjs +243 -581
- package/extensions/greedysearch-dm/extractors/selectors.mjs +32 -1
- package/extensions/greedysearch-dm/extractors/semantic-scholar.mjs +130 -317
- package/extensions/greedysearch-dm/index.js +123 -23
- package/extensions/greedysearch-dm/src/fetcher.mjs +576 -2
- package/extensions/greedysearch-dm/src/formatters/results.js +95 -10
- package/extensions/greedysearch-dm/src/formatters/sources.js +57 -1
- package/extensions/greedysearch-dm/src/formatters/synthesis.js +49 -1
- package/extensions/greedysearch-dm/src/github.mjs +222 -7
- package/extensions/greedysearch-dm/src/reddit.mjs +145 -14
- package/extensions/greedysearch-dm/src/search/browser-lifecycle.mjs +340 -9
- package/extensions/greedysearch-dm/src/search/challenge-detect.mjs +112 -4
- package/extensions/greedysearch-dm/src/search/chrome.mjs +486 -285
- package/extensions/greedysearch-dm/src/search/constants.mjs +109 -8
- package/extensions/greedysearch-dm/src/search/defaults.mjs +10 -1
- package/extensions/greedysearch-dm/src/search/engines.mjs +79 -9
- package/extensions/greedysearch-dm/src/search/fetch-source.mjs +441 -349
- package/extensions/greedysearch-dm/src/search/file-sources.mjs +29 -7
- package/extensions/greedysearch-dm/src/search/minimize.mjs +86 -1
- package/extensions/greedysearch-dm/src/search/output.mjs +51 -5
- package/extensions/greedysearch-dm/src/search/paths.mjs +48 -1
- package/extensions/greedysearch-dm/src/search/pdf.mjs +63 -2
- package/extensions/greedysearch-dm/src/search/port-pid.mjs +69 -1
- package/extensions/greedysearch-dm/src/search/progress.mjs +109 -2
- package/extensions/greedysearch-dm/src/search/query.mjs +21 -1
- package/extensions/greedysearch-dm/src/search/recovery.mjs +49 -1
- package/extensions/greedysearch-dm/src/search/research.mjs +2227 -458
- package/extensions/greedysearch-dm/src/search/scale-aware.mjs +61 -11
- package/extensions/greedysearch-dm/src/search/simple-research.mjs +396 -805
- package/extensions/greedysearch-dm/src/search/sources.mjs +412 -1
- package/extensions/greedysearch-dm/src/search/synthesis-runner.mjs +127 -12
- package/extensions/greedysearch-dm/src/search/synthesis.mjs +202 -12
- package/extensions/greedysearch-dm/src/tools/greedy-search-handler.js +209 -23
- package/extensions/greedysearch-dm/src/tools/shared.js +226 -10
- package/extensions/greedysearch-dm/src/utils/content.mjs +35 -4
- package/extensions/greedysearch-dm/src/utils/helpers.js +22 -1
- package/extensions/greedysearch-dm/src/utils/node-runtime.mjs +10 -1
- package/extensions/greedysearch-dm/src/utils/system-cmds.mjs +61 -1
- package/package.json +1 -1
|
@@ -1,3 +1,129 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { buildCompletionKey, getGlobalSeenMap, markSeenWithTtl } from "./completion-dedupe.js";
|
|
2
|
+
import {
|
|
3
|
+
createCompletionBatcher,
|
|
4
|
+
resolveCompletionBatchConfig
|
|
5
|
+
} from "./completion-batcher.js";
|
|
6
|
+
import { SUBAGENT_ASYNC_COMPLETE_EVENT } from "../../shared/types.js";
|
|
7
|
+
function formatSessionLine(details) {
|
|
8
|
+
if (!details.sessionValue)
|
|
9
|
+
return;
|
|
10
|
+
return details.sessionLabel ? `${details.sessionLabel}: ${details.sessionValue}` : details.sessionValue;
|
|
11
|
+
}
|
|
12
|
+
export function formatSingleCompletion(details) {
|
|
13
|
+
const sessionLine = formatSessionLine(details);
|
|
14
|
+
return [
|
|
15
|
+
`Background task ${details.status}: **${details.agent}**${details.taskInfo ?? ""}`,
|
|
16
|
+
"",
|
|
17
|
+
details.resultPreview.trim() ? details.resultPreview : "(no output)",
|
|
18
|
+
sessionLine ? "" : undefined,
|
|
19
|
+
sessionLine
|
|
20
|
+
].filter((line) => line !== undefined).join(`
|
|
21
|
+
`);
|
|
22
|
+
}
|
|
23
|
+
export function formatGroupedCompletion(details) {
|
|
24
|
+
const header = `Background tasks completed (${details.length}): ${details.map((d) => `**${d.agent}**${d.taskInfo ?? ""}`).join(", ")}`;
|
|
25
|
+
const blocks = [header, ""];
|
|
26
|
+
for (let index = 0;index < details.length; index++) {
|
|
27
|
+
const detail = details[index];
|
|
28
|
+
if (!detail)
|
|
29
|
+
continue;
|
|
30
|
+
const sessionLine = formatSessionLine(detail);
|
|
31
|
+
blocks.push(`${index + 1}. ${detail.agent}${detail.taskInfo ?? ""}`);
|
|
32
|
+
blocks.push(detail.resultPreview.trim() ? detail.resultPreview : "(no output)");
|
|
33
|
+
if (sessionLine)
|
|
34
|
+
blocks.push(sessionLine);
|
|
35
|
+
blocks.push("");
|
|
36
|
+
}
|
|
37
|
+
return blocks.join(`
|
|
38
|
+
`).trimEnd();
|
|
39
|
+
}
|
|
40
|
+
function sendCompletion(pi, details) {
|
|
41
|
+
if (details.length === 0)
|
|
42
|
+
return;
|
|
43
|
+
const content = details.length === 1 ? formatSingleCompletion(details[0]) : formatGroupedCompletion(details);
|
|
44
|
+
pi.sendMessage({
|
|
45
|
+
customType: "subagent-notify",
|
|
46
|
+
content,
|
|
47
|
+
display: true
|
|
48
|
+
}, { triggerTurn: true });
|
|
49
|
+
}
|
|
50
|
+
function completionBatchKey(result) {
|
|
51
|
+
const sessionId = typeof result.sessionId === "string" ? result.sessionId.trim() : "";
|
|
52
|
+
if (sessionId)
|
|
53
|
+
return `session:${sessionId}`;
|
|
54
|
+
const cwd = typeof result.cwd === "string" ? result.cwd.trim() : "";
|
|
55
|
+
return cwd ? `cwd:${cwd}` : "unknown";
|
|
56
|
+
}
|
|
57
|
+
export function buildCompletionDetails(result) {
|
|
58
|
+
const agent = result.agent ?? "unknown";
|
|
59
|
+
const summary = typeof result.summary === "string" ? result.summary : "";
|
|
60
|
+
const paused = !result.success && (result.exitCode === 0 || result.state === "paused" || summary.startsWith("Paused after interrupt."));
|
|
61
|
+
const status = paused ? "paused" : result.success ? "completed" : "failed";
|
|
62
|
+
const taskInfo = result.taskIndex !== undefined && result.totalTasks !== undefined ? ` (${result.taskIndex + 1}/${result.totalTasks})` : undefined;
|
|
63
|
+
const session = result.shareUrl ? { label: "Session", value: result.shareUrl } : result.shareError ? { label: "Session share error", value: result.shareError } : result.sessionFile ? { label: "Session file", value: result.sessionFile } : undefined;
|
|
64
|
+
return {
|
|
65
|
+
agent,
|
|
66
|
+
status,
|
|
67
|
+
...taskInfo ? { taskInfo } : {},
|
|
68
|
+
resultPreview: summary,
|
|
69
|
+
...typeof result.durationMs === "number" ? { durationMs: result.durationMs } : {},
|
|
70
|
+
...session ? { sessionLabel: session.label, sessionValue: session.value } : {}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
export default function registerSubagentNotify(pi, state, options = {}) {
|
|
74
|
+
const unsubscribeStoreKey = "__pi_subagents_notify_unsubscribe__";
|
|
75
|
+
const batcherStoreKey = "__pi_subagents_notify_batcher__";
|
|
76
|
+
const globalStore = globalThis;
|
|
77
|
+
const previousUnsubscribe = globalStore[unsubscribeStoreKey];
|
|
78
|
+
if (typeof previousUnsubscribe === "function") {
|
|
79
|
+
try {
|
|
80
|
+
previousUnsubscribe();
|
|
81
|
+
} catch {}
|
|
82
|
+
}
|
|
83
|
+
const previousBatcher = globalStore[batcherStoreKey];
|
|
84
|
+
if (previousBatcher && typeof previousBatcher.dispose === "function") {
|
|
85
|
+
try {
|
|
86
|
+
previousBatcher.dispose();
|
|
87
|
+
} catch {}
|
|
88
|
+
}
|
|
89
|
+
const seen = getGlobalSeenMap("__pi_subagents_notify_seen__");
|
|
90
|
+
const ttlMs = 10 * 60 * 1000;
|
|
91
|
+
const nowFn = options.now ?? Date.now;
|
|
92
|
+
const batchConfig = resolveCompletionBatchConfig(options.batchConfig);
|
|
93
|
+
const batchers = new Map;
|
|
94
|
+
globalStore[batcherStoreKey] = {
|
|
95
|
+
dispose() {
|
|
96
|
+
for (const batcher of batchers.values())
|
|
97
|
+
batcher.dispose();
|
|
98
|
+
batchers.clear();
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
const handleComplete = (data) => {
|
|
102
|
+
const result = data;
|
|
103
|
+
if (typeof result.sessionId !== "string" || result.sessionId !== state.currentSessionId)
|
|
104
|
+
return;
|
|
105
|
+
const now = nowFn();
|
|
106
|
+
const key = buildCompletionKey(result, "notify");
|
|
107
|
+
if (markSeenWithTtl(seen, key, now, ttlMs))
|
|
108
|
+
return;
|
|
109
|
+
const details = buildCompletionDetails(result);
|
|
110
|
+
const batchKey = completionBatchKey(result);
|
|
111
|
+
let batcher = batchers.get(batchKey);
|
|
112
|
+
if (!batcher) {
|
|
113
|
+
batcher = createCompletionBatcher({
|
|
114
|
+
config: batchConfig,
|
|
115
|
+
emit: (items) => sendCompletion(pi, items),
|
|
116
|
+
...options.timers ? { timers: options.timers } : {},
|
|
117
|
+
now: nowFn
|
|
118
|
+
});
|
|
119
|
+
batchers.set(batchKey, batcher);
|
|
120
|
+
}
|
|
121
|
+
if (details.status !== "completed") {
|
|
122
|
+
batcher.flush();
|
|
123
|
+
sendCompletion(pi, [details]);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
batcher.push(details);
|
|
127
|
+
};
|
|
128
|
+
globalStore[unsubscribeStoreKey] = pi.events.on(SUBAGENT_ASYNC_COMPLETE_EVENT, handleComplete);
|
|
129
|
+
}
|
|
@@ -1 +1,34 @@
|
|
|
1
|
-
function
|
|
1
|
+
function isValidParallelGroup(group, stepCount, chainStepCount) {
|
|
2
|
+
if (typeof group !== "object" || group === null)
|
|
3
|
+
return false;
|
|
4
|
+
const { start, count, stepIndex } = group;
|
|
5
|
+
return typeof start === "number" && typeof count === "number" && typeof stepIndex === "number" && Number.isInteger(start) && Number.isInteger(count) && Number.isInteger(stepIndex) && start >= 0 && count > 0 && stepIndex >= 0 && stepIndex < chainStepCount && start + count <= stepCount;
|
|
6
|
+
}
|
|
7
|
+
export function normalizeParallelGroups(groups, stepCount, chainStepCount) {
|
|
8
|
+
if (!Array.isArray(groups))
|
|
9
|
+
return [];
|
|
10
|
+
return groups.filter((group) => isValidParallelGroup(group, stepCount, chainStepCount)).sort((left, right) => left.stepIndex - right.stepIndex || left.start - right.start);
|
|
11
|
+
}
|
|
12
|
+
export function flatToLogicalStepIndex(flatIndex, chainStepCount, groups) {
|
|
13
|
+
let logicalIndex = 0;
|
|
14
|
+
let cursor = 0;
|
|
15
|
+
for (const group of groups) {
|
|
16
|
+
while (cursor < group.start && logicalIndex < chainStepCount) {
|
|
17
|
+
if (cursor === flatIndex)
|
|
18
|
+
return logicalIndex;
|
|
19
|
+
cursor++;
|
|
20
|
+
logicalIndex++;
|
|
21
|
+
}
|
|
22
|
+
if (flatIndex >= group.start && flatIndex < group.start + group.count)
|
|
23
|
+
return group.stepIndex;
|
|
24
|
+
cursor = group.start + group.count;
|
|
25
|
+
logicalIndex = group.stepIndex + 1;
|
|
26
|
+
}
|
|
27
|
+
while (cursor <= flatIndex && logicalIndex < chainStepCount) {
|
|
28
|
+
if (cursor === flatIndex)
|
|
29
|
+
return logicalIndex;
|
|
30
|
+
cursor++;
|
|
31
|
+
logicalIndex++;
|
|
32
|
+
}
|
|
33
|
+
return Math.max(0, chainStepCount - 1);
|
|
34
|
+
}
|
|
@@ -1,8 +1,238 @@
|
|
|
1
|
-
import
|
|
2
|
-
`)}function G$($){let J=$.children.map((W)=>({...W,summary:W.summary.trim()||"(no output)",children:E(W.children)})),j=l$(J),Z=q$(p(J)),Q=J[0],X={to:$.to,runId:$.runId,mode:$.mode,status:j,summary:Z,source:$.source,children:J,...$.asyncId?{asyncId:$.asyncId}:{},...$.asyncDir?{asyncDir:$.asyncDir}:{},...typeof $.chainSteps==="number"?{chainSteps:$.chainSteps}:{},...Q?.agent?{agent:Q.agent}:{},...Q?.index!==void 0?{index:Q.index}:{},...Q?.artifactPath?{artifactPath:Q.artifactPath}:{},...Q?.sessionPath?{sessionPath:Q.sessionPath}:{},message:""};return X.message=a$(X),X}async function M$($,J,j=500){return t$($,J.to,J.message,j,J)}async function t$($,J,j,Z=500,Q={}){if(typeof $.on!=="function"||typeof $.emit!=="function")return!1;let X=typeof Q.requestId==="string"?Q.requestId:r$();return new Promise((W)=>{let Y=!1,O,L,U=(G)=>{if(Y)return;if(Y=!0,L)clearTimeout(L);O?.(),W(G)};O=$.on(f$,(G)=>{if(!G||typeof G!=="object")return;let b=G;if(b.requestId!==X)return;U(b.delivered===!0)}),L=setTimeout(()=>U(!1),Z);try{$.emit(Y$,{...Q,to:J,message:j,requestId:X})}catch{U(!1)}})}import*as F from"node:fs";import*as M from"node:path";import*as L$ from"node:path";var e$=128,$j=4;function u($){return typeof $==="string"&&$.length>0&&$.length<=e$&&!L$.isAbsolute($)&&!$.includes("/")&&!$.includes("\\")&&!$.includes("..")}function U$($){return typeof $==="number"&&Number.isFinite($)?$:void 0}function V$($,J){return typeof $==="string"&&$.length>0?$.slice(0,J):void 0}function F$($){if(!Array.isArray($))return[];return $.map((J)=>{if(!J||typeof J!=="object")return;let j=J;if(!u(j.runId))return;return{runId:j.runId,...U$(j.stepIndex)!==void 0?{stepIndex:U$(j.stepIndex)}:{},...V$(j.agent,128)?{agent:V$(j.agent,128)}:{}}}).filter((J)=>Boolean(J)).slice(0,$j)}import*as z from"node:path";import{fileURLToPath as T$}from"node:url";import*as A from"node:os";import*as T from"node:path";var W0=T.join(A.homedir(),".config","mcp","mcp.json"),Y0={cursor:[T.join(A.homedir(),".cursor","mcp.json")],"claude-code":[T.join(A.homedir(),".claude","mcp.json"),T.join(A.homedir(),".claude.json"),T.join(A.homedir(),".claude","claude_desktop_config.json")],"claude-desktop":[T.join(A.homedir(),"Library","Application Support","Claude","claude_desktop_config.json")],codex:[T.join(A.homedir(),".codex","config.json")],windsurf:[T.join(A.homedir(),".windsurf","mcp.json")],vscode:[".vscode/mcp.json"]};import{Compile as O0}from"typebox/compile";function z$($,J){let j=T$($),Z=z.extname(j),Q=[".js",".mjs",".cjs",".ts",".mts",".cts"].includes(Z)?Z:".ts";return z.join(z.dirname(j),`${J}${Q}`)}function A$($){return z.basename(T$($)).startsWith("dm-args.")}function Qj($=import.meta.url){let J=A$($)?"subagent-prompt-runtime":z.join("..","runs","shared","subagent-prompt-runtime");return z$($,J)}function Xj($=import.meta.url){let J=A$($)?z.join("..","..","extension","fanout-child"):"fanout-child";return z$($,J)}var E0=Qj(),y0=Xj();import*as Bj from"node:fs";import*as y from"node:path";var Wj=[10,25,50,100,200,500,1000,2000,4000],Yj=new Set(["EACCES","EBUSY","EPERM"]),_$=typeof SharedArrayBuffer<"u"?new SharedArrayBuffer(4):void 0,C$=_$?new Int32Array(_$):void 0;function fj($){if($<=0)return;if(C$)try{Atomics.wait(C$,0,0,$);return}catch{}let J=Date.now()+$;while(Date.now()<J);}function Kj($){let J=$?.code;return typeof J==="string"&&Yj.has(J)}function Oj($,J,j,Z,Q){for(let X=0;;X++)try{$.renameSync(J,j);return}catch(W){let Y=Z[X];if(Y===void 0||!Kj(W))throw W;Q(Y)}}function qj($={}){let J=$.fs??Bj,j=$.now??Date.now,Z=$.pid??process.pid,Q=$.random??Math.random,W=$.retryRenameErrors??process.platform==="win32"?$.retryDelaysMs??Wj:[],Y=$.wait??fj;return(O,L)=>{J.mkdirSync(y.dirname(O),{recursive:!0});let U=y.join(y.dirname(O),`.${y.basename(O)}.${Z}.${j()}.${Q().toString(36).slice(2)}.tmp`);try{J.writeFileSync(U,JSON.stringify(L,null,2),"utf-8"),Oj(J,U,O,W,Y)}finally{J.rmSync(U,{force:!0})}}}var S$=qj();var k=M.join(S,"nested-subagent-events"),Hj="route.json",Gj="registry.json",R$=65536,E$=12,g=16,r=3;function v($){return u($)}function Mj($,J){if(!v(J))throw Error(`${$} must be a non-empty safe id token.`)}function l($,J){Mj($,J)}function i($,J){let j=M.resolve($),Z=M.resolve(J);return Z===j||Z.startsWith(`${j}${M.sep}`)}function I$($){return M.dirname(M.resolve($.eventSink))}function s($){if(l("rootRunId",$.rootRunId),l("capabilityToken",$.capabilityToken),!i(k,$.eventSink))throw Error("Nested event sink is outside the subagent nested event root.");if(!i(k,$.controlInbox))throw Error("Nested control inbox is outside the subagent nested event root.");if(I$($)!==M.dirname(M.resolve($.controlInbox)))throw Error("Nested event sink and control inbox must share one route root.")}function B($){return typeof $==="number"&&Number.isFinite($)?$:void 0}function K($,J=512){return typeof $==="string"&&$.length>0?$.slice(0,J):void 0}function Uj($){if(!$||typeof $!=="object")return;let J=$,j=B(J.input),Z=B(J.output),Q=B(J.total);return j!==void 0&&Z!==void 0&&Q!==void 0?{input:j,output:Z,total:Q}:void 0}function Vj($){if(!$||typeof $!=="object")return;let J=$,j=B(J.inputTokens),Z=B(J.outputTokens),Q=B(J.costUsd);return j!==void 0&&Z!==void 0&&Q!==void 0?{inputTokens:j,outputTokens:Z,costUsd:Q}:void 0}function m($){if(!$||typeof $!=="object")return;let J=$,j=B(J.maxTurns),Z=B(J.graceTurns),Q=B(J.turnCount),X=J.outcome==="within-budget"||J.outcome==="wrap-up-requested"||J.outcome==="exceeded"?J.outcome:void 0;if(j===void 0||Z===void 0||Q===void 0||!X)return;return{maxTurns:j,graceTurns:Z,turnCount:Q,outcome:X,...B(J.wrapUpRequestedAtTurn)!==void 0?{wrapUpRequestedAtTurn:B(J.wrapUpRequestedAtTurn)}:{},...B(J.exceededAtTurn)!==void 0?{exceededAtTurn:B(J.exceededAtTurn)}:{}}}function Lj($,J){return $==="queued"||$==="running"||$==="complete"||$==="failed"||$==="paused"?$:J}function Fj($,J){if(!$||typeof $!=="object")return;let j=$,Z=K(j.agent,128);if(!Z)return;let Q=j.status==="pending"||j.status==="running"||j.status==="complete"||j.status==="completed"||j.status==="failed"||j.status==="paused"?j.status:"pending";return{agent:Z,status:Q,...K(j.sessionFile,2048)?{sessionFile:K(j.sessionFile,2048)}:{},...j.activityState==="active_long_running"||j.activityState==="needs_attention"?{activityState:j.activityState}:{},...B(j.lastActivityAt)!==void 0?{lastActivityAt:B(j.lastActivityAt)}:{},...K(j.currentTool,128)?{currentTool:K(j.currentTool,128)}:{},...B(j.currentToolStartedAt)!==void 0?{currentToolStartedAt:B(j.currentToolStartedAt)}:{},...K(j.currentPath,2048)?{currentPath:K(j.currentPath,2048)}:{},...B(j.turnCount)!==void 0?{turnCount:B(j.turnCount)}:{},...B(j.toolCount)!==void 0?{toolCount:B(j.toolCount)}:{},...B(j.startedAt)!==void 0?{startedAt:B(j.startedAt)}:{},...B(j.endedAt)!==void 0?{endedAt:B(j.endedAt)}:{},...K(j.error,1024)?{error:K(j.error,1024)}:{},...j.timedOut===!0?{timedOut:!0}:{},...m(j.turnBudget)?{turnBudget:m(j.turnBudget)}:{},...j.turnBudgetExceeded===!0?{turnBudgetExceeded:!0}:{},...j.wrapUpRequested===!0?{wrapUpRequested:!0}:{},...J<r&&Array.isArray(j.children)?{children:j.children.map((X)=>D(X,J+1)).filter((X)=>Boolean(X)).slice(0,g)}:{}}}function D($,J=0){if(!$||typeof $!=="object")return;let j=$;if(!v(j.id)||!v(j.parentRunId))return;let Z=F$(j.path),Q=Array.isArray(j.steps)?j.steps.map((Y)=>Fj(Y,J+1)).filter((Y)=>Boolean(Y)).slice(0,E$):void 0,X=Uj(j.totalTokens),W=Vj(j.totalCost);return{id:j.id,parentRunId:j.parentRunId,...B(j.parentStepIndex)!==void 0?{parentStepIndex:B(j.parentStepIndex)}:{},...K(j.parentAgent,128)?{parentAgent:K(j.parentAgent,128)}:{},depth:Math.min(Math.max(0,B(j.depth)??0),r),path:Z,state:Lj(j.state,"running"),...K(j.asyncDir,2048)?{asyncDir:K(j.asyncDir,2048)}:{},...B(j.pid)!==void 0&&B(j.pid)>0&&Number.isInteger(B(j.pid))?{pid:B(j.pid)}:{},...K(j.sessionId,256)?{sessionId:K(j.sessionId,256)}:{},...K(j.sessionFile,2048)?{sessionFile:K(j.sessionFile,2048)}:{},...K(j.intercomTarget,256)?{intercomTarget:K(j.intercomTarget,256)}:{},...K(j.ownerIntercomTarget,256)?{ownerIntercomTarget:K(j.ownerIntercomTarget,256)}:{},...K(j.leafIntercomTarget,256)?{leafIntercomTarget:K(j.leafIntercomTarget,256)}:{},...j.ownerState==="live"||j.ownerState==="gone"||j.ownerState==="unknown"?{ownerState:j.ownerState}:{},...K(j.controlInbox,2048)?{controlInbox:K(j.controlInbox,2048)}:{},...K(j.capabilityToken,128)?{capabilityToken:K(j.capabilityToken,128)}:{},...j.mode==="single"||j.mode==="parallel"||j.mode==="chain"?{mode:j.mode}:{},...K(j.agent,128)?{agent:K(j.agent,128)}:{},...Array.isArray(j.agents)?{agents:j.agents.map((Y)=>K(Y,128)).filter((Y)=>Boolean(Y)).slice(0,E$)}:{},...B(j.currentStep)!==void 0?{currentStep:B(j.currentStep)}:{},...B(j.chainStepCount)!==void 0?{chainStepCount:B(j.chainStepCount)}:{},...j.activityState==="active_long_running"||j.activityState==="needs_attention"?{activityState:j.activityState}:{},...B(j.lastActivityAt)!==void 0?{lastActivityAt:B(j.lastActivityAt)}:{},...K(j.currentTool,128)?{currentTool:K(j.currentTool,128)}:{},...B(j.currentToolStartedAt)!==void 0?{currentToolStartedAt:B(j.currentToolStartedAt)}:{},...K(j.currentPath,2048)?{currentPath:K(j.currentPath,2048)}:{},...B(j.turnCount)!==void 0?{turnCount:B(j.turnCount)}:{},...B(j.toolCount)!==void 0?{toolCount:B(j.toolCount)}:{},...X?{totalTokens:X}:{},...W?{totalCost:W}:{},...B(j.startedAt)!==void 0?{startedAt:B(j.startedAt)}:{},...B(j.endedAt)!==void 0?{endedAt:B(j.endedAt)}:{},...B(j.lastUpdate)!==void 0?{lastUpdate:B(j.lastUpdate)}:{},...B(j.timeoutMs)!==void 0?{timeoutMs:B(j.timeoutMs)}:{},...B(j.deadlineAt)!==void 0?{deadlineAt:B(j.deadlineAt)}:{},...j.timedOut===!0?{timedOut:!0}:{},...m(j.turnBudget)?{turnBudget:m(j.turnBudget)}:{},...j.turnBudgetExceeded===!0?{turnBudgetExceeded:!0}:{},...j.wrapUpRequested===!0?{wrapUpRequested:!0}:{},...K(j.error,1024)?{error:K(j.error,1024)}:{},...Q&&Q.length>0?{steps:Q}:{},...J<r&&Array.isArray(j.children)?{children:j.children.map((Y)=>D(Y,J+1)).filter((Y)=>Boolean(Y)).slice(0,g)}:{}}}function y$($,J){if(Buffer.byteLength($,"utf-8")>R$)return;let j;try{j=JSON.parse($)}catch{return}if(!j||typeof j!=="object")return;let Z=j;if(Z.type!=="subagent.nested.started"&&Z.type!=="subagent.nested.updated"&&Z.type!=="subagent.nested.completed")return;if(Z.rootRunId!==J.rootRunId||Z.capabilityToken!==J.capabilityToken)return;if(!v(Z.parentRunId))return;let Q=B(Z.ts);if(Q===void 0)return;let X=D(Z.child);if(!X||X.id===J.rootRunId)return;let W={...X,controlInbox:J.controlInbox,capabilityToken:J.capabilityToken,ownerState:X.ownerState??"unknown"};return{type:Z.type,ts:Q,rootRunId:J.rootRunId,parentRunId:Z.parentRunId,...B(Z.parentStepIndex)!==void 0?{parentStepIndex:B(Z.parentStepIndex)}:{},capabilityToken:J.capabilityToken,child:W}}function Tj($,J){if(!$.includes(`
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { buildCompletionKey, markSeenWithTtl } from "./completion-dedupe.js";
|
|
4
|
+
import { createFileCoalescer } from "../../shared/file-coalescer.js";
|
|
5
|
+
import {
|
|
6
|
+
SUBAGENT_ASYNC_COMPLETE_EVENT
|
|
7
|
+
} from "../../shared/types.js";
|
|
8
|
+
import {
|
|
9
|
+
attachNestedChildrenToResultChildren,
|
|
10
|
+
buildSubagentResultIntercomPayload,
|
|
11
|
+
compactNestedResultChildren,
|
|
12
|
+
deliverSubagentResultIntercomEvent,
|
|
13
|
+
resolveSubagentResultStatus
|
|
14
|
+
} from "../../intercom/result-intercom.js";
|
|
15
|
+
import { projectNestedRegistryForRoot, sanitizeSummary } from "../shared/nested-events.js";
|
|
16
|
+
const WATCHER_RESTART_DELAY_MS = 3000;
|
|
17
|
+
const POLL_INTERVAL_MS = 3000;
|
|
18
|
+
function sanitizeNestedResultChildren(value, resultPath, label) {
|
|
19
|
+
if (value === undefined)
|
|
20
|
+
return;
|
|
21
|
+
if (!Array.isArray(value)) {
|
|
22
|
+
console.error(`Ignoring invalid nested children in subagent result file '${resultPath}' at ${label}: expected an array.`);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const children = value.map((child) => sanitizeSummary(child)).filter((child) => Boolean(child));
|
|
26
|
+
if (children.length !== value.length) {
|
|
27
|
+
console.error(`Ignoring ${value.length - children.length} invalid nested child record(s) in subagent result file '${resultPath}' at ${label}.`);
|
|
28
|
+
}
|
|
29
|
+
return children.length ? children : undefined;
|
|
30
|
+
}
|
|
31
|
+
function getErrorCode(error) {
|
|
32
|
+
return typeof error === "object" && error !== null && "code" in error ? error.code : undefined;
|
|
33
|
+
}
|
|
34
|
+
function isNotFoundError(error) {
|
|
35
|
+
return getErrorCode(error) === "ENOENT";
|
|
36
|
+
}
|
|
37
|
+
function shouldFallBackToPolling(error) {
|
|
38
|
+
const code = getErrorCode(error);
|
|
39
|
+
return code === "EMFILE" || code === "ENOSPC";
|
|
40
|
+
}
|
|
41
|
+
function resolveNativeWatchDir(fsApi, resultsDir) {
|
|
42
|
+
try {
|
|
43
|
+
return fsApi.realpathSync.native(resultsDir);
|
|
44
|
+
} catch {
|
|
45
|
+
return resultsDir;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export function createResultWatcher(pi, state, resultsDir, completionTtlMs, deps = {}) {
|
|
49
|
+
const fsApi = deps.fs ?? fs;
|
|
50
|
+
const timers = deps.timers ?? { setTimeout, clearTimeout, setInterval, clearInterval };
|
|
51
|
+
const handleResult = async (file) => {
|
|
52
|
+
const resultPath = path.join(resultsDir, file);
|
|
53
|
+
if (!fsApi.existsSync(resultPath))
|
|
54
|
+
return;
|
|
55
|
+
try {
|
|
56
|
+
const data = JSON.parse(fsApi.readFileSync(resultPath, "utf-8"));
|
|
57
|
+
if (typeof data.sessionId !== "string" || data.sessionId !== state.currentSessionId)
|
|
58
|
+
return;
|
|
59
|
+
const runId = data.runId ?? data.id ?? file.replace(/\.json$/i, "");
|
|
60
|
+
const hasExplicitNestedChildren = data.nestedChildren !== undefined;
|
|
61
|
+
let nestedChildren = compactNestedResultChildren(sanitizeNestedResultChildren(data.nestedChildren, resultPath, "nestedChildren"));
|
|
62
|
+
if (!nestedChildren?.length && !hasExplicitNestedChildren) {
|
|
63
|
+
try {
|
|
64
|
+
nestedChildren = compactNestedResultChildren(projectNestedRegistryForRoot(runId)?.children);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error(`Failed to enrich subagent result file '${resultPath}' with nested registry children; will retry later:`, error);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const now = Date.now();
|
|
71
|
+
const completionKey = buildCompletionKey(data, `result:${file}`);
|
|
72
|
+
if (markSeenWithTtl(state.completionSeen, completionKey, now, completionTtlMs)) {
|
|
73
|
+
fsApi.unlinkSync(resultPath);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const hasResultChildren = Array.isArray(data.results) && data.results.length > 0;
|
|
77
|
+
const resultChildren = hasResultChildren ? data.results : [{
|
|
78
|
+
agent: data.agent,
|
|
79
|
+
output: data.summary,
|
|
80
|
+
success: data.success
|
|
81
|
+
}];
|
|
82
|
+
const normalizedChildren = attachNestedChildrenToResultChildren(runId, resultChildren.map((result = {}, index) => {
|
|
83
|
+
const baseOutput = result.output ?? data.summary;
|
|
84
|
+
const hasRealOutput = typeof baseOutput === "string" && baseOutput.trim().length > 0;
|
|
85
|
+
const output = hasRealOutput ? baseOutput : "(no output)";
|
|
86
|
+
const summary = result.success === false && result.error ? `${result.error}${hasRealOutput ? `
|
|
6
87
|
|
|
7
88
|
Output:
|
|
8
|
-
${
|
|
89
|
+
${baseOutput}` : ""}` : output;
|
|
90
|
+
const sessionPath = result.sessionFile ?? (resultChildren.length === 1 ? data.sessionFile : undefined);
|
|
91
|
+
const childNestedChildren = sanitizeNestedResultChildren(result.children, resultPath, `results[${index}].children`);
|
|
92
|
+
return {
|
|
93
|
+
agent: result.agent ?? data.agent ?? `step-${index + 1}`,
|
|
94
|
+
status: resolveSubagentResultStatus({
|
|
95
|
+
success: result.success,
|
|
96
|
+
state: data.state === "paused" || typeof result.success !== "boolean" ? data.state : undefined
|
|
97
|
+
}),
|
|
98
|
+
summary,
|
|
99
|
+
index,
|
|
100
|
+
artifactPath: result.artifactPaths?.outputPath,
|
|
101
|
+
...typeof sessionPath === "string" && fsApi.existsSync(sessionPath) ? { sessionPath } : {},
|
|
102
|
+
...result.intercomTarget ? { intercomTarget: result.intercomTarget } : {},
|
|
103
|
+
...childNestedChildren ? { children: childNestedChildren } : {}
|
|
104
|
+
};
|
|
105
|
+
}), nestedChildren);
|
|
106
|
+
const intercomTarget = data.intercomTarget?.trim();
|
|
107
|
+
if (intercomTarget) {
|
|
108
|
+
const mode = data.mode === "single" || data.mode === "parallel" || data.mode === "chain" ? data.mode : resultChildren.length > 1 ? "chain" : "single";
|
|
109
|
+
const payload = buildSubagentResultIntercomPayload({
|
|
110
|
+
to: intercomTarget,
|
|
111
|
+
runId,
|
|
112
|
+
mode,
|
|
113
|
+
source: "async",
|
|
114
|
+
children: normalizedChildren,
|
|
115
|
+
asyncId: data.id,
|
|
116
|
+
asyncDir: data.asyncDir
|
|
117
|
+
});
|
|
118
|
+
const delivered = await deliverSubagentResultIntercomEvent(pi.events, payload);
|
|
119
|
+
if (!delivered) {
|
|
120
|
+
console.error(`Subagent async grouped result intercom delivery was not acknowledged for '${resultPath}'.`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
pi.events.emit(SUBAGENT_ASYNC_COMPLETE_EVENT, {
|
|
124
|
+
...data,
|
|
125
|
+
runId,
|
|
126
|
+
...nestedChildren?.length ? { nestedChildren } : {},
|
|
127
|
+
...Array.isArray(data.results) ? {
|
|
128
|
+
results: hasResultChildren ? normalizedChildren.map((child, index) => ({
|
|
129
|
+
...data.results[index],
|
|
130
|
+
agent: child.agent,
|
|
131
|
+
status: child.status,
|
|
132
|
+
summary: child.summary,
|
|
133
|
+
index: child.index,
|
|
134
|
+
artifactPath: child.artifactPath,
|
|
135
|
+
sessionPath: child.sessionPath,
|
|
136
|
+
children: child.children
|
|
137
|
+
})) : []
|
|
138
|
+
} : {}
|
|
139
|
+
});
|
|
140
|
+
fsApi.unlinkSync(resultPath);
|
|
141
|
+
} catch (error) {
|
|
142
|
+
if (isNotFoundError(error))
|
|
143
|
+
return;
|
|
144
|
+
console.error(`Failed to process subagent result file '${resultPath}':`, error);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
state.resultFileCoalescer = createFileCoalescer((file) => {
|
|
148
|
+
handleResult(file);
|
|
149
|
+
}, 50);
|
|
150
|
+
const primeExistingResults = () => {
|
|
151
|
+
try {
|
|
152
|
+
fsApi.readdirSync(resultsDir).filter((f) => f.endsWith(".json")).forEach((file) => state.resultFileCoalescer.schedule(file, 0));
|
|
153
|
+
} catch (error) {
|
|
154
|
+
if (isNotFoundError(error))
|
|
155
|
+
return;
|
|
156
|
+
console.error(`Failed to scan subagent result directory '${resultsDir}':`, error);
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
const startPollingFallback = (reason) => {
|
|
160
|
+
state.watcher?.close();
|
|
161
|
+
state.watcher = null;
|
|
162
|
+
if (state.watcherRestartTimer)
|
|
163
|
+
return;
|
|
164
|
+
console.error(`Subagent result watcher for '${resultsDir}' fell back to polling because native fs.watch is unavailable (${getErrorCode(reason) ?? "unknown error"}).`);
|
|
165
|
+
primeExistingResults();
|
|
166
|
+
state.watcherRestartTimer = timers.setInterval(primeExistingResults, POLL_INTERVAL_MS);
|
|
167
|
+
state.watcherRestartTimer.unref?.();
|
|
168
|
+
};
|
|
169
|
+
const scheduleRestart = () => {
|
|
170
|
+
if (state.watcherRestartTimer)
|
|
171
|
+
return;
|
|
172
|
+
state.watcherRestartTimer = timers.setTimeout(() => {
|
|
173
|
+
state.watcherRestartTimer = null;
|
|
174
|
+
try {
|
|
175
|
+
fsApi.mkdirSync(resultsDir, { recursive: true });
|
|
176
|
+
startResultWatcher();
|
|
177
|
+
} catch (error) {
|
|
178
|
+
if (shouldFallBackToPolling(error)) {
|
|
179
|
+
startPollingFallback(error);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
console.error(`Failed to restart subagent result watcher for '${resultsDir}':`, error);
|
|
183
|
+
scheduleRestart();
|
|
184
|
+
}
|
|
185
|
+
}, WATCHER_RESTART_DELAY_MS);
|
|
186
|
+
state.watcherRestartTimer.unref?.();
|
|
187
|
+
};
|
|
188
|
+
const startResultWatcher = () => {
|
|
189
|
+
if (state.watcher)
|
|
190
|
+
return;
|
|
191
|
+
if (state.watcherRestartTimer) {
|
|
192
|
+
timers.clearTimeout(state.watcherRestartTimer);
|
|
193
|
+
timers.clearInterval(state.watcherRestartTimer);
|
|
194
|
+
state.watcherRestartTimer = null;
|
|
195
|
+
}
|
|
196
|
+
try {
|
|
197
|
+
const watchDir = resolveNativeWatchDir(fsApi, resultsDir);
|
|
198
|
+
state.watcher = fsApi.watch(watchDir, (ev, file) => {
|
|
199
|
+
if (ev !== "rename" || !file)
|
|
200
|
+
return;
|
|
201
|
+
const fileName = file.toString();
|
|
202
|
+
if (!fileName.endsWith(".json"))
|
|
203
|
+
return;
|
|
204
|
+
state.resultFileCoalescer.schedule(fileName);
|
|
205
|
+
});
|
|
206
|
+
state.watcher.on("error", (error) => {
|
|
207
|
+
if (shouldFallBackToPolling(error)) {
|
|
208
|
+
startPollingFallback(error);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
console.error(`Subagent result watcher failed for '${resultsDir}':`, error);
|
|
212
|
+
state.watcher?.close();
|
|
213
|
+
state.watcher = null;
|
|
214
|
+
scheduleRestart();
|
|
215
|
+
});
|
|
216
|
+
state.watcher.unref?.();
|
|
217
|
+
} catch (error) {
|
|
218
|
+
if (shouldFallBackToPolling(error)) {
|
|
219
|
+
startPollingFallback(error);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
console.error(`Failed to start subagent result watcher for '${resultsDir}':`, error);
|
|
223
|
+
state.watcher = null;
|
|
224
|
+
scheduleRestart();
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
const stopResultWatcher = () => {
|
|
228
|
+
state.watcher?.close();
|
|
229
|
+
state.watcher = null;
|
|
230
|
+
if (state.watcherRestartTimer) {
|
|
231
|
+
timers.clearTimeout(state.watcherRestartTimer);
|
|
232
|
+
timers.clearInterval(state.watcherRestartTimer);
|
|
233
|
+
}
|
|
234
|
+
state.watcherRestartTimer = null;
|
|
235
|
+
state.resultFileCoalescer.clear();
|
|
236
|
+
};
|
|
237
|
+
return { startResultWatcher, primeExistingResults, stopResultWatcher };
|
|
238
|
+
}
|
|
@@ -1,4 +1,76 @@
|
|
|
1
|
-
import*as b from"node:fs";import*as u from"node:path";import*as _ from"node:os";import*as T from"node:path";function S(j){return j.trim().replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"unknown"}function z$(j){let J=j?.env??process.env,$=j&&Object.hasOwn(j,"getuid")?j.getuid:process.getuid?.bind(process);if(typeof $==="function")return`uid-${$()}`;for(let H of["USERNAME","USER","LOGNAME"]){let Y=J[H];if(Y)return`user-${S(Y)}`}let Z=j&&Object.hasOwn(j,"userInfo")?j.userInfo:_.userInfo;try{let H=Z?.().username;if(H)return`user-${S(H)}`}catch{}let Q=J.USERPROFILE??J.HOME;if(Q)return`home-${S(Q)}`;let W=j&&Object.hasOwn(j,"homedir")?j.homedir:_.homedir;try{let H=W?.();if(H)return`home-${S(H)}`}catch{}return"shared"}var A=T.join(_.tmpdir(),`dm-subagents-${z$()}`),E=T.join(A,"async-subagent-results"),N=T.join(A,"async-subagent-runs"),M$=T.join(A,"chain-runs"),r$=T.join(A,"artifacts");import*as F from"node:fs";import*as V from"node:path";import*as A$ from"node:fs";import*as C from"node:path";var C$=[10,25,50,100,200,500,1000,2000,4000],F$=new Set(["EACCES","EBUSY","EPERM"]),i=typeof SharedArrayBuffer<"u"?new SharedArrayBuffer(4):void 0,s=i?new Int32Array(i):void 0;function q$(j){if(j<=0)return;if(s)try{Atomics.wait(s,0,0,j);return}catch{}let J=Date.now()+j;while(Date.now()<J);}function _$(j){let J=j?.code;return typeof J==="string"&&F$.has(J)}function T$(j,J,$,Z,Q){for(let W=0;;W++)try{j.renameSync(J,$);return}catch(H){let Y=Z[W];if(Y===void 0||!_$(H))throw H;Q(Y)}}function E$(j={}){let J=j.fs??A$,$=j.now??Date.now,Z=j.pid??process.pid,Q=j.random??Math.random,H=j.retryRenameErrors??process.platform==="win32"?j.retryDelaysMs??C$:[],Y=j.wait??q$;return(B,f)=>{J.mkdirSync(C.dirname(B),{recursive:!0});let G=C.join(C.dirname(B),`.${C.basename(B)}.${Z}.${$()}.${Q().toString(36).slice(2)}.tmp`);try{J.writeFileSync(G,JSON.stringify(f,null,2),"utf-8"),T$(J,G,B,H,Y)}finally{J.rmSync(G,{force:!0})}}}var y=E$();var Tj=process.platform==="win32"?"SIGBREAK":"SIGUSR2";import*as L from"node:fs";import*as O from"node:path";import*as e from"node:path";var b$=128,S$=4;function g(j){return typeof j==="string"&&j.length>0&&j.length<=b$&&!e.isAbsolute(j)&&!j.includes("/")&&!j.includes("\\")&&!j.includes("..")}function a(j){return typeof j==="number"&&Number.isFinite(j)?j:void 0}function t(j,J){return typeof j==="string"&&j.length>0?j.slice(0,J):void 0}function $$(j){if(!Array.isArray(j))return[];return j.map((J)=>{if(!J||typeof J!=="object")return;let $=J;if(!g($.runId))return;return{runId:$.runId,...a($.stepIndex)!==void 0?{stepIndex:a($.stepIndex)}:{},...t($.agent,128)?{agent:t($.agent,128)}:{}}}).filter((J)=>Boolean(J)).slice(0,S$)}import*as z from"node:path";import{fileURLToPath as j$}from"node:url";import*as M from"node:os";import*as U from"node:path";var yj=U.join(M.homedir(),".config","mcp","mcp.json"),Rj={cursor:[U.join(M.homedir(),".cursor","mcp.json")],"claude-code":[U.join(M.homedir(),".claude","mcp.json"),U.join(M.homedir(),".claude.json"),U.join(M.homedir(),".claude","claude_desktop_config.json")],"claude-desktop":[U.join(M.homedir(),"Library","Application Support","Claude","claude_desktop_config.json")],codex:[U.join(M.homedir(),".codex","config.json")],windsurf:[U.join(M.homedir(),".windsurf","mcp.json")],vscode:[".vscode/mcp.json"]};import{Compile as kj}from"typebox/compile";function J$(j,J){let $=j$(j),Z=z.extname($),Q=[".js",".mjs",".cjs",".ts",".mts",".cts"].includes(Z)?Z:".ts";return z.join(z.dirname($),`${J}${Q}`)}function Z$(j){return z.basename(j$(j)).startsWith("dm-args.")}function y$(j=import.meta.url){let J=Z$(j)?"subagent-prompt-runtime":z.join("..","runs","shared","subagent-prompt-runtime");return J$(j,J)}function R$(j=import.meta.url){let J=Z$(j)?z.join("..","..","extension","fanout-child"):"fanout-child";return J$(j,J)}var rj=y$(),ij=R$();var x=O.join(A,"nested-subagent-events"),x$="route.json",D$="registry.json",Y$=65536,Q$=12,D=16,m=3;function k(j){return g(j)}function n(j,J){if(!k(J))throw Error(`${j} must be a non-empty safe id token.`)}function h(j,J){n(j,J)}function c(j,J){let $=O.resolve(j),Z=O.resolve(J);return Z===$||Z.startsWith(`${$}${O.sep}`)}function K$(j){return O.dirname(O.resolve(j.eventSink))}function o(j){if(h("rootRunId",j.rootRunId),h("capabilityToken",j.capabilityToken),!c(x,j.eventSink))throw Error("Nested event sink is outside the subagent nested event root.");if(!c(x,j.controlInbox))throw Error("Nested control inbox is outside the subagent nested event root.");if(K$(j)!==O.dirname(O.resolve(j.controlInbox)))throw Error("Nested event sink and control inbox must share one route root.")}function X(j){return typeof j==="number"&&Number.isFinite(j)?j:void 0}function K(j,J=512){return typeof j==="string"&&j.length>0?j.slice(0,J):void 0}function k$(j){if(!j||typeof j!=="object")return;let J=j,$=X(J.input),Z=X(J.output),Q=X(J.total);return $!==void 0&&Z!==void 0&&Q!==void 0?{input:$,output:Z,total:Q}:void 0}function I$(j){if(!j||typeof j!=="object")return;let J=j,$=X(J.inputTokens),Z=X(J.outputTokens),Q=X(J.costUsd);return $!==void 0&&Z!==void 0&&Q!==void 0?{inputTokens:$,outputTokens:Z,costUsd:Q}:void 0}function I(j){if(!j||typeof j!=="object")return;let J=j,$=X(J.maxTurns),Z=X(J.graceTurns),Q=X(J.turnCount),W=J.outcome==="within-budget"||J.outcome==="wrap-up-requested"||J.outcome==="exceeded"?J.outcome:void 0;if($===void 0||Z===void 0||Q===void 0||!W)return;return{maxTurns:$,graceTurns:Z,turnCount:Q,outcome:W,...X(J.wrapUpRequestedAtTurn)!==void 0?{wrapUpRequestedAtTurn:X(J.wrapUpRequestedAtTurn)}:{},...X(J.exceededAtTurn)!==void 0?{exceededAtTurn:X(J.exceededAtTurn)}:{}}}function w$(j,J){return j==="queued"||j==="running"||j==="complete"||j==="failed"||j==="paused"?j:J}function P$(j,J){if(!j||typeof j!=="object")return;let $=j,Z=K($.agent,128);if(!Z)return;let Q=$.status==="pending"||$.status==="running"||$.status==="complete"||$.status==="completed"||$.status==="failed"||$.status==="paused"?$.status:"pending";return{agent:Z,status:Q,...K($.sessionFile,2048)?{sessionFile:K($.sessionFile,2048)}:{},...$.activityState==="active_long_running"||$.activityState==="needs_attention"?{activityState:$.activityState}:{},...X($.lastActivityAt)!==void 0?{lastActivityAt:X($.lastActivityAt)}:{},...K($.currentTool,128)?{currentTool:K($.currentTool,128)}:{},...X($.currentToolStartedAt)!==void 0?{currentToolStartedAt:X($.currentToolStartedAt)}:{},...K($.currentPath,2048)?{currentPath:K($.currentPath,2048)}:{},...X($.turnCount)!==void 0?{turnCount:X($.turnCount)}:{},...X($.toolCount)!==void 0?{toolCount:X($.toolCount)}:{},...X($.startedAt)!==void 0?{startedAt:X($.startedAt)}:{},...X($.endedAt)!==void 0?{endedAt:X($.endedAt)}:{},...K($.error,1024)?{error:K($.error,1024)}:{},...$.timedOut===!0?{timedOut:!0}:{},...I($.turnBudget)?{turnBudget:I($.turnBudget)}:{},...$.turnBudgetExceeded===!0?{turnBudgetExceeded:!0}:{},...$.wrapUpRequested===!0?{wrapUpRequested:!0}:{},...J<m&&Array.isArray($.children)?{children:$.children.map((W)=>P(W,J+1)).filter((W)=>Boolean(W)).slice(0,D)}:{}}}function P(j,J=0){if(!j||typeof j!=="object")return;let $=j;if(!k($.id)||!k($.parentRunId))return;let Z=$$($.path),Q=Array.isArray($.steps)?$.steps.map((Y)=>P$(Y,J+1)).filter((Y)=>Boolean(Y)).slice(0,Q$):void 0,W=k$($.totalTokens),H=I$($.totalCost);return{id:$.id,parentRunId:$.parentRunId,...X($.parentStepIndex)!==void 0?{parentStepIndex:X($.parentStepIndex)}:{},...K($.parentAgent,128)?{parentAgent:K($.parentAgent,128)}:{},depth:Math.min(Math.max(0,X($.depth)??0),m),path:Z,state:w$($.state,"running"),...K($.asyncDir,2048)?{asyncDir:K($.asyncDir,2048)}:{},...X($.pid)!==void 0&&X($.pid)>0&&Number.isInteger(X($.pid))?{pid:X($.pid)}:{},...K($.sessionId,256)?{sessionId:K($.sessionId,256)}:{},...K($.sessionFile,2048)?{sessionFile:K($.sessionFile,2048)}:{},...K($.intercomTarget,256)?{intercomTarget:K($.intercomTarget,256)}:{},...K($.ownerIntercomTarget,256)?{ownerIntercomTarget:K($.ownerIntercomTarget,256)}:{},...K($.leafIntercomTarget,256)?{leafIntercomTarget:K($.leafIntercomTarget,256)}:{},...$.ownerState==="live"||$.ownerState==="gone"||$.ownerState==="unknown"?{ownerState:$.ownerState}:{},...K($.controlInbox,2048)?{controlInbox:K($.controlInbox,2048)}:{},...K($.capabilityToken,128)?{capabilityToken:K($.capabilityToken,128)}:{},...$.mode==="single"||$.mode==="parallel"||$.mode==="chain"?{mode:$.mode}:{},...K($.agent,128)?{agent:K($.agent,128)}:{},...Array.isArray($.agents)?{agents:$.agents.map((Y)=>K(Y,128)).filter((Y)=>Boolean(Y)).slice(0,Q$)}:{},...X($.currentStep)!==void 0?{currentStep:X($.currentStep)}:{},...X($.chainStepCount)!==void 0?{chainStepCount:X($.chainStepCount)}:{},...$.activityState==="active_long_running"||$.activityState==="needs_attention"?{activityState:$.activityState}:{},...X($.lastActivityAt)!==void 0?{lastActivityAt:X($.lastActivityAt)}:{},...K($.currentTool,128)?{currentTool:K($.currentTool,128)}:{},...X($.currentToolStartedAt)!==void 0?{currentToolStartedAt:X($.currentToolStartedAt)}:{},...K($.currentPath,2048)?{currentPath:K($.currentPath,2048)}:{},...X($.turnCount)!==void 0?{turnCount:X($.turnCount)}:{},...X($.toolCount)!==void 0?{toolCount:X($.toolCount)}:{},...W?{totalTokens:W}:{},...H?{totalCost:H}:{},...X($.startedAt)!==void 0?{startedAt:X($.startedAt)}:{},...X($.endedAt)!==void 0?{endedAt:X($.endedAt)}:{},...X($.lastUpdate)!==void 0?{lastUpdate:X($.lastUpdate)}:{},...X($.timeoutMs)!==void 0?{timeoutMs:X($.timeoutMs)}:{},...X($.deadlineAt)!==void 0?{deadlineAt:X($.deadlineAt)}:{},...$.timedOut===!0?{timedOut:!0}:{},...I($.turnBudget)?{turnBudget:I($.turnBudget)}:{},...$.turnBudgetExceeded===!0?{turnBudgetExceeded:!0}:{},...$.wrapUpRequested===!0?{wrapUpRequested:!0}:{},...K($.error,1024)?{error:K($.error,1024)}:{},...Q&&Q.length>0?{steps:Q}:{},...J<m&&Array.isArray($.children)?{children:$.children.map((Y)=>P(Y,J+1)).filter((Y)=>Boolean(Y)).slice(0,D)}:{}}}function W$(j,J){if(Buffer.byteLength(j,"utf-8")>Y$)return;let $;try{$=JSON.parse(j)}catch{return}if(!$||typeof $!=="object")return;let Z=$;if(Z.type!=="subagent.nested.started"&&Z.type!=="subagent.nested.updated"&&Z.type!=="subagent.nested.completed")return;if(Z.rootRunId!==J.rootRunId||Z.capabilityToken!==J.capabilityToken)return;if(!k(Z.parentRunId))return;let Q=X(Z.ts);if(Q===void 0)return;let W=P(Z.child);if(!W||W.id===J.rootRunId)return;let H={...W,controlInbox:J.controlInbox,capabilityToken:J.capabilityToken,ownerState:W.ownerState??"unknown"};return{type:Z.type,ts:Q,rootRunId:J.rootRunId,parentRunId:Z.parentRunId,...X(Z.parentStepIndex)!==void 0?{parentStepIndex:X(Z.parentStepIndex)}:{},capabilityToken:J.capabilityToken,child:H}}function v$(j,J){if(!j.includes(`
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { ASYNC_DIR, RESULTS_DIR } from "../../shared/types.js";
|
|
4
|
+
import { findAsyncRunPrefixMatches } from "./async-resume.js";
|
|
5
|
+
import { assertSafeNestedId, findNestedRunMatchesById } from "../shared/nested-events.js";
|
|
6
|
+
function exactAsyncLocation(id, asyncDirRoot, resultsDir) {
|
|
7
|
+
const asyncDir = path.join(asyncDirRoot, id);
|
|
8
|
+
const resultPath = path.join(resultsDir, `${id}.json`);
|
|
9
|
+
if (!fs.existsSync(asyncDir) && !fs.existsSync(resultPath))
|
|
10
|
+
return;
|
|
11
|
+
return {
|
|
12
|
+
asyncDir: fs.existsSync(asyncDir) ? asyncDir : null,
|
|
13
|
+
resultPath: fs.existsSync(resultPath) ? resultPath : null,
|
|
14
|
+
resolvedId: id
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function foregroundIds(state) {
|
|
18
|
+
if (!state)
|
|
19
|
+
return [];
|
|
20
|
+
return [...new Set([...state.foregroundControls.keys(), ...state.foregroundRuns?.keys() ?? []])];
|
|
21
|
+
}
|
|
22
|
+
function nestedScopeFromState(state) {
|
|
23
|
+
if (!state)
|
|
24
|
+
return;
|
|
25
|
+
const routes = [];
|
|
26
|
+
const seen = new Set;
|
|
27
|
+
const add = (route) => {
|
|
28
|
+
if (!route)
|
|
29
|
+
return;
|
|
30
|
+
const key = `${route.rootRunId}:${route.eventSink}:${route.controlInbox}`;
|
|
31
|
+
if (seen.has(key))
|
|
32
|
+
return;
|
|
33
|
+
seen.add(key);
|
|
34
|
+
routes.push(route);
|
|
35
|
+
};
|
|
36
|
+
for (const control of state.foregroundControls.values())
|
|
37
|
+
add(control.nestedRoute);
|
|
38
|
+
for (const job of state.asyncJobs.values())
|
|
39
|
+
add(job.nestedRoute);
|
|
40
|
+
return { routes };
|
|
41
|
+
}
|
|
42
|
+
function asyncPrefixMatches(prefix, asyncDirRoot, resultsDir) {
|
|
43
|
+
return findAsyncRunPrefixMatches(prefix, asyncDirRoot, resultsDir);
|
|
44
|
+
}
|
|
45
|
+
export function resolveSubagentRunId(id, deps = {}) {
|
|
46
|
+
assertSafeNestedId("id", id);
|
|
47
|
+
const asyncDirRoot = deps.asyncDirRoot ?? ASYNC_DIR;
|
|
48
|
+
const resultsDir = deps.resultsDir ?? RESULTS_DIR;
|
|
49
|
+
const nestedScope = deps.nested ?? nestedScopeFromState(deps.state);
|
|
50
|
+
if (deps.state?.foregroundControls.has(id) || deps.state?.foregroundRuns?.has(id))
|
|
51
|
+
return { kind: "foreground", id };
|
|
52
|
+
const exactAsync = exactAsyncLocation(id, asyncDirRoot, resultsDir);
|
|
53
|
+
if (exactAsync)
|
|
54
|
+
return { kind: "async", id, location: exactAsync };
|
|
55
|
+
const exactNested = findNestedRunMatchesById(id, nestedScope ? { scope: nestedScope } : {});
|
|
56
|
+
if (exactNested.length > 1)
|
|
57
|
+
throw new Error(`Nested run id '${id}' is ambiguous across authorized registries. Provide the full id after stale registries are cleaned up.`);
|
|
58
|
+
if (exactNested[0])
|
|
59
|
+
return { kind: "nested", id, match: exactNested[0] };
|
|
60
|
+
const matches = [];
|
|
61
|
+
for (const foregroundId of foregroundIds(deps.state).filter((candidate) => candidate.startsWith(id))) {
|
|
62
|
+
matches.push({ kind: "foreground", id: foregroundId });
|
|
63
|
+
}
|
|
64
|
+
for (const match of asyncPrefixMatches(id, asyncDirRoot, resultsDir)) {
|
|
65
|
+
matches.push({ kind: "async", id: match.id, location: match.location });
|
|
66
|
+
}
|
|
67
|
+
for (const match of findNestedRunMatchesById(id, nestedScope ? { prefix: true, scope: nestedScope } : { prefix: true })) {
|
|
68
|
+
matches.push({ kind: "nested", id: match.run.id, match });
|
|
69
|
+
}
|
|
70
|
+
const unique = new Map(matches.map((match) => [`${match.kind}:${match.id}`, match]));
|
|
71
|
+
const values = [...unique.values()];
|
|
72
|
+
if (values.length > 1) {
|
|
73
|
+
throw new Error(`Ambiguous subagent run id prefix '${id}' matched: ${values.map((match) => `${match.kind}:${match.id}`).join(", ")}. Provide a longer id.`);
|
|
74
|
+
}
|
|
75
|
+
return values[0];
|
|
76
|
+
}
|