@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/mcp/run-stdio.cjs
CHANGED
|
@@ -883,6 +883,13 @@ function looksLikeMinifiedJsDump(line) {
|
|
|
883
883
|
function looksLikeNestedElectronCrash(line) {
|
|
884
884
|
return /HasCustomHostObject|ElectronInitializeICUandStartNode/i.test(line);
|
|
885
885
|
}
|
|
886
|
+
function looksLikeHomebrewLibuvCrash(line) {
|
|
887
|
+
const uvRun = /uv_run/i.test(line);
|
|
888
|
+
const spin = /SpinEventLoopInternal/i.test(line);
|
|
889
|
+
const homebrewUv = /Cellar\/libuv|libuv\.\d\.dylib/i.test(line);
|
|
890
|
+
const homebrewNode = /Cellar\/node\//i.test(line);
|
|
891
|
+
return uvRun && (homebrewUv || spin || homebrewNode) || spin && (homebrewUv || homebrewNode);
|
|
892
|
+
}
|
|
886
893
|
function clipStderr(text3, maxChars) {
|
|
887
894
|
const trimmed = text3.trim();
|
|
888
895
|
if (trimmed.length <= maxChars) return trimmed;
|
|
@@ -893,6 +900,7 @@ function summarizeTurnStderr(tail, maxChars = 500) {
|
|
|
893
900
|
const cursorStartup = [...tail].reverse().find((line) => /cursor startup failed:/i.test(line));
|
|
894
901
|
if (cursorStartup) return clipStderr(cursorStartup, maxChars);
|
|
895
902
|
if (tail.some(looksLikeNestedElectronCrash)) return NESTED_ELECTRON_SUMMARY;
|
|
903
|
+
if (tail.some(looksLikeHomebrewLibuvCrash)) return HOMEBREW_LIBUV_SUMMARY;
|
|
896
904
|
if (tail.some(
|
|
897
905
|
(line) => /\[resource_exhausted\]|resource_exhausted/i.test(line) || /findFilesWithRipgrep/.test(line)
|
|
898
906
|
)) {
|
|
@@ -915,6 +923,20 @@ function looksLikeInvalidAgentSession(text3) {
|
|
|
915
923
|
if (!lower) return false;
|
|
916
924
|
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);
|
|
917
925
|
}
|
|
926
|
+
function looksLikeRetryableRunnerCrash(text3) {
|
|
927
|
+
if (looksLikeAgentFailureMessage(text3)) return false;
|
|
928
|
+
if (looksLikeInvalidAgentSession(text3)) return false;
|
|
929
|
+
const lower = text3.trim().toLowerCase();
|
|
930
|
+
if (/cannot find (?:package|module)|err_module_not_found/.test(lower)) return false;
|
|
931
|
+
if (!lower) return true;
|
|
932
|
+
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(
|
|
933
|
+
lower
|
|
934
|
+
);
|
|
935
|
+
}
|
|
936
|
+
function shouldRetryFailedAgentTurn(detail, opts) {
|
|
937
|
+
if (looksLikeInvalidAgentSession(detail) && opts.hasSession) return true;
|
|
938
|
+
return looksLikeRetryableRunnerCrash(detail);
|
|
939
|
+
}
|
|
918
940
|
function looksLikeAgentFailureMessage(text3) {
|
|
919
941
|
const lower = text3.trim().toLowerCase();
|
|
920
942
|
if (!lower) return false;
|
|
@@ -959,11 +981,22 @@ function humanizeAgentFailDetail(detail) {
|
|
|
959
981
|
if (/hascustomhostobject|electroninitializeicuandstartnode|nested chromium/i.test(lower)) {
|
|
960
982
|
return `${raw} \u2014 retry the turn; if it keeps failing, pick another agent.`;
|
|
961
983
|
}
|
|
984
|
+
if (/homebrew node \+ shared libuv|uv_run|spineventloopinternal/i.test(lower)) {
|
|
985
|
+
return /brew install node@22/i.test(raw) ? raw : `${raw} \u2014 install Node 22 LTS (\`brew install node@22\`) and retry.`;
|
|
986
|
+
}
|
|
962
987
|
if (/corrupt local agent checkpoint|missing root blob|truncated crash dump/.test(lower)) {
|
|
963
988
|
return `${raw} \u2014 retry the turn (Sideboard will start a fresh Cursor session).`;
|
|
964
989
|
}
|
|
965
990
|
return raw;
|
|
966
991
|
}
|
|
992
|
+
function turnFailChatText(opts) {
|
|
993
|
+
const chat = opts.assistantText.trim();
|
|
994
|
+
if (chat) return chat;
|
|
995
|
+
if (opts.exitCode === 0) return "";
|
|
996
|
+
const detail = opts.detail.trim();
|
|
997
|
+
if (detail) return humanizeAgentFailDetail(detail);
|
|
998
|
+
return formatTurnExitError(opts.exitCode ?? 1, "");
|
|
999
|
+
}
|
|
967
1000
|
function formatTurnExitError(exitCode, stderrSummary) {
|
|
968
1001
|
const code = exitCode ?? 1;
|
|
969
1002
|
const raw = stderrSummary.trim();
|
|
@@ -977,12 +1010,13 @@ function formatTurnExitError(exitCode, stderrSummary) {
|
|
|
977
1010
|
if (looksLikeAgentFailureMessage(raw)) return detail;
|
|
978
1011
|
return `exit ${code}: ${detail}`;
|
|
979
1012
|
}
|
|
980
|
-
var NODE_VERSION_FOOTER, NESTED_ELECTRON_SUMMARY, MINIFIED_DUMP_SUMMARY;
|
|
1013
|
+
var NODE_VERSION_FOOTER, NESTED_ELECTRON_SUMMARY, HOMEBREW_LIBUV_SUMMARY, MINIFIED_DUMP_SUMMARY;
|
|
981
1014
|
var init_error_detail = __esm({
|
|
982
1015
|
"src/agents/error-detail.ts"() {
|
|
983
1016
|
"use strict";
|
|
984
1017
|
NODE_VERSION_FOOTER = /^Node\.js v\d+/i;
|
|
985
1018
|
NESTED_ELECTRON_SUMMARY = "Cursor local agent crashed at Electron startup (nested Chromium / HasCustomHostObject)";
|
|
1019
|
+
HOMEBREW_LIBUV_SUMMARY = "Cursor runner crashed in Node (Homebrew Node + shared libuv). Install Node 22 LTS (`brew install node@22`) and retry.";
|
|
986
1020
|
MINIFIED_DUMP_SUMMARY = "Cursor local agent crashed during startup (truncated crash dump)";
|
|
987
1021
|
}
|
|
988
1022
|
});
|
|
@@ -5007,7 +5041,7 @@ function coordinatorTurnReminder(opts) {
|
|
|
5007
5041
|
goal ? `- Goal / title: ${goal}` : null,
|
|
5008
5042
|
accountDefaultsPlaybookLine(),
|
|
5009
5043
|
`- 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.`,
|
|
5010
|
-
"- 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.",
|
|
5044
|
+
"- 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.",
|
|
5011
5045
|
"- 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.",
|
|
5012
5046
|
"- When naming threads for the user, link them as `[Title](sideboard://thread/<id>)`.",
|
|
5013
5047
|
"- 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."
|
|
@@ -5130,7 +5164,7 @@ var init_coordinator_prompt = __esm({
|
|
|
5130
5164
|
"- 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.",
|
|
5131
5165
|
"- 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.",
|
|
5132
5166
|
"- 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",
|
|
5133
|
-
"- wait_for_turn / get_turn_result \u2014 wait for and read the agent reply",
|
|
5167
|
+
"- 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.",
|
|
5134
5168
|
"- stop_thread \u2014 force-stop: kill in-flight turn AND clear queued prompts (do not leave stale queue after an interrupt)",
|
|
5135
5169
|
"- archive_thread / restore_thread \u2014 archive (tears down worktree when last tab) or restore",
|
|
5136
5170
|
"Setup / run:",
|
|
@@ -6046,6 +6080,55 @@ var init_profile = __esm({
|
|
|
6046
6080
|
}
|
|
6047
6081
|
});
|
|
6048
6082
|
|
|
6083
|
+
// src/agents/packaged-runtime.ts
|
|
6084
|
+
function electronResourcesPath() {
|
|
6085
|
+
const resources = process.resourcesPath;
|
|
6086
|
+
if (typeof resources !== "string" || !resources) return null;
|
|
6087
|
+
return resources;
|
|
6088
|
+
}
|
|
6089
|
+
function packagedCursorRuntimeDir() {
|
|
6090
|
+
const resources = electronResourcesPath();
|
|
6091
|
+
if (!resources) return null;
|
|
6092
|
+
const dir = (0, import_node_path19.join)(resources, "cursor-runtime");
|
|
6093
|
+
if (!(0, import_node_fs18.existsSync)((0, import_node_path19.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
|
|
6094
|
+
return dir;
|
|
6095
|
+
}
|
|
6096
|
+
function packagedCursorRunnerPath() {
|
|
6097
|
+
const dir = packagedCursorRuntimeDir();
|
|
6098
|
+
return dir ? (0, import_node_path19.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
|
|
6099
|
+
}
|
|
6100
|
+
function packagedMcpDir() {
|
|
6101
|
+
const resources = electronResourcesPath();
|
|
6102
|
+
if (!resources) return null;
|
|
6103
|
+
const dir = (0, import_node_path19.join)(resources, "sideboard-mcp");
|
|
6104
|
+
if (!(0, import_node_fs18.existsSync)((0, import_node_path19.join)(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
|
|
6105
|
+
return dir;
|
|
6106
|
+
}
|
|
6107
|
+
function packagedMcpStdioPath() {
|
|
6108
|
+
const dir = packagedMcpDir();
|
|
6109
|
+
return dir ? (0, import_node_path19.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
|
|
6110
|
+
}
|
|
6111
|
+
function packagedBundledNodePath() {
|
|
6112
|
+
const resources = electronResourcesPath();
|
|
6113
|
+
if (!resources) return null;
|
|
6114
|
+
const bin = (0, import_node_path19.join)(resources, "node", "bin", "node");
|
|
6115
|
+
if (!(0, import_node_fs18.existsSync)(bin)) return null;
|
|
6116
|
+
return bin;
|
|
6117
|
+
}
|
|
6118
|
+
function packagedCursorRipgrepCandidate(platformPkg, binName) {
|
|
6119
|
+
const dir = packagedCursorRuntimeDir();
|
|
6120
|
+
if (!dir) return null;
|
|
6121
|
+
return (0, import_node_path19.join)(dir, "node_modules", platformPkg, "bin", binName);
|
|
6122
|
+
}
|
|
6123
|
+
var import_node_fs18, import_node_path19;
|
|
6124
|
+
var init_packaged_runtime = __esm({
|
|
6125
|
+
"src/agents/packaged-runtime.ts"() {
|
|
6126
|
+
"use strict";
|
|
6127
|
+
import_node_fs18 = require("fs");
|
|
6128
|
+
import_node_path19 = require("path");
|
|
6129
|
+
}
|
|
6130
|
+
});
|
|
6131
|
+
|
|
6049
6132
|
// src/agents/node-launch.ts
|
|
6050
6133
|
function isAsarPath(filePath) {
|
|
6051
6134
|
if (/\.asar\.unpacked([/\\]|$)/.test(filePath)) return false;
|
|
@@ -6055,24 +6138,129 @@ function unpackedAsarPath(filePath) {
|
|
|
6055
6138
|
if (!isAsarPath(filePath)) return null;
|
|
6056
6139
|
const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
|
|
6057
6140
|
if (unpacked === filePath) return null;
|
|
6058
|
-
return (0,
|
|
6141
|
+
return (0, import_node_fs19.existsSync)(unpacked) ? unpacked : null;
|
|
6059
6142
|
}
|
|
6060
6143
|
function nodeReadableScriptPath(scriptPath) {
|
|
6061
6144
|
return unpackedAsarPath(scriptPath) ?? scriptPath;
|
|
6062
6145
|
}
|
|
6063
|
-
|
|
6064
|
-
const
|
|
6065
|
-
|
|
6066
|
-
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
|
|
6146
|
+
function parseNodeMajor(version) {
|
|
6147
|
+
const match = /^v?(\d+)/.exec(version.trim());
|
|
6148
|
+
if (!match) return null;
|
|
6149
|
+
const major = Number(match[1]);
|
|
6150
|
+
return Number.isInteger(major) ? major : null;
|
|
6151
|
+
}
|
|
6152
|
+
function scoreNodeForAgentRuntime(candidate) {
|
|
6153
|
+
const major = parseNodeMajor(candidate.version);
|
|
6154
|
+
if (major == null) return Number.NEGATIVE_INFINITY;
|
|
6155
|
+
if (major < 20) return major - 100;
|
|
6156
|
+
const posix = candidate.path.replace(/\\/g, "/");
|
|
6157
|
+
let score = 0;
|
|
6158
|
+
if (major % 2 === 0) {
|
|
6159
|
+
score += 1e3 + major * 10;
|
|
6160
|
+
} else {
|
|
6161
|
+
score += major;
|
|
6162
|
+
}
|
|
6163
|
+
if (/\/Cellar\/node\/\d/.test(posix) && !/\/Cellar\/node@\d+/.test(posix)) {
|
|
6164
|
+
score -= 50;
|
|
6165
|
+
}
|
|
6166
|
+
return score;
|
|
6167
|
+
}
|
|
6168
|
+
function pickPreferredNode(candidates) {
|
|
6169
|
+
let best = null;
|
|
6170
|
+
let bestScore = Number.NEGATIVE_INFINITY;
|
|
6171
|
+
for (const candidate of candidates) {
|
|
6172
|
+
const score = scoreNodeForAgentRuntime(candidate);
|
|
6173
|
+
if (score > bestScore) {
|
|
6174
|
+
bestScore = score;
|
|
6175
|
+
best = candidate;
|
|
6176
|
+
}
|
|
6177
|
+
}
|
|
6178
|
+
return best;
|
|
6179
|
+
}
|
|
6180
|
+
function versionDirNodeBins(root, toBin) {
|
|
6181
|
+
if (!(0, import_node_fs19.existsSync)(root)) return [];
|
|
6182
|
+
try {
|
|
6183
|
+
return (0, import_node_fs19.readdirSync)(root).map(toBin);
|
|
6184
|
+
} catch {
|
|
6185
|
+
return [];
|
|
6186
|
+
}
|
|
6187
|
+
}
|
|
6188
|
+
function defaultNodeBinCandidates(home = (0, import_node_os7.homedir)()) {
|
|
6189
|
+
const kegs = ["/opt/homebrew", "/usr/local"].flatMap(
|
|
6190
|
+
(prefix) => PREFERRED_LTS_MAJORS.map((major) => (0, import_node_path20.join)(prefix, "opt", `node@${major}`, "bin", "node"))
|
|
6191
|
+
);
|
|
6192
|
+
return [
|
|
6193
|
+
...kegs,
|
|
6194
|
+
"/opt/homebrew/bin/node",
|
|
6195
|
+
"/usr/local/bin/node",
|
|
6196
|
+
(0, import_node_path20.join)(home, ".local/share/fnm/aliases/default/bin/node"),
|
|
6197
|
+
(0, import_node_path20.join)(home, ".nvm/current/bin/node"),
|
|
6198
|
+
(0, import_node_path20.join)(home, ".volta/bin/node"),
|
|
6199
|
+
(0, import_node_path20.join)(home, ".asdf/shims/node"),
|
|
6200
|
+
(0, import_node_path20.join)(home, ".local/share/mise/shims/node"),
|
|
6201
|
+
...versionDirNodeBins(
|
|
6202
|
+
(0, import_node_path20.join)(home, ".nvm", "versions", "node"),
|
|
6203
|
+
(name) => (0, import_node_path20.join)(home, ".nvm", "versions", "node", name, "bin", "node")
|
|
6204
|
+
),
|
|
6205
|
+
...versionDirNodeBins(
|
|
6206
|
+
(0, import_node_path20.join)(home, ".local/share/fnm", "node-versions"),
|
|
6207
|
+
(name) => (0, import_node_path20.join)(home, ".local/share/fnm", "node-versions", name, "installation", "bin", "node")
|
|
6208
|
+
),
|
|
6209
|
+
...versionDirNodeBins(
|
|
6210
|
+
(0, import_node_path20.join)(home, ".volta", "tools", "image", "node"),
|
|
6211
|
+
(name) => (0, import_node_path20.join)(home, ".volta", "tools", "image", "node", name, "bin", "node")
|
|
6212
|
+
)
|
|
6071
6213
|
];
|
|
6072
|
-
|
|
6073
|
-
|
|
6214
|
+
}
|
|
6215
|
+
function uniqueExistingNodeBins(paths) {
|
|
6216
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6217
|
+
const out = [];
|
|
6218
|
+
for (const raw of paths) {
|
|
6219
|
+
const p = raw.trim();
|
|
6220
|
+
if (!p || !(0, import_node_fs19.existsSync)(p) || isElectronLikeCommand(p)) continue;
|
|
6221
|
+
let key = p;
|
|
6222
|
+
try {
|
|
6223
|
+
key = (0, import_node_fs19.realpathSync)(p);
|
|
6224
|
+
} catch {
|
|
6225
|
+
continue;
|
|
6226
|
+
}
|
|
6227
|
+
if (seen.has(key)) continue;
|
|
6228
|
+
seen.add(key);
|
|
6229
|
+
out.push(p);
|
|
6074
6230
|
}
|
|
6075
|
-
return
|
|
6231
|
+
return out;
|
|
6232
|
+
}
|
|
6233
|
+
async function whichAllNode() {
|
|
6234
|
+
if (process.platform === "win32") {
|
|
6235
|
+
const located = await run("where", ["node"], { reject: false, timeoutMs: 5e3 });
|
|
6236
|
+
if (located.exitCode !== 0) return [];
|
|
6237
|
+
return located.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
6238
|
+
}
|
|
6239
|
+
const all = await run("which", ["-a", "node"], { reject: false, timeoutMs: 5e3 });
|
|
6240
|
+
if (all.exitCode === 0 && all.stdout.trim()) {
|
|
6241
|
+
return all.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
6242
|
+
}
|
|
6243
|
+
const single = await run("which", ["node"], { reject: false, timeoutMs: 5e3 });
|
|
6244
|
+
if (single.exitCode !== 0 || !single.stdout.trim()) return [];
|
|
6245
|
+
return [single.stdout.trim()];
|
|
6246
|
+
}
|
|
6247
|
+
async function probeNodeVersion(bin) {
|
|
6248
|
+
const probed = await run(bin, ["-v"], { reject: false, timeoutMs: 4e3 });
|
|
6249
|
+
if (probed.exitCode !== 0) return null;
|
|
6250
|
+
const version = probed.stdout.trim().split(/\r?\n/).find(Boolean);
|
|
6251
|
+
return version || null;
|
|
6252
|
+
}
|
|
6253
|
+
async function findSystemNode() {
|
|
6254
|
+
const fromPath = await whichAllNode();
|
|
6255
|
+
const bins = uniqueExistingNodeBins([...fromPath, ...defaultNodeBinCandidates()]);
|
|
6256
|
+
if (bins.length === 0) return null;
|
|
6257
|
+
const probed = await Promise.all(
|
|
6258
|
+
bins.map(async (path) => {
|
|
6259
|
+
const version = await probeNodeVersion(path);
|
|
6260
|
+
return version ? { path, version } : null;
|
|
6261
|
+
})
|
|
6262
|
+
);
|
|
6263
|
+
return pickPreferredNode(probed.filter((c) => c != null));
|
|
6076
6264
|
}
|
|
6077
6265
|
function applyNodeLaunch(launch, args) {
|
|
6078
6266
|
const readableArgs = args.map(nodeReadableScriptPath);
|
|
@@ -6090,9 +6278,13 @@ function applyNodeLaunch(launch, args) {
|
|
|
6090
6278
|
async function resolveNodeLaunch(scriptPath) {
|
|
6091
6279
|
const script = nodeReadableScriptPath(scriptPath);
|
|
6092
6280
|
if (!isAsarPath(script)) {
|
|
6093
|
-
const
|
|
6094
|
-
if (
|
|
6095
|
-
return { file:
|
|
6281
|
+
const bundled = packagedBundledNodePath();
|
|
6282
|
+
if (bundled && !isElectronLikeCommand(bundled)) {
|
|
6283
|
+
return { file: bundled, env: {} };
|
|
6284
|
+
}
|
|
6285
|
+
const node = await findSystemNode();
|
|
6286
|
+
if (node) {
|
|
6287
|
+
return { file: node.path, env: {}, nodeVersion: node.version };
|
|
6096
6288
|
}
|
|
6097
6289
|
}
|
|
6098
6290
|
return {
|
|
@@ -6100,61 +6292,17 @@ async function resolveNodeLaunch(scriptPath) {
|
|
|
6100
6292
|
env: { ELECTRON_RUN_AS_NODE: "1" }
|
|
6101
6293
|
};
|
|
6102
6294
|
}
|
|
6103
|
-
var
|
|
6295
|
+
var import_node_fs19, import_node_os7, import_node_path20, PREFERRED_LTS_MAJORS;
|
|
6104
6296
|
var init_node_launch = __esm({
|
|
6105
6297
|
"src/agents/node-launch.ts"() {
|
|
6106
6298
|
"use strict";
|
|
6107
|
-
|
|
6299
|
+
import_node_fs19 = require("fs");
|
|
6108
6300
|
import_node_os7 = require("os");
|
|
6109
|
-
|
|
6301
|
+
import_node_path20 = require("path");
|
|
6110
6302
|
init_nested_electron_env();
|
|
6111
6303
|
init_run();
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
"/usr/local/bin/node"
|
|
6115
|
-
];
|
|
6116
|
-
}
|
|
6117
|
-
});
|
|
6118
|
-
|
|
6119
|
-
// src/agents/packaged-runtime.ts
|
|
6120
|
-
function electronResourcesPath() {
|
|
6121
|
-
const resources = process.resourcesPath;
|
|
6122
|
-
if (typeof resources !== "string" || !resources) return null;
|
|
6123
|
-
return resources;
|
|
6124
|
-
}
|
|
6125
|
-
function packagedCursorRuntimeDir() {
|
|
6126
|
-
const resources = electronResourcesPath();
|
|
6127
|
-
if (!resources) return null;
|
|
6128
|
-
const dir = (0, import_node_path20.join)(resources, "cursor-runtime");
|
|
6129
|
-
if (!(0, import_node_fs19.existsSync)((0, import_node_path20.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
|
|
6130
|
-
return dir;
|
|
6131
|
-
}
|
|
6132
|
-
function packagedCursorRunnerPath() {
|
|
6133
|
-
const dir = packagedCursorRuntimeDir();
|
|
6134
|
-
return dir ? (0, import_node_path20.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
|
|
6135
|
-
}
|
|
6136
|
-
function packagedMcpDir() {
|
|
6137
|
-
const resources = electronResourcesPath();
|
|
6138
|
-
if (!resources) return null;
|
|
6139
|
-
const dir = (0, import_node_path20.join)(resources, "sideboard-mcp");
|
|
6140
|
-
if (!(0, import_node_fs19.existsSync)((0, import_node_path20.join)(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
|
|
6141
|
-
return dir;
|
|
6142
|
-
}
|
|
6143
|
-
function packagedMcpStdioPath() {
|
|
6144
|
-
const dir = packagedMcpDir();
|
|
6145
|
-
return dir ? (0, import_node_path20.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
|
|
6146
|
-
}
|
|
6147
|
-
function packagedCursorRipgrepCandidate(platformPkg, binName) {
|
|
6148
|
-
const dir = packagedCursorRuntimeDir();
|
|
6149
|
-
if (!dir) return null;
|
|
6150
|
-
return (0, import_node_path20.join)(dir, "node_modules", platformPkg, "bin", binName);
|
|
6151
|
-
}
|
|
6152
|
-
var import_node_fs19, import_node_path20;
|
|
6153
|
-
var init_packaged_runtime = __esm({
|
|
6154
|
-
"src/agents/packaged-runtime.ts"() {
|
|
6155
|
-
"use strict";
|
|
6156
|
-
import_node_fs19 = require("fs");
|
|
6157
|
-
import_node_path20 = require("path");
|
|
6304
|
+
init_packaged_runtime();
|
|
6305
|
+
PREFERRED_LTS_MAJORS = [24, 22, 20];
|
|
6158
6306
|
}
|
|
6159
6307
|
});
|
|
6160
6308
|
|
|
@@ -14161,19 +14309,16 @@ var Orchestrator = class {
|
|
|
14161
14309
|
}
|
|
14162
14310
|
let lastStderr = summarizeTurnStderr(stderrTail);
|
|
14163
14311
|
let detail = lastStderr || (exitCode !== 0 ? fallbackTurnFailDetail(assistantText) : "");
|
|
14164
|
-
if (exitCode !== 0 && !assistantText && parts.length === 0 && !this.stoppedTurns.has(threadId) &&
|
|
14312
|
+
if (exitCode !== 0 && !assistantText && parts.length === 0 && !this.stoppedTurns.has(threadId) && this.requireThread(threadId).agent !== "brightsy" && shouldRetryFailedAgentTurn(detail, {
|
|
14313
|
+
hasSession: Boolean(this.requireThread(threadId).sessionId)
|
|
14314
|
+
})) {
|
|
14165
14315
|
updateThread(threadId, { sessionId: null });
|
|
14166
|
-
|
|
14167
|
-
|
|
14168
|
-
"Agent session missing \u2014 starting a fresh session"
|
|
14169
|
-
);
|
|
14316
|
+
const retryNote = looksLikeInvalidAgentSession(detail) ? "Agent session missing \u2014 starting a fresh session" : "Agent runner crashed \u2014 restarting Node once";
|
|
14317
|
+
pushTurnStderr(stderrTail, retryNote);
|
|
14170
14318
|
this.emit({
|
|
14171
14319
|
type: "turn_output",
|
|
14172
14320
|
threadId,
|
|
14173
|
-
event: {
|
|
14174
|
-
type: "stderr",
|
|
14175
|
-
data: "Agent session missing \u2014 starting a fresh session"
|
|
14176
|
-
}
|
|
14321
|
+
event: { type: "stderr", data: retryNote }
|
|
14177
14322
|
});
|
|
14178
14323
|
const retryThread = this.requireThread(threadId);
|
|
14179
14324
|
const prior = retryThread.messages.slice(0, -1);
|
|
@@ -14222,10 +14367,7 @@ var Orchestrator = class {
|
|
|
14222
14367
|
lastStderr = summarizeTurnStderr(stderrTail);
|
|
14223
14368
|
detail = lastStderr || (exitCode !== 0 ? fallbackTurnFailDetail(assistantText) : "");
|
|
14224
14369
|
}
|
|
14225
|
-
let chatText = assistantText;
|
|
14226
|
-
if (exitCode !== 0 && !chatText && looksLikeAgentFailureMessage(detail)) {
|
|
14227
|
-
chatText = humanizeAgentFailDetail(detail);
|
|
14228
|
-
}
|
|
14370
|
+
let chatText = this.stoppedTurns.has(threadId) ? assistantText : turnFailChatText({ exitCode, assistantText, detail });
|
|
14229
14371
|
if (chatText || parts.length > 0) {
|
|
14230
14372
|
appendMessage(threadId, {
|
|
14231
14373
|
role: "agent",
|
|
@@ -14633,10 +14775,13 @@ var Orchestrator = class {
|
|
|
14633
14775
|
getTurnResult(threadRef) {
|
|
14634
14776
|
const thread = this.requireThread(threadRef);
|
|
14635
14777
|
const lastAgent = [...thread.messages].reverse().find((m) => m.role === "agent");
|
|
14778
|
+
const lastError = thread.lastError ?? null;
|
|
14779
|
+
const text3 = (lastAgent?.text ?? "").trim() || (thread.status === "error" ? lastError ?? "" : "");
|
|
14636
14780
|
return {
|
|
14637
|
-
text:
|
|
14781
|
+
text: text3,
|
|
14638
14782
|
status: thread.status,
|
|
14639
|
-
sessionId: thread.sessionId
|
|
14783
|
+
sessionId: thread.sessionId,
|
|
14784
|
+
lastError
|
|
14640
14785
|
};
|
|
14641
14786
|
}
|
|
14642
14787
|
assertNotGlobal(thread, action) {
|
|
@@ -16729,7 +16874,7 @@ async function startMcpServer() {
|
|
|
16729
16874
|
);
|
|
16730
16875
|
server.tool(
|
|
16731
16876
|
"wait_for_turn",
|
|
16732
|
-
"Block until the thread finishes its current/queued turn (avoids polling). Use after send_to_thread or ask_git
|
|
16877
|
+
"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.",
|
|
16733
16878
|
{
|
|
16734
16879
|
ref: import_zod3.z.string(),
|
|
16735
16880
|
timeoutMs: import_zod3.z.number().optional()
|
|
@@ -16744,7 +16889,8 @@ async function startMcpServer() {
|
|
|
16744
16889
|
text: JSON.stringify({
|
|
16745
16890
|
id: thread.id,
|
|
16746
16891
|
status: result.status,
|
|
16747
|
-
text: result.text
|
|
16892
|
+
text: result.text,
|
|
16893
|
+
lastError: result.lastError
|
|
16748
16894
|
})
|
|
16749
16895
|
}
|
|
16750
16896
|
]
|
|
@@ -16753,7 +16899,7 @@ async function startMcpServer() {
|
|
|
16753
16899
|
);
|
|
16754
16900
|
server.tool(
|
|
16755
16901
|
"get_turn_result",
|
|
16756
|
-
"Final assistant message
|
|
16902
|
+
"Final assistant message (and lastError when the turn failed). Not the full transcript.",
|
|
16757
16903
|
{ ref: import_zod3.z.string() },
|
|
16758
16904
|
async ({ ref }) => {
|
|
16759
16905
|
const result = orch.getTurnResult(ref);
|
package/dist/mcp/run-stdio.js
CHANGED
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
fallbackTurnFailDetail,
|
|
7
7
|
formatTurnExitError,
|
|
8
8
|
getAdapter,
|
|
9
|
-
humanizeAgentFailDetail,
|
|
10
9
|
isSessionQuotaLimit,
|
|
11
10
|
listModelsForAgent,
|
|
12
11
|
looksLikeAgentFailureMessage,
|
|
@@ -15,16 +14,18 @@ import {
|
|
|
15
14
|
parseSessionQuotaResetAt,
|
|
16
15
|
pushTurnStderr,
|
|
17
16
|
resolveQuotaFallbackAgent,
|
|
17
|
+
shouldRetryFailedAgentTurn,
|
|
18
18
|
sideboardMcpProfile,
|
|
19
|
-
summarizeTurnStderr
|
|
20
|
-
|
|
19
|
+
summarizeTurnStderr,
|
|
20
|
+
turnFailChatText
|
|
21
|
+
} from "../chunk-EQPQTLW6.js";
|
|
21
22
|
import "../chunk-DKHGWYWR.js";
|
|
22
23
|
import {
|
|
23
24
|
addWorkspace,
|
|
24
25
|
ensureWorkspace,
|
|
25
26
|
removeWorkspace,
|
|
26
27
|
syncWorkspacesFromThreads
|
|
27
|
-
} from "../chunk-
|
|
28
|
+
} from "../chunk-MRBKGFTL.js";
|
|
28
29
|
import {
|
|
29
30
|
extractPresentedPlan,
|
|
30
31
|
readPlanFile,
|
|
@@ -43,14 +44,14 @@ import {
|
|
|
43
44
|
isOrchestratorThread,
|
|
44
45
|
isSlackCoordinatorThread,
|
|
45
46
|
orchestratorSessionPoisonedByBuiltins
|
|
46
|
-
} from "../chunk-
|
|
47
|
+
} from "../chunk-WQTTUC4N.js";
|
|
47
48
|
import {
|
|
48
49
|
SLACK_REPLY_FORMATTING,
|
|
49
50
|
coordinatorSystemPrompt,
|
|
50
51
|
coordinatorTurnReminder,
|
|
51
52
|
enrichWorkspacesWithGithub,
|
|
52
53
|
ensureGlobalCoordinatorCwd
|
|
53
|
-
} from "../chunk-
|
|
54
|
+
} from "../chunk-IFHKPZHA.js";
|
|
54
55
|
import {
|
|
55
56
|
addPrStackLayer,
|
|
56
57
|
allocateTeamName,
|
|
@@ -944,9 +945,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
944
945
|
`Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
|
|
945
946
|
);
|
|
946
947
|
}
|
|
947
|
-
const { isGlobalThread: isGlobalThread2 } = await import("../global-workspace-
|
|
948
|
+
const { isGlobalThread: isGlobalThread2 } = await import("../global-workspace-YZWYHLQY.js");
|
|
948
949
|
if (isGlobalThread2(thread)) {
|
|
949
|
-
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("../coordinator-prompt-
|
|
950
|
+
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("../coordinator-prompt-OOBSQCWQ.js");
|
|
950
951
|
ensureGlobalCoordinatorCwd2(
|
|
951
952
|
isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
|
|
952
953
|
);
|
|
@@ -1887,7 +1888,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
1887
1888
|
return readThread(thread.id) ?? thread;
|
|
1888
1889
|
}
|
|
1889
1890
|
async function listLinearIssues(agent, repoPath) {
|
|
1890
|
-
const { getAdapter: getAdapter2 } = await import("../agents-
|
|
1891
|
+
const { getAdapter: getAdapter2 } = await import("../agents-CLP5BG4O.js");
|
|
1891
1892
|
await requireAgent(agent, { requireLinear: true });
|
|
1892
1893
|
const adapter = getAdapter2(agent);
|
|
1893
1894
|
if (!adapter.listLinearIssues) {
|
|
@@ -2765,7 +2766,7 @@ async function adoptThread(input) {
|
|
|
2765
2766
|
messages: input.messages ?? []
|
|
2766
2767
|
});
|
|
2767
2768
|
writeThread(thread);
|
|
2768
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("../workspaces-
|
|
2769
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("../workspaces-ENVUDK6C.js");
|
|
2769
2770
|
await ensureWorkspace2(repoPath);
|
|
2770
2771
|
return thread;
|
|
2771
2772
|
}
|
|
@@ -5322,19 +5323,16 @@ var Orchestrator = class {
|
|
|
5322
5323
|
}
|
|
5323
5324
|
let lastStderr = summarizeTurnStderr(stderrTail);
|
|
5324
5325
|
let detail = lastStderr || (exitCode !== 0 ? fallbackTurnFailDetail(assistantText) : "");
|
|
5325
|
-
if (exitCode !== 0 && !assistantText && parts.length === 0 && !this.stoppedTurns.has(threadId) &&
|
|
5326
|
+
if (exitCode !== 0 && !assistantText && parts.length === 0 && !this.stoppedTurns.has(threadId) && this.requireThread(threadId).agent !== "brightsy" && shouldRetryFailedAgentTurn(detail, {
|
|
5327
|
+
hasSession: Boolean(this.requireThread(threadId).sessionId)
|
|
5328
|
+
})) {
|
|
5326
5329
|
updateThread(threadId, { sessionId: null });
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
"Agent session missing \u2014 starting a fresh session"
|
|
5330
|
-
);
|
|
5330
|
+
const retryNote = looksLikeInvalidAgentSession(detail) ? "Agent session missing \u2014 starting a fresh session" : "Agent runner crashed \u2014 restarting Node once";
|
|
5331
|
+
pushTurnStderr(stderrTail, retryNote);
|
|
5331
5332
|
this.emit({
|
|
5332
5333
|
type: "turn_output",
|
|
5333
5334
|
threadId,
|
|
5334
|
-
event: {
|
|
5335
|
-
type: "stderr",
|
|
5336
|
-
data: "Agent session missing \u2014 starting a fresh session"
|
|
5337
|
-
}
|
|
5335
|
+
event: { type: "stderr", data: retryNote }
|
|
5338
5336
|
});
|
|
5339
5337
|
const retryThread = this.requireThread(threadId);
|
|
5340
5338
|
const prior = retryThread.messages.slice(0, -1);
|
|
@@ -5383,10 +5381,7 @@ var Orchestrator = class {
|
|
|
5383
5381
|
lastStderr = summarizeTurnStderr(stderrTail);
|
|
5384
5382
|
detail = lastStderr || (exitCode !== 0 ? fallbackTurnFailDetail(assistantText) : "");
|
|
5385
5383
|
}
|
|
5386
|
-
let chatText = assistantText;
|
|
5387
|
-
if (exitCode !== 0 && !chatText && looksLikeAgentFailureMessage(detail)) {
|
|
5388
|
-
chatText = humanizeAgentFailDetail(detail);
|
|
5389
|
-
}
|
|
5384
|
+
let chatText = this.stoppedTurns.has(threadId) ? assistantText : turnFailChatText({ exitCode, assistantText, detail });
|
|
5390
5385
|
if (chatText || parts.length > 0) {
|
|
5391
5386
|
appendMessage(threadId, {
|
|
5392
5387
|
role: "agent",
|
|
@@ -5794,10 +5789,13 @@ var Orchestrator = class {
|
|
|
5794
5789
|
getTurnResult(threadRef) {
|
|
5795
5790
|
const thread = this.requireThread(threadRef);
|
|
5796
5791
|
const lastAgent = [...thread.messages].reverse().find((m) => m.role === "agent");
|
|
5792
|
+
const lastError = thread.lastError ?? null;
|
|
5793
|
+
const text3 = (lastAgent?.text ?? "").trim() || (thread.status === "error" ? lastError ?? "" : "");
|
|
5797
5794
|
return {
|
|
5798
|
-
text:
|
|
5795
|
+
text: text3,
|
|
5799
5796
|
status: thread.status,
|
|
5800
|
-
sessionId: thread.sessionId
|
|
5797
|
+
sessionId: thread.sessionId,
|
|
5798
|
+
lastError
|
|
5801
5799
|
};
|
|
5802
5800
|
}
|
|
5803
5801
|
assertNotGlobal(thread, action) {
|
|
@@ -6251,7 +6249,7 @@ var Orchestrator = class {
|
|
|
6251
6249
|
this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
|
|
6252
6250
|
if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
|
|
6253
6251
|
try {
|
|
6254
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("../workspaces-
|
|
6252
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("../workspaces-ENVUDK6C.js");
|
|
6255
6253
|
await ensureWorkspace2(thread.repoPath);
|
|
6256
6254
|
} catch {
|
|
6257
6255
|
}
|
|
@@ -7872,7 +7870,7 @@ async function startMcpServer() {
|
|
|
7872
7870
|
);
|
|
7873
7871
|
server.tool(
|
|
7874
7872
|
"wait_for_turn",
|
|
7875
|
-
"Block until the thread finishes its current/queued turn (avoids polling). Use after send_to_thread or ask_git
|
|
7873
|
+
"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.",
|
|
7876
7874
|
{
|
|
7877
7875
|
ref: z3.string(),
|
|
7878
7876
|
timeoutMs: z3.number().optional()
|
|
@@ -7887,7 +7885,8 @@ async function startMcpServer() {
|
|
|
7887
7885
|
text: JSON.stringify({
|
|
7888
7886
|
id: thread.id,
|
|
7889
7887
|
status: result.status,
|
|
7890
|
-
text: result.text
|
|
7888
|
+
text: result.text,
|
|
7889
|
+
lastError: result.lastError
|
|
7891
7890
|
})
|
|
7892
7891
|
}
|
|
7893
7892
|
]
|
|
@@ -7896,7 +7895,7 @@ async function startMcpServer() {
|
|
|
7896
7895
|
);
|
|
7897
7896
|
server.tool(
|
|
7898
7897
|
"get_turn_result",
|
|
7899
|
-
"Final assistant message
|
|
7898
|
+
"Final assistant message (and lastError when the turn failed). Not the full transcript.",
|
|
7900
7899
|
{ ref: z3.string() },
|
|
7901
7900
|
async ({ ref }) => {
|
|
7902
7901
|
const result = orch.getTurnResult(ref);
|
|
@@ -6,9 +6,9 @@ import {
|
|
|
6
6
|
listWorkspaces,
|
|
7
7
|
removeWorkspace,
|
|
8
8
|
syncWorkspacesFromThreads
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-MRBKGFTL.js";
|
|
10
|
+
import "./chunk-WQTTUC4N.js";
|
|
11
|
+
import "./chunk-IFHKPZHA.js";
|
|
12
12
|
import "./chunk-R7BQBSDT.js";
|
|
13
13
|
import "./chunk-B3SJXYIJ.js";
|
|
14
14
|
import "./chunk-JOF3XIEM.js";
|
|
@@ -4,9 +4,9 @@ import {
|
|
|
4
4
|
listWorkspaces,
|
|
5
5
|
removeWorkspace,
|
|
6
6
|
syncWorkspacesFromThreads
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-MHJV4WS3.js";
|
|
8
|
+
import "./chunk-GR4JKWR4.js";
|
|
9
|
+
import "./chunk-HYKZEP5A.js";
|
|
10
10
|
import "./chunk-CIRXAYWS.js";
|
|
11
11
|
import "./chunk-FKOIHGKV.js";
|
|
12
12
|
import "./chunk-FT2SQOL4.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sideboard-ai/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.100",
|
|
4
4
|
"description": "Sideboard core — orchestration, agents, git worktrees, MCP server",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"worktree"
|
|
38
38
|
],
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@cursor/sdk": "^1.0.
|
|
40
|
+
"@cursor/sdk": "^1.0.28",
|
|
41
41
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
42
42
|
"better-sqlite3": "^11.9.1",
|
|
43
43
|
"chokidar": "^4.0.3",
|