@sideboard-ai/core 0.1.89 → 0.1.92
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 +129 -14
- package/dist/agents/cursor-runner.js +4 -1
- package/dist/{agents-LMUFTGKF.js → agents-JXQ5QHDU.js} +4 -4
- package/dist/{agents-ODBP7J6E.js → agents-TUV4NH7S.js} +5 -5
- package/dist/{chunk-RJLBSYUO.js → chunk-35LKGGOC.js} +45 -77
- package/dist/{chunk-WANQFU3S.js → chunk-6XBXVXX2.js} +2 -2
- package/dist/{chunk-7D27DD2X.js → chunk-CIRXAYWS.js} +260 -61
- package/dist/{chunk-B2KIO2SD.js → chunk-CLGO7TLO.js} +2 -2
- package/dist/{chunk-JE75QW2I.js → chunk-GJ2HJQIU.js} +236 -96
- package/dist/{chunk-CBJSPTBG.js → chunk-GXSYI7FH.js} +206 -5
- package/dist/{chunk-UHTNJKZX.js → chunk-NR6APJLD.js} +2 -2
- package/dist/{chunk-6EZRSCIT.js → chunk-QKYO6BHB.js} +2 -2
- package/dist/{chunk-ZXYWWSHZ.js → chunk-R7BQBSDT.js} +254 -61
- package/dist/{chunk-OB6IRIFV.js → chunk-XH2GS2LO.js} +2 -2
- package/dist/{chunk-VZ2L4AEJ.js → chunk-XUWDLRAE.js} +2 -2
- package/dist/{coordinator-prompt-UK5LYFN5.js → coordinator-prompt-AKEY4WSO.js} +2 -2
- package/dist/{coordinator-prompt-CI5SHONJ.js → coordinator-prompt-OQOOD5ET.js} +2 -2
- package/dist/{global-workspace-2YZ2V4I5.js → global-workspace-3GNPQCLE.js} +3 -3
- package/dist/{global-workspace-JQQLPJM5.js → global-workspace-M3OMVDDH.js} +3 -3
- package/dist/index.cjs +941 -455
- package/dist/index.d.cts +77 -19
- package/dist/index.d.ts +77 -19
- package/dist/index.js +166 -42
- package/dist/mcp/run-stdio.cjs +815 -428
- package/dist/mcp/run-stdio.js +77 -40
- package/dist/{workspaces-YWCC3WV4.js → workspaces-ERZC7ULY.js} +4 -4
- package/dist/{workspaces-FDO5L4NI.js → workspaces-J4WG6UFR.js} +4 -4
- package/dist/{worktree-7YNSJ224.js → worktree-DA4BOV7G.js} +7 -1
- package/dist/{worktree-4555QBQ7.js → worktree-EO5QAGJU.js} +7 -1
- package/package.json +1 -1
|
@@ -9,11 +9,13 @@ import {
|
|
|
9
9
|
} from "./chunk-DKHGWYWR.js";
|
|
10
10
|
import {
|
|
11
11
|
isOrchestratorThread
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-NR6APJLD.js";
|
|
13
13
|
import {
|
|
14
14
|
codexUnattendedGitConfigArgs,
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
mergeAgentGitAuthEnv,
|
|
16
|
+
resolveAgentGitAuthEnv,
|
|
17
|
+
resolveCodexGitWritableRoots
|
|
18
|
+
} from "./chunk-R7BQBSDT.js";
|
|
17
19
|
import {
|
|
18
20
|
claudeChromeEnabled,
|
|
19
21
|
isElectronLikeCommand,
|
|
@@ -151,17 +153,27 @@ function extractJsonErrorMessage(obj) {
|
|
|
151
153
|
return null;
|
|
152
154
|
}
|
|
153
155
|
var NODE_VERSION_FOOTER = /^Node\.js v\d+/i;
|
|
156
|
+
function isPinnedStderrLine(line) {
|
|
157
|
+
if (/^\s*at\s/.test(line)) return false;
|
|
158
|
+
return /cannot find (?:package|module)|ERR_MODULE_NOT_FOUND|cursor startup failed:/i.test(
|
|
159
|
+
line
|
|
160
|
+
);
|
|
161
|
+
}
|
|
154
162
|
function pushTurnStderr(tail, line, maxLines = 12) {
|
|
155
163
|
const trimmed = line.trim();
|
|
156
164
|
if (!trimmed) return;
|
|
157
165
|
if (NODE_VERSION_FOOTER.test(trimmed)) return;
|
|
158
166
|
if (/^reconnecting\.\.\./i.test(trimmed)) return;
|
|
159
167
|
tail.push(trimmed);
|
|
160
|
-
while (tail.length > maxLines)
|
|
168
|
+
while (tail.length > maxLines) {
|
|
169
|
+
const dropIdx = tail.findIndex((l) => !isPinnedStderrLine(l));
|
|
170
|
+
if (dropIdx === -1) tail.shift();
|
|
171
|
+
else tail.splice(dropIdx, 1);
|
|
172
|
+
}
|
|
161
173
|
}
|
|
162
174
|
function looksLikeMinifiedJsDump(line) {
|
|
163
175
|
if (line.length < 200) return false;
|
|
164
|
-
return /yield Promise\.all/.test(line) || /\(0,[A-Za-z$]\.\w+\)/.test(line) || /CURSOR_RIPGREP_PATH/.test(line);
|
|
176
|
+
return /yield Promise\.all/.test(line) || /\(0,[A-Za-z$]\.\w+\)/.test(line) || /CURSOR_RIPGREP_PATH/.test(line) || /findFilesWithRipgrep/.test(line) || /@cursor\/sdk\/dist\//.test(line);
|
|
165
177
|
}
|
|
166
178
|
function looksLikeNestedElectronCrash(line) {
|
|
167
179
|
return /HasCustomHostObject|ElectronInitializeICUandStartNode/i.test(line);
|
|
@@ -178,7 +190,15 @@ function summarizeTurnStderr(tail, maxChars = 500) {
|
|
|
178
190
|
const cursorStartup = [...tail].reverse().find((line) => /cursor startup failed:/i.test(line));
|
|
179
191
|
if (cursorStartup) return clipStderr(cursorStartup, maxChars);
|
|
180
192
|
if (tail.some(looksLikeNestedElectronCrash)) return NESTED_ELECTRON_SUMMARY;
|
|
181
|
-
|
|
193
|
+
if (tail.some(
|
|
194
|
+
(line) => /\[resource_exhausted\]|resource_exhausted/i.test(line) || /findFilesWithRipgrep/.test(line)
|
|
195
|
+
)) {
|
|
196
|
+
return clipStderr(
|
|
197
|
+
"Cursor local file search failed (ripgrep / resource_exhausted). Wait a minute and retry; if it keeps happening, check Cursor usage.",
|
|
198
|
+
maxChars
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
const moduleMissing = [...tail].reverse().find((line) => /cannot find (?:package|module)/i.test(line));
|
|
182
202
|
if (moduleMissing) return clipStderr(moduleMissing, maxChars);
|
|
183
203
|
const useful = tail.filter((line) => !looksLikeMinifiedJsDump(line));
|
|
184
204
|
if (useful.length === 0 && tail.some(looksLikeMinifiedJsDump)) {
|
|
@@ -197,7 +217,7 @@ function looksLikeAgentFailureMessage(text) {
|
|
|
197
217
|
if (!lower) return false;
|
|
198
218
|
return /you've hit your|hit your (session|weekly|opus) limit|usage limit/.test(lower) || /credit balance is too low|out of credits|insufficient.?quota|quota.?exceeded/.test(lower) || /invalid user api key|invalid api key|not logged in|not authenticated|unauthorized/.test(
|
|
199
219
|
lower
|
|
200
|
-
) || /\b429\b|too many requests|rate.?limit/.test(lower) || /prompt is too long|context.*(too long|exceed)|conversation too long/.test(lower);
|
|
220
|
+
) || /\b429\b|too many requests|rate.?limit/.test(lower) || /prompt is too long|context.*(too long|exceed)|conversation too long/.test(lower) || /\[resource_exhausted\]|resource_exhausted/.test(lower) || /findFilesWithRipgrep/.test(text);
|
|
201
221
|
}
|
|
202
222
|
function fallbackTurnFailDetail(assistantText) {
|
|
203
223
|
const t = assistantText.trim();
|
|
@@ -219,6 +239,9 @@ function humanizeAgentFailDetail(detail) {
|
|
|
219
239
|
if (/\b429\b|rate.?limit|too many requests/.test(lower)) {
|
|
220
240
|
return `${raw} \u2014 wait a moment and retry.`;
|
|
221
241
|
}
|
|
242
|
+
if (/\[resource_exhausted\]|resource_exhausted|findfileswithripgrep/.test(lower)) {
|
|
243
|
+
return "Cursor local file search failed (ripgrep / resource_exhausted). Wait a minute and retry; if it keeps happening, check Cursor usage.";
|
|
244
|
+
}
|
|
222
245
|
if (/invalid user api key|invalid api key|not logged in|not authenticated|unauthorized|authentication|please run.*login|codex login|claude auth|cursor api/.test(
|
|
223
246
|
lower
|
|
224
247
|
)) {
|
|
@@ -566,7 +589,7 @@ var brightsyAdapter = {
|
|
|
566
589
|
};
|
|
567
590
|
|
|
568
591
|
// src/agents/claude.ts
|
|
569
|
-
import { existsSync as
|
|
592
|
+
import { existsSync as existsSync5 } from "fs";
|
|
570
593
|
|
|
571
594
|
// src/agents/claude-mcp.ts
|
|
572
595
|
function parseMcpList(text) {
|
|
@@ -603,10 +626,10 @@ function mcpAllowTools(servers) {
|
|
|
603
626
|
}
|
|
604
627
|
|
|
605
628
|
// src/agents/injected-mcp.ts
|
|
606
|
-
import { existsSync as
|
|
629
|
+
import { existsSync as existsSync4, mkdtempSync, writeFileSync } from "fs";
|
|
607
630
|
import { createRequire } from "module";
|
|
608
631
|
import { tmpdir } from "os";
|
|
609
|
-
import { dirname, join } from "path";
|
|
632
|
+
import { dirname, join as join3 } from "path";
|
|
610
633
|
import { fileURLToPath } from "url";
|
|
611
634
|
|
|
612
635
|
// src/mcp/profile.ts
|
|
@@ -616,14 +639,46 @@ function sideboardMcpProfile(env = process.env) {
|
|
|
616
639
|
}
|
|
617
640
|
|
|
618
641
|
// src/agents/node-launch.ts
|
|
642
|
+
import { existsSync as existsSync2 } from "fs";
|
|
643
|
+
import { homedir } from "os";
|
|
644
|
+
import { join } from "path";
|
|
619
645
|
function isAsarPath(filePath) {
|
|
646
|
+
if (/\.asar\.unpacked([/\\]|$)/.test(filePath)) return false;
|
|
620
647
|
return /\.asar([/\\]|$)/.test(filePath);
|
|
621
648
|
}
|
|
649
|
+
function unpackedAsarPath(filePath) {
|
|
650
|
+
if (!isAsarPath(filePath)) return null;
|
|
651
|
+
const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
|
|
652
|
+
if (unpacked === filePath) return null;
|
|
653
|
+
return existsSync2(unpacked) ? unpacked : null;
|
|
654
|
+
}
|
|
655
|
+
function nodeReadableScriptPath(scriptPath) {
|
|
656
|
+
return unpackedAsarPath(scriptPath) ?? scriptPath;
|
|
657
|
+
}
|
|
658
|
+
var WELL_KNOWN_NODE_BINS = [
|
|
659
|
+
"/opt/homebrew/bin/node",
|
|
660
|
+
"/usr/local/bin/node"
|
|
661
|
+
];
|
|
662
|
+
async function findSystemNode() {
|
|
663
|
+
const whichNode = await run("which", ["node"], { reject: false });
|
|
664
|
+
const fromWhich = whichNode.exitCode === 0 && whichNode.stdout.trim() ? whichNode.stdout.trim() : "";
|
|
665
|
+
if (fromWhich && !isElectronLikeCommand(fromWhich)) return fromWhich;
|
|
666
|
+
const fallbacks = [
|
|
667
|
+
...WELL_KNOWN_NODE_BINS,
|
|
668
|
+
join(homedir(), ".local/share/fnm/aliases/default/bin/node"),
|
|
669
|
+
join(homedir(), ".nvm/current/bin/node")
|
|
670
|
+
];
|
|
671
|
+
for (const bin of fallbacks) {
|
|
672
|
+
if (existsSync2(bin) && !isElectronLikeCommand(bin)) return bin;
|
|
673
|
+
}
|
|
674
|
+
return null;
|
|
675
|
+
}
|
|
622
676
|
function applyNodeLaunch(launch, args) {
|
|
677
|
+
const readableArgs = args.map(nodeReadableScriptPath);
|
|
623
678
|
if (!launch.env.ELECTRON_RUN_AS_NODE) {
|
|
624
|
-
return { file: launch.file, args, env: launch.env };
|
|
679
|
+
return { file: launch.file, args: readableArgs, env: launch.env };
|
|
625
680
|
}
|
|
626
|
-
const wrapped = wrapElectronAsNodeLaunch(launch.file,
|
|
681
|
+
const wrapped = wrapElectronAsNodeLaunch(launch.file, readableArgs);
|
|
627
682
|
if (process.platform === "win32") {
|
|
628
683
|
return { file: wrapped.file, args: wrapped.args, env: launch.env };
|
|
629
684
|
}
|
|
@@ -632,16 +687,12 @@ function applyNodeLaunch(launch, args) {
|
|
|
632
687
|
return { file: wrapped.file, args: wrapped.args, env };
|
|
633
688
|
}
|
|
634
689
|
async function resolveNodeLaunch(scriptPath) {
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
const whichNode = await run("which", ["node"], { reject: false });
|
|
642
|
-
const nodeBin = whichNode.exitCode === 0 && whichNode.stdout.trim() ? whichNode.stdout.trim() : null;
|
|
643
|
-
if (nodeBin) {
|
|
644
|
-
return { file: nodeBin, env: {} };
|
|
690
|
+
const script = nodeReadableScriptPath(scriptPath);
|
|
691
|
+
if (!isAsarPath(script)) {
|
|
692
|
+
const nodeBin = await findSystemNode();
|
|
693
|
+
if (nodeBin) {
|
|
694
|
+
return { file: nodeBin, env: {} };
|
|
695
|
+
}
|
|
645
696
|
}
|
|
646
697
|
return {
|
|
647
698
|
file: process.execPath,
|
|
@@ -649,6 +700,42 @@ async function resolveNodeLaunch(scriptPath) {
|
|
|
649
700
|
};
|
|
650
701
|
}
|
|
651
702
|
|
|
703
|
+
// src/agents/packaged-runtime.ts
|
|
704
|
+
import { existsSync as existsSync3 } from "fs";
|
|
705
|
+
import { join as join2 } from "path";
|
|
706
|
+
function electronResourcesPath() {
|
|
707
|
+
const resources = process.resourcesPath;
|
|
708
|
+
if (typeof resources !== "string" || !resources) return null;
|
|
709
|
+
return resources;
|
|
710
|
+
}
|
|
711
|
+
function packagedCursorRuntimeDir() {
|
|
712
|
+
const resources = electronResourcesPath();
|
|
713
|
+
if (!resources) return null;
|
|
714
|
+
const dir = join2(resources, "cursor-runtime");
|
|
715
|
+
if (!existsSync3(join2(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
|
|
716
|
+
return dir;
|
|
717
|
+
}
|
|
718
|
+
function packagedCursorRunnerPath() {
|
|
719
|
+
const dir = packagedCursorRuntimeDir();
|
|
720
|
+
return dir ? join2(dir, "core-dist", "agents", "cursor-runner.js") : null;
|
|
721
|
+
}
|
|
722
|
+
function packagedMcpDir() {
|
|
723
|
+
const resources = electronResourcesPath();
|
|
724
|
+
if (!resources) return null;
|
|
725
|
+
const dir = join2(resources, "sideboard-mcp");
|
|
726
|
+
if (!existsSync3(join2(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
|
|
727
|
+
return dir;
|
|
728
|
+
}
|
|
729
|
+
function packagedMcpStdioPath() {
|
|
730
|
+
const dir = packagedMcpDir();
|
|
731
|
+
return dir ? join2(dir, "core-dist", "mcp", "run-stdio.js") : null;
|
|
732
|
+
}
|
|
733
|
+
function packagedCursorRipgrepCandidate(platformPkg, binName) {
|
|
734
|
+
const dir = packagedCursorRuntimeDir();
|
|
735
|
+
if (!dir) return null;
|
|
736
|
+
return join2(dir, "node_modules", platformPkg, "bin", binName);
|
|
737
|
+
}
|
|
738
|
+
|
|
652
739
|
// src/agents/injected-mcp.ts
|
|
653
740
|
var SIDEBOARD_MCP_ALLOWED_TOOLS = [
|
|
654
741
|
"mcp__sideboard",
|
|
@@ -757,7 +844,7 @@ function corePackageDir() {
|
|
|
757
844
|
} catch {
|
|
758
845
|
}
|
|
759
846
|
try {
|
|
760
|
-
const req = createRequire(
|
|
847
|
+
const req = createRequire(join3(process.cwd(), "package.json"));
|
|
761
848
|
return dirname(req.resolve("@sideboard-ai/core"));
|
|
762
849
|
} catch {
|
|
763
850
|
return process.cwd();
|
|
@@ -765,20 +852,22 @@ function corePackageDir() {
|
|
|
765
852
|
}
|
|
766
853
|
function findSideboardMcpJsEntry() {
|
|
767
854
|
const override = process.env.SIDEBOARD_MCP_ENTRY?.trim() || process.env.SIDEBOARD_CLI?.trim();
|
|
768
|
-
if (override &&
|
|
855
|
+
if (override && existsSync4(override)) return override;
|
|
856
|
+
const packaged = packagedMcpStdioPath();
|
|
857
|
+
if (packaged) return packaged;
|
|
769
858
|
let dir = corePackageDir();
|
|
770
859
|
for (let i = 0; i < 10; i++) {
|
|
771
860
|
const candidates = [
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
861
|
+
join3(dir, "mcp/run-stdio.js"),
|
|
862
|
+
join3(dir, "mcp/run-stdio.cjs"),
|
|
863
|
+
join3(dir, "dist/mcp/run-stdio.js"),
|
|
864
|
+
join3(dir, "dist/mcp/run-stdio.cjs"),
|
|
865
|
+
join3(dir, "packages/core/dist/mcp/run-stdio.js"),
|
|
866
|
+
join3(dir, "packages/cli/dist/index.js"),
|
|
867
|
+
join3(dir, "cli/dist/index.js")
|
|
779
868
|
];
|
|
780
869
|
for (const p of candidates) {
|
|
781
|
-
if (
|
|
870
|
+
if (existsSync4(p) && !isAsarPath(p)) return p;
|
|
782
871
|
}
|
|
783
872
|
const parent = dirname(dir);
|
|
784
873
|
if (parent === dir) break;
|
|
@@ -792,12 +881,14 @@ async function resolveSideboardMcpServer() {
|
|
|
792
881
|
const isCli = /[/\\]cli[/\\]dist[/\\]index\.js$/.test(entry);
|
|
793
882
|
const scriptArgs = isCli ? [entry, "mcp"] : [entry];
|
|
794
883
|
const launch = applyNodeLaunch(await resolveNodeLaunch(entry), scriptArgs);
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
884
|
+
if (launch.file !== "/bin/sh" && !isElectronLikeCommand(launch.file)) {
|
|
885
|
+
return {
|
|
886
|
+
name: "sideboard",
|
|
887
|
+
command: launch.file,
|
|
888
|
+
args: launch.args,
|
|
889
|
+
...Object.keys(launch.env).length > 0 ? { env: launch.env } : {}
|
|
890
|
+
};
|
|
891
|
+
}
|
|
801
892
|
}
|
|
802
893
|
const which = await run("which", ["sideboard"], { reject: false });
|
|
803
894
|
if (which.exitCode === 0 && which.stdout.trim()) {
|
|
@@ -820,7 +911,10 @@ async function buildInjectedMcpServers(opts) {
|
|
|
820
911
|
sideboard.env.SIDEBOARD_ORCHESTRATOR_THREAD_ID = orchId;
|
|
821
912
|
}
|
|
822
913
|
try {
|
|
823
|
-
|
|
914
|
+
mergeAgentGitAuthEnv(
|
|
915
|
+
sideboard.env,
|
|
916
|
+
await resolveAgentGitAuthEnv(sideboard.env)
|
|
917
|
+
);
|
|
824
918
|
} catch {
|
|
825
919
|
}
|
|
826
920
|
servers.push(sideboard);
|
|
@@ -842,9 +936,6 @@ async function buildInjectedMcpServers(opts) {
|
|
|
842
936
|
}
|
|
843
937
|
return servers;
|
|
844
938
|
}
|
|
845
|
-
function shSingleQuote(value) {
|
|
846
|
-
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
847
|
-
}
|
|
848
939
|
function cursorSafeMcpLaunch(command, args) {
|
|
849
940
|
if (process.platform === "win32") {
|
|
850
941
|
return args && args.length > 0 ? { command, args } : { command };
|
|
@@ -852,31 +943,13 @@ function cursorSafeMcpLaunch(command, args) {
|
|
|
852
943
|
const unwrapped = unwrapStrippedElectronLaunch(command, args);
|
|
853
944
|
const file = unwrapped?.file ?? command;
|
|
854
945
|
const fileArgs = unwrapped?.args ?? args ?? [];
|
|
855
|
-
|
|
856
|
-
return fileArgs.length > 0 ? { command: file, args: fileArgs } : { command: file };
|
|
857
|
-
}
|
|
858
|
-
const dir = join(appDataDir(), "mcp-launch");
|
|
859
|
-
mkdirSync(dir, { recursive: true });
|
|
860
|
-
const wrap = join(dir, "cursor-electron-as-node.sh");
|
|
861
|
-
const execLine = [file, ...fileArgs].map(shSingleQuote).join(" ");
|
|
862
|
-
writeFileSync(
|
|
863
|
-
wrap,
|
|
864
|
-
[
|
|
865
|
-
"#!/bin/sh",
|
|
866
|
-
"vars=`printenv | awk -F= '/^(ELECTRON_|CHROME_)/{print $1}'`",
|
|
867
|
-
'[ -n "$vars" ] && unset $vars',
|
|
868
|
-
"export ELECTRON_RUN_AS_NODE=1",
|
|
869
|
-
`exec ${execLine} "$@"`,
|
|
870
|
-
""
|
|
871
|
-
].join("\n"),
|
|
872
|
-
{ mode: 493 }
|
|
873
|
-
);
|
|
874
|
-
return { command: wrap };
|
|
946
|
+
return fileArgs.length > 0 ? { command: file, args: fileArgs } : { command: file };
|
|
875
947
|
}
|
|
876
948
|
function mcpSpawnEnv(env) {
|
|
877
949
|
if (!env) return void 0;
|
|
878
950
|
const out = { ...env };
|
|
879
951
|
delete out.ELECTRON_RUN_AS_NODE;
|
|
952
|
+
delete out.ELECTRON_RUN_AS_NODE;
|
|
880
953
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
881
954
|
}
|
|
882
955
|
function toCursorMcpServers(servers) {
|
|
@@ -936,14 +1009,14 @@ function writeMcpServersConfig(servers) {
|
|
|
936
1009
|
...env ? { env } : {}
|
|
937
1010
|
};
|
|
938
1011
|
}
|
|
939
|
-
const dir = mkdtempSync(
|
|
940
|
-
const cfgPath =
|
|
1012
|
+
const dir = mkdtempSync(join3(tmpdir(), "sideboard-mcp-"));
|
|
1013
|
+
const cfgPath = join3(dir, "mcp.json");
|
|
941
1014
|
writeFileSync(cfgPath, JSON.stringify({ mcpServers }, null, 2));
|
|
942
1015
|
return cfgPath;
|
|
943
1016
|
}
|
|
944
1017
|
|
|
945
1018
|
// src/agents/types.ts
|
|
946
|
-
var PLAN_MODE_INSTRUCTION = "Plan mode is active and must remain active until the user turns Plan mode off in the UI (or Approves / Hands off the plan). Analyze the codebase, search and read files as needed, and produce or refine a clear implementation plan. Do not modify, create, or delete any project files except via Sideboard MCP present_plan (writes .context/attachments/plan.md). When you need a clarifying decision (approach forks, auth choice, scope): (1) first write a short chat message that explains the decision and what each option means (tradeoffs, when to pick it) \u2014 do not leave the user staring at bare labels; (2) then call Sideboard MCP ask_user with the same options, including a description on every option. Sideboard shows questions in the composer and mirrors them in chat. After ask_user, wait for the user's next message with their answers before finalizing the plan. When the plan is ready for approval: (1) call present_plan with the full markdown plan (title + content) so Sideboard saves .context/attachments/plan.md and shows it in chat for Approve / Hand off / Copy; (2) Claude should also call ExitPlanMode after present_plan. Do not skip present_plan \u2014 the plan must be a markdown file, not only chat prose.";
|
|
1019
|
+
var PLAN_MODE_INSTRUCTION = "Plan mode is active and must remain active until the user turns Plan mode off in the UI (or Approves / Hands off the plan). Analyze the codebase, search and read files as needed, and produce or refine a clear implementation plan. Do not modify, create, or delete any project files except via Sideboard MCP present_plan (writes .context/attachments/plan.md). When you need a clarifying decision (approach forks, auth choice, scope) \u2014 not greetings, check-ins, or an invented task menu: (1) first write a short chat message that explains the decision and what each option means (tradeoffs, when to pick it) \u2014 do not leave the user staring at bare labels; (2) then call Sideboard MCP ask_user with the same options, including a description on every option. If one option is the obvious default, proceed without asking. Sideboard shows questions in the composer and mirrors them in chat. After ask_user, wait for the user's next message with their answers before finalizing the plan. When the plan is ready for approval: (1) call present_plan with the full markdown plan (title + content) so Sideboard saves .context/attachments/plan.md and shows it in chat for Approve / Hand off / Copy; (2) Claude should also call ExitPlanMode after present_plan. Do not skip present_plan \u2014 the plan must be a markdown file, not only chat prose.";
|
|
947
1020
|
function permissionMode(thread) {
|
|
948
1021
|
if (thread.sourceType === "orchestration") {
|
|
949
1022
|
return {
|
|
@@ -1085,7 +1158,7 @@ var claudeAdapter = {
|
|
|
1085
1158
|
async detect() {
|
|
1086
1159
|
const claude = resolveClaudeExecutable();
|
|
1087
1160
|
if (claude !== "claude") {
|
|
1088
|
-
if (!
|
|
1161
|
+
if (!existsSync5(claude)) {
|
|
1089
1162
|
return {
|
|
1090
1163
|
agent: "claude",
|
|
1091
1164
|
installed: false,
|
|
@@ -1134,7 +1207,7 @@ var claudeAdapter = {
|
|
|
1134
1207
|
);
|
|
1135
1208
|
}
|
|
1136
1209
|
const mode = permissionMode(thread);
|
|
1137
|
-
const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-
|
|
1210
|
+
const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-3GNPQCLE.js");
|
|
1138
1211
|
const isOrchestrator = isOrchestratorThread2(thread);
|
|
1139
1212
|
const injectedServers = await buildInjectedMcpServers({
|
|
1140
1213
|
includeSideboard: true,
|
|
@@ -1336,9 +1409,9 @@ function parseIssuesJson(raw) {
|
|
|
1336
1409
|
}
|
|
1337
1410
|
|
|
1338
1411
|
// src/agents/codex.ts
|
|
1339
|
-
import { existsSync as
|
|
1340
|
-
import { homedir } from "os";
|
|
1341
|
-
import { join as
|
|
1412
|
+
import { existsSync as existsSync6, readFileSync, statSync } from "fs";
|
|
1413
|
+
import { homedir as homedir2 } from "os";
|
|
1414
|
+
import { join as join4 } from "path";
|
|
1342
1415
|
var CODEX_PROMPT_ARG_MAX = 2e5;
|
|
1343
1416
|
var FALLBACK_CODEX_MODELS = [
|
|
1344
1417
|
{ id: "gpt-5.6-sol", displayName: "GPT-5.6 Sol" },
|
|
@@ -1358,7 +1431,7 @@ async function listCodexModels() {
|
|
|
1358
1431
|
if (codex === "codex") {
|
|
1359
1432
|
const which = await run("which", ["codex"], { reject: false });
|
|
1360
1433
|
if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
|
|
1361
|
-
} else if (!
|
|
1434
|
+
} else if (!existsSync6(codex)) {
|
|
1362
1435
|
return FALLBACK_CODEX_MODELS;
|
|
1363
1436
|
}
|
|
1364
1437
|
const listed = await run(codex, ["debug", "models"], { reject: false });
|
|
@@ -1393,11 +1466,11 @@ function usageFromCodex(usage) {
|
|
|
1393
1466
|
}
|
|
1394
1467
|
function codexConfigHasNetworkAccess() {
|
|
1395
1468
|
const candidates = [
|
|
1396
|
-
|
|
1397
|
-
|
|
1469
|
+
join4(homedir2(), ".codex", "config.toml"),
|
|
1470
|
+
join4(homedir2(), ".config", "codex", "config.toml")
|
|
1398
1471
|
];
|
|
1399
1472
|
for (const path of candidates) {
|
|
1400
|
-
if (!
|
|
1473
|
+
if (!existsSync6(path)) continue;
|
|
1401
1474
|
const text = readFileSync(path, "utf8");
|
|
1402
1475
|
if (/network_access\s*=\s*true/.test(text)) return true;
|
|
1403
1476
|
}
|
|
@@ -1430,8 +1503,8 @@ function asRecord(value) {
|
|
|
1430
1503
|
return void 0;
|
|
1431
1504
|
}
|
|
1432
1505
|
function codexLooksAuthenticated() {
|
|
1433
|
-
const authPath =
|
|
1434
|
-
if (!
|
|
1506
|
+
const authPath = join4(homedir2(), ".codex", "auth.json");
|
|
1507
|
+
if (!existsSync6(authPath)) return false;
|
|
1435
1508
|
try {
|
|
1436
1509
|
return statSync(authPath).size > 2;
|
|
1437
1510
|
} catch {
|
|
@@ -1443,7 +1516,7 @@ var codexAdapter = {
|
|
|
1443
1516
|
async detect() {
|
|
1444
1517
|
const codex = resolveAgentExecutable("codex");
|
|
1445
1518
|
if (codex !== "codex") {
|
|
1446
|
-
if (!
|
|
1519
|
+
if (!existsSync6(codex)) {
|
|
1447
1520
|
return {
|
|
1448
1521
|
agent: "codex",
|
|
1449
1522
|
installed: false,
|
|
@@ -1516,8 +1589,13 @@ var codexAdapter = {
|
|
|
1516
1589
|
// `codex exec` rejects `--ask-for-approval` (global-only on newer CLIs).
|
|
1517
1590
|
"-c",
|
|
1518
1591
|
'approval_policy="never"',
|
|
1519
|
-
// Seatbelt cannot use the login Keychain;
|
|
1520
|
-
|
|
1592
|
+
// Seatbelt cannot use the login Keychain; inherit GH_CONFIG_DIR / GIT_CONFIG_*.
|
|
1593
|
+
// Default policy also strips *TOKEN*. Linked worktrees need the main
|
|
1594
|
+
// repo `.git` (+ `.git/worktrees/<name>`) as writable_roots so git commit
|
|
1595
|
+
// can create index.lock.
|
|
1596
|
+
...codexUnattendedGitConfigArgs(mode.codexSandbox, {
|
|
1597
|
+
writableRoots: mode.codexSandbox === "workspace-write" ? await resolveCodexGitWritableRoots(thread.worktreePath) : []
|
|
1598
|
+
}),
|
|
1521
1599
|
...model ? ["--model", model] : [],
|
|
1522
1600
|
...mcpOverrides
|
|
1523
1601
|
];
|
|
@@ -1662,10 +1740,10 @@ var codexAdapter = {
|
|
|
1662
1740
|
};
|
|
1663
1741
|
|
|
1664
1742
|
// src/agents/cursor.ts
|
|
1665
|
-
import { existsSync as
|
|
1666
|
-
import { createRequire as
|
|
1667
|
-
import { dirname as
|
|
1668
|
-
import { fileURLToPath as
|
|
1743
|
+
import { existsSync as existsSync8 } from "fs";
|
|
1744
|
+
import { createRequire as createRequire3 } from "module";
|
|
1745
|
+
import { dirname as dirname3, join as join6 } from "path";
|
|
1746
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
1669
1747
|
import { Cursor } from "@cursor/sdk";
|
|
1670
1748
|
|
|
1671
1749
|
// src/agents/cursor-events.ts
|
|
@@ -1837,6 +1915,65 @@ function parseCursorRunnerLine(line) {
|
|
|
1837
1915
|
}
|
|
1838
1916
|
}
|
|
1839
1917
|
|
|
1918
|
+
// src/agents/cursor-ripgrep.ts
|
|
1919
|
+
import { existsSync as existsSync7 } from "fs";
|
|
1920
|
+
import { createRequire as createRequire2 } from "module";
|
|
1921
|
+
import { dirname as dirname2, isAbsolute, join as join5, parse, resolve as resolvePath } from "path";
|
|
1922
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1923
|
+
var RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
|
|
1924
|
+
function rgBinaryName() {
|
|
1925
|
+
return process.platform === "win32" ? "rg.exe" : "rg";
|
|
1926
|
+
}
|
|
1927
|
+
function platformRipgrepPackage() {
|
|
1928
|
+
return `@cursor/sdk-${process.platform}-${process.arch}`;
|
|
1929
|
+
}
|
|
1930
|
+
function usableRipgrepPath(candidate) {
|
|
1931
|
+
const raw = candidate?.trim();
|
|
1932
|
+
if (!raw || !isAbsolute(raw)) return null;
|
|
1933
|
+
const readable = nodeReadableScriptPath(raw);
|
|
1934
|
+
if (!existsSync7(readable) || isAsarPath(readable)) return null;
|
|
1935
|
+
return readable;
|
|
1936
|
+
}
|
|
1937
|
+
function walkForBundledRipgrep(startFile) {
|
|
1938
|
+
if (!startFile) return null;
|
|
1939
|
+
const pkg = platformRipgrepPackage();
|
|
1940
|
+
const name = rgBinaryName();
|
|
1941
|
+
let dir = dirname2(resolvePath(startFile));
|
|
1942
|
+
const root = parse(dir).root;
|
|
1943
|
+
while (dir !== root) {
|
|
1944
|
+
const hit = usableRipgrepPath(join5(dir, "node_modules", pkg, "bin", name));
|
|
1945
|
+
if (hit) return hit;
|
|
1946
|
+
const next = dirname2(dir);
|
|
1947
|
+
if (next === dir) break;
|
|
1948
|
+
dir = next;
|
|
1949
|
+
}
|
|
1950
|
+
return null;
|
|
1951
|
+
}
|
|
1952
|
+
function requireResolveBundledRipgrep(fromFile) {
|
|
1953
|
+
try {
|
|
1954
|
+
const req = createRequire2(fromFile);
|
|
1955
|
+
const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
|
|
1956
|
+
return usableRipgrepPath(join5(dirname2(pkgJson), "bin", rgBinaryName()));
|
|
1957
|
+
} catch {
|
|
1958
|
+
return null;
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
function resolveCursorRipgrepPath(opts) {
|
|
1962
|
+
const env = opts?.env ?? process.env;
|
|
1963
|
+
const fromEnv = usableRipgrepPath(env[RIPGREP_ENV]);
|
|
1964
|
+
if (fromEnv) return fromEnv;
|
|
1965
|
+
const fromPackaged = usableRipgrepPath(
|
|
1966
|
+
packagedCursorRipgrepCandidate(platformRipgrepPackage(), rgBinaryName())
|
|
1967
|
+
);
|
|
1968
|
+
if (fromPackaged) return fromPackaged;
|
|
1969
|
+
const start = opts?.startFile?.trim() || process.argv[1] || fileURLToPath2(import.meta.url);
|
|
1970
|
+
return walkForBundledRipgrep(start) ?? requireResolveBundledRipgrep(start);
|
|
1971
|
+
}
|
|
1972
|
+
function cursorRipgrepEnv(opts) {
|
|
1973
|
+
const path = resolveCursorRipgrepPath(opts);
|
|
1974
|
+
return path ? { [RIPGREP_ENV]: path } : {};
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1840
1977
|
// src/agents/cursor.ts
|
|
1841
1978
|
var FALLBACK_CURSOR_MODELS = [
|
|
1842
1979
|
{ id: "default", displayName: "Auto" },
|
|
@@ -1883,30 +2020,32 @@ function entryDir() {
|
|
|
1883
2020
|
const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
|
|
1884
2021
|
if (cjsDir) return cjsDir;
|
|
1885
2022
|
try {
|
|
1886
|
-
return
|
|
2023
|
+
return dirname3(fileURLToPath3(import.meta.url));
|
|
1887
2024
|
} catch {
|
|
1888
2025
|
try {
|
|
1889
|
-
const req =
|
|
1890
|
-
return
|
|
2026
|
+
const req = createRequire3(process.cwd() + "/");
|
|
2027
|
+
return dirname3(req.resolve("@sideboard-ai/core"));
|
|
1891
2028
|
} catch {
|
|
1892
2029
|
return process.cwd();
|
|
1893
2030
|
}
|
|
1894
2031
|
}
|
|
1895
2032
|
}
|
|
1896
2033
|
function cursorRunnerPath() {
|
|
2034
|
+
const packaged = packagedCursorRunnerPath();
|
|
2035
|
+
if (packaged) return packaged;
|
|
1897
2036
|
const root = entryDir();
|
|
1898
2037
|
const candidates = [
|
|
1899
|
-
|
|
1900
|
-
|
|
2038
|
+
join6(root, "agents", "cursor-runner.js"),
|
|
2039
|
+
join6(root, "agents", "cursor-runner.cjs"),
|
|
1901
2040
|
// If somehow resolved from package root instead of dist/
|
|
1902
|
-
|
|
1903
|
-
|
|
2041
|
+
join6(root, "dist", "agents", "cursor-runner.js"),
|
|
2042
|
+
join6(root, "dist", "agents", "cursor-runner.cjs"),
|
|
1904
2043
|
// Source tree (dev): packages/core/src/agents/cursor-runner.ts
|
|
1905
|
-
|
|
1906
|
-
|
|
2044
|
+
join6(root, "cursor-runner.ts"),
|
|
2045
|
+
join6(root, "src", "agents", "cursor-runner.ts")
|
|
1907
2046
|
];
|
|
1908
2047
|
for (const candidate of candidates) {
|
|
1909
|
-
if (
|
|
2048
|
+
if (existsSync8(candidate)) return candidate;
|
|
1910
2049
|
}
|
|
1911
2050
|
return candidates[0];
|
|
1912
2051
|
}
|
|
@@ -1969,6 +2108,7 @@ var cursorAdapter = {
|
|
|
1969
2108
|
stdin: JSON.stringify(req),
|
|
1970
2109
|
env: {
|
|
1971
2110
|
...launch.env,
|
|
2111
|
+
...cursorRipgrepEnv({ startFile: runner }),
|
|
1972
2112
|
...apiKey ? { CURSOR_API_KEY: apiKey } : {}
|
|
1973
2113
|
}
|
|
1974
2114
|
};
|
|
@@ -1991,7 +2131,7 @@ var cursorAdapter = {
|
|
|
1991
2131
|
};
|
|
1992
2132
|
|
|
1993
2133
|
// src/agents/opencode.ts
|
|
1994
|
-
import { existsSync as
|
|
2134
|
+
import { existsSync as existsSync9 } from "fs";
|
|
1995
2135
|
var FALLBACK_OPENCODE_MODELS = [
|
|
1996
2136
|
{ id: "opencode/big-pickle", displayName: "opencode \xB7 big-pickle" },
|
|
1997
2137
|
{
|
|
@@ -2032,7 +2172,7 @@ async function listOpencodeModels() {
|
|
|
2032
2172
|
if (opencode === "opencode") {
|
|
2033
2173
|
const which = await run("which", ["opencode"], { reject: false });
|
|
2034
2174
|
if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
|
|
2035
|
-
} else if (!
|
|
2175
|
+
} else if (!existsSync9(opencode)) {
|
|
2036
2176
|
return FALLBACK_OPENCODE_MODELS;
|
|
2037
2177
|
}
|
|
2038
2178
|
const listed = await run(opencode, ["models"], { reject: false });
|
|
@@ -2067,7 +2207,7 @@ var opencodeAdapter = {
|
|
|
2067
2207
|
async detect() {
|
|
2068
2208
|
const opencode = resolveAgentExecutable("opencode");
|
|
2069
2209
|
if (opencode !== "opencode") {
|
|
2070
|
-
if (!
|
|
2210
|
+
if (!existsSync9(opencode)) {
|
|
2071
2211
|
return {
|
|
2072
2212
|
agent: "opencode",
|
|
2073
2213
|
installed: false,
|