@sideboard-ai/core 0.1.99 → 0.1.100
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 +22 -22
- package/dist/agents/cursor-runner.js +1 -1
- package/dist/{agents-ESJKIQQA.js → agents-CLP5BG4O.js} +3 -3
- package/dist/{agents-3MWWWSMF.js → agents-OXZDMPSE.js} +4 -4
- package/dist/{chunk-FYS2BULQ.js → chunk-EQPQTLW6.js} +209 -59
- package/dist/{chunk-FO67IJTY.js → chunk-GR4JKWR4.js} +1 -1
- package/dist/{chunk-GXSYI7FH.js → chunk-HUKCGRAT.js} +209 -59
- package/dist/{chunk-XUWDLRAE.js → chunk-HYKZEP5A.js} +2 -2
- package/dist/{chunk-XH2GS2LO.js → chunk-IFHKPZHA.js} +2 -2
- package/dist/{chunk-UYQYK2RY.js → chunk-MHJV4WS3.js} +1 -1
- package/dist/{chunk-OANJQTVG.js → chunk-MRBKGFTL.js} +1 -1
- package/dist/{chunk-MBP3XG57.js → chunk-OXC3MEFI.js} +3 -3
- package/dist/{chunk-HI2OTFFR.js → chunk-WQTTUC4N.js} +1 -1
- package/dist/{coordinator-prompt-AKEY4WSO.js → coordinator-prompt-HHRKQWCX.js} +1 -1
- package/dist/{coordinator-prompt-OQOOD5ET.js → coordinator-prompt-OOBSQCWQ.js} +1 -1
- package/dist/{global-workspace-RSQXRLT7.js → global-workspace-KYEBFWKB.js} +2 -2
- package/dist/{global-workspace-WMF3BJP5.js → global-workspace-YZWYHLQY.js} +2 -2
- package/dist/index.cjs +231 -85
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +29 -30
- package/dist/mcp/run-stdio.cjs +231 -85
- package/dist/mcp/run-stdio.js +28 -29
- package/dist/{workspaces-MZVQHRSJ.js → workspaces-ENVUDK6C.js} +3 -3
- package/dist/{workspaces-4ZY4QPWQ.js → workspaces-NNPD7QVV.js} +3 -3
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -5147,7 +5147,7 @@ function coordinatorTurnReminder(opts) {
|
|
|
5147
5147
|
goal ? `- Goal / title: ${goal}` : null,
|
|
5148
5148
|
accountDefaultsPlaybookLine(),
|
|
5149
5149
|
`- For "what's going on": call list_threads (and list_workspaces if needed). Summarize fleet status \u2014 do not ls/git-status this synthetic home.`,
|
|
5150
|
-
"- Existing repo: create_thread on a repoPath \u2192 send_to_thread \u2192 wait_for_turn. Commit/push/draft PR with ask_git on the child, then wait_for_turn \u2014 never git/gh from this cwd. Call ask_git merge only if the user explicitly asked to merge.",
|
|
5150
|
+
"- Existing repo: create_thread on a repoPath \u2192 send_to_thread \u2192 wait_for_turn. If status is error, lastError/text is the failure \u2014 adapt (switch agent, tell the user). Commit/push/draft PR with ask_git on the child, then wait_for_turn \u2014 never git/gh from this cwd. Call ask_git merge only if the user explicitly asked to merge.",
|
|
5151
5151
|
"- New repo: Bash (clone or gh repo create under ~/sideboard/repos/<name>) \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn \u2192 ask_git create-draft.",
|
|
5152
5152
|
"- When naming threads for the user, link them as `[Title](sideboard://thread/<id>)`.",
|
|
5153
5153
|
"- If they will wait on Slack or leave the Mac, call set_caffeinate enabled=true. When they say they are done / wrapping up / going to sleep, call set_caffeinate enabled=false. Closing this chat also turns it off."
|
|
@@ -5270,7 +5270,7 @@ var init_coordinator_prompt = __esm({
|
|
|
5270
5270
|
"- 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.",
|
|
5271
5271
|
"- 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.",
|
|
5272
5272
|
"- 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",
|
|
5273
|
-
"- wait_for_turn / get_turn_result \u2014 wait for and read the agent reply",
|
|
5273
|
+
"- wait_for_turn / get_turn_result \u2014 wait for and read the agent reply. On status error, lastError (and text) is the failure \u2014 switch agent, tell the user, or retry; do not treat empty text as success.",
|
|
5274
5274
|
"- stop_thread \u2014 force-stop: kill in-flight turn AND clear queued prompts (do not leave stale queue after an interrupt)",
|
|
5275
5275
|
"- archive_thread / restore_thread \u2014 archive (tears down worktree when last tab) or restore",
|
|
5276
5276
|
"Setup / run:",
|
|
@@ -6133,6 +6133,13 @@ function looksLikeMinifiedJsDump(line) {
|
|
|
6133
6133
|
function looksLikeNestedElectronCrash(line) {
|
|
6134
6134
|
return /HasCustomHostObject|ElectronInitializeICUandStartNode/i.test(line);
|
|
6135
6135
|
}
|
|
6136
|
+
function looksLikeHomebrewLibuvCrash(line) {
|
|
6137
|
+
const uvRun = /uv_run/i.test(line);
|
|
6138
|
+
const spin = /SpinEventLoopInternal/i.test(line);
|
|
6139
|
+
const homebrewUv = /Cellar\/libuv|libuv\.\d\.dylib/i.test(line);
|
|
6140
|
+
const homebrewNode = /Cellar\/node\//i.test(line);
|
|
6141
|
+
return uvRun && (homebrewUv || spin || homebrewNode) || spin && (homebrewUv || homebrewNode);
|
|
6142
|
+
}
|
|
6136
6143
|
function clipStderr(text3, maxChars) {
|
|
6137
6144
|
const trimmed = text3.trim();
|
|
6138
6145
|
if (trimmed.length <= maxChars) return trimmed;
|
|
@@ -6143,6 +6150,7 @@ function summarizeTurnStderr(tail, maxChars = 500) {
|
|
|
6143
6150
|
const cursorStartup = [...tail].reverse().find((line) => /cursor startup failed:/i.test(line));
|
|
6144
6151
|
if (cursorStartup) return clipStderr(cursorStartup, maxChars);
|
|
6145
6152
|
if (tail.some(looksLikeNestedElectronCrash)) return NESTED_ELECTRON_SUMMARY;
|
|
6153
|
+
if (tail.some(looksLikeHomebrewLibuvCrash)) return HOMEBREW_LIBUV_SUMMARY;
|
|
6146
6154
|
if (tail.some(
|
|
6147
6155
|
(line) => /\[resource_exhausted\]|resource_exhausted/i.test(line) || /findFilesWithRipgrep/.test(line)
|
|
6148
6156
|
)) {
|
|
@@ -6165,6 +6173,20 @@ function looksLikeInvalidAgentSession(text3) {
|
|
|
6165
6173
|
if (!lower) return false;
|
|
6166
6174
|
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);
|
|
6167
6175
|
}
|
|
6176
|
+
function looksLikeRetryableRunnerCrash(text3) {
|
|
6177
|
+
if (looksLikeAgentFailureMessage(text3)) return false;
|
|
6178
|
+
if (looksLikeInvalidAgentSession(text3)) return false;
|
|
6179
|
+
const lower = text3.trim().toLowerCase();
|
|
6180
|
+
if (/cannot find (?:package|module)|err_module_not_found/.test(lower)) return false;
|
|
6181
|
+
if (!lower) return true;
|
|
6182
|
+
return /uv_run|spineventloopinternal|libuv|homebrew node \+ shared libuv|hascustomhostobject|electroninitializeicuandstartnode|nested chromium|truncated crash dump|sig(?:segv|abrt|ill)|segmentation fault|illegal instruction|fatal error/.test(
|
|
6183
|
+
lower
|
|
6184
|
+
);
|
|
6185
|
+
}
|
|
6186
|
+
function shouldRetryFailedAgentTurn(detail, opts) {
|
|
6187
|
+
if (looksLikeInvalidAgentSession(detail) && opts.hasSession) return true;
|
|
6188
|
+
return looksLikeRetryableRunnerCrash(detail);
|
|
6189
|
+
}
|
|
6168
6190
|
function looksLikeAgentFailureMessage(text3) {
|
|
6169
6191
|
const lower = text3.trim().toLowerCase();
|
|
6170
6192
|
if (!lower) return false;
|
|
@@ -6209,11 +6231,22 @@ function humanizeAgentFailDetail(detail) {
|
|
|
6209
6231
|
if (/hascustomhostobject|electroninitializeicuandstartnode|nested chromium/i.test(lower)) {
|
|
6210
6232
|
return `${raw} \u2014 retry the turn; if it keeps failing, pick another agent.`;
|
|
6211
6233
|
}
|
|
6234
|
+
if (/homebrew node \+ shared libuv|uv_run|spineventloopinternal/i.test(lower)) {
|
|
6235
|
+
return /brew install node@22/i.test(raw) ? raw : `${raw} \u2014 install Node 22 LTS (\`brew install node@22\`) and retry.`;
|
|
6236
|
+
}
|
|
6212
6237
|
if (/corrupt local agent checkpoint|missing root blob|truncated crash dump/.test(lower)) {
|
|
6213
6238
|
return `${raw} \u2014 retry the turn (Sideboard will start a fresh Cursor session).`;
|
|
6214
6239
|
}
|
|
6215
6240
|
return raw;
|
|
6216
6241
|
}
|
|
6242
|
+
function turnFailChatText(opts) {
|
|
6243
|
+
const chat = opts.assistantText.trim();
|
|
6244
|
+
if (chat) return chat;
|
|
6245
|
+
if (opts.exitCode === 0) return "";
|
|
6246
|
+
const detail = opts.detail.trim();
|
|
6247
|
+
if (detail) return humanizeAgentFailDetail(detail);
|
|
6248
|
+
return formatTurnExitError(opts.exitCode ?? 1, "");
|
|
6249
|
+
}
|
|
6217
6250
|
function formatTurnExitError(exitCode, stderrSummary) {
|
|
6218
6251
|
const code = exitCode ?? 1;
|
|
6219
6252
|
const raw = stderrSummary.trim();
|
|
@@ -6227,12 +6260,13 @@ function formatTurnExitError(exitCode, stderrSummary) {
|
|
|
6227
6260
|
if (looksLikeAgentFailureMessage(raw)) return detail;
|
|
6228
6261
|
return `exit ${code}: ${detail}`;
|
|
6229
6262
|
}
|
|
6230
|
-
var NODE_VERSION_FOOTER, NESTED_ELECTRON_SUMMARY, MINIFIED_DUMP_SUMMARY;
|
|
6263
|
+
var NODE_VERSION_FOOTER, NESTED_ELECTRON_SUMMARY, HOMEBREW_LIBUV_SUMMARY, MINIFIED_DUMP_SUMMARY;
|
|
6231
6264
|
var init_error_detail = __esm({
|
|
6232
6265
|
"src/agents/error-detail.ts"() {
|
|
6233
6266
|
"use strict";
|
|
6234
6267
|
NODE_VERSION_FOOTER = /^Node\.js v\d+/i;
|
|
6235
6268
|
NESTED_ELECTRON_SUMMARY = "Cursor local agent crashed at Electron startup (nested Chromium / HasCustomHostObject)";
|
|
6269
|
+
HOMEBREW_LIBUV_SUMMARY = "Cursor runner crashed in Node (Homebrew Node + shared libuv). Install Node 22 LTS (`brew install node@22`) and retry.";
|
|
6236
6270
|
MINIFIED_DUMP_SUMMARY = "Cursor local agent crashed during startup (truncated crash dump)";
|
|
6237
6271
|
}
|
|
6238
6272
|
});
|
|
@@ -6673,6 +6707,55 @@ var init_profile = __esm({
|
|
|
6673
6707
|
}
|
|
6674
6708
|
});
|
|
6675
6709
|
|
|
6710
|
+
// src/agents/packaged-runtime.ts
|
|
6711
|
+
function electronResourcesPath() {
|
|
6712
|
+
const resources = process.resourcesPath;
|
|
6713
|
+
if (typeof resources !== "string" || !resources) return null;
|
|
6714
|
+
return resources;
|
|
6715
|
+
}
|
|
6716
|
+
function packagedCursorRuntimeDir() {
|
|
6717
|
+
const resources = electronResourcesPath();
|
|
6718
|
+
if (!resources) return null;
|
|
6719
|
+
const dir = (0, import_node_path19.join)(resources, "cursor-runtime");
|
|
6720
|
+
if (!(0, import_node_fs19.existsSync)((0, import_node_path19.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
|
|
6721
|
+
return dir;
|
|
6722
|
+
}
|
|
6723
|
+
function packagedCursorRunnerPath() {
|
|
6724
|
+
const dir = packagedCursorRuntimeDir();
|
|
6725
|
+
return dir ? (0, import_node_path19.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
|
|
6726
|
+
}
|
|
6727
|
+
function packagedMcpDir() {
|
|
6728
|
+
const resources = electronResourcesPath();
|
|
6729
|
+
if (!resources) return null;
|
|
6730
|
+
const dir = (0, import_node_path19.join)(resources, "sideboard-mcp");
|
|
6731
|
+
if (!(0, import_node_fs19.existsSync)((0, import_node_path19.join)(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
|
|
6732
|
+
return dir;
|
|
6733
|
+
}
|
|
6734
|
+
function packagedMcpStdioPath() {
|
|
6735
|
+
const dir = packagedMcpDir();
|
|
6736
|
+
return dir ? (0, import_node_path19.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
|
|
6737
|
+
}
|
|
6738
|
+
function packagedBundledNodePath() {
|
|
6739
|
+
const resources = electronResourcesPath();
|
|
6740
|
+
if (!resources) return null;
|
|
6741
|
+
const bin = (0, import_node_path19.join)(resources, "node", "bin", "node");
|
|
6742
|
+
if (!(0, import_node_fs19.existsSync)(bin)) return null;
|
|
6743
|
+
return bin;
|
|
6744
|
+
}
|
|
6745
|
+
function packagedCursorRipgrepCandidate(platformPkg, binName) {
|
|
6746
|
+
const dir = packagedCursorRuntimeDir();
|
|
6747
|
+
if (!dir) return null;
|
|
6748
|
+
return (0, import_node_path19.join)(dir, "node_modules", platformPkg, "bin", binName);
|
|
6749
|
+
}
|
|
6750
|
+
var import_node_fs19, import_node_path19;
|
|
6751
|
+
var init_packaged_runtime = __esm({
|
|
6752
|
+
"src/agents/packaged-runtime.ts"() {
|
|
6753
|
+
"use strict";
|
|
6754
|
+
import_node_fs19 = require("fs");
|
|
6755
|
+
import_node_path19 = require("path");
|
|
6756
|
+
}
|
|
6757
|
+
});
|
|
6758
|
+
|
|
6676
6759
|
// src/agents/node-launch.ts
|
|
6677
6760
|
function isAsarPath(filePath) {
|
|
6678
6761
|
if (/\.asar\.unpacked([/\\]|$)/.test(filePath)) return false;
|
|
@@ -6682,24 +6765,129 @@ function unpackedAsarPath(filePath) {
|
|
|
6682
6765
|
if (!isAsarPath(filePath)) return null;
|
|
6683
6766
|
const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
|
|
6684
6767
|
if (unpacked === filePath) return null;
|
|
6685
|
-
return (0,
|
|
6768
|
+
return (0, import_node_fs20.existsSync)(unpacked) ? unpacked : null;
|
|
6686
6769
|
}
|
|
6687
6770
|
function nodeReadableScriptPath(scriptPath) {
|
|
6688
6771
|
return unpackedAsarPath(scriptPath) ?? scriptPath;
|
|
6689
6772
|
}
|
|
6690
|
-
|
|
6691
|
-
const
|
|
6692
|
-
|
|
6693
|
-
|
|
6694
|
-
|
|
6695
|
-
|
|
6696
|
-
|
|
6697
|
-
|
|
6773
|
+
function parseNodeMajor(version) {
|
|
6774
|
+
const match = /^v?(\d+)/.exec(version.trim());
|
|
6775
|
+
if (!match) return null;
|
|
6776
|
+
const major = Number(match[1]);
|
|
6777
|
+
return Number.isInteger(major) ? major : null;
|
|
6778
|
+
}
|
|
6779
|
+
function scoreNodeForAgentRuntime(candidate) {
|
|
6780
|
+
const major = parseNodeMajor(candidate.version);
|
|
6781
|
+
if (major == null) return Number.NEGATIVE_INFINITY;
|
|
6782
|
+
if (major < 20) return major - 100;
|
|
6783
|
+
const posix = candidate.path.replace(/\\/g, "/");
|
|
6784
|
+
let score = 0;
|
|
6785
|
+
if (major % 2 === 0) {
|
|
6786
|
+
score += 1e3 + major * 10;
|
|
6787
|
+
} else {
|
|
6788
|
+
score += major;
|
|
6789
|
+
}
|
|
6790
|
+
if (/\/Cellar\/node\/\d/.test(posix) && !/\/Cellar\/node@\d+/.test(posix)) {
|
|
6791
|
+
score -= 50;
|
|
6792
|
+
}
|
|
6793
|
+
return score;
|
|
6794
|
+
}
|
|
6795
|
+
function pickPreferredNode(candidates) {
|
|
6796
|
+
let best = null;
|
|
6797
|
+
let bestScore = Number.NEGATIVE_INFINITY;
|
|
6798
|
+
for (const candidate of candidates) {
|
|
6799
|
+
const score = scoreNodeForAgentRuntime(candidate);
|
|
6800
|
+
if (score > bestScore) {
|
|
6801
|
+
bestScore = score;
|
|
6802
|
+
best = candidate;
|
|
6803
|
+
}
|
|
6804
|
+
}
|
|
6805
|
+
return best;
|
|
6806
|
+
}
|
|
6807
|
+
function versionDirNodeBins(root, toBin) {
|
|
6808
|
+
if (!(0, import_node_fs20.existsSync)(root)) return [];
|
|
6809
|
+
try {
|
|
6810
|
+
return (0, import_node_fs20.readdirSync)(root).map(toBin);
|
|
6811
|
+
} catch {
|
|
6812
|
+
return [];
|
|
6813
|
+
}
|
|
6814
|
+
}
|
|
6815
|
+
function defaultNodeBinCandidates(home = (0, import_node_os7.homedir)()) {
|
|
6816
|
+
const kegs = ["/opt/homebrew", "/usr/local"].flatMap(
|
|
6817
|
+
(prefix) => PREFERRED_LTS_MAJORS.map((major) => (0, import_node_path20.join)(prefix, "opt", `node@${major}`, "bin", "node"))
|
|
6818
|
+
);
|
|
6819
|
+
return [
|
|
6820
|
+
...kegs,
|
|
6821
|
+
"/opt/homebrew/bin/node",
|
|
6822
|
+
"/usr/local/bin/node",
|
|
6823
|
+
(0, import_node_path20.join)(home, ".local/share/fnm/aliases/default/bin/node"),
|
|
6824
|
+
(0, import_node_path20.join)(home, ".nvm/current/bin/node"),
|
|
6825
|
+
(0, import_node_path20.join)(home, ".volta/bin/node"),
|
|
6826
|
+
(0, import_node_path20.join)(home, ".asdf/shims/node"),
|
|
6827
|
+
(0, import_node_path20.join)(home, ".local/share/mise/shims/node"),
|
|
6828
|
+
...versionDirNodeBins(
|
|
6829
|
+
(0, import_node_path20.join)(home, ".nvm", "versions", "node"),
|
|
6830
|
+
(name) => (0, import_node_path20.join)(home, ".nvm", "versions", "node", name, "bin", "node")
|
|
6831
|
+
),
|
|
6832
|
+
...versionDirNodeBins(
|
|
6833
|
+
(0, import_node_path20.join)(home, ".local/share/fnm", "node-versions"),
|
|
6834
|
+
(name) => (0, import_node_path20.join)(home, ".local/share/fnm", "node-versions", name, "installation", "bin", "node")
|
|
6835
|
+
),
|
|
6836
|
+
...versionDirNodeBins(
|
|
6837
|
+
(0, import_node_path20.join)(home, ".volta", "tools", "image", "node"),
|
|
6838
|
+
(name) => (0, import_node_path20.join)(home, ".volta", "tools", "image", "node", name, "bin", "node")
|
|
6839
|
+
)
|
|
6698
6840
|
];
|
|
6699
|
-
|
|
6700
|
-
|
|
6841
|
+
}
|
|
6842
|
+
function uniqueExistingNodeBins(paths) {
|
|
6843
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6844
|
+
const out = [];
|
|
6845
|
+
for (const raw of paths) {
|
|
6846
|
+
const p = raw.trim();
|
|
6847
|
+
if (!p || !(0, import_node_fs20.existsSync)(p) || isElectronLikeCommand(p)) continue;
|
|
6848
|
+
let key = p;
|
|
6849
|
+
try {
|
|
6850
|
+
key = (0, import_node_fs20.realpathSync)(p);
|
|
6851
|
+
} catch {
|
|
6852
|
+
continue;
|
|
6853
|
+
}
|
|
6854
|
+
if (seen.has(key)) continue;
|
|
6855
|
+
seen.add(key);
|
|
6856
|
+
out.push(p);
|
|
6701
6857
|
}
|
|
6702
|
-
return
|
|
6858
|
+
return out;
|
|
6859
|
+
}
|
|
6860
|
+
async function whichAllNode() {
|
|
6861
|
+
if (process.platform === "win32") {
|
|
6862
|
+
const located = await run("where", ["node"], { reject: false, timeoutMs: 5e3 });
|
|
6863
|
+
if (located.exitCode !== 0) return [];
|
|
6864
|
+
return located.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
6865
|
+
}
|
|
6866
|
+
const all = await run("which", ["-a", "node"], { reject: false, timeoutMs: 5e3 });
|
|
6867
|
+
if (all.exitCode === 0 && all.stdout.trim()) {
|
|
6868
|
+
return all.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
6869
|
+
}
|
|
6870
|
+
const single = await run("which", ["node"], { reject: false, timeoutMs: 5e3 });
|
|
6871
|
+
if (single.exitCode !== 0 || !single.stdout.trim()) return [];
|
|
6872
|
+
return [single.stdout.trim()];
|
|
6873
|
+
}
|
|
6874
|
+
async function probeNodeVersion(bin) {
|
|
6875
|
+
const probed = await run(bin, ["-v"], { reject: false, timeoutMs: 4e3 });
|
|
6876
|
+
if (probed.exitCode !== 0) return null;
|
|
6877
|
+
const version = probed.stdout.trim().split(/\r?\n/).find(Boolean);
|
|
6878
|
+
return version || null;
|
|
6879
|
+
}
|
|
6880
|
+
async function findSystemNode() {
|
|
6881
|
+
const fromPath = await whichAllNode();
|
|
6882
|
+
const bins = uniqueExistingNodeBins([...fromPath, ...defaultNodeBinCandidates()]);
|
|
6883
|
+
if (bins.length === 0) return null;
|
|
6884
|
+
const probed = await Promise.all(
|
|
6885
|
+
bins.map(async (path2) => {
|
|
6886
|
+
const version = await probeNodeVersion(path2);
|
|
6887
|
+
return version ? { path: path2, version } : null;
|
|
6888
|
+
})
|
|
6889
|
+
);
|
|
6890
|
+
return pickPreferredNode(probed.filter((c) => c != null));
|
|
6703
6891
|
}
|
|
6704
6892
|
function applyNodeLaunch(launch, args) {
|
|
6705
6893
|
const readableArgs = args.map(nodeReadableScriptPath);
|
|
@@ -6717,9 +6905,13 @@ function applyNodeLaunch(launch, args) {
|
|
|
6717
6905
|
async function resolveNodeLaunch(scriptPath) {
|
|
6718
6906
|
const script = nodeReadableScriptPath(scriptPath);
|
|
6719
6907
|
if (!isAsarPath(script)) {
|
|
6720
|
-
const
|
|
6721
|
-
if (
|
|
6722
|
-
return { file:
|
|
6908
|
+
const bundled = packagedBundledNodePath();
|
|
6909
|
+
if (bundled && !isElectronLikeCommand(bundled)) {
|
|
6910
|
+
return { file: bundled, env: {} };
|
|
6911
|
+
}
|
|
6912
|
+
const node = await findSystemNode();
|
|
6913
|
+
if (node) {
|
|
6914
|
+
return { file: node.path, env: {}, nodeVersion: node.version };
|
|
6723
6915
|
}
|
|
6724
6916
|
}
|
|
6725
6917
|
return {
|
|
@@ -6727,61 +6919,17 @@ async function resolveNodeLaunch(scriptPath) {
|
|
|
6727
6919
|
env: { ELECTRON_RUN_AS_NODE: "1" }
|
|
6728
6920
|
};
|
|
6729
6921
|
}
|
|
6730
|
-
var
|
|
6922
|
+
var import_node_fs20, import_node_os7, import_node_path20, PREFERRED_LTS_MAJORS;
|
|
6731
6923
|
var init_node_launch = __esm({
|
|
6732
6924
|
"src/agents/node-launch.ts"() {
|
|
6733
6925
|
"use strict";
|
|
6734
|
-
|
|
6926
|
+
import_node_fs20 = require("fs");
|
|
6735
6927
|
import_node_os7 = require("os");
|
|
6736
|
-
|
|
6928
|
+
import_node_path20 = require("path");
|
|
6737
6929
|
init_nested_electron_env();
|
|
6738
6930
|
init_run();
|
|
6739
|
-
|
|
6740
|
-
|
|
6741
|
-
"/usr/local/bin/node"
|
|
6742
|
-
];
|
|
6743
|
-
}
|
|
6744
|
-
});
|
|
6745
|
-
|
|
6746
|
-
// src/agents/packaged-runtime.ts
|
|
6747
|
-
function electronResourcesPath() {
|
|
6748
|
-
const resources = process.resourcesPath;
|
|
6749
|
-
if (typeof resources !== "string" || !resources) return null;
|
|
6750
|
-
return resources;
|
|
6751
|
-
}
|
|
6752
|
-
function packagedCursorRuntimeDir() {
|
|
6753
|
-
const resources = electronResourcesPath();
|
|
6754
|
-
if (!resources) return null;
|
|
6755
|
-
const dir = (0, import_node_path20.join)(resources, "cursor-runtime");
|
|
6756
|
-
if (!(0, import_node_fs20.existsSync)((0, import_node_path20.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
|
|
6757
|
-
return dir;
|
|
6758
|
-
}
|
|
6759
|
-
function packagedCursorRunnerPath() {
|
|
6760
|
-
const dir = packagedCursorRuntimeDir();
|
|
6761
|
-
return dir ? (0, import_node_path20.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
|
|
6762
|
-
}
|
|
6763
|
-
function packagedMcpDir() {
|
|
6764
|
-
const resources = electronResourcesPath();
|
|
6765
|
-
if (!resources) return null;
|
|
6766
|
-
const dir = (0, import_node_path20.join)(resources, "sideboard-mcp");
|
|
6767
|
-
if (!(0, import_node_fs20.existsSync)((0, import_node_path20.join)(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
|
|
6768
|
-
return dir;
|
|
6769
|
-
}
|
|
6770
|
-
function packagedMcpStdioPath() {
|
|
6771
|
-
const dir = packagedMcpDir();
|
|
6772
|
-
return dir ? (0, import_node_path20.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
|
|
6773
|
-
}
|
|
6774
|
-
function packagedCursorRipgrepCandidate(platformPkg, binName) {
|
|
6775
|
-
const dir = packagedCursorRuntimeDir();
|
|
6776
|
-
if (!dir) return null;
|
|
6777
|
-
return (0, import_node_path20.join)(dir, "node_modules", platformPkg, "bin", binName);
|
|
6778
|
-
}
|
|
6779
|
-
var import_node_fs20, import_node_path20;
|
|
6780
|
-
var init_packaged_runtime = __esm({
|
|
6781
|
-
"src/agents/packaged-runtime.ts"() {
|
|
6782
|
-
"use strict";
|
|
6783
|
-
import_node_fs20 = require("fs");
|
|
6784
|
-
import_node_path20 = require("path");
|
|
6931
|
+
init_packaged_runtime();
|
|
6932
|
+
PREFERRED_LTS_MAJORS = [24, 22, 20];
|
|
6785
6933
|
}
|
|
6786
6934
|
});
|
|
6787
6935
|
|
|
@@ -16133,19 +16281,16 @@ var Orchestrator = class {
|
|
|
16133
16281
|
}
|
|
16134
16282
|
let lastStderr = summarizeTurnStderr(stderrTail);
|
|
16135
16283
|
let detail = lastStderr || (exitCode !== 0 ? fallbackTurnFailDetail(assistantText) : "");
|
|
16136
|
-
if (exitCode !== 0 && !assistantText && parts.length === 0 && !this.stoppedTurns.has(threadId) &&
|
|
16284
|
+
if (exitCode !== 0 && !assistantText && parts.length === 0 && !this.stoppedTurns.has(threadId) && this.requireThread(threadId).agent !== "brightsy" && shouldRetryFailedAgentTurn(detail, {
|
|
16285
|
+
hasSession: Boolean(this.requireThread(threadId).sessionId)
|
|
16286
|
+
})) {
|
|
16137
16287
|
updateThread(threadId, { sessionId: null });
|
|
16138
|
-
|
|
16139
|
-
|
|
16140
|
-
"Agent session missing \u2014 starting a fresh session"
|
|
16141
|
-
);
|
|
16288
|
+
const retryNote = looksLikeInvalidAgentSession(detail) ? "Agent session missing \u2014 starting a fresh session" : "Agent runner crashed \u2014 restarting Node once";
|
|
16289
|
+
pushTurnStderr(stderrTail, retryNote);
|
|
16142
16290
|
this.emit({
|
|
16143
16291
|
type: "turn_output",
|
|
16144
16292
|
threadId,
|
|
16145
|
-
event: {
|
|
16146
|
-
type: "stderr",
|
|
16147
|
-
data: "Agent session missing \u2014 starting a fresh session"
|
|
16148
|
-
}
|
|
16293
|
+
event: { type: "stderr", data: retryNote }
|
|
16149
16294
|
});
|
|
16150
16295
|
const retryThread = this.requireThread(threadId);
|
|
16151
16296
|
const prior = retryThread.messages.slice(0, -1);
|
|
@@ -16194,10 +16339,7 @@ var Orchestrator = class {
|
|
|
16194
16339
|
lastStderr = summarizeTurnStderr(stderrTail);
|
|
16195
16340
|
detail = lastStderr || (exitCode !== 0 ? fallbackTurnFailDetail(assistantText) : "");
|
|
16196
16341
|
}
|
|
16197
|
-
let chatText = assistantText;
|
|
16198
|
-
if (exitCode !== 0 && !chatText && looksLikeAgentFailureMessage(detail)) {
|
|
16199
|
-
chatText = humanizeAgentFailDetail(detail);
|
|
16200
|
-
}
|
|
16342
|
+
let chatText = this.stoppedTurns.has(threadId) ? assistantText : turnFailChatText({ exitCode, assistantText, detail });
|
|
16201
16343
|
if (chatText || parts.length > 0) {
|
|
16202
16344
|
appendMessage(threadId, {
|
|
16203
16345
|
role: "agent",
|
|
@@ -16605,10 +16747,13 @@ var Orchestrator = class {
|
|
|
16605
16747
|
getTurnResult(threadRef) {
|
|
16606
16748
|
const thread = this.requireThread(threadRef);
|
|
16607
16749
|
const lastAgent = [...thread.messages].reverse().find((m) => m.role === "agent");
|
|
16750
|
+
const lastError = thread.lastError ?? null;
|
|
16751
|
+
const text3 = (lastAgent?.text ?? "").trim() || (thread.status === "error" ? lastError ?? "" : "");
|
|
16608
16752
|
return {
|
|
16609
|
-
text:
|
|
16753
|
+
text: text3,
|
|
16610
16754
|
status: thread.status,
|
|
16611
|
-
sessionId: thread.sessionId
|
|
16755
|
+
sessionId: thread.sessionId,
|
|
16756
|
+
lastError
|
|
16612
16757
|
};
|
|
16613
16758
|
}
|
|
16614
16759
|
assertNotGlobal(thread, action) {
|
|
@@ -18389,7 +18534,7 @@ async function startMcpServer() {
|
|
|
18389
18534
|
);
|
|
18390
18535
|
server.tool(
|
|
18391
18536
|
"wait_for_turn",
|
|
18392
|
-
"Block until the thread finishes its current/queued turn (avoids polling). Use after send_to_thread or ask_git
|
|
18537
|
+
"Block until the thread finishes its current/queued turn (avoids polling). Use after send_to_thread or ask_git. Returns status, text, and lastError. If status is error, lastError/text is the failure \u2014 switch agent, tell the user, or retry; do not treat empty text as success.",
|
|
18393
18538
|
{
|
|
18394
18539
|
ref: import_zod3.z.string(),
|
|
18395
18540
|
timeoutMs: import_zod3.z.number().optional()
|
|
@@ -18404,7 +18549,8 @@ async function startMcpServer() {
|
|
|
18404
18549
|
text: JSON.stringify({
|
|
18405
18550
|
id: thread.id,
|
|
18406
18551
|
status: result.status,
|
|
18407
|
-
text: result.text
|
|
18552
|
+
text: result.text,
|
|
18553
|
+
lastError: result.lastError
|
|
18408
18554
|
})
|
|
18409
18555
|
}
|
|
18410
18556
|
]
|
|
@@ -18413,7 +18559,7 @@ async function startMcpServer() {
|
|
|
18413
18559
|
);
|
|
18414
18560
|
server.tool(
|
|
18415
18561
|
"get_turn_result",
|
|
18416
|
-
"Final assistant message
|
|
18562
|
+
"Final assistant message (and lastError when the turn failed). Not the full transcript.",
|
|
18417
18563
|
{ ref: import_zod3.z.string() },
|
|
18418
18564
|
async ({ ref }) => {
|
|
18419
18565
|
const result = orch.getTurnResult(ref);
|
package/dist/index.d.cts
CHANGED
|
@@ -2953,6 +2953,7 @@ declare class Orchestrator {
|
|
|
2953
2953
|
text: string;
|
|
2954
2954
|
status: string;
|
|
2955
2955
|
sessionId: string | null;
|
|
2956
|
+
lastError: string | null;
|
|
2956
2957
|
};
|
|
2957
2958
|
private assertNotGlobal;
|
|
2958
2959
|
/** MCP set_caffeinate is a detached hold — closing the chat must not leave the Mac awake. */
|
|
@@ -4190,7 +4191,7 @@ declare function userClaudeMcpConfigPath(): string;
|
|
|
4190
4191
|
/** Merge a `sideboard` stdio server into an mcp.json-shaped document. Does not clobber other servers. */
|
|
4191
4192
|
declare function mergeSideboardIntoMcpServersJson(existing: unknown, sideboard: UserMcpStdioLaunch): Record<string, unknown>;
|
|
4192
4193
|
/**
|
|
4193
|
-
* Packaged Sideboard.app: upsert the same absolute `node` + extraResources MCP
|
|
4194
|
+
* Packaged Sideboard.app: upsert the same absolute bundled `node` + extraResources MCP
|
|
4194
4195
|
* into Cursor IDE (always) and Claude Code (only if ~/.claude.json already exists).
|
|
4195
4196
|
* Codex is documented only — do not rewrite ~/.codex/config.toml.
|
|
4196
4197
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -2953,6 +2953,7 @@ declare class Orchestrator {
|
|
|
2953
2953
|
text: string;
|
|
2954
2954
|
status: string;
|
|
2955
2955
|
sessionId: string | null;
|
|
2956
|
+
lastError: string | null;
|
|
2956
2957
|
};
|
|
2957
2958
|
private assertNotGlobal;
|
|
2958
2959
|
/** MCP set_caffeinate is a detached hold — closing the chat must not leave the Mac awake. */
|
|
@@ -4190,7 +4191,7 @@ declare function userClaudeMcpConfigPath(): string;
|
|
|
4190
4191
|
/** Merge a `sideboard` stdio server into an mcp.json-shaped document. Does not clobber other servers. */
|
|
4191
4192
|
declare function mergeSideboardIntoMcpServersJson(existing: unknown, sideboard: UserMcpStdioLaunch): Record<string, unknown>;
|
|
4192
4193
|
/**
|
|
4193
|
-
* Packaged Sideboard.app: upsert the same absolute `node` + extraResources MCP
|
|
4194
|
+
* Packaged Sideboard.app: upsert the same absolute bundled `node` + extraResources MCP
|
|
4194
4195
|
* into Cursor IDE (always) and Claude Code (only if ~/.claude.json already exists).
|
|
4195
4196
|
* Codex is documented only — do not rewrite ~/.codex/config.toml.
|
|
4196
4197
|
*/
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
listWorkspaces,
|
|
5
5
|
removeWorkspace,
|
|
6
6
|
syncWorkspacesFromThreads
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-MHJV4WS3.js";
|
|
8
8
|
import {
|
|
9
9
|
BRIGHTSY_MCP_ALLOWED_TOOLS,
|
|
10
10
|
CLAUDE_MODEL_CATALOG,
|
|
@@ -65,7 +65,7 @@ import {
|
|
|
65
65
|
threadRequestsBrightsyMcp,
|
|
66
66
|
totalTokens,
|
|
67
67
|
writeInjectedMcpConfig
|
|
68
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-OXC3MEFI.js";
|
|
69
69
|
import {
|
|
70
70
|
CLOUD_COORDINATOR_BUSY_REPLY,
|
|
71
71
|
CLOUD_COORDINATOR_STOPPED_REPLY,
|
|
@@ -93,7 +93,7 @@ import {
|
|
|
93
93
|
parseForceStopMessage,
|
|
94
94
|
slackCoordinatorSourceRef,
|
|
95
95
|
takenTeamSlugsForOrchestration
|
|
96
|
-
} from "./chunk-
|
|
96
|
+
} from "./chunk-GR4JKWR4.js";
|
|
97
97
|
import {
|
|
98
98
|
COORDINATOR_TOOL_PLAYBOOK,
|
|
99
99
|
SLACK_REPLY_FORMATTING,
|
|
@@ -102,7 +102,7 @@ import {
|
|
|
102
102
|
enrichWorkspacesWithGithub,
|
|
103
103
|
ensureGlobalCoordinatorCwd,
|
|
104
104
|
formatWorkspaceInventory
|
|
105
|
-
} from "./chunk-
|
|
105
|
+
} from "./chunk-HYKZEP5A.js";
|
|
106
106
|
import {
|
|
107
107
|
brightsyConfigPath,
|
|
108
108
|
brightsyMcpServerName,
|
|
@@ -133,13 +133,14 @@ import {
|
|
|
133
133
|
cursorSdkMessageToEvents,
|
|
134
134
|
fallbackTurnFailDetail,
|
|
135
135
|
formatTurnExitError,
|
|
136
|
-
humanizeAgentFailDetail,
|
|
137
136
|
looksLikeAgentFailureMessage,
|
|
138
137
|
looksLikeInvalidAgentSession,
|
|
139
138
|
parseCursorRunnerLine,
|
|
140
139
|
pushTurnStderr,
|
|
141
|
-
|
|
142
|
-
|
|
140
|
+
shouldRetryFailedAgentTurn,
|
|
141
|
+
summarizeTurnStderr,
|
|
142
|
+
turnFailChatText
|
|
143
|
+
} from "./chunk-HUKCGRAT.js";
|
|
143
144
|
import {
|
|
144
145
|
caffeinateHoldPath,
|
|
145
146
|
getCaffeinateHold,
|
|
@@ -1385,9 +1386,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
1385
1386
|
`Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
|
|
1386
1387
|
);
|
|
1387
1388
|
}
|
|
1388
|
-
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-
|
|
1389
|
+
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-KYEBFWKB.js");
|
|
1389
1390
|
if (isGlobalThread2(thread)) {
|
|
1390
|
-
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-
|
|
1391
|
+
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-HHRKQWCX.js");
|
|
1391
1392
|
ensureGlobalCoordinatorCwd2(
|
|
1392
1393
|
isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
|
|
1393
1394
|
);
|
|
@@ -3880,7 +3881,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
3880
3881
|
return readThread(thread.id) ?? thread;
|
|
3881
3882
|
}
|
|
3882
3883
|
async function listLinearIssues(agent, repoPath) {
|
|
3883
|
-
const { getAdapter: getAdapter2 } = await import("./agents-
|
|
3884
|
+
const { getAdapter: getAdapter2 } = await import("./agents-OXZDMPSE.js");
|
|
3884
3885
|
await requireAgent(agent, { requireLinear: true });
|
|
3885
3886
|
const adapter = getAdapter2(agent);
|
|
3886
3887
|
if (!adapter.listLinearIssues) {
|
|
@@ -4433,7 +4434,7 @@ async function adoptThread(input) {
|
|
|
4433
4434
|
messages: input.messages ?? []
|
|
4434
4435
|
});
|
|
4435
4436
|
writeThread(thread);
|
|
4436
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
4437
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-NNPD7QVV.js");
|
|
4437
4438
|
await ensureWorkspace2(repoPath);
|
|
4438
4439
|
return thread;
|
|
4439
4440
|
}
|
|
@@ -6517,19 +6518,16 @@ var Orchestrator = class {
|
|
|
6517
6518
|
}
|
|
6518
6519
|
let lastStderr = summarizeTurnStderr(stderrTail);
|
|
6519
6520
|
let detail = lastStderr || (exitCode !== 0 ? fallbackTurnFailDetail(assistantText) : "");
|
|
6520
|
-
if (exitCode !== 0 && !assistantText && parts.length === 0 && !this.stoppedTurns.has(threadId) &&
|
|
6521
|
+
if (exitCode !== 0 && !assistantText && parts.length === 0 && !this.stoppedTurns.has(threadId) && this.requireThread(threadId).agent !== "brightsy" && shouldRetryFailedAgentTurn(detail, {
|
|
6522
|
+
hasSession: Boolean(this.requireThread(threadId).sessionId)
|
|
6523
|
+
})) {
|
|
6521
6524
|
updateThread(threadId, { sessionId: null });
|
|
6522
|
-
|
|
6523
|
-
|
|
6524
|
-
"Agent session missing \u2014 starting a fresh session"
|
|
6525
|
-
);
|
|
6525
|
+
const retryNote = looksLikeInvalidAgentSession(detail) ? "Agent session missing \u2014 starting a fresh session" : "Agent runner crashed \u2014 restarting Node once";
|
|
6526
|
+
pushTurnStderr(stderrTail, retryNote);
|
|
6526
6527
|
this.emit({
|
|
6527
6528
|
type: "turn_output",
|
|
6528
6529
|
threadId,
|
|
6529
|
-
event: {
|
|
6530
|
-
type: "stderr",
|
|
6531
|
-
data: "Agent session missing \u2014 starting a fresh session"
|
|
6532
|
-
}
|
|
6530
|
+
event: { type: "stderr", data: retryNote }
|
|
6533
6531
|
});
|
|
6534
6532
|
const retryThread = this.requireThread(threadId);
|
|
6535
6533
|
const prior = retryThread.messages.slice(0, -1);
|
|
@@ -6578,10 +6576,7 @@ var Orchestrator = class {
|
|
|
6578
6576
|
lastStderr = summarizeTurnStderr(stderrTail);
|
|
6579
6577
|
detail = lastStderr || (exitCode !== 0 ? fallbackTurnFailDetail(assistantText) : "");
|
|
6580
6578
|
}
|
|
6581
|
-
let chatText = assistantText;
|
|
6582
|
-
if (exitCode !== 0 && !chatText && looksLikeAgentFailureMessage(detail)) {
|
|
6583
|
-
chatText = humanizeAgentFailDetail(detail);
|
|
6584
|
-
}
|
|
6579
|
+
let chatText = this.stoppedTurns.has(threadId) ? assistantText : turnFailChatText({ exitCode, assistantText, detail });
|
|
6585
6580
|
if (chatText || parts.length > 0) {
|
|
6586
6581
|
appendMessage(threadId, {
|
|
6587
6582
|
role: "agent",
|
|
@@ -6989,10 +6984,13 @@ var Orchestrator = class {
|
|
|
6989
6984
|
getTurnResult(threadRef) {
|
|
6990
6985
|
const thread = this.requireThread(threadRef);
|
|
6991
6986
|
const lastAgent = [...thread.messages].reverse().find((m) => m.role === "agent");
|
|
6987
|
+
const lastError = thread.lastError ?? null;
|
|
6988
|
+
const text3 = (lastAgent?.text ?? "").trim() || (thread.status === "error" ? lastError ?? "" : "");
|
|
6992
6989
|
return {
|
|
6993
|
-
text:
|
|
6990
|
+
text: text3,
|
|
6994
6991
|
status: thread.status,
|
|
6995
|
-
sessionId: thread.sessionId
|
|
6992
|
+
sessionId: thread.sessionId,
|
|
6993
|
+
lastError
|
|
6996
6994
|
};
|
|
6997
6995
|
}
|
|
6998
6996
|
assertNotGlobal(thread, action) {
|
|
@@ -7446,7 +7444,7 @@ var Orchestrator = class {
|
|
|
7446
7444
|
this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
|
|
7447
7445
|
if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
|
|
7448
7446
|
try {
|
|
7449
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
7447
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-NNPD7QVV.js");
|
|
7450
7448
|
await ensureWorkspace2(thread.repoPath);
|
|
7451
7449
|
} catch {
|
|
7452
7450
|
}
|
|
@@ -8757,7 +8755,7 @@ async function startMcpServer() {
|
|
|
8757
8755
|
);
|
|
8758
8756
|
server.tool(
|
|
8759
8757
|
"wait_for_turn",
|
|
8760
|
-
"Block until the thread finishes its current/queued turn (avoids polling). Use after send_to_thread or ask_git
|
|
8758
|
+
"Block until the thread finishes its current/queued turn (avoids polling). Use after send_to_thread or ask_git. Returns status, text, and lastError. If status is error, lastError/text is the failure \u2014 switch agent, tell the user, or retry; do not treat empty text as success.",
|
|
8761
8759
|
{
|
|
8762
8760
|
ref: z3.string(),
|
|
8763
8761
|
timeoutMs: z3.number().optional()
|
|
@@ -8772,7 +8770,8 @@ async function startMcpServer() {
|
|
|
8772
8770
|
text: JSON.stringify({
|
|
8773
8771
|
id: thread.id,
|
|
8774
8772
|
status: result.status,
|
|
8775
|
-
text: result.text
|
|
8773
|
+
text: result.text,
|
|
8774
|
+
lastError: result.lastError
|
|
8776
8775
|
})
|
|
8777
8776
|
}
|
|
8778
8777
|
]
|
|
@@ -8781,7 +8780,7 @@ async function startMcpServer() {
|
|
|
8781
8780
|
);
|
|
8782
8781
|
server.tool(
|
|
8783
8782
|
"get_turn_result",
|
|
8784
|
-
"Final assistant message
|
|
8783
|
+
"Final assistant message (and lastError when the turn failed). Not the full transcript.",
|
|
8785
8784
|
{ ref: z3.string() },
|
|
8786
8785
|
async ({ ref }) => {
|
|
8787
8786
|
const result = orch.getTurnResult(ref);
|