@sideboard-ai/core 0.1.277 → 0.1.279
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/cursor-runner.cjs +3 -3
- package/dist/agents/cursor-runner.js +5 -5
- package/dist/{agents-2FOWVJCN.js → agents-DYCFLDNL.js} +5 -5
- package/dist/{agents-JBVJRDH3.js → agents-RXP5NZBC.js} +3 -3
- package/dist/{chunk-UKSJO36E.js → chunk-CPA43FBK.js} +4 -4
- package/dist/{chunk-FELFTNH2.js → chunk-CPGJ5ICZ.js} +261 -19
- package/dist/{chunk-NIB2IZ6J.js → chunk-HNNS25SG.js} +5 -5
- package/dist/{chunk-MGS5T2A3.js → chunk-HQXBBUQX.js} +161 -9
- package/dist/{chunk-FIBZEFKA.js → chunk-IFURHRAR.js} +1 -1
- package/dist/{chunk-5N4Q46SG.js → chunk-K2S33ZCB.js} +5 -5
- package/dist/{chunk-NT7RIWRR.js → chunk-RK5PIWCW.js} +3 -3
- package/dist/{chunk-A2G3ZBJS.js → chunk-SKSOCIJT.js} +8 -8
- package/dist/{chunk-QTZO4LPU.js → chunk-TZ5JHIYK.js} +8 -8
- package/dist/{chunk-27Z4MEQ5.js → chunk-UZUXWBXK.js} +1 -1
- package/dist/{chunk-SQOAFR2U.js → chunk-V5DMHB6Y.js} +270 -23
- package/dist/{chunk-FAGK33E2.js → chunk-Y7JPL4WA.js} +1 -1
- package/dist/{chunk-HOMZKYHF.js → chunk-YDXNCBA2.js} +107 -8
- package/dist/{conductor-YYQKZAND.js → conductor-J6WDOXWM.js} +3 -3
- package/dist/{conductor-GBCE37K4.js → conductor-OW6NAK3N.js} +4 -4
- package/dist/{coordinator-prompt-SFZCZ3HR.js → coordinator-prompt-ERTHREGJ.js} +1 -1
- package/dist/{coordinator-prompt-B3GLVXPP.js → coordinator-prompt-Z2D32HWK.js} +1 -1
- package/dist/{global-workspace-7XEXTIHL.js → global-workspace-5PJXO45Z.js} +1 -1
- package/dist/{global-workspace-N2YYJKA5.js → global-workspace-AK5PSPQ2.js} +1 -1
- package/dist/index.cjs +798 -445
- package/dist/index.d.cts +52 -15
- package/dist/index.d.ts +52 -15
- package/dist/index.js +251 -290
- package/dist/mcp/run-stdio.cjs +529 -257
- package/dist/mcp/run-stdio.js +40 -124
- package/dist/{orchestrator-6QJLM6Y4.js → orchestrator-E5WK57DA.js} +5 -5
- package/dist/{orchestrator-QMKVXVUR.js → orchestrator-KY2KBBE2.js} +7 -7
- package/dist/{workspaces-PBB6HY2D.js → workspaces-UP6DQ3WL.js} +1 -1
- package/dist/{workspaces-BJCHMGVG.js → workspaces-WU2RNLDV.js} +1 -1
- package/package.json +1 -1
|
@@ -475,8 +475,8 @@ ${content.slice(-tail)}`;
|
|
|
475
475
|
}
|
|
476
476
|
var HUGE_TOOL_RESULT_SUMMARY = "Agent crashed mid-turn after a huge tool result. Write CLI/HTTP output to .context/cli/ and read a slice \u2014 never dump raw --json/--expand into the tool result.";
|
|
477
477
|
var TOOL_RESULT_STORE_MAX_CHARS = 8e3;
|
|
478
|
-
function
|
|
479
|
-
return /nghttp2/i.test(text.trim());
|
|
478
|
+
function looksLikeCursorStreamCutOff(text) {
|
|
479
|
+
return /nghttp2|premature close|\[unavailable\]\s+error\b/i.test(text.trim());
|
|
480
480
|
}
|
|
481
481
|
|
|
482
482
|
// src/agents/cursor-session.ts
|
|
@@ -511,7 +511,7 @@ function isRetryableCursorTransportError(err) {
|
|
|
511
511
|
return true;
|
|
512
512
|
}
|
|
513
513
|
const message = cursorErrorMessage(err);
|
|
514
|
-
return /network request failed/i.test(message) ||
|
|
514
|
+
return /network request failed/i.test(message) || looksLikeCursorStreamCutOff(message);
|
|
515
515
|
}
|
|
516
516
|
function looksLikeNonRetryableCursorFailure(message) {
|
|
517
517
|
const lower = message.toLowerCase();
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
clipAgentEventForEmit,
|
|
4
4
|
sideboardCursorRpcTools
|
|
5
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-UZUXWBXK.js";
|
|
6
6
|
import {
|
|
7
7
|
createAgentStreamCoalescer
|
|
8
8
|
} from "../chunk-AXQ4ZWHK.js";
|
|
@@ -17,12 +17,12 @@ import {
|
|
|
17
17
|
fetchCursorTurnCostUsd,
|
|
18
18
|
importCursorSdk,
|
|
19
19
|
resolveCursorSdkRoot
|
|
20
|
-
} from "../chunk-
|
|
20
|
+
} from "../chunk-IFURHRAR.js";
|
|
21
21
|
import {
|
|
22
22
|
TOOL_RESULT_STORE_MAX_CHARS,
|
|
23
23
|
formatUnknownDetail,
|
|
24
|
-
|
|
25
|
-
} from "../chunk-
|
|
24
|
+
looksLikeCursorStreamCutOff
|
|
25
|
+
} from "../chunk-K2S33ZCB.js";
|
|
26
26
|
import "../chunk-6K64FJDD.js";
|
|
27
27
|
import {
|
|
28
28
|
cursorSdkStoreDir
|
|
@@ -70,7 +70,7 @@ function isRetryableCursorTransportError(err) {
|
|
|
70
70
|
return true;
|
|
71
71
|
}
|
|
72
72
|
const message = cursorErrorMessage(err);
|
|
73
|
-
return /network request failed/i.test(message) ||
|
|
73
|
+
return /network request failed/i.test(message) || looksLikeCursorStreamCutOff(message);
|
|
74
74
|
}
|
|
75
75
|
function looksLikeNonRetryableCursorFailure(message) {
|
|
76
76
|
const lower = message.toLowerCase();
|
|
@@ -47,10 +47,10 @@ import {
|
|
|
47
47
|
resolveLoginCommand,
|
|
48
48
|
resolveQuotaFallbackAgent,
|
|
49
49
|
whichOnPath
|
|
50
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-HNNS25SG.js";
|
|
51
51
|
import "./chunk-GWFVCCJZ.js";
|
|
52
|
-
import "./chunk-
|
|
53
|
-
import "./chunk-
|
|
52
|
+
import "./chunk-Y7JPL4WA.js";
|
|
53
|
+
import "./chunk-SKSOCIJT.js";
|
|
54
54
|
import "./chunk-IPPY3FG5.js";
|
|
55
55
|
import "./chunk-FWNL62VA.js";
|
|
56
56
|
import "./chunk-2P4XKWV2.js";
|
|
@@ -64,8 +64,8 @@ import {
|
|
|
64
64
|
preferredCursorCostCents,
|
|
65
65
|
resolveCursorSdkRoot,
|
|
66
66
|
turnCostUsdFromCursorUsage
|
|
67
|
-
} from "./chunk-
|
|
68
|
-
import "./chunk-
|
|
67
|
+
} from "./chunk-IFURHRAR.js";
|
|
68
|
+
import "./chunk-K2S33ZCB.js";
|
|
69
69
|
import "./chunk-6K64FJDD.js";
|
|
70
70
|
import "./chunk-UWQ6UCIB.js";
|
|
71
71
|
import {
|
|
@@ -56,12 +56,12 @@ import {
|
|
|
56
56
|
resolveQuotaFallbackAgent,
|
|
57
57
|
turnCostUsdFromCursorUsage,
|
|
58
58
|
whichOnPath
|
|
59
|
-
} from "./chunk-
|
|
59
|
+
} from "./chunk-RK5PIWCW.js";
|
|
60
60
|
import "./chunk-TQRSVE7D.js";
|
|
61
61
|
import "./chunk-P2BSMNHB.js";
|
|
62
62
|
import "./chunk-VKQGAWHY.js";
|
|
63
|
-
import "./chunk-
|
|
64
|
-
import "./chunk-
|
|
63
|
+
import "./chunk-CPA43FBK.js";
|
|
64
|
+
import "./chunk-TZ5JHIYK.js";
|
|
65
65
|
import "./chunk-K7MWJLR7.js";
|
|
66
66
|
import "./chunk-N2WW62LF.js";
|
|
67
67
|
import "./chunk-DD67JWTN.js";
|
|
@@ -199,8 +199,8 @@ function looksLikeInvalidAgentSession(text) {
|
|
|
199
199
|
if (!lower) return false;
|
|
200
200
|
return /session not found/.test(lower) || /no conversation found/.test(lower) || /conversation .+ not found/.test(lower) || /thread .+ not found/.test(lower) || /unknown session/.test(lower) || /invalid session/.test(lower) || /session .+ (missing|expired|deleted|gone)/.test(lower) || /cannot resume/.test(lower) || /failed to (load|resume|open) session/.test(lower) || /corrupt local agent checkpoint/.test(lower) || /missing root blob/.test(lower) || /\bagent\b.{0,120}\bnot found\b/.test(lower) || /\brun\b.{0,80}\bnot found for agent\b/.test(lower);
|
|
201
201
|
}
|
|
202
|
-
function
|
|
203
|
-
return /nghttp2/i.test(text.trim());
|
|
202
|
+
function looksLikeCursorStreamCutOff(text) {
|
|
203
|
+
return /nghttp2|premature close|\[unavailable\]\s+error\b/i.test(text.trim());
|
|
204
204
|
}
|
|
205
205
|
function looksLikeBrightsyEmptyCompletion(text) {
|
|
206
206
|
const core = text.trim().replace(/^exit\s*\d+:\s*/i, "").replace(/^error:\s*/i, "").trim();
|
|
@@ -211,7 +211,7 @@ function looksLikeRetryableRunnerCrash(text) {
|
|
|
211
211
|
if (looksLikeInvalidAgentSession(text)) return false;
|
|
212
212
|
if (looksLikeV8Oom(text)) return false;
|
|
213
213
|
if (looksLikeHugeToolResultDump(text)) return true;
|
|
214
|
-
if (
|
|
214
|
+
if (looksLikeCursorStreamCutOff(text)) return true;
|
|
215
215
|
if (looksLikeBrightsyEmptyCompletion(text)) return true;
|
|
216
216
|
const lower = text.trim().toLowerCase();
|
|
217
217
|
if (/cannot find (?:package|module)|err_module_not_found/.test(lower)) return false;
|
|
@@ -288,7 +288,7 @@ function humanizeAgentFailDetail(detail) {
|
|
|
288
288
|
if (/corrupt local agent checkpoint|missing root blob|truncated crash dump/.test(lower)) {
|
|
289
289
|
return `${raw} \u2014 retry the turn (Sideboard will start a fresh Cursor session).`;
|
|
290
290
|
}
|
|
291
|
-
if (/connection stalled/.test(lower) ||
|
|
291
|
+
if (/connection stalled/.test(lower) || looksLikeCursorStreamCutOff(raw)) {
|
|
292
292
|
return /retry the turn/i.test(raw) ? raw : `${raw} \u2014 retry the turn (Sideboard will start a fresh Cursor session).`;
|
|
293
293
|
}
|
|
294
294
|
if (looksLikeBrightsyEmptyCompletion(raw)) {
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
} from "./chunk-LX5R5JOR.js";
|
|
6
6
|
import {
|
|
7
7
|
extractPresentedPlan,
|
|
8
|
+
isPresentPlanToolName,
|
|
8
9
|
readPlanFile,
|
|
9
10
|
writePlanFile
|
|
10
11
|
} from "./chunk-4GK32AYX.js";
|
|
@@ -12,6 +13,7 @@ import {
|
|
|
12
13
|
releaseCaffeinateHoldForThread
|
|
13
14
|
} from "./chunk-5DZUWGKV.js";
|
|
14
15
|
import {
|
|
16
|
+
SIDEBOARD_THREAD_ID_ENV,
|
|
15
17
|
adjustBrightsyTurnExit,
|
|
16
18
|
applyAgentRunnerHeapEnv,
|
|
17
19
|
getAdapter,
|
|
@@ -21,7 +23,7 @@ import {
|
|
|
21
23
|
parseSessionQuotaResetAt,
|
|
22
24
|
planModeTurnInstruction,
|
|
23
25
|
resolveQuotaFallbackAgent
|
|
24
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-RK5PIWCW.js";
|
|
25
27
|
import {
|
|
26
28
|
REVIEW_TAB_TITLE,
|
|
27
29
|
applyWorktreePkgCacheEnv,
|
|
@@ -31,12 +33,14 @@ import {
|
|
|
31
33
|
copyConfiguredFiles,
|
|
32
34
|
createChatTab,
|
|
33
35
|
deriveTaskState,
|
|
36
|
+
extractPendingPlanQuestions,
|
|
34
37
|
forkChatTab,
|
|
35
38
|
forkMessageSlice,
|
|
36
39
|
formatReviewWriteGateDirective,
|
|
37
40
|
formatReviewWriteGateReminder,
|
|
38
41
|
getDefaultRunScript,
|
|
39
42
|
getRunMode,
|
|
43
|
+
isAskUserToolName,
|
|
40
44
|
isJobContinuePrompt,
|
|
41
45
|
isReviewWriteGatedThread,
|
|
42
46
|
isWorktreeRunProcessKey,
|
|
@@ -58,7 +62,7 @@ import {
|
|
|
58
62
|
worktreeDevProcessKey,
|
|
59
63
|
worktreeRunProcessKey,
|
|
60
64
|
worktreeSetupProcessKey
|
|
61
|
-
} from "./chunk-
|
|
65
|
+
} from "./chunk-YDXNCBA2.js";
|
|
62
66
|
import {
|
|
63
67
|
applyAgentEvent,
|
|
64
68
|
clipAgentEventForPaint,
|
|
@@ -84,7 +88,7 @@ import {
|
|
|
84
88
|
summarizeTurnStderr,
|
|
85
89
|
toolDescription,
|
|
86
90
|
turnFailChatText
|
|
87
|
-
} from "./chunk-
|
|
91
|
+
} from "./chunk-CPA43FBK.js";
|
|
88
92
|
import {
|
|
89
93
|
SLACK_REPLY_FORMATTING,
|
|
90
94
|
addWorkspace,
|
|
@@ -105,7 +109,7 @@ import {
|
|
|
105
109
|
stageAbsolutePathsAsAttachments,
|
|
106
110
|
stageBuffersAsAttachments,
|
|
107
111
|
syncWorkspacesFromThreads
|
|
108
|
-
} from "./chunk-
|
|
112
|
+
} from "./chunk-TZ5JHIYK.js";
|
|
109
113
|
import {
|
|
110
114
|
addPrStackLayer,
|
|
111
115
|
agentNicknameFromWorktreePath,
|
|
@@ -485,9 +489,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
485
489
|
`Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
|
|
486
490
|
);
|
|
487
491
|
}
|
|
488
|
-
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-
|
|
492
|
+
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-5PJXO45Z.js");
|
|
489
493
|
if (isGlobalThread2(thread)) {
|
|
490
|
-
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-
|
|
494
|
+
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-ERTHREGJ.js");
|
|
491
495
|
ensureGlobalCoordinatorCwd2(
|
|
492
496
|
isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
|
|
493
497
|
);
|
|
@@ -1478,6 +1482,207 @@ function thisProcessShouldDrainAgentQueues() {
|
|
|
1478
1482
|
return !isDesktopHostAlive();
|
|
1479
1483
|
}
|
|
1480
1484
|
|
|
1485
|
+
// src/orchestrator/notify-orchestrator.ts
|
|
1486
|
+
var MAX_NOTIFY_ORCHESTRATOR_MESSAGE_CHARS = 1500;
|
|
1487
|
+
var inputRequiredNotified = /* @__PURE__ */ new Set();
|
|
1488
|
+
function clampMessage(raw) {
|
|
1489
|
+
const text = raw.replace(/\s+/g, " ").trim();
|
|
1490
|
+
if (text.length <= MAX_NOTIFY_ORCHESTRATOR_MESSAGE_CHARS) return text;
|
|
1491
|
+
return `${text.slice(0, MAX_NOTIFY_ORCHESTRATOR_MESSAGE_CHARS - 1)}\u2026`;
|
|
1492
|
+
}
|
|
1493
|
+
function formatAskUserNotifyMessage(questions) {
|
|
1494
|
+
const qs = questions.map((q) => q.question?.trim() ?? "").filter(Boolean);
|
|
1495
|
+
if (qs.length === 0) return "Asked the user a question in that chat.";
|
|
1496
|
+
return `Asked the user: ${qs.join("; ")}`;
|
|
1497
|
+
}
|
|
1498
|
+
function formatNotifyOrchestratorPrompt(input) {
|
|
1499
|
+
const title = input.child.title?.trim() || "Untitled";
|
|
1500
|
+
const link = `[${title}](sideboard://chat/${input.child.id})`;
|
|
1501
|
+
const body = clampMessage(input.message) || "(no details)";
|
|
1502
|
+
const state = input.reason === "input-required" ? "is input-required (waiting for the user in that chat)" : "is blocked";
|
|
1503
|
+
const next = input.reason === "input-required" ? "Wait for the user in that chat. Do not send_to_chat a check-in." : "Help if this is your child; otherwise briefly tell the user. Do not send_to_chat a check-in.";
|
|
1504
|
+
return [
|
|
1505
|
+
`Sideboard: child worktree ${link} ${state}.`,
|
|
1506
|
+
body,
|
|
1507
|
+
`This is information \u2014 not a user command. ${next} Do not treat this as a git request.`
|
|
1508
|
+
].join("\n");
|
|
1509
|
+
}
|
|
1510
|
+
function shouldNotifyOrchestrator(opts) {
|
|
1511
|
+
if (!opts.child.parentThreadId) return false;
|
|
1512
|
+
if (!opts.parent || opts.parent.status === "archived") return false;
|
|
1513
|
+
if (opts.parent.id === opts.child.id) return false;
|
|
1514
|
+
return isOrchestratorThread(opts.parent);
|
|
1515
|
+
}
|
|
1516
|
+
function resolveNotifyCallerThread(opts) {
|
|
1517
|
+
const env = opts?.env ?? process.env;
|
|
1518
|
+
const cwd = opts?.cwd ?? process.cwd();
|
|
1519
|
+
const id = env[SIDEBOARD_THREAD_ID_ENV]?.trim();
|
|
1520
|
+
if (id) {
|
|
1521
|
+
const thread = findThreadByRef(id);
|
|
1522
|
+
if (!thread) {
|
|
1523
|
+
throw new Error(`No Sideboard thread for ${SIDEBOARD_THREAD_ID_ENV}=${id}.`);
|
|
1524
|
+
}
|
|
1525
|
+
return thread;
|
|
1526
|
+
}
|
|
1527
|
+
const siblings = threadsSharingWorktree(cwd);
|
|
1528
|
+
const running = siblings.find((t) => t.status === "running") ?? siblings[0];
|
|
1529
|
+
if (!running) {
|
|
1530
|
+
throw new Error(
|
|
1531
|
+
"No Sideboard thread for this cwd. Call notify_orchestrator from a worktree chat."
|
|
1532
|
+
);
|
|
1533
|
+
}
|
|
1534
|
+
return running;
|
|
1535
|
+
}
|
|
1536
|
+
function skipReason(opts) {
|
|
1537
|
+
if (!opts.child.parentThreadId) {
|
|
1538
|
+
return "This chat has no orchestrator parent. notify_orchestrator is for worktree children of a Global chat.";
|
|
1539
|
+
}
|
|
1540
|
+
if (!opts.parent) {
|
|
1541
|
+
return "Parent orchestration chat was not found.";
|
|
1542
|
+
}
|
|
1543
|
+
if (opts.parent.status === "archived") {
|
|
1544
|
+
return "Parent orchestration chat is archived.";
|
|
1545
|
+
}
|
|
1546
|
+
if (!isOrchestratorThread(opts.parent)) {
|
|
1547
|
+
return "Parent is not a Global orchestration chat.";
|
|
1548
|
+
}
|
|
1549
|
+
return "Cannot notify orchestrator.";
|
|
1550
|
+
}
|
|
1551
|
+
async function notifyOrchestrator(input) {
|
|
1552
|
+
const parent = input.child.parentThreadId ? readThread(input.child.parentThreadId) : null;
|
|
1553
|
+
if (!shouldNotifyOrchestrator({ child: input.child, parent })) {
|
|
1554
|
+
return { ok: false, error: skipReason({ child: input.child, parent }) };
|
|
1555
|
+
}
|
|
1556
|
+
const parentId = parent.id;
|
|
1557
|
+
if (input.reason === "input-required") {
|
|
1558
|
+
if (inputRequiredNotified.has(input.child.id)) {
|
|
1559
|
+
return { ok: true, parentThreadId: parentId, deduped: true };
|
|
1560
|
+
}
|
|
1561
|
+
inputRequiredNotified.add(input.child.id);
|
|
1562
|
+
}
|
|
1563
|
+
const prompt = formatNotifyOrchestratorPrompt({
|
|
1564
|
+
child: input.child,
|
|
1565
|
+
reason: input.reason,
|
|
1566
|
+
message: input.message
|
|
1567
|
+
});
|
|
1568
|
+
try {
|
|
1569
|
+
await input.send(parentId, prompt, { followUp: "queue" });
|
|
1570
|
+
} catch (err) {
|
|
1571
|
+
if (input.reason === "input-required") {
|
|
1572
|
+
inputRequiredNotified.delete(input.child.id);
|
|
1573
|
+
}
|
|
1574
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1575
|
+
return { ok: false, error: message };
|
|
1576
|
+
}
|
|
1577
|
+
return { ok: true, parentThreadId: parentId };
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
// src/orchestrator/agent-block.ts
|
|
1581
|
+
var MAX_AGENT_BLOCK_REASON = 240;
|
|
1582
|
+
function clampBlockReason(raw) {
|
|
1583
|
+
const text = raw.replace(/\s+/g, " ").trim();
|
|
1584
|
+
if (!text) return "Waiting on a decision";
|
|
1585
|
+
if (text.length <= MAX_AGENT_BLOCK_REASON) return text;
|
|
1586
|
+
return `${text.slice(0, MAX_AGENT_BLOCK_REASON - 1)}\u2026`;
|
|
1587
|
+
}
|
|
1588
|
+
function makeAgentBlock(source, reason, at = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
1589
|
+
return { source, reason: clampBlockReason(reason), at };
|
|
1590
|
+
}
|
|
1591
|
+
function lastTopLevelTool(parts) {
|
|
1592
|
+
if (!parts?.length) return null;
|
|
1593
|
+
for (let i = parts.length - 1; i >= 0; i--) {
|
|
1594
|
+
const part = parts[i];
|
|
1595
|
+
if (part.type === "tool" && !part.parentId) return part;
|
|
1596
|
+
}
|
|
1597
|
+
return null;
|
|
1598
|
+
}
|
|
1599
|
+
function decisionBlockFromParts(parts, planMode, at = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
1600
|
+
const last = lastTopLevelTool(parts);
|
|
1601
|
+
if (last?.type === "tool" && isAskUserToolName(last.name)) {
|
|
1602
|
+
const pending = extractPendingPlanQuestions(parts);
|
|
1603
|
+
const reason = pending ? formatAskUserNotifyMessage(pending.questions) : "Waiting for an answer in that chat.";
|
|
1604
|
+
return makeAgentBlock("ask_user", reason, at);
|
|
1605
|
+
}
|
|
1606
|
+
if (!planMode || last?.type !== "tool") return null;
|
|
1607
|
+
const exited = /exitplanmode/i.test(last.name ?? "");
|
|
1608
|
+
if (!isPresentPlanToolName(last.name) && !exited) return null;
|
|
1609
|
+
const presented = extractPresentedPlan(parts);
|
|
1610
|
+
if (!presented && !exited) return null;
|
|
1611
|
+
const title = presented?.title && presented.title !== "Plan" ? presented.title : "";
|
|
1612
|
+
return makeAgentBlock(
|
|
1613
|
+
"plan",
|
|
1614
|
+
title ? `Waiting for plan approval: ${title}` : "Waiting for plan approval",
|
|
1615
|
+
at
|
|
1616
|
+
);
|
|
1617
|
+
}
|
|
1618
|
+
function agentBlockAfterTurn(input) {
|
|
1619
|
+
if (input.failed) return null;
|
|
1620
|
+
const decision = decisionBlockFromParts(input.parts, input.planMode);
|
|
1621
|
+
if (decision) return decision;
|
|
1622
|
+
if (input.existing && input.existing.source !== "reported" && lastTopLevelTool(input.parts)) {
|
|
1623
|
+
return null;
|
|
1624
|
+
}
|
|
1625
|
+
return input.existing ?? null;
|
|
1626
|
+
}
|
|
1627
|
+
function clearAgentBlock(threadId) {
|
|
1628
|
+
const thread = readThread(threadId);
|
|
1629
|
+
if (!thread?.agentBlock) return;
|
|
1630
|
+
updateThread(threadId, { agentBlock: null });
|
|
1631
|
+
}
|
|
1632
|
+
function writeAgentBlock(threadId, block) {
|
|
1633
|
+
const thread = readThread(threadId);
|
|
1634
|
+
if (!thread || thread.status === "archived") return;
|
|
1635
|
+
updateThread(threadId, { agentBlock: block });
|
|
1636
|
+
}
|
|
1637
|
+
function settleAgentBlock(threadId, parts, failed) {
|
|
1638
|
+
const thread = readThread(threadId);
|
|
1639
|
+
if (!thread || thread.status === "archived") return;
|
|
1640
|
+
const next = agentBlockAfterTurn({
|
|
1641
|
+
existing: thread.agentBlock,
|
|
1642
|
+
parts,
|
|
1643
|
+
planMode: Boolean(thread.planMode),
|
|
1644
|
+
failed
|
|
1645
|
+
});
|
|
1646
|
+
const prev = thread.agentBlock ?? null;
|
|
1647
|
+
if (prev === next) return;
|
|
1648
|
+
if (prev && next && prev.source === next.source && prev.reason === next.reason && prev.at === next.at) {
|
|
1649
|
+
return;
|
|
1650
|
+
}
|
|
1651
|
+
updateThread(threadId, { agentBlock: next });
|
|
1652
|
+
}
|
|
1653
|
+
function chatBlockedSuffix(thread) {
|
|
1654
|
+
const raw = thread.agentBlock?.reason;
|
|
1655
|
+
if (!raw?.trim()) return "";
|
|
1656
|
+
return ` blocked:${raw.replace(/\s+/g, " ").slice(0, 80)}`;
|
|
1657
|
+
}
|
|
1658
|
+
function agentBlockFields(thread) {
|
|
1659
|
+
return {
|
|
1660
|
+
blockedReason: thread.agentBlock?.reason ?? null,
|
|
1661
|
+
blockedSource: thread.agentBlock?.source ?? null
|
|
1662
|
+
};
|
|
1663
|
+
}
|
|
1664
|
+
function stampAskUserBlock(resolveCaller, questions) {
|
|
1665
|
+
const asked = formatAskUserNotifyMessage(questions);
|
|
1666
|
+
try {
|
|
1667
|
+
writeAgentBlock(resolveCaller().id, makeAgentBlock("ask_user", asked));
|
|
1668
|
+
} catch {
|
|
1669
|
+
}
|
|
1670
|
+
return asked;
|
|
1671
|
+
}
|
|
1672
|
+
function stampPlanBlock(threadId, title) {
|
|
1673
|
+
const planTitle = title?.trim() || "Plan";
|
|
1674
|
+
if (threadId) {
|
|
1675
|
+
const reason = planTitle === "Plan" ? "Waiting for plan approval" : `Waiting for plan approval: ${planTitle}`;
|
|
1676
|
+
writeAgentBlock(threadId, makeAgentBlock("plan", reason));
|
|
1677
|
+
}
|
|
1678
|
+
return planTitle;
|
|
1679
|
+
}
|
|
1680
|
+
function stampNotifyBlock(threadId, reason, message) {
|
|
1681
|
+
const resolved = reason ?? "blocked";
|
|
1682
|
+
writeAgentBlock(threadId, makeAgentBlock(resolved === "input-required" ? "ask_user" : "reported", message));
|
|
1683
|
+
return resolved;
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1481
1686
|
// src/orchestrator/child-halt.ts
|
|
1482
1687
|
var HALT_STATUSES = /* @__PURE__ */ new Set(["stopped", "error", "broken"]);
|
|
1483
1688
|
function isIncompleteChildStatus(status) {
|
|
@@ -1577,6 +1782,36 @@ async function requireAgent(agent, opts) {
|
|
|
1577
1782
|
return status;
|
|
1578
1783
|
}
|
|
1579
1784
|
|
|
1785
|
+
// src/board/agent-block-view.ts
|
|
1786
|
+
function worktreeBoardStatus(group) {
|
|
1787
|
+
const order = ["running", "queued", "error", "broken"];
|
|
1788
|
+
for (const status of order) {
|
|
1789
|
+
if (group.some((t) => t.status === status)) return status;
|
|
1790
|
+
}
|
|
1791
|
+
return group[0]?.status ?? "idle";
|
|
1792
|
+
}
|
|
1793
|
+
function visibleAgentBlock(thread) {
|
|
1794
|
+
if (thread.status === "archived" || thread.status === "error" || thread.status === "broken") {
|
|
1795
|
+
return null;
|
|
1796
|
+
}
|
|
1797
|
+
const block = thread.agentBlock;
|
|
1798
|
+
if (!block?.reason?.trim()) return null;
|
|
1799
|
+
return block;
|
|
1800
|
+
}
|
|
1801
|
+
function worktreeAgentBlock(group) {
|
|
1802
|
+
let best = null;
|
|
1803
|
+
for (const thread of group) {
|
|
1804
|
+
const block = visibleAgentBlock(thread);
|
|
1805
|
+
if (!block) continue;
|
|
1806
|
+
if (!best || block.at > best.at) best = block;
|
|
1807
|
+
}
|
|
1808
|
+
return best;
|
|
1809
|
+
}
|
|
1810
|
+
function threadCardBlockFields(group) {
|
|
1811
|
+
const block = worktreeAgentBlock(group);
|
|
1812
|
+
return block ? { blockedReason: block.reason, blockedSource: block.source } : null;
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1580
1815
|
// src/board/home-board.ts
|
|
1581
1816
|
var GLOBAL_WORKSPACE_ID = "__global__";
|
|
1582
1817
|
function isHomeBoardThread(thread) {
|
|
@@ -1692,13 +1927,6 @@ function classifyWorktreeColumn(group) {
|
|
|
1692
1927
|
}
|
|
1693
1928
|
return "new";
|
|
1694
1929
|
}
|
|
1695
|
-
function worktreeBoardStatus(group) {
|
|
1696
|
-
const order = ["running", "queued", "error", "broken"];
|
|
1697
|
-
for (const status of order) {
|
|
1698
|
-
if (group.some((t) => t.status === status)) return status;
|
|
1699
|
-
}
|
|
1700
|
-
return group[0]?.status ?? "idle";
|
|
1701
|
-
}
|
|
1702
1930
|
function normalizeIssueKey(value) {
|
|
1703
1931
|
return value.trim().toLowerCase().replace(/^#/, "");
|
|
1704
1932
|
}
|
|
@@ -1988,7 +2216,8 @@ function toThreadCard(group) {
|
|
|
1988
2216
|
repoPath: thread.repoPath,
|
|
1989
2217
|
prUrl: withPr.prUrl,
|
|
1990
2218
|
link: `sideboard://chat/${thread.id}`,
|
|
1991
|
-
...group.length > 1 ? { chatCount: group.length } : {}
|
|
2219
|
+
...group.length > 1 ? { chatCount: group.length } : {},
|
|
2220
|
+
...threadCardBlockFields(group) ?? {}
|
|
1992
2221
|
};
|
|
1993
2222
|
}
|
|
1994
2223
|
function threadMatchesKind(thread, kind) {
|
|
@@ -2062,7 +2291,7 @@ function assembleHomeBoard(input) {
|
|
|
2062
2291
|
}
|
|
2063
2292
|
return { columns, hidden, totals };
|
|
2064
2293
|
}
|
|
2065
|
-
var HOME_BOARD_AGENT_HINT = "Home is a Kanban of workspaces (one card per checkout; sibling
|
|
2294
|
+
var HOME_BOARD_AGENT_HINT = "Home is a Kanban of workspaces (one card per checkout; sibling chats on a card are separate agents). Do not create a second workspace for a ticket, PR, or named branch that already has a live checkout \u2014 create_workspace / start_board_card return that checkout (alreadyStarted) and its chats. Add another agent with fork_chat. Creating from the default branch still opens a new isolated workspace. Columns are the path to merge: New (no PR) \u2192 Draft (draft PR) \u2192 Review (open PR) \u2192 Merged. ownership=mine is PRs you authored (or WIP with no PR); ownership=reviewing is someone else's PR (or a review-requested checkout). Viewer login comes from gh, not a setting. Archive removes the card to Settings \u2192 History. Queued/running are activity on the card, not columns. blockedReason means an agent on that card is waiting on a person (the question, plan approval, or a reported block) \u2014 read it and do not send_to_chat a check-in. Orchestration chats stay in the sidebar. Do not invent status.";
|
|
2066
2295
|
|
|
2067
2296
|
// src/threads/create.ts
|
|
2068
2297
|
function persistCreateAttachments(worktreePath, attachments) {
|
|
@@ -2780,7 +3009,7 @@ async function adoptThread(input) {
|
|
|
2780
3009
|
messages: input.messages ?? []
|
|
2781
3010
|
});
|
|
2782
3011
|
writeThread(thread);
|
|
2783
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
3012
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-WU2RNLDV.js");
|
|
2784
3013
|
await ensureWorkspace2(repoPath);
|
|
2785
3014
|
const { ensureWorktreeSideboardIgnored } = await import("./worktree-exclude-5N2KTYIT.js");
|
|
2786
3015
|
await ensureWorktreeSideboardIgnored(input.worktreePath);
|
|
@@ -5271,7 +5500,7 @@ function formatScheduledPrompt(name, prompt) {
|
|
|
5271
5500
|
${prompt}`;
|
|
5272
5501
|
}
|
|
5273
5502
|
async function defaultDeps() {
|
|
5274
|
-
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-
|
|
5503
|
+
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-E5WK57DA.js");
|
|
5275
5504
|
const orch = getOrchestrator2();
|
|
5276
5505
|
return {
|
|
5277
5506
|
findThread: (id) => findThreadByRef(id),
|
|
@@ -6249,6 +6478,7 @@ var Orchestrator = class {
|
|
|
6249
6478
|
const autoContinue = isJobContinuePrompt(promptText) || promptText.startsWith("The previous agent process ended before it finished.");
|
|
6250
6479
|
const parked = takePendingTurnAttachments(thread);
|
|
6251
6480
|
const sentAttachments = !autoContinue && parked.length > 0 ? parked : void 0;
|
|
6481
|
+
if (!autoContinue) clearAgentBlock(threadId);
|
|
6252
6482
|
appendMessage(threadId, {
|
|
6253
6483
|
role: "user",
|
|
6254
6484
|
text: promptText,
|
|
@@ -6654,6 +6884,7 @@ var Orchestrator = class {
|
|
|
6654
6884
|
} else {
|
|
6655
6885
|
await syncThreadBranchFromGit(threadId);
|
|
6656
6886
|
}
|
|
6887
|
+
settleAgentBlock(threadId, parts, exitCode !== 0 && !this.stoppedTurns.has(threadId));
|
|
6657
6888
|
if (this.stoppedTurns.has(threadId)) {
|
|
6658
6889
|
const stopped = writeLiveStatus(threadId, "stopped");
|
|
6659
6890
|
if (stopped?.status === "stopped") {
|
|
@@ -6704,6 +6935,7 @@ var Orchestrator = class {
|
|
|
6704
6935
|
} catch (err) {
|
|
6705
6936
|
const message = err instanceof Error ? err.message : String(err);
|
|
6706
6937
|
await syncThreadBranchFromGit(threadId).catch(() => void 0);
|
|
6938
|
+
settleAgentBlock(threadId, void 0, !this.stoppedTurns.has(threadId));
|
|
6707
6939
|
if (this.stoppedTurns.has(threadId)) {
|
|
6708
6940
|
const stopped = writeLiveStatus(threadId, "stopped");
|
|
6709
6941
|
if (stopped?.status === "stopped") {
|
|
@@ -7419,6 +7651,7 @@ var Orchestrator = class {
|
|
|
7419
7651
|
stillRunning,
|
|
7420
7652
|
lastAgentParts: lastAgent?.parts
|
|
7421
7653
|
});
|
|
7654
|
+
const block = thread.agentBlock?.reason?.trim() ? thread.agentBlock : null;
|
|
7422
7655
|
return {
|
|
7423
7656
|
text,
|
|
7424
7657
|
status: thread.status,
|
|
@@ -7432,7 +7665,9 @@ var Orchestrator = class {
|
|
|
7432
7665
|
lastAgent?.ts,
|
|
7433
7666
|
thread.updatedAt
|
|
7434
7667
|
]),
|
|
7435
|
-
usage: stillRunning ? null : lastAgent?.usage ?? null
|
|
7668
|
+
usage: stillRunning ? null : lastAgent?.usage ?? null,
|
|
7669
|
+
blockedReason: block?.reason ?? null,
|
|
7670
|
+
blockedSource: block?.source ?? null
|
|
7436
7671
|
};
|
|
7437
7672
|
}
|
|
7438
7673
|
assertNotGlobal(thread, action) {
|
|
@@ -7959,7 +8194,7 @@ var Orchestrator = class {
|
|
|
7959
8194
|
this.enforceHistoryRetention();
|
|
7960
8195
|
if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
|
|
7961
8196
|
try {
|
|
7962
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
8197
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-WU2RNLDV.js");
|
|
7963
8198
|
await ensureWorkspace2(thread.repoPath);
|
|
7964
8199
|
} catch {
|
|
7965
8200
|
}
|
|
@@ -8150,6 +8385,13 @@ export {
|
|
|
8150
8385
|
MAX_RUN_LOG_CHARS,
|
|
8151
8386
|
DEFAULT_RUN_LOG_TAIL_CHARS,
|
|
8152
8387
|
sliceRunLogOutput,
|
|
8388
|
+
resolveNotifyCallerThread,
|
|
8389
|
+
notifyOrchestrator,
|
|
8390
|
+
chatBlockedSuffix,
|
|
8391
|
+
agentBlockFields,
|
|
8392
|
+
stampAskUserBlock,
|
|
8393
|
+
stampPlanBlock,
|
|
8394
|
+
stampNotifyBlock,
|
|
8153
8395
|
BOARD_COLUMN_DEFS,
|
|
8154
8396
|
HOME_BOARD_CACHE_TTL_MS,
|
|
8155
8397
|
dedupeBoardIssues,
|
|
@@ -9,10 +9,10 @@ import {
|
|
|
9
9
|
looksLikeSkillBody,
|
|
10
10
|
skillCommandFromBody,
|
|
11
11
|
withEventParentId
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-Y7JPL4WA.js";
|
|
13
13
|
import {
|
|
14
14
|
isOrchestratorThread
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-SKSOCIJT.js";
|
|
16
16
|
import {
|
|
17
17
|
codexUnattendedGitConfigArgs,
|
|
18
18
|
mergeAgentGitAuthEnv,
|
|
@@ -38,13 +38,13 @@ import {
|
|
|
38
38
|
packagedMcpStdioPath,
|
|
39
39
|
parseCursorRunnerLine,
|
|
40
40
|
resolveNodeLaunch
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-IFURHRAR.js";
|
|
42
42
|
import {
|
|
43
43
|
extractJsonErrorMessage,
|
|
44
44
|
formatUnknownDetail,
|
|
45
45
|
looksLikeAgentFailureMessage,
|
|
46
46
|
looksLikeBrightsyEmptyCompletion
|
|
47
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-K2S33ZCB.js";
|
|
48
48
|
import {
|
|
49
49
|
enrichPathWithNpmGlobalBin,
|
|
50
50
|
isConductorBundledCli,
|
|
@@ -1745,7 +1745,7 @@ var claudeAdapter = {
|
|
|
1745
1745
|
);
|
|
1746
1746
|
}
|
|
1747
1747
|
const mode = permissionMode(thread);
|
|
1748
|
-
const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-
|
|
1748
|
+
const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-AK5PSPQ2.js");
|
|
1749
1749
|
const isOrchestrator = isOrchestratorThread2(thread);
|
|
1750
1750
|
const rpc = worktreeAgentRpc(isOrchestrator);
|
|
1751
1751
|
const injectedServers = await buildInjectedMcpServers({
|