@sideboard-ai/core 0.1.133 → 0.1.136
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/dist/{agents-NHS6P25H.js → agents-ELWR7A2T.js} +5 -5
- package/dist/{agents-SOU5GPWI.js → agents-QNTTLMG2.js} +5 -5
- package/dist/{chunk-Y645NFYN.js → chunk-4XKUHP6G.js} +2 -2
- package/dist/{chunk-4YAVXWFR.js → chunk-CYM5DCHI.js} +39 -5
- package/dist/{chunk-LTP7GHIF.js → chunk-GSKRGF7B.js} +286 -5
- package/dist/{chunk-WEU5M7BW.js → chunk-HQQNLDVC.js} +1 -1
- package/dist/{chunk-IM36S4HZ.js → chunk-IFZ4MOTN.js} +3 -3
- package/dist/{chunk-G6X6UFJO.js → chunk-J5IBSVB3.js} +42 -12
- package/dist/{chunk-AK7SWE2U.js → chunk-JPBRMUM6.js} +9 -5
- package/dist/{chunk-YEIH7P7D.js → chunk-K5YT5GX2.js} +244 -5
- package/dist/{chunk-3UVVWNHF.js → chunk-MDCKV2NF.js} +2 -2
- package/dist/{chunk-HLJUNJBF.js → chunk-PM3C2J6K.js} +42 -12
- package/dist/{chunk-Q6XQXCOM.js → chunk-QAV3HGVS.js} +1 -1
- package/dist/{chunk-TG7YU2KG.js → chunk-TIGKDMIA.js} +144 -271
- package/dist/{chunk-6CRKPD4C.js → chunk-TQ4S5AGJ.js} +3 -3
- package/dist/{chunk-VSON7EJ6.js → chunk-WS5LFFU3.js} +140 -222
- package/dist/{coordinator-prompt-DXHEDRRN.js → coordinator-prompt-2OWSUAUR.js} +3 -3
- package/dist/{coordinator-prompt-XF7LVOUN.js → coordinator-prompt-IPL4Z6SL.js} +3 -3
- package/dist/{global-workspace-2LO5ATOH.js → global-workspace-JDUCUL7S.js} +4 -4
- package/dist/{global-workspace-MLQNULOU.js → global-workspace-NIKZAKOO.js} +4 -4
- package/dist/index.cjs +873 -628
- package/dist/index.d.cts +26 -1
- package/dist/index.d.ts +26 -1
- package/dist/index.js +42 -19
- package/dist/mcp/run-stdio.cjs +700 -498
- package/dist/mcp/run-stdio.js +22 -11
- package/dist/{orchestrator-P2SYHVLS.js → orchestrator-6I47JMU2.js} +7 -7
- package/dist/{orchestrator-KR5RA5B7.js → orchestrator-KK3CUW37.js} +7 -7
- package/dist/{thread-store-5MLYY35S.js → thread-store-CRLQJ2HM.js} +3 -1
- package/dist/{thread-store-F6BCARQG.js → thread-store-FADXSMEJ.js} +3 -1
- package/dist/{workspaces-MINB764G.js → workspaces-5EWNNALF.js} +5 -5
- package/dist/{workspaces-ARWPZG6F.js → workspaces-KZA3TCEE.js} +5 -5
- package/dist/{worktree-EBZMUUAL.js → worktree-BC6XDMQK.js} +2 -2
- package/dist/{worktree-S7MKMYAT.js → worktree-MX7XBX6Z.js} +2 -2
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
resolveGithubRepoSlug
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-QAV3HGVS.js";
|
|
6
6
|
import {
|
|
7
7
|
resolveThreadDefaults
|
|
8
8
|
} from "./chunk-GKKHXZCT.js";
|
|
@@ -66,7 +66,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
|
|
|
66
66
|
"- fork_worktree \u2014 fork a worktree chat into a NEW git worktree + chat (transcript attached); optional agent; leave model unset (Auto) unless you have a reason. Not for orchestration chats.",
|
|
67
67
|
"- fork_chat \u2014 fork a worktree chat (same worktree tab) OR a Global orchestration chat (new orchestration tab); optional agent; leave model unset (Auto) unless you have a reason. Remote coordinators: use this to continue another orchestration chat on a different agent after session limits.",
|
|
68
68
|
"- send_to_thread \u2014 queue a prompt (start/continue a chat turn); pass force_stop: true to interrupt mid-turn / clear stale queued prompts before replacing with a new request",
|
|
69
|
-
"- wait_for_turn / get_turn_result \u2014 wait for and read the agent reply (includes last-turn usage / costUsd when the child agent reported it). wait_for_turn returns within ~45s even if the child is still working (MCP clients kill longer tool calls). If stillRunning is true, progress is a live snapshot of tools/thinking \u2014 call wait_for_turn again. status=queued with no lastActivityAt means the child has not started yet (concurrency cap) \u2014 keep waiting; do not force_stop or send a check-in. Do not send \u201Care you stuck?\u201D or assume a hang while lastActivityAt is recent. On status error, lastError (and text) is the failure \u2014 switch agent, tell the user, or retry; do not treat empty text as success.",
|
|
69
|
+
"- wait_for_turn / get_turn_result \u2014 wait for and read the agent reply (includes last-turn usage / costUsd when the child agent reported it). wait_for_turn returns within ~45s even if the child is still working (MCP clients kill longer tool calls). If stillRunning is true, progress is a live snapshot of tools/thinking \u2014 call wait_for_turn again. status=queued with no lastActivityAt means the child has not started yet (concurrency cap) \u2014 keep waiting; do not force_stop or send a check-in. Do not send \u201Care you stuck?\u201D or assume a hang while lastActivityAt is recent. On status error, lastError (and text) is the failure \u2014 switch agent, tell the user, or retry; do not treat empty text as success. On status stopped or broken (or incomplete=true), the child was interrupted or died \u2014 resume with send_to_thread or tell the user; never treat stopped as a finished turn. Sideboard also injects a notice into this chat when a child stops unexpectedly.",
|
|
70
70
|
"- stop_thread \u2014 force-stop: kill in-flight turn AND clear queued prompts (do not leave stale queue after an interrupt)",
|
|
71
71
|
"- archive_thread / restore_thread \u2014 archive (tears down worktree when last tab) or restore",
|
|
72
72
|
"Setup / run:",
|
|
@@ -106,7 +106,7 @@ function coordinatorTurnReminder(opts) {
|
|
|
106
106
|
`- YOUR orchestration thread id is ${opts.parentId} \u2014 pass parentThreadId="${opts.parentId}" on create_thread, or omit it.`,
|
|
107
107
|
goal ? `- Goal / title: ${goal}` : null,
|
|
108
108
|
accountDefaultsPlaybookLine(),
|
|
109
|
-
"- Status: list_board (worktree Kanban: New \u2192 Draft \u2192 Review \u2192 Merged) or list_threads. Link chats as `[Title](sideboard://thread/<id>)`. Merge only if the user asked."
|
|
109
|
+
"- Status: list_board (worktree Kanban: New \u2192 Draft \u2192 Review \u2192 Merged) or list_threads. Link chats as `[Title](sideboard://thread/<id>)`. Merge only if the user asked. If a child is stopped/error/broken, it did not finish \u2014 resume or tell the user."
|
|
110
110
|
].filter(Boolean).join("\n");
|
|
111
111
|
}
|
|
112
112
|
function ensureGlobalCoordinatorCwd(opts) {
|
|
@@ -31,13 +31,13 @@ import {
|
|
|
31
31
|
summarizeTurnStderr,
|
|
32
32
|
toolDescription,
|
|
33
33
|
turnFailChatText
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-JPBRMUM6.js";
|
|
35
35
|
import {
|
|
36
36
|
addWorkspace,
|
|
37
37
|
ensureWorkspace,
|
|
38
38
|
removeWorkspace,
|
|
39
39
|
syncWorkspacesFromThreads
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-4XKUHP6G.js";
|
|
41
41
|
import {
|
|
42
42
|
extractPresentedPlan,
|
|
43
43
|
readPlanFile,
|
|
@@ -48,6 +48,7 @@ import {
|
|
|
48
48
|
} from "./chunk-KLBOWJ74.js";
|
|
49
49
|
import {
|
|
50
50
|
assertOrchestratorCapableAgent,
|
|
51
|
+
attachmentsFromWorktreePaths,
|
|
51
52
|
coerceOrchestratorAgent,
|
|
52
53
|
createGlobalChat,
|
|
53
54
|
healOrchestrationSoccerTitles,
|
|
@@ -57,15 +58,18 @@ import {
|
|
|
57
58
|
isOrchestratorCapableAgent,
|
|
58
59
|
isOrchestratorThread,
|
|
59
60
|
isSlackCoordinatorThread,
|
|
60
|
-
orchestratorSessionPoisonedByBuiltins
|
|
61
|
-
|
|
61
|
+
orchestratorSessionPoisonedByBuiltins,
|
|
62
|
+
persistPendingFileAttachments,
|
|
63
|
+
stageAbsolutePathsAsAttachments,
|
|
64
|
+
stageBuffersAsAttachments
|
|
65
|
+
} from "./chunk-K5YT5GX2.js";
|
|
62
66
|
import {
|
|
63
67
|
SLACK_REPLY_FORMATTING,
|
|
64
68
|
coordinatorSystemPrompt,
|
|
65
69
|
coordinatorTurnReminder,
|
|
66
70
|
enrichWorkspacesWithGithub,
|
|
67
71
|
ensureGlobalCoordinatorCwd
|
|
68
|
-
} from "./chunk-
|
|
72
|
+
} from "./chunk-TQ4S5AGJ.js";
|
|
69
73
|
import {
|
|
70
74
|
addPrStackLayer,
|
|
71
75
|
allocateTeamName,
|
|
@@ -110,11 +114,10 @@ import {
|
|
|
110
114
|
withRepoGitLock,
|
|
111
115
|
worktreeDisplayLabelForGroup,
|
|
112
116
|
worktreeNameFromPath
|
|
113
|
-
} from "./chunk-
|
|
117
|
+
} from "./chunk-QAV3HGVS.js";
|
|
114
118
|
import {
|
|
115
119
|
ATTACHMENTS_DIR,
|
|
116
|
-
LEGACY_ATTACHMENTS_DIR
|
|
117
|
-
attachmentsGitignoreBody
|
|
120
|
+
LEGACY_ATTACHMENTS_DIR
|
|
118
121
|
} from "./chunk-B3SJXYIJ.js";
|
|
119
122
|
import {
|
|
120
123
|
appendMessage,
|
|
@@ -127,7 +130,7 @@ import {
|
|
|
127
130
|
updateThread,
|
|
128
131
|
withThreadLock,
|
|
129
132
|
writeThread
|
|
130
|
-
} from "./chunk-
|
|
133
|
+
} from "./chunk-J5IBSVB3.js";
|
|
131
134
|
import {
|
|
132
135
|
clearStaleIndexLocks,
|
|
133
136
|
enrichPathWithNpmGlobalBin,
|
|
@@ -384,7 +387,7 @@ async function continueSourceThread(threadId, prompt) {
|
|
|
384
387
|
await continueOnReply(threadId, prompt);
|
|
385
388
|
return;
|
|
386
389
|
}
|
|
387
|
-
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-
|
|
390
|
+
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-KK3CUW37.js");
|
|
388
391
|
await getOrchestrator2().send(threadId, prompt);
|
|
389
392
|
} catch {
|
|
390
393
|
}
|
|
@@ -644,7 +647,7 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
644
647
|
}
|
|
645
648
|
|
|
646
649
|
// src/orchestrator/orchestrator.ts
|
|
647
|
-
import { existsSync as
|
|
650
|
+
import { existsSync as existsSync15 } from "fs";
|
|
648
651
|
|
|
649
652
|
// src/agents/spawn.ts
|
|
650
653
|
import { createInterface } from "readline";
|
|
@@ -725,9 +728,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
725
728
|
`Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
|
|
726
729
|
);
|
|
727
730
|
}
|
|
728
|
-
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-
|
|
731
|
+
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-JDUCUL7S.js");
|
|
729
732
|
if (isGlobalThread2(thread)) {
|
|
730
|
-
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-
|
|
733
|
+
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-2OWSUAUR.js");
|
|
731
734
|
ensureGlobalCoordinatorCwd2(
|
|
732
735
|
isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
|
|
733
736
|
);
|
|
@@ -2238,6 +2241,45 @@ function thisProcessShouldDrainAgentQueues() {
|
|
|
2238
2241
|
return !isDesktopHostAlive();
|
|
2239
2242
|
}
|
|
2240
2243
|
|
|
2244
|
+
// src/orchestrator/child-halt.ts
|
|
2245
|
+
var HALT_STATUSES = /* @__PURE__ */ new Set(["stopped", "error", "broken"]);
|
|
2246
|
+
function isIncompleteChildStatus(status) {
|
|
2247
|
+
return HALT_STATUSES.has(status);
|
|
2248
|
+
}
|
|
2249
|
+
function childHaltNotice(child, status) {
|
|
2250
|
+
const title = child.title?.trim() || "Untitled";
|
|
2251
|
+
const link = `[${title}](sideboard://thread/${child.id})`;
|
|
2252
|
+
const why = child.lastError?.trim();
|
|
2253
|
+
const extra = why ? ` lastError: ${why}` : "";
|
|
2254
|
+
return [
|
|
2255
|
+
`Sideboard: child worktree ${link} ${status} before finishing (status=${status}).${extra}`,
|
|
2256
|
+
"This is information \u2014 not a user command. Resume with send_to_thread or tell the user. Do not treat this as a successful turn."
|
|
2257
|
+
].join("\n");
|
|
2258
|
+
}
|
|
2259
|
+
function shouldNotifyParentOfChildHalt(opts) {
|
|
2260
|
+
if (!isIncompleteChildStatus(opts.status)) return false;
|
|
2261
|
+
if (!opts.child.parentThreadId) return false;
|
|
2262
|
+
if (!opts.parent || opts.parent.status === "archived") return false;
|
|
2263
|
+
if (opts.parent.id === opts.child.id) return false;
|
|
2264
|
+
return isOrchestratorThread(opts.parent);
|
|
2265
|
+
}
|
|
2266
|
+
var notified = /* @__PURE__ */ new Set();
|
|
2267
|
+
function noticeKey(childId, status) {
|
|
2268
|
+
return `${childId}:${status}`;
|
|
2269
|
+
}
|
|
2270
|
+
function notifyParentOfChildHalt(child, status, send) {
|
|
2271
|
+
const parent = child.parentThreadId ? readThread(child.parentThreadId) : null;
|
|
2272
|
+
if (!shouldNotifyParentOfChildHalt({ child, parent, status })) return false;
|
|
2273
|
+
const key = noticeKey(child.id, status);
|
|
2274
|
+
if (notified.has(key)) return false;
|
|
2275
|
+
notified.add(key);
|
|
2276
|
+
const parentId = parent.id;
|
|
2277
|
+
void send(parentId, childHaltNotice(child, status)).catch(() => {
|
|
2278
|
+
notified.delete(key);
|
|
2279
|
+
});
|
|
2280
|
+
return true;
|
|
2281
|
+
}
|
|
2282
|
+
|
|
2241
2283
|
// src/threads/create.ts
|
|
2242
2284
|
import { existsSync as existsSync7 } from "fs";
|
|
2243
2285
|
|
|
@@ -2704,6 +2746,9 @@ function assembleHomeBoard(input) {
|
|
|
2704
2746
|
var HOME_BOARD_AGENT_HINT = "Home is a Kanban of worktrees (one card per checkout; sibling chat tabs nest as inner cards). create_thread reuses a live worktree for the same ticket, PR, or named branch \u2014 do not recreate it. Columns are the path to merge: New (no PR) \u2192 Draft (draft PR) \u2192 Review (open PR) \u2192 Merged. Archive removes the card to Settings \u2192 History. Queued/running are activity on the card, not columns. Orchestration chats stay in the sidebar. Do not invent status.";
|
|
2705
2747
|
|
|
2706
2748
|
// src/threads/create.ts
|
|
2749
|
+
function persistCreateAttachments(worktreePath, attachments) {
|
|
2750
|
+
return persistPendingFileAttachments(worktreePath, attachments ?? []);
|
|
2751
|
+
}
|
|
2707
2752
|
async function createThread(input, _onSetupLine) {
|
|
2708
2753
|
const repoPath = await resolveRepoRoot(input.repoPath);
|
|
2709
2754
|
if (!existsSync7(repoPath)) {
|
|
@@ -2723,7 +2768,16 @@ async function createThread(input, _onSetupLine) {
|
|
|
2723
2768
|
repoPath: canonicalizeRepoPath(t.repoPath)
|
|
2724
2769
|
}))
|
|
2725
2770
|
);
|
|
2726
|
-
if (existing)
|
|
2771
|
+
if (existing) {
|
|
2772
|
+
const thread2 = readThread(existing.id) ?? existing;
|
|
2773
|
+
if (!input.attachments?.length) return thread2;
|
|
2774
|
+
return updateThread(thread2.id, {
|
|
2775
|
+
attachments: persistCreateAttachments(thread2.worktreePath, [
|
|
2776
|
+
...thread2.attachments,
|
|
2777
|
+
...input.attachments
|
|
2778
|
+
])
|
|
2779
|
+
});
|
|
2780
|
+
}
|
|
2727
2781
|
}
|
|
2728
2782
|
const resolved = resolveNewThreadOptions({
|
|
2729
2783
|
agent: input.agent,
|
|
@@ -2771,7 +2825,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
2771
2825
|
effort: resolved.effort,
|
|
2772
2826
|
fast: resolved.fast,
|
|
2773
2827
|
planMode: Boolean(input.planMode),
|
|
2774
|
-
attachments: input.attachments
|
|
2828
|
+
attachments: persistCreateAttachments(repoPath, input.attachments),
|
|
2775
2829
|
sourceIsFork: false,
|
|
2776
2830
|
parentThreadId: input.parentThreadId ?? null,
|
|
2777
2831
|
status: "idle",
|
|
@@ -2850,7 +2904,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
2850
2904
|
effort: resolved.effort,
|
|
2851
2905
|
fast: resolved.fast,
|
|
2852
2906
|
planMode: Boolean(input.planMode),
|
|
2853
|
-
attachments,
|
|
2907
|
+
attachments: persistCreateAttachments(worktreePath, attachments),
|
|
2854
2908
|
sourceIsFork,
|
|
2855
2909
|
parentThreadId: input.parentThreadId ?? null,
|
|
2856
2910
|
status: "idle",
|
|
@@ -2862,7 +2916,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
2862
2916
|
return readThread(thread.id) ?? thread;
|
|
2863
2917
|
}
|
|
2864
2918
|
async function listLinearIssues(agent, repoPath) {
|
|
2865
|
-
const { getAdapter: getAdapter2 } = await import("./agents-
|
|
2919
|
+
const { getAdapter: getAdapter2 } = await import("./agents-ELWR7A2T.js");
|
|
2866
2920
|
await requireAgent(agent, { requireLinear: true });
|
|
2867
2921
|
const adapter = getAdapter2(agent);
|
|
2868
2922
|
if (!adapter.listLinearIssues) {
|
|
@@ -3259,7 +3313,7 @@ async function adoptThread(input) {
|
|
|
3259
3313
|
messages: input.messages ?? []
|
|
3260
3314
|
});
|
|
3261
3315
|
writeThread(thread);
|
|
3262
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
3316
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-5EWNNALF.js");
|
|
3263
3317
|
await ensureWorkspace2(repoPath);
|
|
3264
3318
|
return thread;
|
|
3265
3319
|
}
|
|
@@ -4809,193 +4863,9 @@ function expandComposerPrompt(worktreePath, prompt, opts) {
|
|
|
4809
4863
|
};
|
|
4810
4864
|
}
|
|
4811
4865
|
|
|
4812
|
-
// src/composer/stage-files.ts
|
|
4813
|
-
import { copyFileSync as copyFileSync3, existsSync as existsSync13, mkdirSync as mkdirSync4, readFileSync as readFileSync10, statSync as statSync4, writeFileSync as writeFileSync5 } from "fs";
|
|
4814
|
-
import { basename as basename3, extname, join as join12 } from "path";
|
|
4815
|
-
import { randomUUID as randomUUID4 } from "crypto";
|
|
4816
|
-
var IMAGE_EXTENSIONS2 = /* @__PURE__ */ new Set([
|
|
4817
|
-
"png",
|
|
4818
|
-
"jpg",
|
|
4819
|
-
"jpeg",
|
|
4820
|
-
"gif",
|
|
4821
|
-
"webp",
|
|
4822
|
-
"svg",
|
|
4823
|
-
"bmp",
|
|
4824
|
-
"ico"
|
|
4825
|
-
]);
|
|
4826
|
-
var IMAGE_MIME_BY_EXT = {
|
|
4827
|
-
png: "image/png",
|
|
4828
|
-
jpg: "image/jpeg",
|
|
4829
|
-
jpeg: "image/jpeg",
|
|
4830
|
-
gif: "image/gif",
|
|
4831
|
-
webp: "image/webp",
|
|
4832
|
-
svg: "image/svg+xml",
|
|
4833
|
-
bmp: "image/bmp",
|
|
4834
|
-
ico: "image/x-icon"
|
|
4835
|
-
};
|
|
4836
|
-
var MAX_INLINE_BYTES = 4e5;
|
|
4837
|
-
var MAX_PREVIEW_BYTES = 5e6;
|
|
4838
|
-
function fileExtension(filePath) {
|
|
4839
|
-
const base = basename3(filePath).toLowerCase();
|
|
4840
|
-
return base.includes(".") ? base.split(".").pop() || "" : "";
|
|
4841
|
-
}
|
|
4842
|
-
function isImageFilePath(filePath) {
|
|
4843
|
-
return IMAGE_EXTENSIONS2.has(fileExtension(filePath));
|
|
4844
|
-
}
|
|
4845
|
-
function imageMimeType(filePath) {
|
|
4846
|
-
return IMAGE_MIME_BY_EXT[fileExtension(filePath)] || "image/png";
|
|
4847
|
-
}
|
|
4848
|
-
function ensureAttachmentsDir(worktreePath) {
|
|
4849
|
-
const dir = join12(worktreePath, ATTACHMENTS_DIR);
|
|
4850
|
-
mkdirSync4(dir, { recursive: true });
|
|
4851
|
-
const gi = join12(dir, ".gitignore");
|
|
4852
|
-
if (!existsSync13(gi)) {
|
|
4853
|
-
writeFileSync5(gi, attachmentsGitignoreBody(), "utf8");
|
|
4854
|
-
}
|
|
4855
|
-
return dir;
|
|
4856
|
-
}
|
|
4857
|
-
function uniqueAttachmentName(dir, originalName) {
|
|
4858
|
-
const safe = originalName.replace(/[/\\]/g, "_") || "file";
|
|
4859
|
-
if (!existsSync13(join12(dir, safe))) return safe;
|
|
4860
|
-
const ext = extname(safe);
|
|
4861
|
-
const stem = ext ? safe.slice(0, -ext.length) : safe;
|
|
4862
|
-
for (let i = 1; i < 1e4; i++) {
|
|
4863
|
-
const candidate = `${stem}-${i}${ext}`;
|
|
4864
|
-
if (!existsSync13(join12(dir, candidate))) return candidate;
|
|
4865
|
-
}
|
|
4866
|
-
return `${stem}-${randomUUID4()}${ext}`;
|
|
4867
|
-
}
|
|
4868
|
-
function previewDataUrlFromBuf(filePath, buf) {
|
|
4869
|
-
if (!isImageFilePath(filePath)) return void 0;
|
|
4870
|
-
if (buf.length > MAX_PREVIEW_BYTES) return void 0;
|
|
4871
|
-
return `data:${imageMimeType(filePath)};base64,${buf.toString("base64")}`;
|
|
4872
|
-
}
|
|
4873
|
-
function attachmentFromBuffer(name, buf, opts) {
|
|
4874
|
-
const previewDataUrl = previewDataUrlFromBuf(name, buf);
|
|
4875
|
-
if (isImageFilePath(name)) {
|
|
4876
|
-
const pathHint = opts.path ? `\`${opts.path}\`` : opts.sourceLabel || name;
|
|
4877
|
-
return {
|
|
4878
|
-
id: randomUUID4(),
|
|
4879
|
-
name,
|
|
4880
|
-
kind: "file",
|
|
4881
|
-
path: opts.path,
|
|
4882
|
-
previewDataUrl,
|
|
4883
|
-
content: [
|
|
4884
|
-
`Image attached: ${pathHint}`,
|
|
4885
|
-
opts.path ? `Use the Read tool on \`${opts.path}\` to view this image.` : "The image is shown in the composer; copy it into the worktree if you need to inspect pixels."
|
|
4886
|
-
].join("\n")
|
|
4887
|
-
};
|
|
4888
|
-
}
|
|
4889
|
-
if (buf.length > MAX_INLINE_BYTES) {
|
|
4890
|
-
return {
|
|
4891
|
-
id: randomUUID4(),
|
|
4892
|
-
name,
|
|
4893
|
-
kind: "file",
|
|
4894
|
-
path: opts.path,
|
|
4895
|
-
content: opts.path ? `(file too large to attach inline: \`${opts.path}\`, ${buf.length} bytes \u2014 use the Read tool)` : `(file too large to attach inline: ${opts.sourceLabel || name}, ${buf.length} bytes)`
|
|
4896
|
-
};
|
|
4897
|
-
}
|
|
4898
|
-
if (buf.includes(0)) {
|
|
4899
|
-
return {
|
|
4900
|
-
id: randomUUID4(),
|
|
4901
|
-
name,
|
|
4902
|
-
kind: "file",
|
|
4903
|
-
path: opts.path,
|
|
4904
|
-
content: opts.path ? `(binary file at \`${opts.path}\` \u2014 use tools to inspect)` : `(binary file attached by path only: ${opts.sourceLabel || name})`
|
|
4905
|
-
};
|
|
4906
|
-
}
|
|
4907
|
-
return {
|
|
4908
|
-
id: randomUUID4(),
|
|
4909
|
-
name,
|
|
4910
|
-
kind: "file",
|
|
4911
|
-
path: opts.path,
|
|
4912
|
-
content: buf.toString("utf8")
|
|
4913
|
-
};
|
|
4914
|
-
}
|
|
4915
|
-
function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
|
|
4916
|
-
if (absolutePaths.length === 0) return [];
|
|
4917
|
-
const dir = ensureAttachmentsDir(worktreePath);
|
|
4918
|
-
const out = [];
|
|
4919
|
-
for (const abs of absolutePaths) {
|
|
4920
|
-
const originalName = basename3(abs);
|
|
4921
|
-
try {
|
|
4922
|
-
const st = statSync4(abs);
|
|
4923
|
-
if (!st.isFile()) continue;
|
|
4924
|
-
const name = uniqueAttachmentName(dir, originalName);
|
|
4925
|
-
const destAbs = join12(dir, name);
|
|
4926
|
-
copyFileSync3(abs, destAbs);
|
|
4927
|
-
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
4928
|
-
const buf = readFileSync10(destAbs);
|
|
4929
|
-
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
4930
|
-
} catch (err) {
|
|
4931
|
-
out.push({
|
|
4932
|
-
id: randomUUID4(),
|
|
4933
|
-
name: originalName,
|
|
4934
|
-
kind: "file",
|
|
4935
|
-
content: `(could not attach ${abs}: ${err instanceof Error ? err.message : String(err)})`
|
|
4936
|
-
});
|
|
4937
|
-
}
|
|
4938
|
-
}
|
|
4939
|
-
return out;
|
|
4940
|
-
}
|
|
4941
|
-
function stageBuffersAsAttachments(worktreePath, buffers2) {
|
|
4942
|
-
if (buffers2.length === 0) return [];
|
|
4943
|
-
const dir = ensureAttachmentsDir(worktreePath);
|
|
4944
|
-
const out = [];
|
|
4945
|
-
for (const item of buffers2) {
|
|
4946
|
-
const originalName = (item.name || "file").replace(/[/\\]/g, "_") || "file";
|
|
4947
|
-
try {
|
|
4948
|
-
const buf = Buffer.from(item.dataBase64, "base64");
|
|
4949
|
-
const name = uniqueAttachmentName(dir, originalName);
|
|
4950
|
-
const destAbs = join12(dir, name);
|
|
4951
|
-
writeFileSync5(destAbs, buf);
|
|
4952
|
-
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
4953
|
-
out.push(attachmentFromBuffer(name, buf, { path: rel }));
|
|
4954
|
-
} catch (err) {
|
|
4955
|
-
out.push({
|
|
4956
|
-
id: randomUUID4(),
|
|
4957
|
-
name: originalName,
|
|
4958
|
-
kind: "file",
|
|
4959
|
-
content: `(could not attach ${originalName}: ${err instanceof Error ? err.message : String(err)})`
|
|
4960
|
-
});
|
|
4961
|
-
}
|
|
4962
|
-
}
|
|
4963
|
-
return out;
|
|
4964
|
-
}
|
|
4965
|
-
function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
|
|
4966
|
-
const out = [];
|
|
4967
|
-
for (const rel of relativePaths) {
|
|
4968
|
-
if (!rel || rel.includes("..") || rel.startsWith("/")) {
|
|
4969
|
-
out.push({
|
|
4970
|
-
id: randomUUID4(),
|
|
4971
|
-
name: basename3(rel) || "file",
|
|
4972
|
-
kind: "file",
|
|
4973
|
-
content: `(invalid path: ${rel})`
|
|
4974
|
-
});
|
|
4975
|
-
continue;
|
|
4976
|
-
}
|
|
4977
|
-
const name = basename3(rel);
|
|
4978
|
-
try {
|
|
4979
|
-
const abs = join12(worktreePath, rel);
|
|
4980
|
-
const st = statSync4(abs);
|
|
4981
|
-
if (!st.isFile()) continue;
|
|
4982
|
-
const buf = readFileSync10(abs);
|
|
4983
|
-
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
4984
|
-
} catch (err) {
|
|
4985
|
-
out.push({
|
|
4986
|
-
id: randomUUID4(),
|
|
4987
|
-
name,
|
|
4988
|
-
kind: "file",
|
|
4989
|
-
content: `(could not read ${rel}: ${err instanceof Error ? err.message : String(err)})`
|
|
4990
|
-
});
|
|
4991
|
-
}
|
|
4992
|
-
}
|
|
4993
|
-
return out;
|
|
4994
|
-
}
|
|
4995
|
-
|
|
4996
4866
|
// src/agents/instructions.ts
|
|
4997
|
-
import { existsSync as
|
|
4998
|
-
import { join as
|
|
4867
|
+
import { existsSync as existsSync13, readFileSync as readFileSync10, statSync as statSync4 } from "fs";
|
|
4868
|
+
import { join as join12 } from "path";
|
|
4999
4869
|
function normPath(p) {
|
|
5000
4870
|
return p.replace(/\/+$/, "");
|
|
5001
4871
|
}
|
|
@@ -5170,9 +5040,9 @@ async function syncThreadBranchFromGit(threadId) {
|
|
|
5170
5040
|
}
|
|
5171
5041
|
|
|
5172
5042
|
// src/store/schedules.ts
|
|
5173
|
-
import { randomUUID as
|
|
5174
|
-
import { existsSync as
|
|
5175
|
-
import { join as
|
|
5043
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
5044
|
+
import { existsSync as existsSync14, readFileSync as readFileSync11 } from "fs";
|
|
5045
|
+
import { join as join13 } from "path";
|
|
5176
5046
|
import { Cron } from "croner";
|
|
5177
5047
|
var DURATION_RE = /^(\d+)(s|m|h|d)$/i;
|
|
5178
5048
|
var UNIT_MS = {
|
|
@@ -5182,7 +5052,7 @@ var UNIT_MS = {
|
|
|
5182
5052
|
d: 864e5
|
|
5183
5053
|
};
|
|
5184
5054
|
function schedulesPath() {
|
|
5185
|
-
return
|
|
5055
|
+
return join13(appDataDir(), "schedules.json");
|
|
5186
5056
|
}
|
|
5187
5057
|
function parseDurationMs(every) {
|
|
5188
5058
|
const m = every.trim().match(DURATION_RE);
|
|
@@ -5282,9 +5152,9 @@ function normalizeTask(raw) {
|
|
|
5282
5152
|
}
|
|
5283
5153
|
function readAll() {
|
|
5284
5154
|
const path = schedulesPath();
|
|
5285
|
-
if (!
|
|
5155
|
+
if (!existsSync14(path)) return [];
|
|
5286
5156
|
try {
|
|
5287
|
-
const parsed = JSON.parse(
|
|
5157
|
+
const parsed = JSON.parse(readFileSync11(path, "utf8"));
|
|
5288
5158
|
if (!Array.isArray(parsed)) return [];
|
|
5289
5159
|
return parsed.map((row) => {
|
|
5290
5160
|
try {
|
|
@@ -5309,7 +5179,7 @@ function buildTask(input, now) {
|
|
|
5309
5179
|
const ts = nowIso(now);
|
|
5310
5180
|
const agent = input.agent ? coerceOrchestratorAgent(input.agent) : null;
|
|
5311
5181
|
return {
|
|
5312
|
-
id:
|
|
5182
|
+
id: randomUUID4(),
|
|
5313
5183
|
name: input.name?.trim() || defaultScheduleName(prompt),
|
|
5314
5184
|
prompt,
|
|
5315
5185
|
enabled: input.enabled !== false,
|
|
@@ -5407,7 +5277,7 @@ function formatScheduledPrompt(name, prompt) {
|
|
|
5407
5277
|
${prompt}`;
|
|
5408
5278
|
}
|
|
5409
5279
|
async function defaultDeps() {
|
|
5410
|
-
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-
|
|
5280
|
+
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-KK3CUW37.js");
|
|
5411
5281
|
const orch = getOrchestrator2();
|
|
5412
5282
|
return {
|
|
5413
5283
|
findThread: (id) => findThreadByRef(id),
|
|
@@ -5613,7 +5483,7 @@ var Orchestrator = class {
|
|
|
5613
5483
|
}
|
|
5614
5484
|
continue;
|
|
5615
5485
|
}
|
|
5616
|
-
if (!
|
|
5486
|
+
if (!existsSync15(thread.worktreePath)) {
|
|
5617
5487
|
setStatus(thread.id, "broken", "Worktree missing on disk");
|
|
5618
5488
|
this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
|
|
5619
5489
|
continue;
|
|
@@ -5650,6 +5520,9 @@ var Orchestrator = class {
|
|
|
5650
5520
|
* MCP-created review threads don't stay `queued` after the MCP child exits.
|
|
5651
5521
|
*/
|
|
5652
5522
|
adoptPersistedQueues() {
|
|
5523
|
+
if (thisProcessShouldDrainAgentQueues()) {
|
|
5524
|
+
this.healStaleRunningTurns();
|
|
5525
|
+
}
|
|
5653
5526
|
for (const thread of listThreads()) {
|
|
5654
5527
|
if (thread.status === "stopped" || thread.status === "archived") continue;
|
|
5655
5528
|
const pid = thread.agentPid;
|
|
@@ -5670,6 +5543,32 @@ var Orchestrator = class {
|
|
|
5670
5543
|
}
|
|
5671
5544
|
}
|
|
5672
5545
|
}
|
|
5546
|
+
/**
|
|
5547
|
+
* Mid-session: a worktree can sit at `running` after the agent process dies
|
|
5548
|
+
* (Cursor/CLI crash, OOM) while wait_for_turn still reports stillRunning.
|
|
5549
|
+
* Reclaim those and wake the parent orchestration chat.
|
|
5550
|
+
*/
|
|
5551
|
+
healStaleRunningTurns() {
|
|
5552
|
+
for (const thread of listThreads()) {
|
|
5553
|
+
if (thread.status === "archived") continue;
|
|
5554
|
+
const handle = this.activeTurns.get(thread.id);
|
|
5555
|
+
if (handle) {
|
|
5556
|
+
const pid = thread.agentPid;
|
|
5557
|
+
if (typeof pid === "number" && pid > 0 && !isPidAlive(pid)) {
|
|
5558
|
+
handle.kill();
|
|
5559
|
+
}
|
|
5560
|
+
continue;
|
|
5561
|
+
}
|
|
5562
|
+
if (!this.shouldReclaimRunningThread(thread)) continue;
|
|
5563
|
+
setStatus(thread.id, "stopped", "Process died (agent exited)");
|
|
5564
|
+
this.emit({ type: "status_changed", threadId: thread.id, status: "stopped" });
|
|
5565
|
+
this.emit({ type: "turn_finished", threadId: thread.id, exitCode: 1 });
|
|
5566
|
+
const latest = readThread(thread.id);
|
|
5567
|
+
if (latest) {
|
|
5568
|
+
notifyParentOfChildHalt(latest, "stopped", (id, prompt) => this.send(id, prompt));
|
|
5569
|
+
}
|
|
5570
|
+
}
|
|
5571
|
+
}
|
|
5673
5572
|
clearQuotaResumeTimer(threadId) {
|
|
5674
5573
|
const timer = this.quotaResumeTimers.get(threadId);
|
|
5675
5574
|
if (timer) clearTimeout(timer);
|
|
@@ -6387,6 +6286,12 @@ var Orchestrator = class {
|
|
|
6387
6286
|
assistantText: chatText,
|
|
6388
6287
|
partsCount: parts.length
|
|
6389
6288
|
});
|
|
6289
|
+
if (!this.crashContinued.has(threadId)) {
|
|
6290
|
+
const failed = readThread(threadId);
|
|
6291
|
+
if (failed) {
|
|
6292
|
+
notifyParentOfChildHalt(failed, "error", (id, prompt2) => this.send(id, prompt2));
|
|
6293
|
+
}
|
|
6294
|
+
}
|
|
6390
6295
|
}
|
|
6391
6296
|
}
|
|
6392
6297
|
} catch (err) {
|
|
@@ -6411,6 +6316,12 @@ var Orchestrator = class {
|
|
|
6411
6316
|
assistantText: "",
|
|
6412
6317
|
partsCount: 0
|
|
6413
6318
|
});
|
|
6319
|
+
if (!this.crashContinued.has(threadId)) {
|
|
6320
|
+
const failed = readThread(threadId);
|
|
6321
|
+
if (failed) {
|
|
6322
|
+
notifyParentOfChildHalt(failed, "error", (id, prompt2) => this.send(id, prompt2));
|
|
6323
|
+
}
|
|
6324
|
+
}
|
|
6414
6325
|
}
|
|
6415
6326
|
} finally {
|
|
6416
6327
|
this.startingTurns.delete(threadId);
|
|
@@ -6466,6 +6377,9 @@ var Orchestrator = class {
|
|
|
6466
6377
|
const stopped = writeLiveStatus(thread.id, "stopped") ?? readThread(thread.id) ?? thread;
|
|
6467
6378
|
if (stopped.status === "stopped") {
|
|
6468
6379
|
this.emit({ type: "status_changed", threadId: thread.id, status: "stopped" });
|
|
6380
|
+
if (opts?.notifyParent !== false) {
|
|
6381
|
+
notifyParentOfChildHalt(stopped, "stopped", (id, prompt) => this.send(id, prompt));
|
|
6382
|
+
}
|
|
6469
6383
|
}
|
|
6470
6384
|
return stopped;
|
|
6471
6385
|
}
|
|
@@ -6710,21 +6624,25 @@ var Orchestrator = class {
|
|
|
6710
6624
|
fn();
|
|
6711
6625
|
};
|
|
6712
6626
|
const off = this.on((event) => {
|
|
6713
|
-
if (
|
|
6627
|
+
if (!("threadId" in event) || event.threadId !== thread.id) return;
|
|
6628
|
+
if (event.type === "turn_finished" || event.type === "error") {
|
|
6714
6629
|
const latest = readThread(thread.id);
|
|
6715
6630
|
if (!latest) {
|
|
6716
6631
|
finish(() => reject(new Error(`Thread not found: ${thread.id}`)));
|
|
6717
6632
|
return;
|
|
6718
6633
|
}
|
|
6719
6634
|
finish(() => resolve(latest));
|
|
6635
|
+
return;
|
|
6720
6636
|
}
|
|
6721
|
-
if (event.type === "
|
|
6637
|
+
if (event.type === "status_changed") {
|
|
6722
6638
|
const latest = readThread(thread.id);
|
|
6723
6639
|
if (!latest) {
|
|
6724
6640
|
finish(() => reject(new Error(`Thread not found: ${thread.id}`)));
|
|
6725
6641
|
return;
|
|
6726
6642
|
}
|
|
6727
|
-
|
|
6643
|
+
if (!["running", "queued"].includes(latest.status)) {
|
|
6644
|
+
finish(() => resolve(latest));
|
|
6645
|
+
}
|
|
6728
6646
|
}
|
|
6729
6647
|
});
|
|
6730
6648
|
timer = setInterval(() => {
|
|
@@ -6759,7 +6677,7 @@ var Orchestrator = class {
|
|
|
6759
6677
|
const thread = this.requireThread(threadRef);
|
|
6760
6678
|
const lastAgent = [...thread.messages].reverse().find((m) => m.role === "agent");
|
|
6761
6679
|
const lastError = thread.lastError ?? null;
|
|
6762
|
-
const text = (lastAgent?.text ?? "").trim() || (thread.status === "error" ? lastError ?? "" : "");
|
|
6680
|
+
const text = (lastAgent?.text ?? "").trim() || (thread.status === "error" || thread.status === "stopped" || thread.status === "broken" ? lastError ?? "" : "");
|
|
6763
6681
|
const stillRunning = thread.status === "running" || thread.status === "queued";
|
|
6764
6682
|
const live = stillRunning ? readTurnLive(thread.id) : null;
|
|
6765
6683
|
const queuedHint = thread.status === "queued" && !live?.summary ? "Queued \u2014 waiting for a concurrency slot" : null;
|
|
@@ -7246,7 +7164,7 @@ var Orchestrator = class {
|
|
|
7246
7164
|
this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
|
|
7247
7165
|
if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
|
|
7248
7166
|
try {
|
|
7249
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
7167
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-5EWNNALF.js");
|
|
7250
7168
|
await ensureWorkspace2(thread.repoPath);
|
|
7251
7169
|
} catch {
|
|
7252
7170
|
}
|
|
@@ -7294,13 +7212,13 @@ var Orchestrator = class {
|
|
|
7294
7212
|
this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
|
|
7295
7213
|
return restored2;
|
|
7296
7214
|
}
|
|
7297
|
-
if (!
|
|
7215
|
+
if (!existsSync15(thread.worktreePath)) {
|
|
7298
7216
|
if (isCowboyThread(thread) || isPrimaryCheckoutThread(thread)) {
|
|
7299
7217
|
throw new Error(
|
|
7300
7218
|
`Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
|
|
7301
7219
|
);
|
|
7302
7220
|
}
|
|
7303
|
-
const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-
|
|
7221
|
+
const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-BC6XDMQK.js");
|
|
7304
7222
|
const slug = thread.worktreePath.split("/").pop();
|
|
7305
7223
|
const dest = thread.worktreePath;
|
|
7306
7224
|
await withRepoGitLock(thread.repoPath, async () => {
|
|
@@ -7408,7 +7326,7 @@ async function startOrchestration(opts) {
|
|
|
7408
7326
|
sourceRef: "default",
|
|
7409
7327
|
...createOpts
|
|
7410
7328
|
}).catch(async () => {
|
|
7411
|
-
const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-
|
|
7329
|
+
const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-BC6XDMQK.js");
|
|
7412
7330
|
const repo = await resolveRepoRoot2(repoPath);
|
|
7413
7331
|
const def = await resolveDefaultBranch2(repo);
|
|
7414
7332
|
return orch.createThread({
|
|
@@ -7418,7 +7336,7 @@ async function startOrchestration(opts) {
|
|
|
7418
7336
|
repoPath: repo
|
|
7419
7337
|
});
|
|
7420
7338
|
});
|
|
7421
|
-
const { updateThread: upd } = await import("./thread-store-
|
|
7339
|
+
const { updateThread: upd } = await import("./thread-store-FADXSMEJ.js");
|
|
7422
7340
|
const updated = upd(thread.id, {
|
|
7423
7341
|
sourceType: "orchestration",
|
|
7424
7342
|
sourceRef: goal
|
|
@@ -9,10 +9,10 @@ import {
|
|
|
9
9
|
enrichWorkspacesWithGithub,
|
|
10
10
|
ensureGlobalCoordinatorCwd,
|
|
11
11
|
formatWorkspaceInventory
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-
|
|
12
|
+
} from "./chunk-TQ4S5AGJ.js";
|
|
13
|
+
import "./chunk-QAV3HGVS.js";
|
|
14
14
|
import "./chunk-B3SJXYIJ.js";
|
|
15
|
-
import "./chunk-
|
|
15
|
+
import "./chunk-J5IBSVB3.js";
|
|
16
16
|
import "./chunk-KPIYENTF.js";
|
|
17
17
|
import "./chunk-GKKHXZCT.js";
|
|
18
18
|
import "./chunk-NSTQ6QKD.js";
|
|
@@ -7,13 +7,13 @@ import {
|
|
|
7
7
|
enrichWorkspacesWithGithub,
|
|
8
8
|
ensureGlobalCoordinatorCwd,
|
|
9
9
|
formatWorkspaceInventory
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
10
|
+
} from "./chunk-IFZ4MOTN.js";
|
|
11
|
+
import "./chunk-HQQNLDVC.js";
|
|
12
12
|
import "./chunk-FKOIHGKV.js";
|
|
13
13
|
import "./chunk-GJBHOJCZ.js";
|
|
14
14
|
import "./chunk-4TR3HZFT.js";
|
|
15
15
|
import "./chunk-JT7R45JB.js";
|
|
16
|
-
import "./chunk-
|
|
16
|
+
import "./chunk-PM3C2J6K.js";
|
|
17
17
|
import "./chunk-77WWLBCI.js";
|
|
18
18
|
import "./chunk-QZQEXME2.js";
|
|
19
19
|
import "./chunk-DVM4ID64.js";
|