@sideboard-ai/core 0.1.43 → 0.1.45
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.js +1 -1
- package/dist/{agents-T3EA7GZV.js → agents-JSHCAZUZ.js} +15 -5
- package/dist/{app-settings-ZKVZHJPQ.js → app-settings-LYGVDGZY.js} +5 -1
- package/dist/{chunk-Z2BQMXVM.js → chunk-6NAPN2N5.js} +6 -2
- package/dist/{chunk-VC7NORFX.js → chunk-ANZ566Z5.js} +184 -3
- package/dist/{chunk-7PCTK4WO.js → chunk-FV6FN6V5.js} +1 -1
- package/dist/{chunk-AGU52GTV.js → chunk-I6QGZOOS.js} +488 -32
- package/dist/{chunk-PU27NUO4.js → chunk-J5JTEJ5O.js} +7 -2
- package/dist/{chunk-ENSD62HW.js → chunk-O6W3P7V3.js} +3 -1
- package/dist/{chunk-FUCEOJFO.js → chunk-U3EQKJHA.js} +2 -2
- package/dist/{chunk-FSIK442J.js → chunk-WYY3J7GR.js} +21 -0
- package/dist/{chunk-X6P2QVRJ.js → chunk-ZNSM2DDD.js} +3 -3
- package/dist/{coordinator-prompt-BHXBQRPM.js → coordinator-prompt-2XFYG3C5.js} +3 -3
- package/dist/{global-workspace-SNN45OCN.js → global-workspace-YFOQUGWD.js} +4 -4
- package/dist/index.cjs +735 -25
- package/dist/index.d.cts +107 -2
- package/dist/index.d.ts +107 -2
- package/dist/index.js +35 -9
- package/dist/mcp/run-stdio.cjs +805 -123
- package/dist/mcp/run-stdio.js +9 -9
- package/dist/{thread-store-EHROA3VZ.js → thread-store-OV2X6PYO.js} +1 -1
- package/dist/{workspaces-AUYIJ64Z.js → workspaces-TIKLNDW3.js} +5 -5
- package/dist/{worktree-N4PRV4V3.js → worktree-TEDAJ57S.js} +2 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -412,6 +412,8 @@ __export(app_settings_exports, {
|
|
|
412
412
|
isLinearConnected: () => isLinearConnected,
|
|
413
413
|
loadAppSettings: () => loadAppSettings,
|
|
414
414
|
maxConcurrentAgents: () => maxConcurrentAgents,
|
|
415
|
+
orchestrationQuotaFallbackAgent: () => orchestrationQuotaFallbackAgent,
|
|
416
|
+
orchestrationQuotaOnLimit: () => orchestrationQuotaOnLimit,
|
|
415
417
|
resolveClaudeExecutable: () => resolveClaudeExecutable,
|
|
416
418
|
resolveEffectiveIssueSource: () => resolveEffectiveIssueSource,
|
|
417
419
|
resolveThreadDefaults: () => resolveThreadDefaults,
|
|
@@ -523,6 +525,12 @@ function normalizeAdvanced(raw) {
|
|
|
523
525
|
if (typeof source.autoCleanupOrphans === "boolean") {
|
|
524
526
|
out.autoCleanupOrphans = source.autoCleanupOrphans;
|
|
525
527
|
}
|
|
528
|
+
if (source.orchestrationQuotaOnLimit === "switch_agent" || source.orchestrationQuotaOnLimit === "wait_reset") {
|
|
529
|
+
out.orchestrationQuotaOnLimit = source.orchestrationQuotaOnLimit;
|
|
530
|
+
}
|
|
531
|
+
if (typeof source.orchestrationQuotaFallbackAgent === "string" && DEFAULT_AGENTS.has(source.orchestrationQuotaFallbackAgent)) {
|
|
532
|
+
out.orchestrationQuotaFallbackAgent = source.orchestrationQuotaFallbackAgent;
|
|
533
|
+
}
|
|
526
534
|
return out;
|
|
527
535
|
}
|
|
528
536
|
function normalizeSettings(raw) {
|
|
@@ -757,6 +765,12 @@ function updateAdvancedSettings(patch) {
|
|
|
757
765
|
if (typeof patch.autoCleanupOrphans === "boolean") {
|
|
758
766
|
advanced.autoCleanupOrphans = patch.autoCleanupOrphans;
|
|
759
767
|
}
|
|
768
|
+
if (patch.orchestrationQuotaOnLimit === "switch_agent" || patch.orchestrationQuotaOnLimit === "wait_reset") {
|
|
769
|
+
advanced.orchestrationQuotaOnLimit = patch.orchestrationQuotaOnLimit;
|
|
770
|
+
}
|
|
771
|
+
if (typeof patch.orchestrationQuotaFallbackAgent === "string" && DEFAULT_AGENTS.has(patch.orchestrationQuotaFallbackAgent)) {
|
|
772
|
+
advanced.orchestrationQuotaFallbackAgent = patch.orchestrationQuotaFallbackAgent;
|
|
773
|
+
}
|
|
760
774
|
return saveAppSettings({ ...current, advanced });
|
|
761
775
|
}
|
|
762
776
|
function autoRenameBranchEnabled(settings = loadAppSettings()) {
|
|
@@ -777,6 +791,13 @@ function deleteBranchOnPurgeEnabled(settings = loadAppSettings()) {
|
|
|
777
791
|
function autoCleanupOrphansEnabled(settings = loadAppSettings()) {
|
|
778
792
|
return Boolean(settings.advanced.autoCleanupOrphans);
|
|
779
793
|
}
|
|
794
|
+
function orchestrationQuotaOnLimit(settings = loadAppSettings()) {
|
|
795
|
+
return settings.advanced.orchestrationQuotaOnLimit ?? "switch_agent";
|
|
796
|
+
}
|
|
797
|
+
function orchestrationQuotaFallbackAgent(settings = loadAppSettings()) {
|
|
798
|
+
const preferred = settings.advanced.orchestrationQuotaFallbackAgent;
|
|
799
|
+
return preferred && DEFAULT_AGENTS.has(preferred) ? preferred : "cursor";
|
|
800
|
+
}
|
|
780
801
|
function maxConcurrentAgents(settings = loadAppSettings()) {
|
|
781
802
|
const n = settings.advanced.maxConcurrent;
|
|
782
803
|
if (typeof n === "number" && Number.isFinite(n)) {
|
|
@@ -893,7 +914,9 @@ function normalizeThread(raw) {
|
|
|
893
914
|
attachments: Array.isArray(raw.attachments) ? raw.attachments : [],
|
|
894
915
|
prTitle: raw.prTitle ?? null,
|
|
895
916
|
userSetTitle: Boolean(raw.userSetTitle),
|
|
896
|
-
activeRuns: Array.isArray(raw.activeRuns) ? raw.activeRuns : []
|
|
917
|
+
activeRuns: Array.isArray(raw.activeRuns) ? raw.activeRuns : [],
|
|
918
|
+
quotaResumeAt: raw.quotaResumeAt ?? null,
|
|
919
|
+
quotaContinuedFromId: raw.quotaContinuedFromId ?? null
|
|
897
920
|
};
|
|
898
921
|
}
|
|
899
922
|
function createEmptyThread(partial) {
|
|
@@ -3184,11 +3207,14 @@ var init_coordinator_prompt = __esm({
|
|
|
3184
3207
|
"Discover:",
|
|
3185
3208
|
"- list_workspaces \u2014 registered repos (path + github slug when known)",
|
|
3186
3209
|
"- list_branches / list_prs / list_issues \u2014 pass repoPath from list_workspaces (issues: Linear API or GitHub Issues)",
|
|
3210
|
+
"- list_models \u2014 only when you need a specific model (rare); otherwise leave model unset = Auto",
|
|
3187
3211
|
"- list_threads / get_thread \u2014 fleet status (what is going on)",
|
|
3188
3212
|
"Workspaces:",
|
|
3189
3213
|
"- add_workspace / remove_workspace \u2014 register or unregister a git repo",
|
|
3190
3214
|
"Worktree threads (chats):",
|
|
3191
3215
|
"- create_thread \u2014 create a worktree + chat from branch | pr | ticket; pass repoPath + parentThreadId",
|
|
3216
|
+
"- 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.",
|
|
3217
|
+
"- 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.",
|
|
3192
3218
|
"- 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",
|
|
3193
3219
|
"- wait_for_turn / get_turn_result \u2014 wait for and read the agent reply",
|
|
3194
3220
|
"- stop_thread \u2014 force-stop: kill in-flight turn AND clear queued prompts (do not leave stale queue after an interrupt)",
|
|
@@ -3196,8 +3222,9 @@ var init_coordinator_prompt = __esm({
|
|
|
3196
3222
|
"Setup / run:",
|
|
3197
3223
|
"- run_setup \u2014 re-run worktree setup",
|
|
3198
3224
|
"- list_run_scripts / run_dev_script / stop_dev_script \u2014 start/stop named run scripts",
|
|
3199
|
-
"Inspect / PRs:",
|
|
3225
|
+
"Inspect / review / PRs:",
|
|
3200
3226
|
"- get_diff \u2014 compact diff summary",
|
|
3227
|
+
"- request_review \u2014 open a Review chat tab on a worktree thread (merge-readiness recommendation); then wait_for_turn / get_turn_result on the returned id",
|
|
3201
3228
|
"- Ask the worktree agent via send_to_thread to open a draft PR with `gh pr create --draft -R <origin-owner/name>` (workspace `github:` slug / that worktree's origin \u2014 never upstream). Do not open PRs from the orchestrator yourself.",
|
|
3202
3229
|
"Human-only (do not attempt): merge, ready-for-review land, purge_thread.",
|
|
3203
3230
|
"Thread links in replies: when mentioning a chat/thread for the user, include a markdown link `[Title](sideboard://thread/<id>)` using the full id (or the link field from create_thread / list_threads). Sideboard renders these as clickable opens.",
|
|
@@ -3940,11 +3967,15 @@ function humanizeAgentFailDetail(detail) {
|
|
|
3940
3967
|
}
|
|
3941
3968
|
function formatTurnExitError(exitCode, stderrSummary) {
|
|
3942
3969
|
const code = exitCode ?? 1;
|
|
3943
|
-
const
|
|
3970
|
+
const raw = stderrSummary.trim();
|
|
3971
|
+
if (/^exit\s*\d+$/i.test(raw)) {
|
|
3972
|
+
return `exit ${code}: agent exited without details (credits, auth, rate limits, or a CLI error)`;
|
|
3973
|
+
}
|
|
3974
|
+
const detail = humanizeAgentFailDetail(raw);
|
|
3944
3975
|
if (!detail) {
|
|
3945
3976
|
return `exit ${code}: agent exited without details (credits, auth, rate limits, or a CLI error)`;
|
|
3946
3977
|
}
|
|
3947
|
-
if (looksLikeAgentFailureMessage(
|
|
3978
|
+
if (looksLikeAgentFailureMessage(raw)) return detail;
|
|
3948
3979
|
return `exit ${code}: ${detail}`;
|
|
3949
3980
|
}
|
|
3950
3981
|
var NODE_VERSION_FOOTER;
|
|
@@ -5708,6 +5739,199 @@ var init_opencode = __esm({
|
|
|
5708
5739
|
}
|
|
5709
5740
|
});
|
|
5710
5741
|
|
|
5742
|
+
// src/agents/list-models.ts
|
|
5743
|
+
async function listBrightsyModels() {
|
|
5744
|
+
try {
|
|
5745
|
+
const targets = await listBrightsyChatTargets();
|
|
5746
|
+
const accountId = targets.activeAccountId;
|
|
5747
|
+
const models = (targets.models ?? []).map((m) => ({
|
|
5748
|
+
id: encodeBrightsyTarget("model", m.id, accountId),
|
|
5749
|
+
displayName: m.name || m.id,
|
|
5750
|
+
description: m.description ?? void 0
|
|
5751
|
+
}));
|
|
5752
|
+
const agents = (targets.agents ?? []).map((a) => ({
|
|
5753
|
+
id: encodeBrightsyTarget("agent", a.id, accountId),
|
|
5754
|
+
displayName: a.name || a.id,
|
|
5755
|
+
description: a.description ?? "Brightsy agent target"
|
|
5756
|
+
}));
|
|
5757
|
+
return [...models, ...agents].slice(0, 80);
|
|
5758
|
+
} catch {
|
|
5759
|
+
return [];
|
|
5760
|
+
}
|
|
5761
|
+
}
|
|
5762
|
+
async function listModelsForAgent(agent) {
|
|
5763
|
+
const kinds = agent ? [agent] : ["claude", "codex", "opencode", "cursor", "brightsy"];
|
|
5764
|
+
const out = [];
|
|
5765
|
+
for (const kind of kinds) {
|
|
5766
|
+
if (kind === "claude") {
|
|
5767
|
+
out.push({
|
|
5768
|
+
agent: kind,
|
|
5769
|
+
auto: true,
|
|
5770
|
+
models: CLAUDE_MODEL_CATALOG,
|
|
5771
|
+
note: "Default Auto \u2014 only pass a model id when you have a reason."
|
|
5772
|
+
});
|
|
5773
|
+
continue;
|
|
5774
|
+
}
|
|
5775
|
+
if (kind === "codex") {
|
|
5776
|
+
out.push({
|
|
5777
|
+
agent: kind,
|
|
5778
|
+
auto: true,
|
|
5779
|
+
models: await listCodexModels(),
|
|
5780
|
+
note: "Default Auto \u2014 only pass a model slug when you have a reason."
|
|
5781
|
+
});
|
|
5782
|
+
continue;
|
|
5783
|
+
}
|
|
5784
|
+
if (kind === "opencode") {
|
|
5785
|
+
out.push({
|
|
5786
|
+
agent: kind,
|
|
5787
|
+
auto: true,
|
|
5788
|
+
models: await listOpencodeModels(),
|
|
5789
|
+
note: "Default Auto \u2014 only pass a provider/model id when you have a reason."
|
|
5790
|
+
});
|
|
5791
|
+
continue;
|
|
5792
|
+
}
|
|
5793
|
+
if (kind === "cursor") {
|
|
5794
|
+
out.push({
|
|
5795
|
+
agent: kind,
|
|
5796
|
+
auto: true,
|
|
5797
|
+
models: await listCursorModels(),
|
|
5798
|
+
note: 'Default Auto \u2014 only pass a model id when you have a reason (or use "default").'
|
|
5799
|
+
});
|
|
5800
|
+
continue;
|
|
5801
|
+
}
|
|
5802
|
+
if (kind === "brightsy") {
|
|
5803
|
+
const models = await listBrightsyModels();
|
|
5804
|
+
out.push({
|
|
5805
|
+
agent: kind,
|
|
5806
|
+
auto: true,
|
|
5807
|
+
models,
|
|
5808
|
+
note: models.length ? "Default Auto / Default agent \u2014 only pass a model/agent id when you have a reason." : "Brightsy not logged in or no targets \u2014 leave model unset for Default."
|
|
5809
|
+
});
|
|
5810
|
+
}
|
|
5811
|
+
}
|
|
5812
|
+
return out;
|
|
5813
|
+
}
|
|
5814
|
+
var CLAUDE_MODEL_CATALOG;
|
|
5815
|
+
var init_list_models = __esm({
|
|
5816
|
+
"src/agents/list-models.ts"() {
|
|
5817
|
+
"use strict";
|
|
5818
|
+
init_brightsy();
|
|
5819
|
+
init_brightsy_targets();
|
|
5820
|
+
init_codex();
|
|
5821
|
+
init_cursor();
|
|
5822
|
+
init_opencode();
|
|
5823
|
+
CLAUDE_MODEL_CATALOG = [
|
|
5824
|
+
{ id: "fable", displayName: "Fable" },
|
|
5825
|
+
{ id: "opus", displayName: "Opus" },
|
|
5826
|
+
{ id: "sonnet", displayName: "Sonnet" },
|
|
5827
|
+
{ id: "haiku", displayName: "Haiku" }
|
|
5828
|
+
];
|
|
5829
|
+
}
|
|
5830
|
+
});
|
|
5831
|
+
|
|
5832
|
+
// src/agents/session-quota.ts
|
|
5833
|
+
function isSessionQuotaLimit(text) {
|
|
5834
|
+
const lower = text.trim().toLowerCase();
|
|
5835
|
+
if (!lower) return false;
|
|
5836
|
+
if (/credit balance is too low|out of credits|insufficient.?quota|billing/.test(lower)) {
|
|
5837
|
+
return false;
|
|
5838
|
+
}
|
|
5839
|
+
if (/prompt is too long|context.*(too long|exceed)|conversation too long/.test(lower)) {
|
|
5840
|
+
return false;
|
|
5841
|
+
}
|
|
5842
|
+
return /you've hit your/.test(lower) || /hit your (session|weekly|opus) limit/.test(lower) || /usage limit/.test(lower) || /rate.?limit|too many requests|\b429\b/.test(lower) && /reset/i.test(text);
|
|
5843
|
+
}
|
|
5844
|
+
function parseSessionQuotaResetAt(text, now = /* @__PURE__ */ new Date()) {
|
|
5845
|
+
const absolute = text.match(
|
|
5846
|
+
/resets\s+(?:at\s+)?(\d{1,2}):(\d{2})\s*(am|pm)(?:\s*\(([^)]+)\))?/i
|
|
5847
|
+
);
|
|
5848
|
+
if (absolute) {
|
|
5849
|
+
const hour12 = Number(absolute[1]);
|
|
5850
|
+
const minute = Number(absolute[2]);
|
|
5851
|
+
const ampm = absolute[3].toLowerCase();
|
|
5852
|
+
const timeZone = absolute[4]?.trim() || Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
5853
|
+
let hour = hour12 % 12;
|
|
5854
|
+
if (ampm === "pm") hour += 12;
|
|
5855
|
+
const at = zonedWallTimeToUtc(now, hour, minute, timeZone);
|
|
5856
|
+
if (!at) return null;
|
|
5857
|
+
if (at.getTime() <= now.getTime() + 3e4) {
|
|
5858
|
+
const tomorrow = new Date(now.getTime() + 24 * 60 * 60 * 1e3);
|
|
5859
|
+
return zonedWallTimeToUtc(tomorrow, hour, minute, timeZone);
|
|
5860
|
+
}
|
|
5861
|
+
return at;
|
|
5862
|
+
}
|
|
5863
|
+
const relative = text.match(
|
|
5864
|
+
/resets\s+in\s+(\d+)\s*(minutes?|hours?|days?)/i
|
|
5865
|
+
);
|
|
5866
|
+
if (relative) {
|
|
5867
|
+
const n = Number(relative[1]);
|
|
5868
|
+
const unit = relative[2].toLowerCase();
|
|
5869
|
+
const ms = unit.startsWith("day") ? n * 24 * 60 * 60 * 1e3 : unit.startsWith("hour") ? n * 60 * 60 * 1e3 : n * 60 * 1e3;
|
|
5870
|
+
return new Date(now.getTime() + ms);
|
|
5871
|
+
}
|
|
5872
|
+
return null;
|
|
5873
|
+
}
|
|
5874
|
+
function zonedWallTimeToUtc(day, hour, minute, timeZone) {
|
|
5875
|
+
try {
|
|
5876
|
+
const cal = new Intl.DateTimeFormat("en-US", {
|
|
5877
|
+
timeZone,
|
|
5878
|
+
year: "numeric",
|
|
5879
|
+
month: "2-digit",
|
|
5880
|
+
day: "2-digit"
|
|
5881
|
+
});
|
|
5882
|
+
const parts = Object.fromEntries(
|
|
5883
|
+
cal.formatToParts(day).filter((p) => p.type !== "literal").map((p) => [p.type, p.value])
|
|
5884
|
+
);
|
|
5885
|
+
const year = Number(parts.year);
|
|
5886
|
+
const month = Number(parts.month);
|
|
5887
|
+
const date = Number(parts.day);
|
|
5888
|
+
if (![year, month, date].every((n) => Number.isFinite(n))) return null;
|
|
5889
|
+
const utcGuess = Date.UTC(year, month - 1, date, hour, minute, 0);
|
|
5890
|
+
const dtf = new Intl.DateTimeFormat("en-US", {
|
|
5891
|
+
timeZone,
|
|
5892
|
+
year: "numeric",
|
|
5893
|
+
month: "2-digit",
|
|
5894
|
+
day: "2-digit",
|
|
5895
|
+
hour: "2-digit",
|
|
5896
|
+
minute: "2-digit",
|
|
5897
|
+
second: "2-digit",
|
|
5898
|
+
hourCycle: "h23"
|
|
5899
|
+
});
|
|
5900
|
+
const asParts = Object.fromEntries(
|
|
5901
|
+
dtf.formatToParts(new Date(utcGuess)).filter((p) => p.type !== "literal").map((p) => [p.type, p.value])
|
|
5902
|
+
);
|
|
5903
|
+
const asUtc = Date.UTC(
|
|
5904
|
+
Number(asParts.year),
|
|
5905
|
+
Number(asParts.month) - 1,
|
|
5906
|
+
Number(asParts.day),
|
|
5907
|
+
Number(asParts.hour),
|
|
5908
|
+
Number(asParts.minute),
|
|
5909
|
+
Number(asParts.second || "0")
|
|
5910
|
+
);
|
|
5911
|
+
const offset = asUtc - utcGuess;
|
|
5912
|
+
return new Date(utcGuess - offset);
|
|
5913
|
+
} catch {
|
|
5914
|
+
return null;
|
|
5915
|
+
}
|
|
5916
|
+
}
|
|
5917
|
+
function resolveQuotaFallbackAgent(current, preferred) {
|
|
5918
|
+
const ordered = preferred ? [preferred, ...FALLBACK_ORDER.filter((a) => a !== preferred)] : FALLBACK_ORDER;
|
|
5919
|
+
return ordered.find((a) => a !== current) ?? (current === "cursor" ? "codex" : "cursor");
|
|
5920
|
+
}
|
|
5921
|
+
var FALLBACK_ORDER;
|
|
5922
|
+
var init_session_quota = __esm({
|
|
5923
|
+
"src/agents/session-quota.ts"() {
|
|
5924
|
+
"use strict";
|
|
5925
|
+
FALLBACK_ORDER = [
|
|
5926
|
+
"cursor",
|
|
5927
|
+
"codex",
|
|
5928
|
+
"opencode",
|
|
5929
|
+
"brightsy",
|
|
5930
|
+
"claude"
|
|
5931
|
+
];
|
|
5932
|
+
}
|
|
5933
|
+
});
|
|
5934
|
+
|
|
5711
5935
|
// src/agents/install.ts
|
|
5712
5936
|
function getAgentSetupInfo(agent) {
|
|
5713
5937
|
return SETUP[agent];
|
|
@@ -5888,6 +6112,7 @@ var init_install = __esm({
|
|
|
5888
6112
|
// src/agents/index.ts
|
|
5889
6113
|
var agents_exports = {};
|
|
5890
6114
|
__export(agents_exports, {
|
|
6115
|
+
CLAUDE_MODEL_CATALOG: () => CLAUDE_MODEL_CATALOG,
|
|
5891
6116
|
PLAN_MODE_INSTRUCTION: () => PLAN_MODE_INSTRUCTION,
|
|
5892
6117
|
allAdapters: () => allAdapters,
|
|
5893
6118
|
brightsyAdapter: () => brightsyAdapter,
|
|
@@ -5902,17 +6127,21 @@ __export(agents_exports, {
|
|
|
5902
6127
|
getAgentSetupInfo: () => getAgentSetupInfo,
|
|
5903
6128
|
installAgent: () => installAgent,
|
|
5904
6129
|
isCursorAutoModel: () => isCursorAutoModel,
|
|
6130
|
+
isSessionQuotaLimit: () => isSessionQuotaLimit,
|
|
5905
6131
|
listAgentSetupInfo: () => listAgentSetupInfo,
|
|
5906
6132
|
listBrightsyChatTargets: () => listBrightsyChatTargets,
|
|
5907
6133
|
listCodexModels: () => listCodexModels,
|
|
5908
6134
|
listCursorModels: () => listCursorModels,
|
|
6135
|
+
listModelsForAgent: () => listModelsForAgent,
|
|
5909
6136
|
listOpencodeModels: () => listOpencodeModels,
|
|
5910
6137
|
loginAgent: () => loginAgent,
|
|
5911
6138
|
openInSystemTerminal: () => openInSystemTerminal,
|
|
5912
6139
|
opencodeAdapter: () => opencodeAdapter,
|
|
5913
6140
|
parseCursorRunnerLine: () => parseCursorRunnerLine,
|
|
6141
|
+
parseSessionQuotaResetAt: () => parseSessionQuotaResetAt,
|
|
5914
6142
|
permissionMode: () => permissionMode,
|
|
5915
|
-
resolveCursorModelId: () => resolveCursorModelId
|
|
6143
|
+
resolveCursorModelId: () => resolveCursorModelId,
|
|
6144
|
+
resolveQuotaFallbackAgent: () => resolveQuotaFallbackAgent
|
|
5916
6145
|
});
|
|
5917
6146
|
function getAdapter(kind) {
|
|
5918
6147
|
return adapters[kind];
|
|
@@ -5938,6 +6167,8 @@ var init_agents = __esm({
|
|
|
5938
6167
|
init_cursor_events();
|
|
5939
6168
|
init_cursor();
|
|
5940
6169
|
init_opencode();
|
|
6170
|
+
init_list_models();
|
|
6171
|
+
init_session_quota();
|
|
5941
6172
|
init_path();
|
|
5942
6173
|
init_install();
|
|
5943
6174
|
adapters = {
|
|
@@ -5958,10 +6189,10 @@ __export(cursor_recover_exports, {
|
|
|
5958
6189
|
function recoverFinishedCursorRun(opts) {
|
|
5959
6190
|
const agentId = opts.agentId.trim();
|
|
5960
6191
|
if (!agentId) return null;
|
|
5961
|
-
const runsPath = (0,
|
|
5962
|
-
if (!(0,
|
|
6192
|
+
const runsPath = (0, import_node_path24.join)(appDataDir(), "cursor-sdk-store", "runs.ndjson");
|
|
6193
|
+
if (!(0, import_node_fs25.existsSync)(runsPath)) return null;
|
|
5963
6194
|
try {
|
|
5964
|
-
const lines = (0,
|
|
6195
|
+
const lines = (0, import_node_fs25.readFileSync)(runsPath, "utf8").split("\n");
|
|
5965
6196
|
let best = null;
|
|
5966
6197
|
for (const line of lines) {
|
|
5967
6198
|
const trimmed = line.trim();
|
|
@@ -5987,12 +6218,12 @@ function recoverFinishedCursorRun(opts) {
|
|
|
5987
6218
|
return null;
|
|
5988
6219
|
}
|
|
5989
6220
|
}
|
|
5990
|
-
var
|
|
6221
|
+
var import_node_fs25, import_node_path24;
|
|
5991
6222
|
var init_cursor_recover = __esm({
|
|
5992
6223
|
"src/agents/cursor-recover.ts"() {
|
|
5993
6224
|
"use strict";
|
|
5994
|
-
|
|
5995
|
-
|
|
6225
|
+
import_node_fs25 = require("fs");
|
|
6226
|
+
import_node_path24 = require("path");
|
|
5996
6227
|
init_paths();
|
|
5997
6228
|
}
|
|
5998
6229
|
});
|
|
@@ -6033,6 +6264,7 @@ var index_exports = {};
|
|
|
6033
6264
|
__export(index_exports, {
|
|
6034
6265
|
BRIGHTSY_MCP_ALLOWED_TOOLS: () => BRIGHTSY_MCP_ALLOWED_TOOLS,
|
|
6035
6266
|
BrightsySideboardApi: () => BrightsySideboardApi,
|
|
6267
|
+
CLAUDE_MODEL_CATALOG: () => CLAUDE_MODEL_CATALOG,
|
|
6036
6268
|
CLOUD_COORDINATOR_BUSY_REPLY: () => CLOUD_COORDINATOR_BUSY_REPLY,
|
|
6037
6269
|
CLOUD_COORDINATOR_STOPPED_REPLY: () => CLOUD_COORDINATOR_STOPPED_REPLY,
|
|
6038
6270
|
CLOUD_COORDINATOR_TIMEOUT_REPLY: () => CLOUD_COORDINATOR_TIMEOUT_REPLY,
|
|
@@ -6050,6 +6282,9 @@ __export(index_exports, {
|
|
|
6050
6282
|
PASTE_ATTACH_MIN_CHARS: () => PASTE_ATTACH_MIN_CHARS,
|
|
6051
6283
|
PASTE_ATTACH_MIN_LINES: () => PASTE_ATTACH_MIN_LINES,
|
|
6052
6284
|
PLAN_MODE_INSTRUCTION: () => PLAN_MODE_INSTRUCTION,
|
|
6285
|
+
REVIEW_REQUEST_NAME: () => REVIEW_REQUEST_NAME,
|
|
6286
|
+
REVIEW_REQUEST_PATH: () => REVIEW_REQUEST_PATH,
|
|
6287
|
+
REVIEW_REQUEST_PREFILL: () => REVIEW_REQUEST_PREFILL,
|
|
6053
6288
|
SIDEBOARD_FORCE_STOP: () => SIDEBOARD_FORCE_STOP,
|
|
6054
6289
|
SIDEBOARD_MCP_ALLOWED_TOOLS: () => SIDEBOARD_MCP_ALLOWED_TOOLS,
|
|
6055
6290
|
THINKING_EFFORTS: () => THINKING_EFFORTS,
|
|
@@ -6085,6 +6320,7 @@ __export(index_exports, {
|
|
|
6085
6320
|
buildDiffCommentAttachment: () => buildDiffCommentAttachment,
|
|
6086
6321
|
buildForkTranscriptAttachment: () => buildForkTranscriptAttachment,
|
|
6087
6322
|
buildPastedTextAttachment: () => buildPastedTextAttachment,
|
|
6323
|
+
buildReviewRequestAttachment: () => buildReviewRequestAttachment,
|
|
6088
6324
|
buildSessionSeed: () => buildSessionSeed,
|
|
6089
6325
|
buildWorkspaceScriptEnv: () => buildWorkspaceScriptEnv,
|
|
6090
6326
|
caffeinateWhileCloudConnectEnabled: () => caffeinateWhileCloudConnectEnabled,
|
|
@@ -6205,6 +6441,7 @@ __export(index_exports, {
|
|
|
6205
6441
|
isOrchestratorThread: () => isOrchestratorThread,
|
|
6206
6442
|
isPidAlive: () => isPidAlive,
|
|
6207
6443
|
isPlaceholderBranch: () => isPlaceholderBranch,
|
|
6444
|
+
isSessionQuotaLimit: () => isSessionQuotaLimit,
|
|
6208
6445
|
isThinkingEffort: () => isThinkingEffort,
|
|
6209
6446
|
listAgentSetupInfo: () => listAgentSetupInfo,
|
|
6210
6447
|
listBranchCommits: () => listBranchCommits,
|
|
@@ -6220,6 +6457,7 @@ __export(index_exports, {
|
|
|
6220
6457
|
listIssues: () => listIssues,
|
|
6221
6458
|
listLinearIssues: () => listLinearIssues,
|
|
6222
6459
|
listLinearIssuesDirect: () => listLinearIssuesDirect,
|
|
6460
|
+
listModelsForAgent: () => listModelsForAgent,
|
|
6223
6461
|
listOpencodeModels: () => listOpencodeModels,
|
|
6224
6462
|
listPrs: () => listPrs,
|
|
6225
6463
|
listRunScripts: () => listRunScripts,
|
|
@@ -6251,6 +6489,8 @@ __export(index_exports, {
|
|
|
6251
6489
|
normalizeWorktreePath: () => normalizeWorktreePath,
|
|
6252
6490
|
openInSystemTerminal: () => openInSystemTerminal,
|
|
6253
6491
|
opencodeAdapter: () => opencodeAdapter,
|
|
6492
|
+
orchestrationQuotaFallbackAgent: () => orchestrationQuotaFallbackAgent,
|
|
6493
|
+
orchestrationQuotaOnLimit: () => orchestrationQuotaOnLimit,
|
|
6254
6494
|
orchestrationTitleNeedsSoccerNickname: () => orchestrationTitleNeedsSoccerNickname,
|
|
6255
6495
|
orchestratorSessionPoisonedByBuiltins: () => orchestratorSessionPoisonedByBuiltins,
|
|
6256
6496
|
originGhRepoEnv: () => originGhRepoEnv,
|
|
@@ -6258,11 +6498,13 @@ __export(index_exports, {
|
|
|
6258
6498
|
parseForceStopMessage: () => parseForceStopMessage,
|
|
6259
6499
|
parseGithubSlugFromRemoteUrl: () => parseGithubSlugFromRemoteUrl,
|
|
6260
6500
|
parseMcpList: () => parseMcpList,
|
|
6501
|
+
parseSessionQuotaResetAt: () => parseSessionQuotaResetAt,
|
|
6261
6502
|
partsToAssistantText: () => partsToAssistantText,
|
|
6262
6503
|
pastedTextStats: () => pastedTextStats,
|
|
6263
6504
|
permissionMode: () => permissionMode,
|
|
6264
6505
|
previewLand: () => previewLand,
|
|
6265
6506
|
pushBranch: () => pushBranch,
|
|
6507
|
+
readExistingReviewRequestFile: () => readExistingReviewRequestFile,
|
|
6266
6508
|
readSkillBody: () => readSkillBody,
|
|
6267
6509
|
readThread: () => readThread,
|
|
6268
6510
|
readWorktreeFile: () => readWorktreeFile,
|
|
@@ -6272,6 +6514,7 @@ __export(index_exports, {
|
|
|
6272
6514
|
removeWorkspace: () => removeWorkspace,
|
|
6273
6515
|
removeWorktree: () => removeWorktree,
|
|
6274
6516
|
repoSlug: () => repoSlug,
|
|
6517
|
+
requestReview: () => requestReview,
|
|
6275
6518
|
requireAgent: () => requireAgent,
|
|
6276
6519
|
resolveClaudeExecutable: () => resolveClaudeExecutable,
|
|
6277
6520
|
resolveConductorCursorAgentId: () => resolveConductorCursorAgentId,
|
|
@@ -6282,6 +6525,7 @@ __export(index_exports, {
|
|
|
6282
6525
|
resolveFilesToCopy: () => resolveFilesToCopy,
|
|
6283
6526
|
resolveGithubRepoSlug: () => resolveGithubRepoSlug,
|
|
6284
6527
|
resolvePrSelector: () => resolvePrSelector,
|
|
6528
|
+
resolveQuotaFallbackAgent: () => resolveQuotaFallbackAgent,
|
|
6285
6529
|
resolveRepoRoot: () => resolveRepoRoot,
|
|
6286
6530
|
resolveThreadDefaults: () => resolveThreadDefaults,
|
|
6287
6531
|
resolveThreadEffort: () => resolveThreadEffort,
|
|
@@ -9168,16 +9412,24 @@ function forkChatTab(input) {
|
|
|
9168
9412
|
const from = requireThread(input.threadId);
|
|
9169
9413
|
const slice = forkMessageSlice(from, input.throughIndex);
|
|
9170
9414
|
const attachment = buildForkTranscriptAttachment(from.title || "Chat", slice);
|
|
9171
|
-
|
|
9415
|
+
const tab = createChatTab({
|
|
9172
9416
|
fromThreadId: input.threadId,
|
|
9173
9417
|
agent: input.agent ?? from.agent,
|
|
9418
|
+
model: input.model,
|
|
9174
9419
|
title: input.title?.trim() || void 0,
|
|
9175
9420
|
attachments: [attachment]
|
|
9176
9421
|
});
|
|
9422
|
+
if (isOrchestratorThread(from) && tab.parentThreadId !== from.id) {
|
|
9423
|
+
const next = { ...tab, parentThreadId: from.id };
|
|
9424
|
+
writeThread(next);
|
|
9425
|
+
return next;
|
|
9426
|
+
}
|
|
9427
|
+
return tab;
|
|
9177
9428
|
}
|
|
9178
9429
|
|
|
9179
9430
|
// src/threads/fork-worktree.ts
|
|
9180
9431
|
init_thread_store();
|
|
9432
|
+
init_global_workspace();
|
|
9181
9433
|
function requireThread2(idOrRef) {
|
|
9182
9434
|
const thread = findThreadByRef(idOrRef) ?? null;
|
|
9183
9435
|
if (!thread) throw new Error(`Thread not found: ${idOrRef}`);
|
|
@@ -9185,16 +9437,28 @@ function requireThread2(idOrRef) {
|
|
|
9185
9437
|
}
|
|
9186
9438
|
async function forkThreadWorktree(input, onSetupLine) {
|
|
9187
9439
|
const from = requireThread2(input.threadId);
|
|
9440
|
+
if (isOrchestratorThread(from)) {
|
|
9441
|
+
throw new Error(
|
|
9442
|
+
"fork_worktree targets a worktree agent thread (not the orchestrator). Pass a child/worktree thread ref."
|
|
9443
|
+
);
|
|
9444
|
+
}
|
|
9445
|
+
if (!from.branchName?.trim() || !from.repoPath?.trim()) {
|
|
9446
|
+
throw new Error(
|
|
9447
|
+
`Cannot fork worktree: thread ${from.id} has no branch/repo (need a real worktree chat).`
|
|
9448
|
+
);
|
|
9449
|
+
}
|
|
9188
9450
|
const slice = forkMessageSlice(from, input.throughIndex);
|
|
9189
9451
|
const attachment = buildForkTranscriptAttachment(from.title || "Chat", slice);
|
|
9452
|
+
const nextAgent = input.agent ?? from.agent;
|
|
9453
|
+
const nextModel = input.model !== void 0 ? input.model : input.agent && input.agent !== from.agent ? null : from.model;
|
|
9190
9454
|
const thread = await createThread(
|
|
9191
9455
|
{
|
|
9192
9456
|
sourceType: "branch",
|
|
9193
9457
|
sourceRef: from.branchName,
|
|
9194
9458
|
repoPath: from.repoPath,
|
|
9195
|
-
agent:
|
|
9459
|
+
agent: nextAgent,
|
|
9196
9460
|
autonomy: from.autonomy,
|
|
9197
|
-
model:
|
|
9461
|
+
model: nextModel,
|
|
9198
9462
|
effort: from.effort,
|
|
9199
9463
|
fast: from.fast,
|
|
9200
9464
|
planMode: from.planMode,
|
|
@@ -9491,7 +9755,7 @@ async function importConductorWorkspaceAsync(workspaceId) {
|
|
|
9491
9755
|
|
|
9492
9756
|
// src/orchestrator/orchestrator.ts
|
|
9493
9757
|
var import_node_events = require("events");
|
|
9494
|
-
var
|
|
9758
|
+
var import_node_fs26 = require("fs");
|
|
9495
9759
|
init_error_detail();
|
|
9496
9760
|
init_agents();
|
|
9497
9761
|
init_worktree();
|
|
@@ -9735,6 +9999,169 @@ async function cloneRepoIntoSideboard(opts) {
|
|
|
9735
9999
|
|
|
9736
10000
|
// src/orchestrator/orchestrator.ts
|
|
9737
10001
|
init_thread_store();
|
|
10002
|
+
|
|
10003
|
+
// src/review/request-review.ts
|
|
10004
|
+
var import_node_crypto5 = require("crypto");
|
|
10005
|
+
var import_node_fs24 = require("fs");
|
|
10006
|
+
var import_node_path23 = require("path");
|
|
10007
|
+
init_global_workspace();
|
|
10008
|
+
init_thread_store();
|
|
10009
|
+
var REVIEW_REQUEST_PATH = ".sideboard/attachments/Review request.md";
|
|
10010
|
+
var REVIEW_REQUEST_NAME = "Review request.md";
|
|
10011
|
+
var REVIEW_REQUEST_PREFILL = `Please review the changes in this workspace and recommend whether they are ready to merge.
|
|
10012
|
+
|
|
10013
|
+
Start with a **Recommendation**: Approve, Approve with nits, Request changes, or Needs more information \u2014 and say why in 1\u20133 sentences. Then list blocking findings vs nits (findings may be empty).`;
|
|
10014
|
+
function buildReviewRequestAttachment(content) {
|
|
10015
|
+
return {
|
|
10016
|
+
id: (0, import_node_crypto5.randomUUID)(),
|
|
10017
|
+
name: REVIEW_REQUEST_NAME,
|
|
10018
|
+
kind: "file",
|
|
10019
|
+
path: REVIEW_REQUEST_PATH,
|
|
10020
|
+
content
|
|
10021
|
+
};
|
|
10022
|
+
}
|
|
10023
|
+
function readExistingReviewRequestFile(worktreePath) {
|
|
10024
|
+
const abs = (0, import_node_path23.join)(worktreePath, REVIEW_REQUEST_PATH);
|
|
10025
|
+
if (!(0, import_node_fs24.existsSync)(abs)) return null;
|
|
10026
|
+
try {
|
|
10027
|
+
const content = (0, import_node_fs24.readFileSync)(abs, "utf8");
|
|
10028
|
+
return content.trim() ? content : null;
|
|
10029
|
+
} catch {
|
|
10030
|
+
return null;
|
|
10031
|
+
}
|
|
10032
|
+
}
|
|
10033
|
+
async function requestReview(threadRef, send) {
|
|
10034
|
+
const from = findThreadByRef(threadRef);
|
|
10035
|
+
if (!from) throw new Error(`Thread not found: ${threadRef}`);
|
|
10036
|
+
if (isOrchestratorThread(from)) {
|
|
10037
|
+
throw new Error(
|
|
10038
|
+
"request_review targets a worktree agent thread (not the orchestrator). Pass a child/worktree thread ref."
|
|
10039
|
+
);
|
|
10040
|
+
}
|
|
10041
|
+
if (from.status === "archived") {
|
|
10042
|
+
throw new Error(`Thread is archived: ${from.id}`);
|
|
10043
|
+
}
|
|
10044
|
+
const existing = readExistingReviewRequestFile(from.worktreePath);
|
|
10045
|
+
const attachments = existing ? [buildReviewRequestAttachment(existing)] : [];
|
|
10046
|
+
const tab = createChatTab({
|
|
10047
|
+
fromThreadId: from.id,
|
|
10048
|
+
title: "Review",
|
|
10049
|
+
attachments
|
|
10050
|
+
});
|
|
10051
|
+
const started = await send(tab.id, REVIEW_REQUEST_PREFILL);
|
|
10052
|
+
return { tab: started, from };
|
|
10053
|
+
}
|
|
10054
|
+
|
|
10055
|
+
// src/orchestrator/quota-failover.ts
|
|
10056
|
+
var import_node_crypto6 = require("crypto");
|
|
10057
|
+
init_session_quota();
|
|
10058
|
+
init_app_settings();
|
|
10059
|
+
init_global_workspace();
|
|
10060
|
+
init_thread_store();
|
|
10061
|
+
function planOrchestrationQuotaFailover(thread, limitText, opts) {
|
|
10062
|
+
if (!isOrchestratorThread(thread)) return null;
|
|
10063
|
+
if (!isSessionQuotaLimit(limitText)) return null;
|
|
10064
|
+
const onLimit = opts?.onLimit ?? orchestrationQuotaOnLimit();
|
|
10065
|
+
const resumeAt = parseSessionQuotaResetAt(limitText, opts?.now);
|
|
10066
|
+
if (thread.quotaContinuedFromId) {
|
|
10067
|
+
if (resumeAt) {
|
|
10068
|
+
return {
|
|
10069
|
+
action: "wait_reset",
|
|
10070
|
+
reason: "Already continued once; waiting for quota reset instead.",
|
|
10071
|
+
limitText,
|
|
10072
|
+
resumeAt
|
|
10073
|
+
};
|
|
10074
|
+
}
|
|
10075
|
+
return {
|
|
10076
|
+
action: "none",
|
|
10077
|
+
reason: "Already continued once; no parseable reset time.",
|
|
10078
|
+
limitText
|
|
10079
|
+
};
|
|
10080
|
+
}
|
|
10081
|
+
if (onLimit === "wait_reset") {
|
|
10082
|
+
if (!resumeAt) {
|
|
10083
|
+
return {
|
|
10084
|
+
action: "none",
|
|
10085
|
+
reason: "wait_reset configured but reset time could not be parsed.",
|
|
10086
|
+
limitText
|
|
10087
|
+
};
|
|
10088
|
+
}
|
|
10089
|
+
return {
|
|
10090
|
+
action: "wait_reset",
|
|
10091
|
+
reason: "Settings: wait for quota reset.",
|
|
10092
|
+
limitText,
|
|
10093
|
+
resumeAt
|
|
10094
|
+
};
|
|
10095
|
+
}
|
|
10096
|
+
const preferred = opts?.fallbackAgent ?? orchestrationQuotaFallbackAgent();
|
|
10097
|
+
const fallbackAgent = resolveQuotaFallbackAgent(thread.agent, preferred);
|
|
10098
|
+
return {
|
|
10099
|
+
action: "switch_agent",
|
|
10100
|
+
reason: `Continue on ${fallbackAgent} (Auto) after ${thread.agent} session limit.`,
|
|
10101
|
+
limitText,
|
|
10102
|
+
fallbackAgent
|
|
10103
|
+
};
|
|
10104
|
+
}
|
|
10105
|
+
function buildQuotaHandoffAttachment(from, limitText, fallbackAgent) {
|
|
10106
|
+
const children = listThreads({ includeArchived: false }).filter((t) => t.parentThreadId === from.id && t.status !== "archived").slice(0, 40).map(
|
|
10107
|
+
(t) => `- ${t.title} \xB7 ${t.status} \xB7 ${t.agent} \xB7 sideboard://thread/${t.id}`
|
|
10108
|
+
);
|
|
10109
|
+
const recent = from.messages.slice(-8).map((m) => {
|
|
10110
|
+
const role = m.role === "user" ? "User" : m.role === "agent" ? "Agent" : "Summary";
|
|
10111
|
+
const text = m.text.trim().replace(/\s+/g, " ").slice(0, 280);
|
|
10112
|
+
return text ? `- ${role}: ${text}` : null;
|
|
10113
|
+
}).filter(Boolean);
|
|
10114
|
+
const body = [
|
|
10115
|
+
`# Orchestration handoff`,
|
|
10116
|
+
"",
|
|
10117
|
+
`Previous chat: ${from.title} (\`${from.id}\`) on **${from.agent}** hit a session/usage limit.`,
|
|
10118
|
+
`Limit: ${limitText.trim()}`,
|
|
10119
|
+
`Continuing on **${fallbackAgent}** with Auto model.`,
|
|
10120
|
+
"",
|
|
10121
|
+
`## Goal`,
|
|
10122
|
+
from.sourceRef?.trim() || "(none)",
|
|
10123
|
+
"",
|
|
10124
|
+
`## Child threads`,
|
|
10125
|
+
children.length ? children.join("\n") : "(none listed \u2014 call list_threads)",
|
|
10126
|
+
"",
|
|
10127
|
+
`## Recent turns (truncated)`,
|
|
10128
|
+
recent.length ? recent.join("\n") : "(none)",
|
|
10129
|
+
"",
|
|
10130
|
+
`## Instructions`,
|
|
10131
|
+
`- Continue fleet orchestration from this handoff.`,
|
|
10132
|
+
`- Prefer Sideboard MCP (list_threads, get_thread, send_to_thread, \u2026) for live status.`,
|
|
10133
|
+
`- Leave model Auto unless there is a specific reason to pin one.`,
|
|
10134
|
+
`- Do not wait on the limited ${from.agent} account; keep going on ${fallbackAgent}.`
|
|
10135
|
+
].join("\n");
|
|
10136
|
+
return {
|
|
10137
|
+
id: (0, import_node_crypto6.randomUUID)(),
|
|
10138
|
+
name: "Orchestration quota handoff.md",
|
|
10139
|
+
kind: "transcript",
|
|
10140
|
+
content: body
|
|
10141
|
+
};
|
|
10142
|
+
}
|
|
10143
|
+
var QUOTA_CONTINUE_PROMPT = (fromAgent, fallback) => [
|
|
10144
|
+
`${fromAgent} hit a session/usage limit. Continue this orchestration on ${fallback} using the attached handoff.`,
|
|
10145
|
+
"Call list_threads for live fleet status, then proceed with the goal. Leave model Auto unless needed."
|
|
10146
|
+
].join(" ");
|
|
10147
|
+
var QUOTA_RESUME_PROMPT = "Session/usage limit window should have reset. Continue the orchestration from where you left off. Use list_threads for fleet status.";
|
|
10148
|
+
function createQuotaFailoverChat(from, fallbackAgent, limitText) {
|
|
10149
|
+
const handoff = buildQuotaHandoffAttachment(from, limitText, fallbackAgent);
|
|
10150
|
+
const tab = createChatTab({
|
|
10151
|
+
fromThreadId: from.id,
|
|
10152
|
+
agent: fallbackAgent,
|
|
10153
|
+
model: null,
|
|
10154
|
+
attachments: [handoff]
|
|
10155
|
+
});
|
|
10156
|
+
return updateThread(tab.id, {
|
|
10157
|
+
parentThreadId: from.id,
|
|
10158
|
+
quotaContinuedFromId: from.id,
|
|
10159
|
+
sourceRef: from.sourceRef,
|
|
10160
|
+
sourceType: "orchestration"
|
|
10161
|
+
});
|
|
10162
|
+
}
|
|
10163
|
+
|
|
10164
|
+
// src/orchestrator/orchestrator.ts
|
|
9738
10165
|
init_types();
|
|
9739
10166
|
init_settings();
|
|
9740
10167
|
|
|
@@ -9804,6 +10231,8 @@ var Orchestrator = class {
|
|
|
9804
10231
|
haltDrain = /* @__PURE__ */ new Set();
|
|
9805
10232
|
/** WIP snapshot SHA at the start of the latest agent turn (per thread). */
|
|
9806
10233
|
turnBaselines = /* @__PURE__ */ new Map();
|
|
10234
|
+
/** Timers for orchestration session-quota auto-resume. */
|
|
10235
|
+
quotaResumeTimers = /* @__PURE__ */ new Map();
|
|
9807
10236
|
maxConcurrent;
|
|
9808
10237
|
runningCount = 0;
|
|
9809
10238
|
constructor(opts) {
|
|
@@ -9853,7 +10282,7 @@ var Orchestrator = class {
|
|
|
9853
10282
|
}
|
|
9854
10283
|
continue;
|
|
9855
10284
|
}
|
|
9856
|
-
if (!(0,
|
|
10285
|
+
if (!(0, import_node_fs26.existsSync)(thread.worktreePath)) {
|
|
9857
10286
|
setStatus(thread.id, "broken", "Worktree missing on disk");
|
|
9858
10287
|
this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
|
|
9859
10288
|
continue;
|
|
@@ -9883,6 +10312,113 @@ var Orchestrator = class {
|
|
|
9883
10312
|
void this.drainQueue(thread.id);
|
|
9884
10313
|
}
|
|
9885
10314
|
}
|
|
10315
|
+
this.schedulePendingQuotaResumes();
|
|
10316
|
+
}
|
|
10317
|
+
clearQuotaResumeTimer(threadId) {
|
|
10318
|
+
const timer = this.quotaResumeTimers.get(threadId);
|
|
10319
|
+
if (timer) clearTimeout(timer);
|
|
10320
|
+
this.quotaResumeTimers.delete(threadId);
|
|
10321
|
+
}
|
|
10322
|
+
/** Schedule (or fire) auto-retry after a provider session/usage limit reset. */
|
|
10323
|
+
scheduleQuotaResume(threadId, resumeAt) {
|
|
10324
|
+
this.clearQuotaResumeTimer(threadId);
|
|
10325
|
+
updateThread(threadId, { quotaResumeAt: resumeAt.toISOString() });
|
|
10326
|
+
const delay = Math.max(5e3, resumeAt.getTime() - Date.now());
|
|
10327
|
+
const capped = Math.min(delay, 2147483647);
|
|
10328
|
+
const timer = setTimeout(() => {
|
|
10329
|
+
this.quotaResumeTimers.delete(threadId);
|
|
10330
|
+
void this.resumeAfterQuotaWait(threadId);
|
|
10331
|
+
}, capped);
|
|
10332
|
+
this.quotaResumeTimers.set(threadId, timer);
|
|
10333
|
+
}
|
|
10334
|
+
schedulePendingQuotaResumes() {
|
|
10335
|
+
for (const thread of listThreads({ includeArchived: false })) {
|
|
10336
|
+
if (!thread.quotaResumeAt) continue;
|
|
10337
|
+
const at = new Date(thread.quotaResumeAt);
|
|
10338
|
+
if (Number.isNaN(at.getTime())) continue;
|
|
10339
|
+
if (at.getTime() <= Date.now()) {
|
|
10340
|
+
void this.resumeAfterQuotaWait(thread.id);
|
|
10341
|
+
} else if (!this.quotaResumeTimers.has(thread.id)) {
|
|
10342
|
+
this.scheduleQuotaResume(thread.id, at);
|
|
10343
|
+
}
|
|
10344
|
+
}
|
|
10345
|
+
}
|
|
10346
|
+
async resumeAfterQuotaWait(threadId) {
|
|
10347
|
+
const thread = findThreadByRef(threadId);
|
|
10348
|
+
if (!thread || thread.status === "archived") return;
|
|
10349
|
+
this.clearQuotaResumeTimer(threadId);
|
|
10350
|
+
try {
|
|
10351
|
+
updateThread(threadId, { quotaResumeAt: null });
|
|
10352
|
+
} catch {
|
|
10353
|
+
return;
|
|
10354
|
+
}
|
|
10355
|
+
if (thread.status === "running" || this.activeTurns.has(threadId) || this.startingTurns.has(threadId)) {
|
|
10356
|
+
return;
|
|
10357
|
+
}
|
|
10358
|
+
await this.send(threadId, QUOTA_RESUME_PROMPT);
|
|
10359
|
+
}
|
|
10360
|
+
/**
|
|
10361
|
+
* Host-side continue when an orchestration chat hits a provider session/usage
|
|
10362
|
+
* limit (not context size): switch agent (Auto) or wait until reset.
|
|
10363
|
+
*/
|
|
10364
|
+
async maybeHandleOrchestrationQuotaFailover(threadId, limitText) {
|
|
10365
|
+
const thread = findThreadByRef(threadId);
|
|
10366
|
+
if (!thread) return;
|
|
10367
|
+
const plan = planOrchestrationQuotaFailover(thread, limitText);
|
|
10368
|
+
if (!plan || plan.action === "none") return;
|
|
10369
|
+
if (plan.action === "wait_reset" && plan.resumeAt) {
|
|
10370
|
+
this.haltDrain.add(threadId);
|
|
10371
|
+
this.scheduleQuotaResume(threadId, plan.resumeAt);
|
|
10372
|
+
setStatus(threadId, "idle", null);
|
|
10373
|
+
appendMessage(threadId, {
|
|
10374
|
+
role: "agent",
|
|
10375
|
+
text: `Sideboard will auto-retry this orchestration around ${plan.resumeAt.toLocaleString()} when the session limit resets.`,
|
|
10376
|
+
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
10377
|
+
});
|
|
10378
|
+
this.emit({
|
|
10379
|
+
type: "quota_failover",
|
|
10380
|
+
threadId,
|
|
10381
|
+
action: "wait_reset",
|
|
10382
|
+
message: plan.reason,
|
|
10383
|
+
resumeAt: plan.resumeAt.toISOString()
|
|
10384
|
+
});
|
|
10385
|
+
this.emit({ type: "status_changed", threadId, status: "idle" });
|
|
10386
|
+
return;
|
|
10387
|
+
}
|
|
10388
|
+
if (plan.action === "switch_agent" && plan.fallbackAgent) {
|
|
10389
|
+
this.haltDrain.add(threadId);
|
|
10390
|
+
const next = createQuotaFailoverChat(
|
|
10391
|
+
thread,
|
|
10392
|
+
plan.fallbackAgent,
|
|
10393
|
+
plan.limitText
|
|
10394
|
+
);
|
|
10395
|
+
this.clearQuotaResumeTimer(threadId);
|
|
10396
|
+
try {
|
|
10397
|
+
updateThread(threadId, { quotaResumeAt: null });
|
|
10398
|
+
} catch {
|
|
10399
|
+
}
|
|
10400
|
+
appendMessage(threadId, {
|
|
10401
|
+
role: "agent",
|
|
10402
|
+
text: `Session limit on ${thread.agent}. Sideboard continued on ${plan.fallbackAgent} (Auto) in [${next.title}](sideboard://thread/${next.id}).`,
|
|
10403
|
+
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
10404
|
+
});
|
|
10405
|
+
this.emit({
|
|
10406
|
+
type: "quota_failover",
|
|
10407
|
+
threadId,
|
|
10408
|
+
action: "switch_agent",
|
|
10409
|
+
toThreadId: next.id,
|
|
10410
|
+
message: plan.reason
|
|
10411
|
+
});
|
|
10412
|
+
this.emit({
|
|
10413
|
+
type: "status_changed",
|
|
10414
|
+
threadId: next.id,
|
|
10415
|
+
status: next.status
|
|
10416
|
+
});
|
|
10417
|
+
await this.send(
|
|
10418
|
+
next.id,
|
|
10419
|
+
QUOTA_CONTINUE_PROMPT(thread.agent, plan.fallbackAgent)
|
|
10420
|
+
);
|
|
10421
|
+
}
|
|
9886
10422
|
}
|
|
9887
10423
|
getThreads(includeArchived = false) {
|
|
9888
10424
|
return listThreads({ includeArchived });
|
|
@@ -10241,11 +10777,16 @@ var Orchestrator = class {
|
|
|
10241
10777
|
}
|
|
10242
10778
|
}
|
|
10243
10779
|
}
|
|
10244
|
-
const
|
|
10245
|
-
|
|
10780
|
+
const lastStderr = summarizeTurnStderr(stderrTail);
|
|
10781
|
+
const detail = lastStderr || (exitCode !== 0 ? fallbackTurnFailDetail(assistantText) : "");
|
|
10782
|
+
let chatText = assistantText;
|
|
10783
|
+
if (exitCode !== 0 && !chatText && looksLikeAgentFailureMessage(detail)) {
|
|
10784
|
+
chatText = humanizeAgentFailDetail(detail);
|
|
10785
|
+
}
|
|
10786
|
+
if (chatText || parts.length > 0) {
|
|
10246
10787
|
appendMessage(threadId, {
|
|
10247
10788
|
role: "agent",
|
|
10248
|
-
text:
|
|
10789
|
+
text: chatText,
|
|
10249
10790
|
parts: parts.length > 0 ? parts : void 0,
|
|
10250
10791
|
durationMs: Math.max(0, Date.now() - turnStartedAt),
|
|
10251
10792
|
usage,
|
|
@@ -10264,13 +10805,12 @@ var Orchestrator = class {
|
|
|
10264
10805
|
this.emit({ type: "status_changed", threadId, status: "stopped" });
|
|
10265
10806
|
this.emit({ type: "turn_finished", threadId, exitCode });
|
|
10266
10807
|
} else {
|
|
10267
|
-
const lastStderr = summarizeTurnStderr(stderrTail);
|
|
10268
|
-
const detail = lastStderr || (exitCode !== 0 ? fallbackTurnFailDetail(assistantText) : "");
|
|
10269
10808
|
const failDetail = formatTurnExitError(exitCode, detail);
|
|
10809
|
+
const explainedInChat = exitCode !== 0 && Boolean(chatText) && (looksLikeAgentFailureMessage(chatText) || failDetail && chatText.includes(failDetail.replace(/^exit\s*\d+:\s*/i, "").trim()));
|
|
10270
10810
|
setStatus(
|
|
10271
10811
|
threadId,
|
|
10272
10812
|
exitCode === 0 ? "idle" : "error",
|
|
10273
|
-
exitCode === 0 ? null : failDetail
|
|
10813
|
+
exitCode === 0 || explainedInChat ? null : failDetail
|
|
10274
10814
|
);
|
|
10275
10815
|
this.emit({
|
|
10276
10816
|
type: "status_changed",
|
|
@@ -10278,6 +10818,10 @@ var Orchestrator = class {
|
|
|
10278
10818
|
status: exitCode === 0 ? "idle" : "error"
|
|
10279
10819
|
});
|
|
10280
10820
|
this.emit({ type: "turn_finished", threadId, exitCode });
|
|
10821
|
+
if (exitCode !== 0) {
|
|
10822
|
+
const blob = [chatText, detail].filter(Boolean).join("\n");
|
|
10823
|
+
void this.maybeHandleOrchestrationQuotaFailover(threadId, blob);
|
|
10824
|
+
}
|
|
10281
10825
|
}
|
|
10282
10826
|
} catch (err) {
|
|
10283
10827
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -10291,6 +10835,7 @@ var Orchestrator = class {
|
|
|
10291
10835
|
this.emit({ type: "error", threadId, message });
|
|
10292
10836
|
this.emit({ type: "status_changed", threadId, status: "error" });
|
|
10293
10837
|
this.emit({ type: "turn_finished", threadId, exitCode: 1 });
|
|
10838
|
+
void this.maybeHandleOrchestrationQuotaFailover(threadId, message);
|
|
10294
10839
|
}
|
|
10295
10840
|
} finally {
|
|
10296
10841
|
this.startingTurns.delete(threadId);
|
|
@@ -10751,6 +11296,15 @@ var Orchestrator = class {
|
|
|
10751
11296
|
setAutonomy(threadRef, autonomy) {
|
|
10752
11297
|
return this.setThreadOptions(threadRef, { autonomy });
|
|
10753
11298
|
}
|
|
11299
|
+
/**
|
|
11300
|
+
* Open a Review chat tab on a worktree thread (same as the desktop Review button)
|
|
11301
|
+
* and send the merge-readiness prefill.
|
|
11302
|
+
*/
|
|
11303
|
+
async requestReview(threadRef) {
|
|
11304
|
+
const { tab } = await requestReview(threadRef, (ref, prompt) => this.send(ref, prompt));
|
|
11305
|
+
this.emit({ type: "status_changed", threadId: tab.id, status: tab.status });
|
|
11306
|
+
return tab;
|
|
11307
|
+
}
|
|
10754
11308
|
setThreadOptions(threadRef, patch) {
|
|
10755
11309
|
const thread = this.requireThread(threadRef);
|
|
10756
11310
|
const next = {};
|
|
@@ -10875,7 +11429,7 @@ var Orchestrator = class {
|
|
|
10875
11429
|
updateThread(thread.id, { worktreePath: globalAgentCwd2() });
|
|
10876
11430
|
return setStatus(thread.id, "idle");
|
|
10877
11431
|
}
|
|
10878
|
-
if (!(0,
|
|
11432
|
+
if (!(0, import_node_fs26.existsSync)(thread.worktreePath)) {
|
|
10879
11433
|
const { createThreadWorktree: createThreadWorktree2 } = await Promise.resolve().then(() => (init_worktree(), worktree_exports));
|
|
10880
11434
|
const { execa: execa7 } = await import("execa");
|
|
10881
11435
|
const slug = thread.worktreePath.split("/").pop();
|
|
@@ -10989,9 +11543,10 @@ init_coordinator_prompt();
|
|
|
10989
11543
|
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
10990
11544
|
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
10991
11545
|
var import_zod = require("zod");
|
|
10992
|
-
var
|
|
11546
|
+
var import_node_path25 = require("path");
|
|
10993
11547
|
init_worktree();
|
|
10994
11548
|
init_global_workspace();
|
|
11549
|
+
init_list_models();
|
|
10995
11550
|
|
|
10996
11551
|
// src/mcp/archive-guard.ts
|
|
10997
11552
|
init_global_workspace();
|
|
@@ -11037,7 +11592,7 @@ async function startMcpServer() {
|
|
|
11037
11592
|
async () => {
|
|
11038
11593
|
const threads = orch.getThreads(true);
|
|
11039
11594
|
const lines = threads.map((t) => {
|
|
11040
|
-
const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0,
|
|
11595
|
+
const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path25.basename)(t.repoPath) || t.repoPath;
|
|
11041
11596
|
return `${t.id.slice(0, 8)} ${t.status.padEnd(9)} ${t.agent.padEnd(8)} ${repo} ${t.sourceType}:${t.sourceRef} ${t.title} sideboard://thread/${t.id}${t.devPort ? ` http://localhost:${t.devPort}` : ""}`;
|
|
11042
11597
|
});
|
|
11043
11598
|
return {
|
|
@@ -11380,6 +11935,148 @@ async function startMcpServer() {
|
|
|
11380
11935
|
};
|
|
11381
11936
|
}
|
|
11382
11937
|
);
|
|
11938
|
+
server.tool(
|
|
11939
|
+
"request_review",
|
|
11940
|
+
"Start a merge-readiness Review on a worktree agent thread (same as the desktop Review button). Opens a new Review chat tab, optionally attaches .sideboard/attachments/Review request.md when present, and asks for Approve / Approve with nits / Request changes / Needs more information. Pass a worktree thread ref \u2014 not the orchestrator. Then wait_for_turn / get_turn_result on the returned review tab id.",
|
|
11941
|
+
{ ref: import_zod.z.string().describe("Worktree thread id/ref to review") },
|
|
11942
|
+
async ({ ref }) => {
|
|
11943
|
+
try {
|
|
11944
|
+
const tab = await orch.requestReview(ref);
|
|
11945
|
+
const from = orch.getThread(ref);
|
|
11946
|
+
return {
|
|
11947
|
+
content: [
|
|
11948
|
+
{
|
|
11949
|
+
type: "text",
|
|
11950
|
+
text: JSON.stringify({
|
|
11951
|
+
id: tab.id,
|
|
11952
|
+
title: tab.title,
|
|
11953
|
+
status: tab.status,
|
|
11954
|
+
fromThreadId: from?.id ?? ref,
|
|
11955
|
+
link: `sideboard://thread/${tab.id}`
|
|
11956
|
+
})
|
|
11957
|
+
}
|
|
11958
|
+
]
|
|
11959
|
+
};
|
|
11960
|
+
} catch (err) {
|
|
11961
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
11962
|
+
return { content: [{ type: "text", text: message }], isError: true };
|
|
11963
|
+
}
|
|
11964
|
+
}
|
|
11965
|
+
);
|
|
11966
|
+
const agentEnum = import_zod.z.enum(["claude", "codex", "opencode", "brightsy", "cursor"]);
|
|
11967
|
+
server.tool(
|
|
11968
|
+
"list_models",
|
|
11969
|
+
"List models for an agent. Prefer Auto: do not call this unless you have a reason to pin a specific model (user request, cost/latency, capability). Omit agent to list all.",
|
|
11970
|
+
{
|
|
11971
|
+
agent: agentEnum.optional().describe("Limit to one agent; omit for all")
|
|
11972
|
+
},
|
|
11973
|
+
async ({ agent }) => {
|
|
11974
|
+
try {
|
|
11975
|
+
const catalogs = await listModelsForAgent(agent);
|
|
11976
|
+
return {
|
|
11977
|
+
content: [{ type: "text", text: JSON.stringify(catalogs, null, 2) }]
|
|
11978
|
+
};
|
|
11979
|
+
} catch (err) {
|
|
11980
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
11981
|
+
return { content: [{ type: "text", text: message }], isError: true };
|
|
11982
|
+
}
|
|
11983
|
+
}
|
|
11984
|
+
);
|
|
11985
|
+
server.tool(
|
|
11986
|
+
"fork_worktree",
|
|
11987
|
+
"Fork a worktree agent chat into a NEW git worktree + chat (desktop \u201CFork to new workspace\u201D). Seeds a transcript (through through_index, default all). Optional agent override. Leave model unset for Auto (default) \u2014 only pass model when you have a reason. Not for the orchestrator. Then send_to_thread / wait_for_turn on the returned id.",
|
|
11988
|
+
{
|
|
11989
|
+
ref: import_zod.z.string().describe("Worktree thread id/ref to fork"),
|
|
11990
|
+
through_index: import_zod.z.number().optional().describe("Inclusive message index to include in the transcript (default: all)"),
|
|
11991
|
+
agent: agentEnum.optional().describe("Agent for the forked chat (default: same as source)"),
|
|
11992
|
+
model: import_zod.z.string().nullable().optional().describe("Usually omit (Auto). Only set from list_models when you need a specific model"),
|
|
11993
|
+
title: import_zod.z.string().optional()
|
|
11994
|
+
},
|
|
11995
|
+
async ({ ref, through_index, agent, model, title }) => {
|
|
11996
|
+
try {
|
|
11997
|
+
const source = orch.getThread(ref);
|
|
11998
|
+
if (source) await orch.reconcile(source.repoPath);
|
|
11999
|
+
const thread = await orch.forkThreadWorktree({
|
|
12000
|
+
threadId: ref,
|
|
12001
|
+
throughIndex: through_index,
|
|
12002
|
+
agent,
|
|
12003
|
+
model,
|
|
12004
|
+
title
|
|
12005
|
+
});
|
|
12006
|
+
return {
|
|
12007
|
+
content: [
|
|
12008
|
+
{
|
|
12009
|
+
type: "text",
|
|
12010
|
+
text: JSON.stringify({
|
|
12011
|
+
id: thread.id,
|
|
12012
|
+
title: thread.title,
|
|
12013
|
+
status: thread.status,
|
|
12014
|
+
agent: thread.agent,
|
|
12015
|
+
model: thread.model,
|
|
12016
|
+
branchName: thread.branchName,
|
|
12017
|
+
worktreePath: thread.worktreePath,
|
|
12018
|
+
fromThreadId: source?.id ?? ref,
|
|
12019
|
+
link: `sideboard://thread/${thread.id}`
|
|
12020
|
+
})
|
|
12021
|
+
}
|
|
12022
|
+
]
|
|
12023
|
+
};
|
|
12024
|
+
} catch (err) {
|
|
12025
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
12026
|
+
return { content: [{ type: "text", text: message }], isError: true };
|
|
12027
|
+
}
|
|
12028
|
+
}
|
|
12029
|
+
);
|
|
12030
|
+
server.tool(
|
|
12031
|
+
"fork_chat",
|
|
12032
|
+
"Fork a chat into a NEW tab on the SAME workspace: worktree agent \u2192 same worktree tab; Global orchestration chat \u2192 new orchestration chat (same synthetic home). Seeds a transcript; optional agent override. Leave model unset for Auto unless you have a reason. Remote coordinators use this to continue an orchestration chat on another agent after session limits. Then send_to_thread / wait_for_turn on the returned id. Use fork_worktree only for worktree agents that need a new git worktree.",
|
|
12033
|
+
{
|
|
12034
|
+
ref: import_zod.z.string().describe("Thread id/ref to fork (worktree agent or orchestration chat)"),
|
|
12035
|
+
through_index: import_zod.z.number().optional().describe("Inclusive message index to include in the transcript (default: all)"),
|
|
12036
|
+
agent: agentEnum.optional().describe("Agent for the forked chat (default: same as source)"),
|
|
12037
|
+
model: import_zod.z.string().nullable().optional().describe("Usually omit (Auto). Only set from list_models when you need a specific model"),
|
|
12038
|
+
title: import_zod.z.string().optional()
|
|
12039
|
+
},
|
|
12040
|
+
async ({ ref, through_index, agent, model, title }) => {
|
|
12041
|
+
try {
|
|
12042
|
+
const source = orch.getThread(ref);
|
|
12043
|
+
if (!source) {
|
|
12044
|
+
return {
|
|
12045
|
+
content: [{ type: "text", text: `Thread not found: ${ref}` }],
|
|
12046
|
+
isError: true
|
|
12047
|
+
};
|
|
12048
|
+
}
|
|
12049
|
+
const tab = orch.forkChatTab({
|
|
12050
|
+
threadId: source.id,
|
|
12051
|
+
throughIndex: through_index,
|
|
12052
|
+
agent,
|
|
12053
|
+
model,
|
|
12054
|
+
title
|
|
12055
|
+
});
|
|
12056
|
+
return {
|
|
12057
|
+
content: [
|
|
12058
|
+
{
|
|
12059
|
+
type: "text",
|
|
12060
|
+
text: JSON.stringify({
|
|
12061
|
+
id: tab.id,
|
|
12062
|
+
title: tab.title,
|
|
12063
|
+
status: tab.status,
|
|
12064
|
+
agent: tab.agent,
|
|
12065
|
+
model: tab.model,
|
|
12066
|
+
sourceType: tab.sourceType,
|
|
12067
|
+
worktreePath: tab.worktreePath,
|
|
12068
|
+
fromThreadId: source.id,
|
|
12069
|
+
link: `sideboard://thread/${tab.id}`
|
|
12070
|
+
})
|
|
12071
|
+
}
|
|
12072
|
+
]
|
|
12073
|
+
};
|
|
12074
|
+
} catch (err) {
|
|
12075
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
12076
|
+
return { content: [{ type: "text", text: message }], isError: true };
|
|
12077
|
+
}
|
|
12078
|
+
}
|
|
12079
|
+
);
|
|
11383
12080
|
server.tool(
|
|
11384
12081
|
"run_dev_script",
|
|
11385
12082
|
"Start a .sideboard/.conductor run script for a thread (default script if name omitted); returns port",
|
|
@@ -11906,6 +12603,7 @@ init_injected_mcp();
|
|
|
11906
12603
|
0 && (module.exports = {
|
|
11907
12604
|
BRIGHTSY_MCP_ALLOWED_TOOLS,
|
|
11908
12605
|
BrightsySideboardApi,
|
|
12606
|
+
CLAUDE_MODEL_CATALOG,
|
|
11909
12607
|
CLOUD_COORDINATOR_BUSY_REPLY,
|
|
11910
12608
|
CLOUD_COORDINATOR_STOPPED_REPLY,
|
|
11911
12609
|
CLOUD_COORDINATOR_TIMEOUT_REPLY,
|
|
@@ -11923,6 +12621,9 @@ init_injected_mcp();
|
|
|
11923
12621
|
PASTE_ATTACH_MIN_CHARS,
|
|
11924
12622
|
PASTE_ATTACH_MIN_LINES,
|
|
11925
12623
|
PLAN_MODE_INSTRUCTION,
|
|
12624
|
+
REVIEW_REQUEST_NAME,
|
|
12625
|
+
REVIEW_REQUEST_PATH,
|
|
12626
|
+
REVIEW_REQUEST_PREFILL,
|
|
11926
12627
|
SIDEBOARD_FORCE_STOP,
|
|
11927
12628
|
SIDEBOARD_MCP_ALLOWED_TOOLS,
|
|
11928
12629
|
THINKING_EFFORTS,
|
|
@@ -11958,6 +12659,7 @@ init_injected_mcp();
|
|
|
11958
12659
|
buildDiffCommentAttachment,
|
|
11959
12660
|
buildForkTranscriptAttachment,
|
|
11960
12661
|
buildPastedTextAttachment,
|
|
12662
|
+
buildReviewRequestAttachment,
|
|
11961
12663
|
buildSessionSeed,
|
|
11962
12664
|
buildWorkspaceScriptEnv,
|
|
11963
12665
|
caffeinateWhileCloudConnectEnabled,
|
|
@@ -12078,6 +12780,7 @@ init_injected_mcp();
|
|
|
12078
12780
|
isOrchestratorThread,
|
|
12079
12781
|
isPidAlive,
|
|
12080
12782
|
isPlaceholderBranch,
|
|
12783
|
+
isSessionQuotaLimit,
|
|
12081
12784
|
isThinkingEffort,
|
|
12082
12785
|
listAgentSetupInfo,
|
|
12083
12786
|
listBranchCommits,
|
|
@@ -12093,6 +12796,7 @@ init_injected_mcp();
|
|
|
12093
12796
|
listIssues,
|
|
12094
12797
|
listLinearIssues,
|
|
12095
12798
|
listLinearIssuesDirect,
|
|
12799
|
+
listModelsForAgent,
|
|
12096
12800
|
listOpencodeModels,
|
|
12097
12801
|
listPrs,
|
|
12098
12802
|
listRunScripts,
|
|
@@ -12124,6 +12828,8 @@ init_injected_mcp();
|
|
|
12124
12828
|
normalizeWorktreePath,
|
|
12125
12829
|
openInSystemTerminal,
|
|
12126
12830
|
opencodeAdapter,
|
|
12831
|
+
orchestrationQuotaFallbackAgent,
|
|
12832
|
+
orchestrationQuotaOnLimit,
|
|
12127
12833
|
orchestrationTitleNeedsSoccerNickname,
|
|
12128
12834
|
orchestratorSessionPoisonedByBuiltins,
|
|
12129
12835
|
originGhRepoEnv,
|
|
@@ -12131,11 +12837,13 @@ init_injected_mcp();
|
|
|
12131
12837
|
parseForceStopMessage,
|
|
12132
12838
|
parseGithubSlugFromRemoteUrl,
|
|
12133
12839
|
parseMcpList,
|
|
12840
|
+
parseSessionQuotaResetAt,
|
|
12134
12841
|
partsToAssistantText,
|
|
12135
12842
|
pastedTextStats,
|
|
12136
12843
|
permissionMode,
|
|
12137
12844
|
previewLand,
|
|
12138
12845
|
pushBranch,
|
|
12846
|
+
readExistingReviewRequestFile,
|
|
12139
12847
|
readSkillBody,
|
|
12140
12848
|
readThread,
|
|
12141
12849
|
readWorktreeFile,
|
|
@@ -12145,6 +12853,7 @@ init_injected_mcp();
|
|
|
12145
12853
|
removeWorkspace,
|
|
12146
12854
|
removeWorktree,
|
|
12147
12855
|
repoSlug,
|
|
12856
|
+
requestReview,
|
|
12148
12857
|
requireAgent,
|
|
12149
12858
|
resolveClaudeExecutable,
|
|
12150
12859
|
resolveConductorCursorAgentId,
|
|
@@ -12155,6 +12864,7 @@ init_injected_mcp();
|
|
|
12155
12864
|
resolveFilesToCopy,
|
|
12156
12865
|
resolveGithubRepoSlug,
|
|
12157
12866
|
resolvePrSelector,
|
|
12867
|
+
resolveQuotaFallbackAgent,
|
|
12158
12868
|
resolveRepoRoot,
|
|
12159
12869
|
resolveThreadDefaults,
|
|
12160
12870
|
resolveThreadEffort,
|