@sideboard-ai/core 0.1.89 → 0.1.95
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-HBLA6FEV.js} +4 -4
- package/dist/{agents-ODBP7J6E.js → agents-WS5QV6LE.js} +5 -5
- 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-CBJSPTBG.js → chunk-GXSYI7FH.js} +206 -5
- package/dist/{chunk-RJLBSYUO.js → chunk-KWNUZ4LR.js} +46 -77
- 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-JE75QW2I.js → chunk-WBX46OPD.js} +237 -96
- 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 +1021 -473
- package/dist/index.d.cts +91 -20
- package/dist/index.d.ts +91 -20
- package/dist/index.js +244 -59
- package/dist/mcp/run-stdio.cjs +816 -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) {
|
|
@@ -885,6 +958,7 @@ function toCursorMcpServers(servers) {
|
|
|
885
958
|
const env = mcpSpawnEnv(s.env);
|
|
886
959
|
const launch = cursorSafeMcpLaunch(s.command, s.args);
|
|
887
960
|
out[s.name] = {
|
|
961
|
+
type: "stdio",
|
|
888
962
|
command: launch.command,
|
|
889
963
|
...launch.args && launch.args.length > 0 ? { args: launch.args } : {},
|
|
890
964
|
...env ? { env } : {}
|
|
@@ -936,14 +1010,14 @@ function writeMcpServersConfig(servers) {
|
|
|
936
1010
|
...env ? { env } : {}
|
|
937
1011
|
};
|
|
938
1012
|
}
|
|
939
|
-
const dir = mkdtempSync(
|
|
940
|
-
const cfgPath =
|
|
1013
|
+
const dir = mkdtempSync(join3(tmpdir(), "sideboard-mcp-"));
|
|
1014
|
+
const cfgPath = join3(dir, "mcp.json");
|
|
941
1015
|
writeFileSync(cfgPath, JSON.stringify({ mcpServers }, null, 2));
|
|
942
1016
|
return cfgPath;
|
|
943
1017
|
}
|
|
944
1018
|
|
|
945
1019
|
// 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.";
|
|
1020
|
+
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
1021
|
function permissionMode(thread) {
|
|
948
1022
|
if (thread.sourceType === "orchestration") {
|
|
949
1023
|
return {
|
|
@@ -1085,7 +1159,7 @@ var claudeAdapter = {
|
|
|
1085
1159
|
async detect() {
|
|
1086
1160
|
const claude = resolveClaudeExecutable();
|
|
1087
1161
|
if (claude !== "claude") {
|
|
1088
|
-
if (!
|
|
1162
|
+
if (!existsSync5(claude)) {
|
|
1089
1163
|
return {
|
|
1090
1164
|
agent: "claude",
|
|
1091
1165
|
installed: false,
|
|
@@ -1134,7 +1208,7 @@ var claudeAdapter = {
|
|
|
1134
1208
|
);
|
|
1135
1209
|
}
|
|
1136
1210
|
const mode = permissionMode(thread);
|
|
1137
|
-
const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-
|
|
1211
|
+
const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-3GNPQCLE.js");
|
|
1138
1212
|
const isOrchestrator = isOrchestratorThread2(thread);
|
|
1139
1213
|
const injectedServers = await buildInjectedMcpServers({
|
|
1140
1214
|
includeSideboard: true,
|
|
@@ -1336,9 +1410,9 @@ function parseIssuesJson(raw) {
|
|
|
1336
1410
|
}
|
|
1337
1411
|
|
|
1338
1412
|
// src/agents/codex.ts
|
|
1339
|
-
import { existsSync as
|
|
1340
|
-
import { homedir } from "os";
|
|
1341
|
-
import { join as
|
|
1413
|
+
import { existsSync as existsSync6, readFileSync, statSync } from "fs";
|
|
1414
|
+
import { homedir as homedir2 } from "os";
|
|
1415
|
+
import { join as join4 } from "path";
|
|
1342
1416
|
var CODEX_PROMPT_ARG_MAX = 2e5;
|
|
1343
1417
|
var FALLBACK_CODEX_MODELS = [
|
|
1344
1418
|
{ id: "gpt-5.6-sol", displayName: "GPT-5.6 Sol" },
|
|
@@ -1358,7 +1432,7 @@ async function listCodexModels() {
|
|
|
1358
1432
|
if (codex === "codex") {
|
|
1359
1433
|
const which = await run("which", ["codex"], { reject: false });
|
|
1360
1434
|
if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
|
|
1361
|
-
} else if (!
|
|
1435
|
+
} else if (!existsSync6(codex)) {
|
|
1362
1436
|
return FALLBACK_CODEX_MODELS;
|
|
1363
1437
|
}
|
|
1364
1438
|
const listed = await run(codex, ["debug", "models"], { reject: false });
|
|
@@ -1393,11 +1467,11 @@ function usageFromCodex(usage) {
|
|
|
1393
1467
|
}
|
|
1394
1468
|
function codexConfigHasNetworkAccess() {
|
|
1395
1469
|
const candidates = [
|
|
1396
|
-
|
|
1397
|
-
|
|
1470
|
+
join4(homedir2(), ".codex", "config.toml"),
|
|
1471
|
+
join4(homedir2(), ".config", "codex", "config.toml")
|
|
1398
1472
|
];
|
|
1399
1473
|
for (const path of candidates) {
|
|
1400
|
-
if (!
|
|
1474
|
+
if (!existsSync6(path)) continue;
|
|
1401
1475
|
const text = readFileSync(path, "utf8");
|
|
1402
1476
|
if (/network_access\s*=\s*true/.test(text)) return true;
|
|
1403
1477
|
}
|
|
@@ -1430,8 +1504,8 @@ function asRecord(value) {
|
|
|
1430
1504
|
return void 0;
|
|
1431
1505
|
}
|
|
1432
1506
|
function codexLooksAuthenticated() {
|
|
1433
|
-
const authPath =
|
|
1434
|
-
if (!
|
|
1507
|
+
const authPath = join4(homedir2(), ".codex", "auth.json");
|
|
1508
|
+
if (!existsSync6(authPath)) return false;
|
|
1435
1509
|
try {
|
|
1436
1510
|
return statSync(authPath).size > 2;
|
|
1437
1511
|
} catch {
|
|
@@ -1443,7 +1517,7 @@ var codexAdapter = {
|
|
|
1443
1517
|
async detect() {
|
|
1444
1518
|
const codex = resolveAgentExecutable("codex");
|
|
1445
1519
|
if (codex !== "codex") {
|
|
1446
|
-
if (!
|
|
1520
|
+
if (!existsSync6(codex)) {
|
|
1447
1521
|
return {
|
|
1448
1522
|
agent: "codex",
|
|
1449
1523
|
installed: false,
|
|
@@ -1516,8 +1590,13 @@ var codexAdapter = {
|
|
|
1516
1590
|
// `codex exec` rejects `--ask-for-approval` (global-only on newer CLIs).
|
|
1517
1591
|
"-c",
|
|
1518
1592
|
'approval_policy="never"',
|
|
1519
|
-
// Seatbelt cannot use the login Keychain;
|
|
1520
|
-
|
|
1593
|
+
// Seatbelt cannot use the login Keychain; inherit GH_CONFIG_DIR / GIT_CONFIG_*.
|
|
1594
|
+
// Default policy also strips *TOKEN*. Linked worktrees need the main
|
|
1595
|
+
// repo `.git` (+ `.git/worktrees/<name>`) as writable_roots so git commit
|
|
1596
|
+
// can create index.lock.
|
|
1597
|
+
...codexUnattendedGitConfigArgs(mode.codexSandbox, {
|
|
1598
|
+
writableRoots: mode.codexSandbox === "workspace-write" ? await resolveCodexGitWritableRoots(thread.worktreePath) : []
|
|
1599
|
+
}),
|
|
1521
1600
|
...model ? ["--model", model] : [],
|
|
1522
1601
|
...mcpOverrides
|
|
1523
1602
|
];
|
|
@@ -1662,10 +1741,10 @@ var codexAdapter = {
|
|
|
1662
1741
|
};
|
|
1663
1742
|
|
|
1664
1743
|
// src/agents/cursor.ts
|
|
1665
|
-
import { existsSync as
|
|
1666
|
-
import { createRequire as
|
|
1667
|
-
import { dirname as
|
|
1668
|
-
import { fileURLToPath as
|
|
1744
|
+
import { existsSync as existsSync8 } from "fs";
|
|
1745
|
+
import { createRequire as createRequire3 } from "module";
|
|
1746
|
+
import { dirname as dirname3, join as join6 } from "path";
|
|
1747
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
1669
1748
|
import { Cursor } from "@cursor/sdk";
|
|
1670
1749
|
|
|
1671
1750
|
// src/agents/cursor-events.ts
|
|
@@ -1837,6 +1916,65 @@ function parseCursorRunnerLine(line) {
|
|
|
1837
1916
|
}
|
|
1838
1917
|
}
|
|
1839
1918
|
|
|
1919
|
+
// src/agents/cursor-ripgrep.ts
|
|
1920
|
+
import { existsSync as existsSync7 } from "fs";
|
|
1921
|
+
import { createRequire as createRequire2 } from "module";
|
|
1922
|
+
import { dirname as dirname2, isAbsolute, join as join5, parse, resolve as resolvePath } from "path";
|
|
1923
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1924
|
+
var RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
|
|
1925
|
+
function rgBinaryName() {
|
|
1926
|
+
return process.platform === "win32" ? "rg.exe" : "rg";
|
|
1927
|
+
}
|
|
1928
|
+
function platformRipgrepPackage() {
|
|
1929
|
+
return `@cursor/sdk-${process.platform}-${process.arch}`;
|
|
1930
|
+
}
|
|
1931
|
+
function usableRipgrepPath(candidate) {
|
|
1932
|
+
const raw = candidate?.trim();
|
|
1933
|
+
if (!raw || !isAbsolute(raw)) return null;
|
|
1934
|
+
const readable = nodeReadableScriptPath(raw);
|
|
1935
|
+
if (!existsSync7(readable) || isAsarPath(readable)) return null;
|
|
1936
|
+
return readable;
|
|
1937
|
+
}
|
|
1938
|
+
function walkForBundledRipgrep(startFile) {
|
|
1939
|
+
if (!startFile) return null;
|
|
1940
|
+
const pkg = platformRipgrepPackage();
|
|
1941
|
+
const name = rgBinaryName();
|
|
1942
|
+
let dir = dirname2(resolvePath(startFile));
|
|
1943
|
+
const root = parse(dir).root;
|
|
1944
|
+
while (dir !== root) {
|
|
1945
|
+
const hit = usableRipgrepPath(join5(dir, "node_modules", pkg, "bin", name));
|
|
1946
|
+
if (hit) return hit;
|
|
1947
|
+
const next = dirname2(dir);
|
|
1948
|
+
if (next === dir) break;
|
|
1949
|
+
dir = next;
|
|
1950
|
+
}
|
|
1951
|
+
return null;
|
|
1952
|
+
}
|
|
1953
|
+
function requireResolveBundledRipgrep(fromFile) {
|
|
1954
|
+
try {
|
|
1955
|
+
const req = createRequire2(fromFile);
|
|
1956
|
+
const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
|
|
1957
|
+
return usableRipgrepPath(join5(dirname2(pkgJson), "bin", rgBinaryName()));
|
|
1958
|
+
} catch {
|
|
1959
|
+
return null;
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
function resolveCursorRipgrepPath(opts) {
|
|
1963
|
+
const env = opts?.env ?? process.env;
|
|
1964
|
+
const fromEnv = usableRipgrepPath(env[RIPGREP_ENV]);
|
|
1965
|
+
if (fromEnv) return fromEnv;
|
|
1966
|
+
const fromPackaged = usableRipgrepPath(
|
|
1967
|
+
packagedCursorRipgrepCandidate(platformRipgrepPackage(), rgBinaryName())
|
|
1968
|
+
);
|
|
1969
|
+
if (fromPackaged) return fromPackaged;
|
|
1970
|
+
const start = opts?.startFile?.trim() || process.argv[1] || fileURLToPath2(import.meta.url);
|
|
1971
|
+
return walkForBundledRipgrep(start) ?? requireResolveBundledRipgrep(start);
|
|
1972
|
+
}
|
|
1973
|
+
function cursorRipgrepEnv(opts) {
|
|
1974
|
+
const path = resolveCursorRipgrepPath(opts);
|
|
1975
|
+
return path ? { [RIPGREP_ENV]: path } : {};
|
|
1976
|
+
}
|
|
1977
|
+
|
|
1840
1978
|
// src/agents/cursor.ts
|
|
1841
1979
|
var FALLBACK_CURSOR_MODELS = [
|
|
1842
1980
|
{ id: "default", displayName: "Auto" },
|
|
@@ -1883,30 +2021,32 @@ function entryDir() {
|
|
|
1883
2021
|
const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
|
|
1884
2022
|
if (cjsDir) return cjsDir;
|
|
1885
2023
|
try {
|
|
1886
|
-
return
|
|
2024
|
+
return dirname3(fileURLToPath3(import.meta.url));
|
|
1887
2025
|
} catch {
|
|
1888
2026
|
try {
|
|
1889
|
-
const req =
|
|
1890
|
-
return
|
|
2027
|
+
const req = createRequire3(process.cwd() + "/");
|
|
2028
|
+
return dirname3(req.resolve("@sideboard-ai/core"));
|
|
1891
2029
|
} catch {
|
|
1892
2030
|
return process.cwd();
|
|
1893
2031
|
}
|
|
1894
2032
|
}
|
|
1895
2033
|
}
|
|
1896
2034
|
function cursorRunnerPath() {
|
|
2035
|
+
const packaged = packagedCursorRunnerPath();
|
|
2036
|
+
if (packaged) return packaged;
|
|
1897
2037
|
const root = entryDir();
|
|
1898
2038
|
const candidates = [
|
|
1899
|
-
|
|
1900
|
-
|
|
2039
|
+
join6(root, "agents", "cursor-runner.js"),
|
|
2040
|
+
join6(root, "agents", "cursor-runner.cjs"),
|
|
1901
2041
|
// If somehow resolved from package root instead of dist/
|
|
1902
|
-
|
|
1903
|
-
|
|
2042
|
+
join6(root, "dist", "agents", "cursor-runner.js"),
|
|
2043
|
+
join6(root, "dist", "agents", "cursor-runner.cjs"),
|
|
1904
2044
|
// Source tree (dev): packages/core/src/agents/cursor-runner.ts
|
|
1905
|
-
|
|
1906
|
-
|
|
2045
|
+
join6(root, "cursor-runner.ts"),
|
|
2046
|
+
join6(root, "src", "agents", "cursor-runner.ts")
|
|
1907
2047
|
];
|
|
1908
2048
|
for (const candidate of candidates) {
|
|
1909
|
-
if (
|
|
2049
|
+
if (existsSync8(candidate)) return candidate;
|
|
1910
2050
|
}
|
|
1911
2051
|
return candidates[0];
|
|
1912
2052
|
}
|
|
@@ -1969,6 +2109,7 @@ var cursorAdapter = {
|
|
|
1969
2109
|
stdin: JSON.stringify(req),
|
|
1970
2110
|
env: {
|
|
1971
2111
|
...launch.env,
|
|
2112
|
+
...cursorRipgrepEnv({ startFile: runner }),
|
|
1972
2113
|
...apiKey ? { CURSOR_API_KEY: apiKey } : {}
|
|
1973
2114
|
}
|
|
1974
2115
|
};
|
|
@@ -1991,7 +2132,7 @@ var cursorAdapter = {
|
|
|
1991
2132
|
};
|
|
1992
2133
|
|
|
1993
2134
|
// src/agents/opencode.ts
|
|
1994
|
-
import { existsSync as
|
|
2135
|
+
import { existsSync as existsSync9 } from "fs";
|
|
1995
2136
|
var FALLBACK_OPENCODE_MODELS = [
|
|
1996
2137
|
{ id: "opencode/big-pickle", displayName: "opencode \xB7 big-pickle" },
|
|
1997
2138
|
{
|
|
@@ -2032,7 +2173,7 @@ async function listOpencodeModels() {
|
|
|
2032
2173
|
if (opencode === "opencode") {
|
|
2033
2174
|
const which = await run("which", ["opencode"], { reject: false });
|
|
2034
2175
|
if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
|
|
2035
|
-
} else if (!
|
|
2176
|
+
} else if (!existsSync9(opencode)) {
|
|
2036
2177
|
return FALLBACK_OPENCODE_MODELS;
|
|
2037
2178
|
}
|
|
2038
2179
|
const listed = await run(opencode, ["models"], { reject: false });
|
|
@@ -2067,7 +2208,7 @@ var opencodeAdapter = {
|
|
|
2067
2208
|
async detect() {
|
|
2068
2209
|
const opencode = resolveAgentExecutable("opencode");
|
|
2069
2210
|
if (opencode !== "opencode") {
|
|
2070
|
-
if (!
|
|
2211
|
+
if (!existsSync9(opencode)) {
|
|
2071
2212
|
return {
|
|
2072
2213
|
agent: "opencode",
|
|
2073
2214
|
installed: false,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
resolveGithubRepoSlug
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-R7BQBSDT.js";
|
|
6
6
|
import {
|
|
7
7
|
resolveThreadDefaults
|
|
8
8
|
} from "./chunk-6LFV4VFI.js";
|
|
@@ -53,7 +53,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
|
|
|
53
53
|
"- get_pr_stack / open_pr_stack_layers / add_stack_layer / create_pr_stack \u2014 GitHub stacked PRs (`gh stack`); one worktree per layer",
|
|
54
54
|
"- list_models \u2014 only when you need a specific model (rare); otherwise omit model so Account defaults apply",
|
|
55
55
|
"- list_threads / get_thread \u2014 fleet status (what is going on)",
|
|
56
|
-
"- ask_user \u2014 multiple-choice
|
|
56
|
+
"- ask_user \u2014 composer multiple-choice only when blocked on a concrete choice (approach fork, which API). Never for hellos, check-ins, or invented \u201Cwhat should we do?\u201D menus \u2014 reply in chat. Explain options first, description on every option, then wait.",
|
|
57
57
|
"- set_caffeinate \u2014 keep this Mac awake across turns (macOS caffeinate). Turn on for Slack / away-from-keyboard work. Turn OFF when the user says they are done, wrapping up, going to sleep, or no longer need the machine awake. Closing this chat also releases it.",
|
|
58
58
|
"Workspaces:",
|
|
59
59
|
"- add_workspace / remove_workspace \u2014 register or unregister a git repo",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
resolveGithubRepoSlug
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-CIRXAYWS.js";
|
|
4
4
|
import {
|
|
5
5
|
resolveThreadDefaults
|
|
6
6
|
} from "./chunk-FT2SQOL4.js";
|
|
@@ -51,7 +51,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
|
|
|
51
51
|
"- get_pr_stack / open_pr_stack_layers / add_stack_layer / create_pr_stack \u2014 GitHub stacked PRs (`gh stack`); one worktree per layer",
|
|
52
52
|
"- list_models \u2014 only when you need a specific model (rare); otherwise omit model so Account defaults apply",
|
|
53
53
|
"- list_threads / get_thread \u2014 fleet status (what is going on)",
|
|
54
|
-
"- ask_user \u2014 multiple-choice
|
|
54
|
+
"- ask_user \u2014 composer multiple-choice only when blocked on a concrete choice (approach fork, which API). Never for hellos, check-ins, or invented \u201Cwhat should we do?\u201D menus \u2014 reply in chat. Explain options first, description on every option, then wait.",
|
|
55
55
|
"- set_caffeinate \u2014 keep this Mac awake across turns (macOS caffeinate). Turn on for Slack / away-from-keyboard work. Turn OFF when the user says they are done, wrapping up, going to sleep, or no longer need the machine awake. Closing this chat also releases it.",
|
|
56
56
|
"Workspaces:",
|
|
57
57
|
"- add_workspace / remove_workspace \u2014 register or unregister a git repo",
|
|
@@ -7,8 +7,8 @@ import {
|
|
|
7
7
|
enrichWorkspacesWithGithub,
|
|
8
8
|
ensureGlobalCoordinatorCwd,
|
|
9
9
|
formatWorkspaceInventory
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
10
|
+
} from "./chunk-XUWDLRAE.js";
|
|
11
|
+
import "./chunk-CIRXAYWS.js";
|
|
12
12
|
import "./chunk-FKOIHGKV.js";
|
|
13
13
|
import "./chunk-FT2SQOL4.js";
|
|
14
14
|
import "./chunk-TLPJHLLM.js";
|
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
enrichWorkspacesWithGithub,
|
|
10
10
|
ensureGlobalCoordinatorCwd,
|
|
11
11
|
formatWorkspaceInventory
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-
|
|
12
|
+
} from "./chunk-XH2GS2LO.js";
|
|
13
|
+
import "./chunk-R7BQBSDT.js";
|
|
14
14
|
import "./chunk-B3SJXYIJ.js";
|
|
15
15
|
import "./chunk-JOF3XIEM.js";
|
|
16
16
|
import "./chunk-6LFV4VFI.js";
|