@sideboard-ai/core 0.1.217 → 0.1.219
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/{abletime-QGGYL2G4.js → abletime-BF253OZT.js} +5 -4
- package/dist/{abletime-GDZLZRMY.js → abletime-D6773P33.js} +5 -5
- package/dist/{abletime-oauth-F335TWKY.js → abletime-oauth-H4672PRH.js} +4 -3
- package/dist/{abletime-oauth-3X3BAPTF.js → abletime-oauth-KQPVVBKA.js} +4 -4
- package/dist/{abletime-rest-PLJVY3H3.js → abletime-rest-DAFPXZ7H.js} +4 -4
- package/dist/{abletime-rest-LAGTPAJL.js → abletime-rest-OPEVV3XC.js} +4 -3
- package/dist/agents/cursor-runner.js +5 -5
- package/dist/{agents-HETHRRZJ.js → agents-IFVGY77W.js} +9 -9
- package/dist/{agents-WBDDLRBY.js → agents-IK3U4Z2O.js} +8 -7
- package/dist/{app-settings-XCRNCEEE.js → app-settings-5RQMQKSB.js} +2 -1
- package/dist/{app-settings-2TN3WLZV.js → app-settings-V2BBCX2H.js} +2 -2
- package/dist/{chunk-MN6YUD4O.js → chunk-3NWUHXU3.js} +3 -3
- package/dist/{chunk-G4TANQC3.js → chunk-646I442S.js} +5 -5
- package/dist/{chunk-FNQNJOHY.js → chunk-ABOBTSO6.js} +4 -1
- package/dist/{chunk-YVE4PXCJ.js → chunk-CLI5DVU4.js} +2 -2
- package/dist/{chunk-C32SBNA3.js → chunk-EIICOB7P.js} +457 -294
- package/dist/{chunk-LS6TSOCE.js → chunk-HSYE5ID6.js} +5 -5
- package/dist/{chunk-UFHNSFAS.js → chunk-HVUVQXZ2.js} +5 -1
- package/dist/{chunk-7MTVRNP4.js → chunk-IAP5NXQ4.js} +1206 -1192
- package/dist/{chunk-SALM35KD.js → chunk-IILG7DPX.js} +5 -5
- package/dist/{chunk-DFTVZEZY.js → chunk-K642ORWF.js} +1085 -1057
- package/dist/{chunk-NI243N27.js → chunk-KTZESHYH.js} +15 -7
- package/dist/{chunk-FNGXKY5W.js → chunk-N2VST3NL.js} +68 -8
- package/dist/{chunk-XYKVRRC2.js → chunk-NFWPDEN4.js} +15 -7
- package/dist/{chunk-KFD2OXCE.js → chunk-P2EAAM3H.js} +68 -8
- package/dist/{chunk-QQKDGPUI.js → chunk-PO4M4JAJ.js} +1 -1
- package/dist/{chunk-2M5B7YNY.js → chunk-RRW2XWAY.js} +2 -2
- package/dist/{chunk-REZRGCKV.js → chunk-SOGGKYFV.js} +3 -3
- package/dist/{chunk-3OHR73VK.js → chunk-SVXIJ2IC.js} +1 -1
- package/dist/{chunk-SYFVUF2C.js → chunk-SZJZEFTY.js} +1 -1
- package/dist/{chunk-42IULNIY.js → chunk-THLVCXLF.js} +3 -3
- package/dist/{chunk-JZHRZ3DR.js → chunk-TQBUXKIB.js} +5 -5
- package/dist/chunk-WWUABK6B.js +56 -0
- package/dist/{chunk-D2IKXMF3.js → chunk-XGE6YUO6.js} +453 -289
- package/dist/{chunk-BTC2D6LS.js → chunk-Y5JES2VV.js} +3 -51
- package/dist/{connected-teams-WK47ATT7.js → connected-teams-LX5DLL2I.js} +3 -2
- package/dist/{connected-teams-PU4AMFNA.js → connected-teams-PQETXUWV.js} +3 -2
- package/dist/{coordinator-prompt-FQX6ALAI.js → coordinator-prompt-JLMQVORO.js} +6 -6
- package/dist/{coordinator-prompt-LE2GQZ2X.js → coordinator-prompt-VZ7OSRLD.js} +6 -5
- package/dist/{global-workspace-6P236KKG.js → global-workspace-3FDAUNN2.js} +6 -6
- package/dist/{global-workspace-KT3FRHZL.js → global-workspace-QPSJEXGR.js} +6 -5
- package/dist/index.cjs +1107 -826
- package/dist/index.d.cts +15 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.js +24 -18
- package/dist/mcp/run-stdio.cjs +1912 -1652
- package/dist/mcp/run-stdio.js +16 -14
- package/dist/{orchestrator-MI7A5DQZ.js → orchestrator-5VVR7LOU.js} +9 -8
- package/dist/{orchestrator-WVZPTHBV.js → orchestrator-LFC3V3AX.js} +10 -10
- package/dist/{run-EBWL2Q4N.js → run-QDZCTP4Y.js} +2 -1
- package/dist/{run-CAGKZLHA.js → run-UEQM4JMZ.js} +2 -1
- package/dist/{workspaces-R5LJCJRB.js → workspaces-76W7IEKR.js} +8 -6
- package/dist/{workspaces-KM7KTLVO.js → workspaces-TDBA64II.js} +8 -5
- package/dist/{worktree-MDMTCAHX.js → worktree-7V67XTEO.js} +5 -5
- package/dist/{worktree-VXRI7LYM.js → worktree-I573UOPD.js} +5 -4
- package/dist/{worktree-exclude-N5X5I422.js → worktree-exclude-K7QK4RI5.js} +3 -2
- package/dist/{worktree-exclude-X54WSOXM.js → worktree-exclude-L32WEBX6.js} +3 -2
- package/package.json +1 -1
- package/dist/{chunk-L5CIEBLR.js → chunk-EWHJNJHV.js} +3 -3
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
isOrchestratorThread
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-P2EAAM3H.js";
|
|
6
6
|
import {
|
|
7
7
|
applyConnectedTeamToCli,
|
|
8
8
|
brightsyMcpServerName,
|
|
9
9
|
ensureCliTeamTracked,
|
|
10
10
|
ensureConnectedBrightsyTeamTokens
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-SVXIJ2IC.js";
|
|
12
12
|
import {
|
|
13
13
|
loadBrightsyConfig
|
|
14
14
|
} from "./chunk-Y4MIXGPA.js";
|
|
@@ -20,29 +20,31 @@ import {
|
|
|
20
20
|
mergeAgentGitAuthEnv,
|
|
21
21
|
resolveAgentGitAuthEnv,
|
|
22
22
|
resolveCodexGitWritableRoots
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-NFWPDEN4.js";
|
|
24
24
|
import {
|
|
25
25
|
enrichPathWithNpmGlobalBin,
|
|
26
26
|
isConductorBundledCli,
|
|
27
27
|
resolveCommandBinarySync,
|
|
28
28
|
run,
|
|
29
29
|
withExportedPath
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-ABOBTSO6.js";
|
|
31
31
|
import {
|
|
32
32
|
claudeChromeEnabled,
|
|
33
33
|
fromInclusiveInputUsage,
|
|
34
34
|
isAbleTimeConnected,
|
|
35
|
-
isElectronLikeCommand,
|
|
36
35
|
isLinearConnected,
|
|
37
36
|
loadAppSettings,
|
|
38
37
|
resolveAgentExecutable,
|
|
39
|
-
resolveClaudeExecutable
|
|
40
|
-
|
|
41
|
-
wrapElectronAsNodeLaunch
|
|
42
|
-
} from "./chunk-BTC2D6LS.js";
|
|
38
|
+
resolveClaudeExecutable
|
|
39
|
+
} from "./chunk-Y5JES2VV.js";
|
|
43
40
|
import {
|
|
44
41
|
appDataDir
|
|
45
42
|
} from "./chunk-EQNRWDLN.js";
|
|
43
|
+
import {
|
|
44
|
+
isElectronLikeCommand,
|
|
45
|
+
unwrapStrippedElectronLaunch,
|
|
46
|
+
wrapElectronAsNodeLaunch
|
|
47
|
+
} from "./chunk-WWUABK6B.js";
|
|
46
48
|
|
|
47
49
|
// src/agents/brightsy.ts
|
|
48
50
|
import { existsSync } from "fs";
|
|
@@ -800,27 +802,9 @@ var brightsyAdapter = {
|
|
|
800
802
|
};
|
|
801
803
|
|
|
802
804
|
// src/agents/claude.ts
|
|
803
|
-
import { existsSync as
|
|
805
|
+
import { existsSync as existsSync8 } from "fs";
|
|
804
806
|
|
|
805
807
|
// src/agents/claude-mcp.ts
|
|
806
|
-
function parseMcpList(text) {
|
|
807
|
-
const servers = [];
|
|
808
|
-
const seen = /* @__PURE__ */ new Set();
|
|
809
|
-
for (const raw of text.split("\n")) {
|
|
810
|
-
const line = raw.trim();
|
|
811
|
-
if (!line || /^Checking MCP/i.test(line)) continue;
|
|
812
|
-
const m = line.match(/^(.+?):\s+\S+/);
|
|
813
|
-
if (!m) continue;
|
|
814
|
-
const name = m[1].trim();
|
|
815
|
-
if (!name || seen.has(name)) continue;
|
|
816
|
-
const needsAuth = /Needs authentication/i.test(line);
|
|
817
|
-
const connected = !needsAuth && /Connected/i.test(line);
|
|
818
|
-
if (!needsAuth && !connected) continue;
|
|
819
|
-
seen.add(name);
|
|
820
|
-
servers.push({ name, connected, needsAuth });
|
|
821
|
-
}
|
|
822
|
-
return servers;
|
|
823
|
-
}
|
|
824
808
|
function sanitizeMcpServerName(name) {
|
|
825
809
|
return name.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
826
810
|
}
|
|
@@ -835,1169 +819,1317 @@ function mcpAllowTools(servers) {
|
|
|
835
819
|
}
|
|
836
820
|
return out;
|
|
837
821
|
}
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
return input;
|
|
843
|
-
}
|
|
844
|
-
return void 0;
|
|
822
|
+
function mcpAllowToolsFromNames(names) {
|
|
823
|
+
return mcpAllowTools(
|
|
824
|
+
[...names].map((name) => name.trim()).filter(Boolean).map((name) => ({ name, connected: true, needsAuth: false }))
|
|
825
|
+
);
|
|
845
826
|
}
|
|
846
|
-
|
|
847
|
-
|
|
827
|
+
|
|
828
|
+
// src/agents/orch-mcp-isolation.ts
|
|
829
|
+
import { existsSync as existsSync7, readFileSync as readFileSync3 } from "fs";
|
|
830
|
+
import { homedir as homedir3 } from "os";
|
|
831
|
+
import { join as join6 } from "path";
|
|
832
|
+
import { parse as parseToml } from "smol-toml";
|
|
833
|
+
|
|
834
|
+
// src/agents/user-mcp-config.ts
|
|
835
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
836
|
+
import { homedir as homedir2 } from "os";
|
|
837
|
+
import { dirname as dirname3, join as join5 } from "path";
|
|
838
|
+
|
|
839
|
+
// src/agents/injected-mcp.ts
|
|
840
|
+
import { existsSync as existsSync5, mkdtempSync, writeFileSync as writeFileSync2 } from "fs";
|
|
841
|
+
import { createRequire } from "module";
|
|
842
|
+
import { tmpdir } from "os";
|
|
843
|
+
import { dirname as dirname2, join as join4 } from "path";
|
|
844
|
+
import { fileURLToPath } from "url";
|
|
845
|
+
|
|
846
|
+
// src/mcp/profile.ts
|
|
847
|
+
var SIDEBOARD_MCP_PROFILE_ENV = "SIDEBOARD_MCP_PROFILE";
|
|
848
|
+
function sideboardMcpProfile(env = process.env) {
|
|
849
|
+
return env[SIDEBOARD_MCP_PROFILE_ENV]?.trim().toLowerCase() === "worktree" ? "worktree" : "orchestration";
|
|
848
850
|
}
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
851
|
+
|
|
852
|
+
// src/agents/node-launch.ts
|
|
853
|
+
import { existsSync as existsSync4, readdirSync, realpathSync } from "fs";
|
|
854
|
+
import { homedir } from "os";
|
|
855
|
+
import { join as join3 } from "path";
|
|
856
|
+
|
|
857
|
+
// src/http/system-ca.ts
|
|
858
|
+
import { spawnSync } from "child_process";
|
|
859
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync, statSync, writeFileSync } from "fs";
|
|
860
|
+
import { dirname, join } from "path";
|
|
861
|
+
import tls from "tls";
|
|
862
|
+
var NODE_USE_SYSTEM_CA = "NODE_USE_SYSTEM_CA";
|
|
863
|
+
var NODE_EXTRA_CA_CERTS = "NODE_EXTRA_CA_CERTS";
|
|
864
|
+
var BUNDLE_NAME = "system-ca.pem";
|
|
865
|
+
var BUNDLE_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
866
|
+
var LINUX_CA_FILES = [
|
|
867
|
+
"/etc/ssl/certs/ca-certificates.crt",
|
|
868
|
+
"/etc/pki/tls/certs/ca-bundle.crt",
|
|
869
|
+
"/etc/ssl/ca-bundle.pem",
|
|
870
|
+
"/etc/ssl/cert.pem"
|
|
871
|
+
];
|
|
872
|
+
var PEM_CERT_RE = /-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g;
|
|
873
|
+
function splitPemCertificates(pem) {
|
|
874
|
+
return pem.match(PEM_CERT_RE) ?? [];
|
|
854
875
|
}
|
|
855
|
-
function
|
|
856
|
-
if (!input) return void 0;
|
|
857
|
-
const command = str(input.command) ?? str(input.cmd);
|
|
858
|
-
if (command) return clipChatLine(command);
|
|
859
|
-
const pattern = str(input.pattern) ?? str(input.glob) ?? str(input.glob_pattern);
|
|
860
|
-
const isSearch = /grep|glob|search|ripgrep|findfiles|semsearch/i.test(name);
|
|
861
|
-
if (isSearch && pattern) {
|
|
862
|
-
return pattern.length > 80 ? `${pattern.slice(0, 77)}\u2026` : pattern;
|
|
863
|
-
}
|
|
864
|
-
const path = str(input.file_path) ?? str(input.path) ?? str(input.filePath) ?? str(input.filename);
|
|
865
|
-
if (path) return path;
|
|
866
|
-
if (pattern) return pattern.length > 80 ? `${pattern.slice(0, 77)}\u2026` : pattern;
|
|
867
|
-
const query = str(input.query) ?? str(input.prompt);
|
|
868
|
-
if (query) return query.length > 80 ? `${query.slice(0, 77)}\u2026` : query;
|
|
876
|
+
function readExistingFile(path) {
|
|
869
877
|
try {
|
|
870
|
-
|
|
871
|
-
return raw.length > 80 ? `${raw.slice(0, 77)}\u2026` : raw;
|
|
878
|
+
return existsSync2(path) ? readFileSync(path, "utf8") : "";
|
|
872
879
|
} catch {
|
|
873
|
-
return
|
|
880
|
+
return "";
|
|
874
881
|
}
|
|
875
882
|
}
|
|
876
|
-
function
|
|
877
|
-
const
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
}
|
|
882
|
-
if (
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
883
|
+
function darwinKeychainPem(spawn) {
|
|
884
|
+
const result = spawn("/usr/bin/security", ["find-certificate", "-a", "-p"], {
|
|
885
|
+
encoding: "utf8",
|
|
886
|
+
maxBuffer: 32 * 1024 * 1024,
|
|
887
|
+
timeout: 15e3
|
|
888
|
+
});
|
|
889
|
+
if (result.status !== 0) return "";
|
|
890
|
+
return typeof result.stdout === "string" ? result.stdout : "";
|
|
891
|
+
}
|
|
892
|
+
function linuxSystemCaPem() {
|
|
893
|
+
for (const path of LINUX_CA_FILES) {
|
|
894
|
+
const pem = readExistingFile(path);
|
|
895
|
+
if (splitPemCertificates(pem).length > 0) return pem;
|
|
887
896
|
}
|
|
888
|
-
|
|
889
|
-
|
|
897
|
+
return "";
|
|
898
|
+
}
|
|
899
|
+
function collectSystemCaPem(io = {}) {
|
|
900
|
+
const platform = io.platform ?? process.platform;
|
|
901
|
+
if (platform === "darwin") {
|
|
902
|
+
return darwinKeychainPem(io.spawn ?? spawnSync);
|
|
890
903
|
}
|
|
891
|
-
if (
|
|
892
|
-
return
|
|
904
|
+
if (platform === "linux") {
|
|
905
|
+
return linuxSystemCaPem();
|
|
893
906
|
}
|
|
894
|
-
|
|
895
|
-
|
|
907
|
+
return "";
|
|
908
|
+
}
|
|
909
|
+
function systemCaBundlePath(io = {}) {
|
|
910
|
+
return join((io.appData ?? appDataDir)(), BUNDLE_NAME);
|
|
911
|
+
}
|
|
912
|
+
function bundleIsFresh(path, now) {
|
|
913
|
+
try {
|
|
914
|
+
if (!existsSync2(path)) return false;
|
|
915
|
+
if (splitPemCertificates(readFileSync(path, "utf8")).length === 0) return false;
|
|
916
|
+
return now - statSync(path).mtimeMs < BUNDLE_MAX_AGE_MS;
|
|
917
|
+
} catch {
|
|
918
|
+
return false;
|
|
896
919
|
}
|
|
897
|
-
|
|
898
|
-
|
|
920
|
+
}
|
|
921
|
+
function materializeSystemCaBundle(io = {}) {
|
|
922
|
+
const inherited = process.env.NODE_EXTRA_CA_CERTS?.trim();
|
|
923
|
+
if (inherited && splitPemCertificates(readExistingFile(inherited)).length > 0) {
|
|
924
|
+
return inherited;
|
|
899
925
|
}
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
const
|
|
903
|
-
|
|
904
|
-
if (/^spawn_agent$/i.test(name)) {
|
|
905
|
-
return str(input?.prompt) ?? desc ?? "Subagent";
|
|
906
|
-
}
|
|
907
|
-
if (/connectedAgentRequest/i.test(name)) {
|
|
908
|
-
return str(input?.agent_id) ? `Ask connected agent` : "Ask connected agent";
|
|
926
|
+
const platform = io.platform ?? process.platform;
|
|
927
|
+
if (platform === "linux") {
|
|
928
|
+
for (const path of LINUX_CA_FILES) {
|
|
929
|
+
if (splitPemCertificates(readExistingFile(path)).length > 0) return path;
|
|
909
930
|
}
|
|
910
|
-
if (desc && kind) return `${kind}: ${desc}${subagentLiveSuffix(input)}`;
|
|
911
|
-
if (desc) return `${desc}${subagentLiveSuffix(input)}`;
|
|
912
|
-
return `Subagent${subagentLiveSuffix(input)}`;
|
|
913
|
-
}
|
|
914
|
-
if (/^(create|update)_artifact$/i.test(name.replace(/^mcp__[^_]+__/, ""))) {
|
|
915
|
-
return str(input?.title) ? `Artifact ${str(input?.title)}` : "Artifact";
|
|
916
|
-
}
|
|
917
|
-
if (!input) return n;
|
|
918
|
-
if (/bash|shell|terminal/i.test(name) && str(input.command)) {
|
|
919
|
-
const cmd = str(input.command);
|
|
920
|
-
if (/git\s+fetch/i.test(cmd)) return "Fetch latest from origin and check status";
|
|
921
|
-
if (/git\s+status/i.test(cmd)) return "Check git status";
|
|
922
|
-
if (/git\s+log/i.test(cmd)) return "Inspect recent commits";
|
|
923
|
-
if (/git\s+branch/i.test(cmd)) return "List branches";
|
|
924
|
-
if (/grep|rg\b/i.test(cmd)) return "Search repository";
|
|
925
|
-
return "Run shell command";
|
|
926
|
-
}
|
|
927
|
-
if (/edit|write|apply/i.test(name)) {
|
|
928
|
-
const path = str(input.file_path) ?? str(input.path);
|
|
929
|
-
return path ? `Edit ${path.split("/").pop()}` : "Edit file";
|
|
930
|
-
}
|
|
931
|
-
if (/read/i.test(name)) {
|
|
932
|
-
const path = str(input.file_path) ?? str(input.path);
|
|
933
|
-
return path ? `Read ${path.split("/").pop()}` : "Read file";
|
|
934
|
-
}
|
|
935
|
-
if (/grep/i.test(name)) return "Search files";
|
|
936
|
-
if (/glob/i.test(name)) return "Find files";
|
|
937
|
-
const compact = n.replace(/[_-]/g, "");
|
|
938
|
-
if (/^taskoutput$/i.test(compact)) {
|
|
939
|
-
return str(input.task_id) ? `Wait for ${str(input.task_id)}` : "Wait for background task";
|
|
940
931
|
}
|
|
941
|
-
|
|
942
|
-
|
|
932
|
+
const dest = systemCaBundlePath(io);
|
|
933
|
+
const now = (io.now ?? Date.now)();
|
|
934
|
+
if (bundleIsFresh(dest, now)) return dest;
|
|
935
|
+
const pem = collectSystemCaPem(io);
|
|
936
|
+
if (splitPemCertificates(pem).length === 0) {
|
|
937
|
+
return existsSync2(dest) && splitPemCertificates(readExistingFile(dest)).length > 0 ? dest : void 0;
|
|
943
938
|
}
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
939
|
+
try {
|
|
940
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
941
|
+
writeFileSync(dest, pem.endsWith("\n") ? pem : `${pem}
|
|
942
|
+
`, { mode: 384 });
|
|
943
|
+
return dest;
|
|
944
|
+
} catch {
|
|
945
|
+
return void 0;
|
|
947
946
|
}
|
|
948
|
-
return n;
|
|
949
947
|
}
|
|
950
|
-
function
|
|
951
|
-
if (!
|
|
952
|
-
|
|
953
|
-
const status = str(input.live_status);
|
|
954
|
-
if (status && !/^runn(ing)?$|^working$/i.test(status)) bits.push(status);
|
|
955
|
-
if (typeof input.live_tool_uses === "number") bits.push(`${input.live_tool_uses} tools`);
|
|
956
|
-
if (typeof input.live_duration_ms === "number") {
|
|
957
|
-
bits.push(`${Math.max(0, Math.round(Number(input.live_duration_ms) / 1e3))}s`);
|
|
948
|
+
function applySystemCaEnv(env) {
|
|
949
|
+
if (!String(env[NODE_USE_SYSTEM_CA] ?? "").trim()) {
|
|
950
|
+
env[NODE_USE_SYSTEM_CA] = "1";
|
|
958
951
|
}
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
}
|
|
963
|
-
function isSubagentToolName(name) {
|
|
964
|
-
const n = (name ?? "").trim();
|
|
965
|
-
if (/^(task|agent|spawn_agent)$/i.test(n)) return true;
|
|
966
|
-
return /connectedAgentRequest/i.test(n);
|
|
967
|
-
}
|
|
968
|
-
function isInternalAgentStatusText(text) {
|
|
969
|
-
const t = text.trim();
|
|
970
|
-
if (!t) return false;
|
|
971
|
-
if (/waiting for gate to pass/i.test(t)) return true;
|
|
972
|
-
if (/^agent is running\b/i.test(t) && t.length < 160) return true;
|
|
973
|
-
return false;
|
|
952
|
+
if (String(env[NODE_EXTRA_CA_CERTS] ?? "").trim()) return;
|
|
953
|
+
const inherited = process.env.NODE_EXTRA_CA_CERTS?.trim();
|
|
954
|
+
if (inherited) env[NODE_EXTRA_CA_CERTS] = inherited;
|
|
974
955
|
}
|
|
975
|
-
function
|
|
976
|
-
const
|
|
977
|
-
|
|
956
|
+
function extraCertsFromBundle() {
|
|
957
|
+
const path = process.env.NODE_EXTRA_CA_CERTS?.trim();
|
|
958
|
+
if (path) return splitPemCertificates(readExistingFile(path));
|
|
959
|
+
const dest = systemCaBundlePath();
|
|
960
|
+
return splitPemCertificates(readExistingFile(dest));
|
|
978
961
|
}
|
|
979
|
-
function
|
|
980
|
-
|
|
981
|
-
const
|
|
982
|
-
if (
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
962
|
+
function trustSystemCertificates(io = {}) {
|
|
963
|
+
try {
|
|
964
|
+
const api = tls;
|
|
965
|
+
if (typeof api.getCACertificates !== "function" || typeof api.setDefaultCACertificates !== "function") {
|
|
966
|
+
return false;
|
|
967
|
+
}
|
|
968
|
+
const current = api.getCACertificates("default");
|
|
969
|
+
const system = api.getCACertificates("system");
|
|
970
|
+
let extra = extraCertsFromBundle();
|
|
971
|
+
if (system.length === 0 && extra.length === 0) {
|
|
972
|
+
extra = splitPemCertificates(collectSystemCaPem(io));
|
|
973
|
+
}
|
|
974
|
+
if (system.length === 0 && extra.length === 0) return false;
|
|
975
|
+
api.setDefaultCACertificates([...current, ...system, ...extra]);
|
|
976
|
+
return true;
|
|
977
|
+
} catch {
|
|
978
|
+
return false;
|
|
979
|
+
}
|
|
988
980
|
}
|
|
989
|
-
|
|
990
|
-
|
|
981
|
+
|
|
982
|
+
// src/agents/packaged-runtime.ts
|
|
983
|
+
import { existsSync as existsSync3 } from "fs";
|
|
984
|
+
import { join as join2 } from "path";
|
|
985
|
+
function electronResourcesPath() {
|
|
986
|
+
const resources = process.resourcesPath;
|
|
987
|
+
if (typeof resources !== "string" || !resources) return null;
|
|
988
|
+
return resources;
|
|
991
989
|
}
|
|
992
|
-
function
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
(t) => t.status === "running" && !t.parentId && isSubagentToolName(t.name)
|
|
999
|
-
);
|
|
1000
|
-
const runningNested = [...tools].reverse().find((t) => t.status === "running" && t.parentId && !isPollWrapperToolName(t.name));
|
|
1001
|
-
const runningTop = [...tools].reverse().find(
|
|
1002
|
-
(t) => t.status === "running" && !t.parentId && !isPollWrapperToolName(t.name) && !isSubagentToolName(t.name)
|
|
1003
|
-
);
|
|
1004
|
-
const runningPoll = [...tools].reverse().find((t) => t.status === "running" && isPollWrapperToolName(t.name));
|
|
1005
|
-
const thinking = lastTextPart(parts, "thinking");
|
|
1006
|
-
const text = lastTextPart(parts, "text");
|
|
1007
|
-
if (runningSubs.length > 0) {
|
|
1008
|
-
const heads = runningSubs.map(toolLabel);
|
|
1009
|
-
const head = runningSubs.length === 1 ? heads[0] : `${runningSubs.length} subagents \xB7 ${heads.slice(0, 2).join(" \xB7 ")}`;
|
|
1010
|
-
if (runningNested) return `${head} \xB7 ${toolLabel(runningNested)}`;
|
|
1011
|
-
return head;
|
|
1012
|
-
}
|
|
1013
|
-
if (runningTop) return toolLabel(runningTop);
|
|
1014
|
-
if (runningPoll) return toolLabel(runningPoll);
|
|
1015
|
-
if (thinking) return thinking.length > 96 ? `\u2026${thinking.slice(-96)}` : thinking;
|
|
1016
|
-
if (text) return "Writing reply\u2026";
|
|
1017
|
-
const last = [...tools].reverse().find((t) => !isPollWrapperToolName(t.name)) ?? tools.at(-1);
|
|
1018
|
-
if (last) {
|
|
1019
|
-
const label = toolLabel(last);
|
|
1020
|
-
return last.status === "running" ? label : `Finished ${label}`;
|
|
1021
|
-
}
|
|
1022
|
-
return "Working\u2026";
|
|
990
|
+
function packagedCursorRuntimeDir() {
|
|
991
|
+
const resources = electronResourcesPath();
|
|
992
|
+
if (!resources) return null;
|
|
993
|
+
const dir = join2(resources, "cursor-runtime");
|
|
994
|
+
if (!existsSync3(join2(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
|
|
995
|
+
return dir;
|
|
1023
996
|
}
|
|
1024
|
-
function
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
}
|
|
1028
|
-
return void 0;
|
|
997
|
+
function packagedCursorRunnerPath() {
|
|
998
|
+
const dir = packagedCursorRuntimeDir();
|
|
999
|
+
return dir ? join2(dir, "core-dist", "agents", "cursor-runner.js") : null;
|
|
1029
1000
|
}
|
|
1030
|
-
function
|
|
1031
|
-
|
|
1001
|
+
function packagedMcpDir() {
|
|
1002
|
+
const resources = electronResourcesPath();
|
|
1003
|
+
if (!resources) return null;
|
|
1004
|
+
const dir = join2(resources, "sideboard-mcp");
|
|
1005
|
+
if (!existsSync3(join2(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
|
|
1006
|
+
return dir;
|
|
1032
1007
|
}
|
|
1033
|
-
function
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
return { ...event, parentId: event.parentId ?? parentId };
|
|
1037
|
-
}
|
|
1038
|
-
return event;
|
|
1008
|
+
function packagedMcpStdioPath() {
|
|
1009
|
+
const dir = packagedMcpDir();
|
|
1010
|
+
return dir ? join2(dir, "core-dist", "mcp", "run-stdio.js") : null;
|
|
1039
1011
|
}
|
|
1040
|
-
function
|
|
1041
|
-
|
|
1042
|
-
|
|
1012
|
+
function packagedBundledNodePath() {
|
|
1013
|
+
const resources = electronResourcesPath();
|
|
1014
|
+
if (!resources) return null;
|
|
1015
|
+
const bin = join2(resources, "node", "bin", "node");
|
|
1016
|
+
if (!existsSync3(bin)) return null;
|
|
1017
|
+
return bin;
|
|
1043
1018
|
}
|
|
1044
|
-
function
|
|
1045
|
-
|
|
1046
|
-
|
|
1019
|
+
function packagedCursorRipgrepCandidate(platformPkg, binName) {
|
|
1020
|
+
const dir = packagedCursorRuntimeDir();
|
|
1021
|
+
if (!dir) return null;
|
|
1022
|
+
return join2(dir, "node_modules", platformPkg, "bin", binName);
|
|
1047
1023
|
}
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1024
|
+
|
|
1025
|
+
// src/agents/node-launch.ts
|
|
1026
|
+
var AGENT_RUNNER_MAX_OLD_SPACE_MB = 8192;
|
|
1027
|
+
var MAX_OLD_SPACE_FLAG = /(?:^|\s)(--max[-_]old[-_]space[-_]size)(?:[= ](\d+))?(?=\s|$)/;
|
|
1028
|
+
function withMaxOldSpaceSize(nodeOptions, heapMb) {
|
|
1029
|
+
const existing = (nodeOptions ?? "").trim();
|
|
1030
|
+
const match = MAX_OLD_SPACE_FLAG.exec(existing);
|
|
1031
|
+
if (match) {
|
|
1032
|
+
const current = match[2] ? Number(match[2]) : 0;
|
|
1033
|
+
if (Number.isFinite(current) && current >= heapMb) return existing;
|
|
1034
|
+
return existing.replace(MAX_OLD_SPACE_FLAG, ` --max-old-space-size=${heapMb}`).trim();
|
|
1057
1035
|
}
|
|
1058
|
-
return {}
|
|
1036
|
+
return existing ? `${existing} --max-old-space-size=${heapMb}` : `--max-old-space-size=${heapMb}`;
|
|
1059
1037
|
}
|
|
1060
|
-
function
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
return {
|
|
1065
|
-
additions: Number(paired[1]),
|
|
1066
|
-
deletions: Number(paired[2])
|
|
1067
|
-
};
|
|
1068
|
-
}
|
|
1069
|
-
const verbose = result.match(
|
|
1070
|
-
/(\d+)\s+insertions?(?:,\s*(\d+)\s+deletions?)?/i
|
|
1038
|
+
function applyAgentRunnerHeapEnv(env) {
|
|
1039
|
+
env.NODE_OPTIONS = withMaxOldSpaceSize(
|
|
1040
|
+
env.NODE_OPTIONS,
|
|
1041
|
+
AGENT_RUNNER_MAX_OLD_SPACE_MB
|
|
1071
1042
|
);
|
|
1072
|
-
|
|
1073
|
-
return {
|
|
1074
|
-
additions: Number(verbose[1]),
|
|
1075
|
-
deletions: verbose[2] != null ? Number(verbose[2]) : void 0
|
|
1076
|
-
};
|
|
1077
|
-
}
|
|
1078
|
-
return {};
|
|
1043
|
+
applySystemCaEnv(env);
|
|
1079
1044
|
}
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
return marker + text.slice(text.length - Math.max(1, max - marker.length));
|
|
1045
|
+
function envWithAgentHeap(env) {
|
|
1046
|
+
const next = { ...env };
|
|
1047
|
+
applyAgentRunnerHeapEnv(next);
|
|
1048
|
+
return next;
|
|
1085
1049
|
}
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
if (text.length <= max) return text;
|
|
1090
|
-
const marker = "\u2026(truncated)\n";
|
|
1091
|
-
return marker + text.slice(text.length - Math.max(1, max - marker.length));
|
|
1050
|
+
function isAsarPath(filePath) {
|
|
1051
|
+
if (/\.asar\.unpacked([/\\]|$)/.test(filePath)) return false;
|
|
1052
|
+
return /\.asar([/\\]|$)/.test(filePath);
|
|
1092
1053
|
}
|
|
1093
|
-
function
|
|
1094
|
-
if (
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1054
|
+
function unpackedAsarPath(filePath) {
|
|
1055
|
+
if (!isAsarPath(filePath)) return null;
|
|
1056
|
+
const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
|
|
1057
|
+
if (unpacked === filePath) return null;
|
|
1058
|
+
return existsSync4(unpacked) ? unpacked : null;
|
|
1059
|
+
}
|
|
1060
|
+
function nodeReadableScriptPath(scriptPath) {
|
|
1061
|
+
return unpackedAsarPath(scriptPath) ?? scriptPath;
|
|
1062
|
+
}
|
|
1063
|
+
var PREFERRED_LTS_MAJORS = [24, 22];
|
|
1064
|
+
function parseNodeMajor(version) {
|
|
1065
|
+
const match = /^v?(\d+)/.exec(version.trim());
|
|
1066
|
+
if (!match) return null;
|
|
1067
|
+
const major = Number(match[1]);
|
|
1068
|
+
return Number.isInteger(major) ? major : null;
|
|
1069
|
+
}
|
|
1070
|
+
function scoreNodeForAgentRuntime(candidate) {
|
|
1071
|
+
const major = parseNodeMajor(candidate.version);
|
|
1072
|
+
if (major == null) return Number.NEGATIVE_INFINITY;
|
|
1073
|
+
if (major < 22) return major - 100;
|
|
1074
|
+
const posix = candidate.path.replace(/\\/g, "/");
|
|
1075
|
+
let score = 0;
|
|
1076
|
+
if (major % 2 === 0) {
|
|
1077
|
+
score += 1e3 + major * 10;
|
|
1078
|
+
} else {
|
|
1079
|
+
score += major;
|
|
1104
1080
|
}
|
|
1105
|
-
if (
|
|
1106
|
-
|
|
1081
|
+
if (/\/Cellar\/node\/\d/.test(posix) && !/\/Cellar\/node@\d+/.test(posix)) {
|
|
1082
|
+
score -= 50;
|
|
1107
1083
|
}
|
|
1108
|
-
return
|
|
1109
|
-
}
|
|
1110
|
-
function withPartTimes(next, prev) {
|
|
1111
|
-
const now = Date.now();
|
|
1112
|
-
const startedAt = prev && typeof prev.startedAt === "number" ? prev.startedAt : now;
|
|
1113
|
-
return { ...next, startedAt, updatedAt: now };
|
|
1084
|
+
return score;
|
|
1114
1085
|
}
|
|
1115
|
-
function
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
const
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
{
|
|
1124
|
-
type: "text",
|
|
1125
|
-
text: last.text + data,
|
|
1126
|
-
...event.parentId ? { parentId: event.parentId } : {}
|
|
1127
|
-
},
|
|
1128
|
-
last
|
|
1129
|
-
);
|
|
1130
|
-
} else {
|
|
1131
|
-
next.push(
|
|
1132
|
-
withPartTimes({
|
|
1133
|
-
type: "text",
|
|
1134
|
-
text: data,
|
|
1135
|
-
...event.parentId ? { parentId: event.parentId } : {}
|
|
1136
|
-
})
|
|
1137
|
-
);
|
|
1086
|
+
function pickPreferredNode(candidates) {
|
|
1087
|
+
let best = null;
|
|
1088
|
+
let bestScore = Number.NEGATIVE_INFINITY;
|
|
1089
|
+
for (const candidate of candidates) {
|
|
1090
|
+
const score = scoreNodeForAgentRuntime(candidate);
|
|
1091
|
+
if (score > bestScore) {
|
|
1092
|
+
bestScore = score;
|
|
1093
|
+
best = candidate;
|
|
1138
1094
|
}
|
|
1139
|
-
return next;
|
|
1140
1095
|
}
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
next[i] = withPartTimes(
|
|
1150
|
-
{
|
|
1151
|
-
type: "thinking",
|
|
1152
|
-
text: clipThinkingForStore(data),
|
|
1153
|
-
...event.parentId ? { parentId: event.parentId } : {}
|
|
1154
|
-
},
|
|
1155
|
-
prev
|
|
1156
|
-
);
|
|
1157
|
-
return next;
|
|
1158
|
-
}
|
|
1159
|
-
}
|
|
1160
|
-
next.push(
|
|
1161
|
-
withPartTimes({
|
|
1162
|
-
type: "thinking",
|
|
1163
|
-
text: clipThinkingForStore(data),
|
|
1164
|
-
...event.parentId ? { parentId: event.parentId } : {}
|
|
1165
|
-
})
|
|
1166
|
-
);
|
|
1167
|
-
return next;
|
|
1168
|
-
}
|
|
1169
|
-
const last = next[next.length - 1];
|
|
1170
|
-
if (last?.type === "thinking" && sameParentId(last.parentId, event.parentId)) {
|
|
1171
|
-
next[next.length - 1] = withPartTimes(
|
|
1172
|
-
{
|
|
1173
|
-
type: "thinking",
|
|
1174
|
-
text: clipThinkingForStore(last.text + data),
|
|
1175
|
-
...event.parentId ? { parentId: event.parentId } : {}
|
|
1176
|
-
},
|
|
1177
|
-
last
|
|
1178
|
-
);
|
|
1179
|
-
} else {
|
|
1180
|
-
next.push(
|
|
1181
|
-
withPartTimes({
|
|
1182
|
-
type: "thinking",
|
|
1183
|
-
text: clipThinkingForStore(data),
|
|
1184
|
-
...event.parentId ? { parentId: event.parentId } : {}
|
|
1185
|
-
})
|
|
1186
|
-
);
|
|
1187
|
-
}
|
|
1188
|
-
return next;
|
|
1096
|
+
return best;
|
|
1097
|
+
}
|
|
1098
|
+
function versionDirNodeBins(root, toBin) {
|
|
1099
|
+
if (!existsSync4(root)) return [];
|
|
1100
|
+
try {
|
|
1101
|
+
return readdirSync(root).map(toBin);
|
|
1102
|
+
} catch {
|
|
1103
|
+
return [];
|
|
1189
1104
|
}
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1105
|
+
}
|
|
1106
|
+
function defaultNodeBinCandidates(home = homedir()) {
|
|
1107
|
+
const kegs = ["/opt/homebrew", "/usr/local"].flatMap(
|
|
1108
|
+
(prefix) => PREFERRED_LTS_MAJORS.map((major) => join3(prefix, "opt", `node@${major}`, "bin", "node"))
|
|
1109
|
+
);
|
|
1110
|
+
return [
|
|
1111
|
+
...kegs,
|
|
1112
|
+
"/opt/homebrew/bin/node",
|
|
1113
|
+
"/usr/local/bin/node",
|
|
1114
|
+
join3(home, ".local/share/fnm/aliases/default/bin/node"),
|
|
1115
|
+
join3(home, ".nvm/current/bin/node"),
|
|
1116
|
+
join3(home, ".volta/bin/node"),
|
|
1117
|
+
join3(home, ".asdf/shims/node"),
|
|
1118
|
+
join3(home, ".local/share/mise/shims/node"),
|
|
1119
|
+
...versionDirNodeBins(
|
|
1120
|
+
join3(home, ".nvm", "versions", "node"),
|
|
1121
|
+
(name) => join3(home, ".nvm", "versions", "node", name, "bin", "node")
|
|
1122
|
+
),
|
|
1123
|
+
...versionDirNodeBins(
|
|
1124
|
+
join3(home, ".local/share/fnm", "node-versions"),
|
|
1125
|
+
(name) => join3(home, ".local/share/fnm", "node-versions", name, "installation", "bin", "node")
|
|
1126
|
+
),
|
|
1127
|
+
...versionDirNodeBins(
|
|
1128
|
+
join3(home, ".volta", "tools", "image", "node"),
|
|
1129
|
+
(name) => join3(home, ".volta", "tools", "image", "node", name, "bin", "node")
|
|
1130
|
+
)
|
|
1131
|
+
];
|
|
1132
|
+
}
|
|
1133
|
+
function uniqueExistingNodeBins(paths) {
|
|
1134
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1135
|
+
const out = [];
|
|
1136
|
+
for (const raw of paths) {
|
|
1137
|
+
const p = raw.trim();
|
|
1138
|
+
if (!p || !existsSync4(p) || isElectronLikeCommand(p)) continue;
|
|
1139
|
+
let key = p;
|
|
1140
|
+
try {
|
|
1141
|
+
key = realpathSync(p);
|
|
1142
|
+
} catch {
|
|
1143
|
+
continue;
|
|
1217
1144
|
}
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
type: "tool",
|
|
1222
|
-
id: event.id,
|
|
1223
|
-
name: event.name,
|
|
1224
|
-
input,
|
|
1225
|
-
description: toolDescription(event.name, input),
|
|
1226
|
-
detail: toolDetail(event.name, input),
|
|
1227
|
-
status: "running",
|
|
1228
|
-
filePath: toolFilePath(input),
|
|
1229
|
-
...event.parentId ? { parentId: event.parentId } : {},
|
|
1230
|
-
...diff
|
|
1231
|
-
})
|
|
1232
|
-
];
|
|
1145
|
+
if (seen.has(key)) continue;
|
|
1146
|
+
seen.add(key);
|
|
1147
|
+
out.push(p);
|
|
1233
1148
|
}
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
withPartTimes({
|
|
1242
|
-
type: "tool",
|
|
1243
|
-
id: event.id,
|
|
1244
|
-
name: "tool",
|
|
1245
|
-
description: "tool",
|
|
1246
|
-
status: event.isError ? "error" : "running",
|
|
1247
|
-
result: clipToolResultForStore(event.content),
|
|
1248
|
-
...event.parentId ? { parentId: event.parentId } : {}
|
|
1249
|
-
})
|
|
1250
|
-
];
|
|
1251
|
-
}
|
|
1252
|
-
return parts.map((p, i) => {
|
|
1253
|
-
if (i !== existing || p.type !== "tool") return p;
|
|
1254
|
-
if (p.status === "done" || p.status === "error") return p;
|
|
1255
|
-
return withPartTimes(
|
|
1256
|
-
{
|
|
1257
|
-
...p,
|
|
1258
|
-
result: clipToolResultForStore(event.content) ?? p.result
|
|
1259
|
-
},
|
|
1260
|
-
p
|
|
1261
|
-
);
|
|
1262
|
-
});
|
|
1263
|
-
}
|
|
1264
|
-
if (existing < 0) {
|
|
1265
|
-
return [
|
|
1266
|
-
...parts,
|
|
1267
|
-
withPartTimes({
|
|
1268
|
-
type: "tool",
|
|
1269
|
-
id: event.id,
|
|
1270
|
-
name: "tool",
|
|
1271
|
-
description: "tool",
|
|
1272
|
-
status: event.isError ? "error" : "done",
|
|
1273
|
-
result: clipToolResultForStore(event.content),
|
|
1274
|
-
...event.parentId ? { parentId: event.parentId } : {},
|
|
1275
|
-
...fromResult.additions != null ? { additions: fromResult.additions } : {},
|
|
1276
|
-
...fromResult.deletions != null ? { deletions: fromResult.deletions } : {}
|
|
1277
|
-
})
|
|
1278
|
-
];
|
|
1279
|
-
}
|
|
1280
|
-
return parts.map((p, i) => {
|
|
1281
|
-
if (i !== existing || p.type !== "tool") return p;
|
|
1282
|
-
return withPartTimes(
|
|
1283
|
-
{
|
|
1284
|
-
...p,
|
|
1285
|
-
status: event.isError ? "error" : "done",
|
|
1286
|
-
result: clipToolResultForStore(event.content),
|
|
1287
|
-
...fromResult.additions != null ? { additions: fromResult.additions } : {},
|
|
1288
|
-
...fromResult.deletions != null ? { deletions: fromResult.deletions } : {}
|
|
1289
|
-
},
|
|
1290
|
-
p
|
|
1291
|
-
);
|
|
1292
|
-
});
|
|
1149
|
+
return out;
|
|
1150
|
+
}
|
|
1151
|
+
async function whichAllNode() {
|
|
1152
|
+
if (process.platform === "win32") {
|
|
1153
|
+
const located = await run("where", ["node"], { reject: false, timeoutMs: 5e3 });
|
|
1154
|
+
if (located.exitCode !== 0) return [];
|
|
1155
|
+
return located.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
1293
1156
|
}
|
|
1294
|
-
|
|
1157
|
+
const all = await run("which", ["-a", "node"], { reject: false, timeoutMs: 5e3 });
|
|
1158
|
+
if (all.exitCode === 0 && all.stdout.trim()) {
|
|
1159
|
+
return all.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
1160
|
+
}
|
|
1161
|
+
const single = await run("which", ["node"], { reject: false, timeoutMs: 5e3 });
|
|
1162
|
+
if (single.exitCode !== 0 || !single.stdout.trim()) return [];
|
|
1163
|
+
return [single.stdout.trim()];
|
|
1295
1164
|
}
|
|
1296
|
-
function
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1165
|
+
async function probeNodeVersion(bin) {
|
|
1166
|
+
const probed = await run(bin, ["-v"], { reject: false, timeoutMs: 4e3 });
|
|
1167
|
+
if (probed.exitCode !== 0) return null;
|
|
1168
|
+
const version = probed.stdout.trim().split(/\r?\n/).find(Boolean);
|
|
1169
|
+
return version || null;
|
|
1300
1170
|
}
|
|
1301
|
-
function
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1171
|
+
async function findSystemNode() {
|
|
1172
|
+
const fromPath = await whichAllNode();
|
|
1173
|
+
const bins = uniqueExistingNodeBins([...fromPath, ...defaultNodeBinCandidates()]);
|
|
1174
|
+
if (bins.length === 0) return null;
|
|
1175
|
+
const probed = await Promise.all(
|
|
1176
|
+
bins.map(async (path) => {
|
|
1177
|
+
const version = await probeNodeVersion(path);
|
|
1178
|
+
return version ? { path, version } : null;
|
|
1179
|
+
})
|
|
1307
1180
|
);
|
|
1308
|
-
|
|
1309
|
-
return out.trim();
|
|
1310
|
-
}
|
|
1311
|
-
function isBrightsyNdjsonLine(line) {
|
|
1312
|
-
const t = line.trim();
|
|
1313
|
-
if (!t.startsWith("{")) return false;
|
|
1314
|
-
return /"type"\s*:\s*"(tool_use|tool_result|tool|thinking|usage|done|error|text)"/.test(t);
|
|
1181
|
+
return pickPreferredNode(probed.filter((c) => c != null));
|
|
1315
1182
|
}
|
|
1316
|
-
function
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1183
|
+
function applyNodeLaunch(launch, args) {
|
|
1184
|
+
const readableArgs = args.map(nodeReadableScriptPath);
|
|
1185
|
+
if (!launch.env.ELECTRON_RUN_AS_NODE) {
|
|
1186
|
+
return {
|
|
1187
|
+
file: launch.file,
|
|
1188
|
+
args: readableArgs,
|
|
1189
|
+
env: envWithAgentHeap(launch.env)
|
|
1190
|
+
};
|
|
1191
|
+
}
|
|
1192
|
+
const wrapped = wrapElectronAsNodeLaunch(launch.file, readableArgs);
|
|
1193
|
+
if (process.platform === "win32") {
|
|
1194
|
+
return {
|
|
1195
|
+
file: wrapped.file,
|
|
1196
|
+
args: wrapped.args,
|
|
1197
|
+
env: envWithAgentHeap(launch.env)
|
|
1198
|
+
};
|
|
1199
|
+
}
|
|
1200
|
+
const env = envWithAgentHeap(launch.env);
|
|
1201
|
+
delete env.ELECTRON_RUN_AS_NODE;
|
|
1202
|
+
return { file: wrapped.file, args: wrapped.args, env };
|
|
1320
1203
|
}
|
|
1321
|
-
function
|
|
1322
|
-
|
|
1323
|
-
|
|
1204
|
+
async function resolveNodeLaunch(scriptPath) {
|
|
1205
|
+
const script = nodeReadableScriptPath(scriptPath);
|
|
1206
|
+
if (!isAsarPath(script)) {
|
|
1207
|
+
const bundled = packagedBundledNodePath();
|
|
1208
|
+
if (bundled && !isElectronLikeCommand(bundled)) {
|
|
1209
|
+
return { file: bundled, env: {} };
|
|
1210
|
+
}
|
|
1211
|
+
const node = await findSystemNode();
|
|
1212
|
+
if (node) {
|
|
1213
|
+
return { file: node.path, env: {}, nodeVersion: node.version };
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
return {
|
|
1217
|
+
file: process.execPath,
|
|
1218
|
+
env: { ELECTRON_RUN_AS_NODE: "1" }
|
|
1219
|
+
};
|
|
1324
1220
|
}
|
|
1325
1221
|
|
|
1326
1222
|
// src/agents/injected-mcp.ts
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
import { dirname as dirname2, join as join4 } from "path";
|
|
1331
|
-
import { fileURLToPath } from "url";
|
|
1332
|
-
|
|
1333
|
-
// src/mcp/profile.ts
|
|
1334
|
-
var SIDEBOARD_MCP_PROFILE_ENV = "SIDEBOARD_MCP_PROFILE";
|
|
1335
|
-
function sideboardMcpProfile(env = process.env) {
|
|
1336
|
-
return env[SIDEBOARD_MCP_PROFILE_ENV]?.trim().toLowerCase() === "worktree" ? "worktree" : "orchestration";
|
|
1337
|
-
}
|
|
1338
|
-
|
|
1339
|
-
// src/agents/node-launch.ts
|
|
1340
|
-
import { existsSync as existsSync4, readdirSync, realpathSync } from "fs";
|
|
1341
|
-
import { homedir } from "os";
|
|
1342
|
-
import { join as join3 } from "path";
|
|
1343
|
-
|
|
1344
|
-
// src/http/system-ca.ts
|
|
1345
|
-
import { spawnSync } from "child_process";
|
|
1346
|
-
import { existsSync as existsSync2, mkdirSync, readFileSync, statSync, writeFileSync } from "fs";
|
|
1347
|
-
import { dirname, join } from "path";
|
|
1348
|
-
import tls from "tls";
|
|
1349
|
-
var NODE_USE_SYSTEM_CA = "NODE_USE_SYSTEM_CA";
|
|
1350
|
-
var NODE_EXTRA_CA_CERTS = "NODE_EXTRA_CA_CERTS";
|
|
1351
|
-
var BUNDLE_NAME = "system-ca.pem";
|
|
1352
|
-
var BUNDLE_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
1353
|
-
var LINUX_CA_FILES = [
|
|
1354
|
-
"/etc/ssl/certs/ca-certificates.crt",
|
|
1355
|
-
"/etc/pki/tls/certs/ca-bundle.crt",
|
|
1356
|
-
"/etc/ssl/ca-bundle.pem",
|
|
1357
|
-
"/etc/ssl/cert.pem"
|
|
1223
|
+
var SIDEBOARD_MCP_ALLOWED_TOOLS = [
|
|
1224
|
+
"mcp__sideboard",
|
|
1225
|
+
"mcp__sideboard__*"
|
|
1358
1226
|
];
|
|
1359
|
-
var
|
|
1360
|
-
|
|
1361
|
-
|
|
1227
|
+
var SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS = [
|
|
1228
|
+
"mcp__sideboard__present_artifact",
|
|
1229
|
+
"mcp__sideboard__present_schema",
|
|
1230
|
+
"mcp__sideboard__present_files",
|
|
1231
|
+
"mcp__sideboard__ask_user",
|
|
1232
|
+
"mcp__sideboard__present_plan",
|
|
1233
|
+
"mcp__sideboard__wait_for_job",
|
|
1234
|
+
"mcp__sideboard__stop_job",
|
|
1235
|
+
"mcp__sideboard__get_viewer_context",
|
|
1236
|
+
"mcp__sideboard__update_viewer_context"
|
|
1237
|
+
];
|
|
1238
|
+
var SIDEBOARD_GITHUB_MCP_ALLOWED_TOOLS = ["mcp__sideboard__github_*"];
|
|
1239
|
+
var SIDEBOARD_LINEAR_MCP_ALLOWED_TOOLS = ["mcp__sideboard__linear_*"];
|
|
1240
|
+
var SIDEBOARD_ABLETIME_MCP_ALLOWED_TOOLS = ["mcp__sideboard__abletime_*"];
|
|
1241
|
+
function sideboardWorktreeAllowedTools(opts) {
|
|
1242
|
+
const out = [...SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS];
|
|
1243
|
+
if (opts?.github !== false) out.push(...SIDEBOARD_GITHUB_MCP_ALLOWED_TOOLS);
|
|
1244
|
+
if (opts?.linear) out.push(...SIDEBOARD_LINEAR_MCP_ALLOWED_TOOLS);
|
|
1245
|
+
if (opts?.abletime) out.push(...SIDEBOARD_ABLETIME_MCP_ALLOWED_TOOLS);
|
|
1246
|
+
return out;
|
|
1247
|
+
}
|
|
1248
|
+
var brightsyMcpCommandCache = null;
|
|
1249
|
+
async function resolveBrightsyMcpCommand() {
|
|
1250
|
+
const now = Date.now();
|
|
1251
|
+
if (brightsyMcpCommandCache && now - brightsyMcpCommandCache.at < 6e4 && brightsyMcpCommandCache.command) {
|
|
1252
|
+
return brightsyMcpCommandCache.command;
|
|
1253
|
+
}
|
|
1254
|
+
const which = await run("which", ["brightsy-mcp"], { reject: false });
|
|
1255
|
+
const command = which.exitCode === 0 && which.stdout.trim() ? "brightsy-mcp" : "npx";
|
|
1256
|
+
brightsyMcpCommandCache = { at: now, command };
|
|
1257
|
+
return command;
|
|
1258
|
+
}
|
|
1259
|
+
function isBrightsyConnected() {
|
|
1260
|
+
try {
|
|
1261
|
+
loadBrightsyConfig();
|
|
1262
|
+
return true;
|
|
1263
|
+
} catch {
|
|
1264
|
+
return false;
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
var BRIGHTSY_WORD = /(?<![a-z0-9_-])brightsy(?![a-z0-9_-])/i;
|
|
1268
|
+
function promptMentionsBrightsy(text) {
|
|
1269
|
+
return BRIGHTSY_WORD.test(text ?? "");
|
|
1270
|
+
}
|
|
1271
|
+
function isBrightsyMcpToolName(name) {
|
|
1272
|
+
const n = name.toLowerCase();
|
|
1273
|
+
return n === "brightsy" || n.startsWith("mcp__brightsy") || n.startsWith("brightsy_");
|
|
1274
|
+
}
|
|
1275
|
+
function toolInputUsesBrightsyDatasource(input) {
|
|
1276
|
+
const ds = input?.datasource;
|
|
1277
|
+
return typeof ds === "string" && ds.toLowerCase() === "brightsy";
|
|
1278
|
+
}
|
|
1279
|
+
function messageUsedBrightsyMcp(msg) {
|
|
1280
|
+
if (msg.role === "user" && promptMentionsBrightsy(msg.text)) return true;
|
|
1281
|
+
for (const part of msg.parts ?? []) {
|
|
1282
|
+
if (part.type !== "tool") continue;
|
|
1283
|
+
if (isBrightsyMcpToolName(part.name)) return true;
|
|
1284
|
+
if (/present_(schema|files)$/i.test(part.name) && toolInputUsesBrightsyDatasource(part.input)) {
|
|
1285
|
+
return true;
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
return false;
|
|
1289
|
+
}
|
|
1290
|
+
function threadRequestsBrightsyMcp(thread) {
|
|
1291
|
+
return (thread?.messages ?? []).some(messageUsedBrightsyMcp);
|
|
1292
|
+
}
|
|
1293
|
+
function shouldInjectBrightsyMcp(thread, opts) {
|
|
1294
|
+
if (!(opts?.connected ?? isBrightsyConnected())) return false;
|
|
1295
|
+
if (opts?.orchestrator) return true;
|
|
1296
|
+
const alwaysOn = opts?.alwaysOnWorktree ?? Boolean(loadAppSettings().brightsy?.injectWorktreeMcp);
|
|
1297
|
+
if (alwaysOn) return true;
|
|
1298
|
+
return threadRequestsBrightsyMcp(thread);
|
|
1299
|
+
}
|
|
1300
|
+
function mcpLaunch(cmd, name, env) {
|
|
1301
|
+
if (cmd === "brightsy-mcp") {
|
|
1302
|
+
return { name, command: "brightsy-mcp", ...env ? { env } : {} };
|
|
1303
|
+
}
|
|
1304
|
+
return {
|
|
1305
|
+
name,
|
|
1306
|
+
command: "npx",
|
|
1307
|
+
args: ["-y", "@brightsy/mcp-server"],
|
|
1308
|
+
...env ? { env } : {}
|
|
1309
|
+
};
|
|
1310
|
+
}
|
|
1311
|
+
function teamEnv(team) {
|
|
1312
|
+
const endpoint = (team.endpoint || "https://brightsy.ai").replace(/\/$/, "");
|
|
1313
|
+
return {
|
|
1314
|
+
BRIGHTSY_API_TOKEN: team.access_token,
|
|
1315
|
+
...team.refresh_token ? { BRIGHTSY_REFRESH_TOKEN: team.refresh_token } : {},
|
|
1316
|
+
BRIGHTSY_ACCOUNT_ID: team.id,
|
|
1317
|
+
BRIGHTSY_API_URL: endpoint
|
|
1318
|
+
};
|
|
1319
|
+
}
|
|
1320
|
+
function brightsyMcpAllowedTools(serverNames) {
|
|
1321
|
+
const out = [];
|
|
1322
|
+
for (const name of serverNames) {
|
|
1323
|
+
out.push(`mcp__${name}`, `mcp__${name}__*`);
|
|
1324
|
+
}
|
|
1325
|
+
return out;
|
|
1326
|
+
}
|
|
1327
|
+
function corePackageDir() {
|
|
1328
|
+
const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
|
|
1329
|
+
if (cjsDir) return cjsDir;
|
|
1330
|
+
try {
|
|
1331
|
+
const url = import.meta.url;
|
|
1332
|
+
if (typeof url === "string" && url.length > 0) {
|
|
1333
|
+
return dirname2(fileURLToPath(url));
|
|
1334
|
+
}
|
|
1335
|
+
} catch {
|
|
1336
|
+
}
|
|
1337
|
+
try {
|
|
1338
|
+
const req = createRequire(join4(process.cwd(), "package.json"));
|
|
1339
|
+
return dirname2(req.resolve("@sideboard-ai/core"));
|
|
1340
|
+
} catch {
|
|
1341
|
+
return process.cwd();
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
function findSideboardMcpJsEntry() {
|
|
1345
|
+
const override = process.env.SIDEBOARD_MCP_ENTRY?.trim() || process.env.SIDEBOARD_CLI?.trim();
|
|
1346
|
+
if (override && existsSync5(override)) return override;
|
|
1347
|
+
const packaged = packagedMcpStdioPath();
|
|
1348
|
+
if (packaged) return packaged;
|
|
1349
|
+
let dir = corePackageDir();
|
|
1350
|
+
for (let i = 0; i < 10; i++) {
|
|
1351
|
+
const candidates = [
|
|
1352
|
+
join4(dir, "mcp/run-stdio.js"),
|
|
1353
|
+
join4(dir, "mcp/run-stdio.cjs"),
|
|
1354
|
+
join4(dir, "dist/mcp/run-stdio.js"),
|
|
1355
|
+
join4(dir, "dist/mcp/run-stdio.cjs"),
|
|
1356
|
+
join4(dir, "packages/core/dist/mcp/run-stdio.js"),
|
|
1357
|
+
join4(dir, "packages/cli/dist/index.js"),
|
|
1358
|
+
join4(dir, "cli/dist/index.js")
|
|
1359
|
+
];
|
|
1360
|
+
for (const p of candidates) {
|
|
1361
|
+
if (existsSync5(p) && !isAsarPath(p)) return p;
|
|
1362
|
+
}
|
|
1363
|
+
const parent = dirname2(dir);
|
|
1364
|
+
if (parent === dir) break;
|
|
1365
|
+
dir = parent;
|
|
1366
|
+
}
|
|
1367
|
+
return null;
|
|
1368
|
+
}
|
|
1369
|
+
async function resolveSideboardMcpServer() {
|
|
1370
|
+
const entry = findSideboardMcpJsEntry();
|
|
1371
|
+
if (entry) {
|
|
1372
|
+
const isCli = /[/\\]cli[/\\]dist[/\\]index\.js$/.test(entry);
|
|
1373
|
+
const scriptArgs = isCli ? [entry, "mcp"] : [entry];
|
|
1374
|
+
const launch = applyNodeLaunch(await resolveNodeLaunch(entry), scriptArgs);
|
|
1375
|
+
if (launch.file !== "/bin/sh" && !isElectronLikeCommand(launch.file)) {
|
|
1376
|
+
return {
|
|
1377
|
+
name: "sideboard",
|
|
1378
|
+
command: launch.file,
|
|
1379
|
+
args: launch.args,
|
|
1380
|
+
...Object.keys(launch.env).length > 0 ? { env: launch.env } : {}
|
|
1381
|
+
};
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
const which = await run("which", ["sideboard"], { reject: false });
|
|
1385
|
+
if (which.exitCode === 0 && which.stdout.trim()) {
|
|
1386
|
+
return { name: "sideboard", command: which.stdout.trim(), args: ["mcp"] };
|
|
1387
|
+
}
|
|
1388
|
+
return { name: "sideboard", command: "sideboard", args: ["mcp"] };
|
|
1389
|
+
}
|
|
1390
|
+
async function buildInjectedMcpServers(opts) {
|
|
1391
|
+
const servers = [];
|
|
1392
|
+
if (opts.includeSideboard) {
|
|
1393
|
+
const sideboard = await resolveSideboardMcpServer();
|
|
1394
|
+
const orchId = opts.orchestratorThreadId?.trim();
|
|
1395
|
+
const profile = orchId ? "orchestration" : "worktree";
|
|
1396
|
+
sideboard.env = {
|
|
1397
|
+
...sideboard.env ?? {},
|
|
1398
|
+
SIDEBOARD_APP_DATA: appDataDir(),
|
|
1399
|
+
[SIDEBOARD_MCP_PROFILE_ENV]: profile
|
|
1400
|
+
};
|
|
1401
|
+
if (orchId) {
|
|
1402
|
+
sideboard.env.SIDEBOARD_ORCHESTRATOR_THREAD_ID = orchId;
|
|
1403
|
+
}
|
|
1404
|
+
try {
|
|
1405
|
+
mergeAgentGitAuthEnv(
|
|
1406
|
+
sideboard.env,
|
|
1407
|
+
await resolveAgentGitAuthEnv(sideboard.env)
|
|
1408
|
+
);
|
|
1409
|
+
} catch {
|
|
1410
|
+
}
|
|
1411
|
+
applyAgentRunnerHeapEnv(sideboard.env);
|
|
1412
|
+
servers.push(sideboard);
|
|
1413
|
+
}
|
|
1414
|
+
if (opts.includeBrightsy && isBrightsyConnected()) {
|
|
1415
|
+
const cmd = await resolveBrightsyMcpCommand();
|
|
1416
|
+
const teams = await ensureConnectedBrightsyTeamTokens();
|
|
1417
|
+
if (teams.length > 0) {
|
|
1418
|
+
const used = /* @__PURE__ */ new Set();
|
|
1419
|
+
for (const team of teams) {
|
|
1420
|
+
let name = brightsyMcpServerName(team.slug);
|
|
1421
|
+
if (used.has(name)) name = `${name}_${team.id.slice(0, 8)}`;
|
|
1422
|
+
used.add(name);
|
|
1423
|
+
servers.push(mcpLaunch(cmd, name, teamEnv(team)));
|
|
1424
|
+
}
|
|
1425
|
+
} else {
|
|
1426
|
+
servers.push(mcpLaunch(cmd, "brightsy"));
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
return servers;
|
|
1362
1430
|
}
|
|
1363
|
-
function
|
|
1364
|
-
|
|
1365
|
-
return
|
|
1366
|
-
} catch {
|
|
1367
|
-
return "";
|
|
1431
|
+
function cursorSafeMcpLaunch(command, args) {
|
|
1432
|
+
if (process.platform === "win32") {
|
|
1433
|
+
return args && args.length > 0 ? { command, args } : { command };
|
|
1368
1434
|
}
|
|
1435
|
+
const unwrapped = unwrapStrippedElectronLaunch(command, args);
|
|
1436
|
+
const file = unwrapped?.file ?? command;
|
|
1437
|
+
const fileArgs = unwrapped?.args ?? args ?? [];
|
|
1438
|
+
return fileArgs.length > 0 ? { command: file, args: fileArgs } : { command: file };
|
|
1369
1439
|
}
|
|
1370
|
-
function
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
if (result.status !== 0) return "";
|
|
1377
|
-
return typeof result.stdout === "string" ? result.stdout : "";
|
|
1440
|
+
function mcpSpawnEnv(env) {
|
|
1441
|
+
if (!env) return void 0;
|
|
1442
|
+
const out = { ...env };
|
|
1443
|
+
delete out.ELECTRON_RUN_AS_NODE;
|
|
1444
|
+
delete out.ELECTRON_RUN_AS_NODE;
|
|
1445
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
1378
1446
|
}
|
|
1379
|
-
function
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1447
|
+
function toCursorMcpServers(servers) {
|
|
1448
|
+
const out = {};
|
|
1449
|
+
for (const s of servers) {
|
|
1450
|
+
const env = mcpSpawnEnv(s.env);
|
|
1451
|
+
const launch = cursorSafeMcpLaunch(s.command, s.args);
|
|
1452
|
+
out[s.name] = {
|
|
1453
|
+
type: "stdio",
|
|
1454
|
+
command: launch.command,
|
|
1455
|
+
...launch.args && launch.args.length > 0 ? { args: launch.args } : {},
|
|
1456
|
+
...env ? { env } : {}
|
|
1457
|
+
};
|
|
1383
1458
|
}
|
|
1384
|
-
return
|
|
1459
|
+
return out;
|
|
1385
1460
|
}
|
|
1386
|
-
function
|
|
1387
|
-
const
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1461
|
+
function toCodexMcpConfigArgs(servers) {
|
|
1462
|
+
const args = [];
|
|
1463
|
+
for (const s of servers) {
|
|
1464
|
+
const prefix = `mcp_servers.${s.name}`;
|
|
1465
|
+
args.push("-c", `${prefix}.command=${JSON.stringify(s.command)}`);
|
|
1466
|
+
if (s.args?.length) {
|
|
1467
|
+
args.push("-c", `${prefix}.args=${JSON.stringify(s.args)}`);
|
|
1468
|
+
}
|
|
1469
|
+
const env = mcpSpawnEnv(s.env);
|
|
1470
|
+
if (env) {
|
|
1471
|
+
for (const [key, value] of Object.entries(env)) {
|
|
1472
|
+
args.push("-c", `${prefix}.env.${key}=${JSON.stringify(value)}`);
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
args.push("-c", `${prefix}.default_tools_approval_mode=${JSON.stringify("approve")}`);
|
|
1476
|
+
args.push("-c", `${prefix}.tool_timeout_sec=300`);
|
|
1477
|
+
args.push("-c", `${prefix}.startup_timeout_sec=30`);
|
|
1393
1478
|
}
|
|
1394
|
-
return
|
|
1395
|
-
}
|
|
1396
|
-
function systemCaBundlePath(io = {}) {
|
|
1397
|
-
return join((io.appData ?? appDataDir)(), BUNDLE_NAME);
|
|
1479
|
+
return args;
|
|
1398
1480
|
}
|
|
1399
|
-
function
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1481
|
+
function toOpencodeMcpConfigContent(servers, opts) {
|
|
1482
|
+
const mcp = {};
|
|
1483
|
+
for (const s of servers) {
|
|
1484
|
+
const env = mcpSpawnEnv(s.env);
|
|
1485
|
+
mcp[s.name] = {
|
|
1486
|
+
type: "local",
|
|
1487
|
+
command: [s.command, ...s.args ?? []],
|
|
1488
|
+
enabled: true,
|
|
1489
|
+
...env ? { environment: env } : {}
|
|
1490
|
+
};
|
|
1406
1491
|
}
|
|
1492
|
+
for (const name of opts?.disableNames ?? []) {
|
|
1493
|
+
const key = name.trim();
|
|
1494
|
+
if (!key || mcp[key]?.enabled === true) continue;
|
|
1495
|
+
mcp[key] = { ...mcp[key], enabled: false };
|
|
1496
|
+
}
|
|
1497
|
+
return JSON.stringify({ mcp });
|
|
1407
1498
|
}
|
|
1408
|
-
function
|
|
1409
|
-
const
|
|
1410
|
-
|
|
1411
|
-
|
|
1499
|
+
function stripElectronFromUserMcpEntry(entry) {
|
|
1500
|
+
const next = { ...entry };
|
|
1501
|
+
const env = next.env;
|
|
1502
|
+
if (!env || typeof env !== "object" || Array.isArray(env)) return next;
|
|
1503
|
+
const cleaned = { ...env };
|
|
1504
|
+
delete cleaned.ELECTRON_RUN_AS_NODE;
|
|
1505
|
+
next.env = cleaned;
|
|
1506
|
+
return next;
|
|
1507
|
+
}
|
|
1508
|
+
function writeMcpServersConfig(servers, extraServers) {
|
|
1509
|
+
const mcpServers = {};
|
|
1510
|
+
for (const s of servers) {
|
|
1511
|
+
const env = mcpSpawnEnv(s.env);
|
|
1512
|
+
mcpServers[s.name] = {
|
|
1513
|
+
command: s.command,
|
|
1514
|
+
...s.args ? { args: s.args } : {},
|
|
1515
|
+
...env ? { env } : {}
|
|
1516
|
+
};
|
|
1412
1517
|
}
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
if (
|
|
1518
|
+
if (extraServers) {
|
|
1519
|
+
for (const [rawName, entry] of Object.entries(extraServers)) {
|
|
1520
|
+
const name = rawName.trim();
|
|
1521
|
+
if (!name || mcpServers[name] || !entry) continue;
|
|
1522
|
+
mcpServers[name] = stripElectronFromUserMcpEntry(entry);
|
|
1417
1523
|
}
|
|
1418
1524
|
}
|
|
1419
|
-
|
|
1420
|
-
const
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1525
|
+
if (Object.keys(mcpServers).length === 0) return null;
|
|
1526
|
+
const dir = mkdtempSync(join4(tmpdir(), "sideboard-mcp-"));
|
|
1527
|
+
const cfgPath = join4(dir, "mcp.json");
|
|
1528
|
+
writeFileSync2(cfgPath, JSON.stringify({ mcpServers }, null, 2));
|
|
1529
|
+
return cfgPath;
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
// src/agents/user-mcp-config.ts
|
|
1533
|
+
function userClaudeMcpConfigPath() {
|
|
1534
|
+
return join5(homedir2(), ".claude.json");
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
// src/agents/orch-mcp-isolation.ts
|
|
1538
|
+
function isInjectedOrchMcpName(name) {
|
|
1539
|
+
const n = name.trim().toLowerCase();
|
|
1540
|
+
return n === "sideboard" || n === "brightsy" || n.startsWith("brightsy_");
|
|
1541
|
+
}
|
|
1542
|
+
function asObject(value) {
|
|
1543
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
1544
|
+
return value;
|
|
1545
|
+
}
|
|
1546
|
+
function listMcpNamesFromJsonMap(raw, key) {
|
|
1547
|
+
return Object.keys(asObject(asObject(raw)[key])).filter((n) => n.trim());
|
|
1548
|
+
}
|
|
1549
|
+
function listMcpNamesFromCodexToml(text) {
|
|
1426
1550
|
try {
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
`, { mode: 384 });
|
|
1430
|
-
return dest;
|
|
1551
|
+
const parsed = parseToml(text);
|
|
1552
|
+
return Object.keys(asObject(parsed.mcp_servers)).filter((n) => n.trim());
|
|
1431
1553
|
} catch {
|
|
1432
|
-
return
|
|
1554
|
+
return [];
|
|
1433
1555
|
}
|
|
1434
1556
|
}
|
|
1435
|
-
function
|
|
1436
|
-
|
|
1437
|
-
|
|
1557
|
+
function readJsonObject(path) {
|
|
1558
|
+
try {
|
|
1559
|
+
return JSON.parse(readFileSync3(path, "utf8"));
|
|
1560
|
+
} catch {
|
|
1561
|
+
return {};
|
|
1438
1562
|
}
|
|
1439
|
-
if (String(env[NODE_EXTRA_CA_CERTS] ?? "").trim()) return;
|
|
1440
|
-
const inherited = process.env.NODE_EXTRA_CA_CERTS?.trim();
|
|
1441
|
-
if (inherited) env[NODE_EXTRA_CA_CERTS] = inherited;
|
|
1442
1563
|
}
|
|
1443
|
-
function
|
|
1444
|
-
const path = process.env.NODE_EXTRA_CA_CERTS?.trim();
|
|
1445
|
-
if (path) return splitPemCertificates(readExistingFile(path));
|
|
1446
|
-
const dest = systemCaBundlePath();
|
|
1447
|
-
return splitPemCertificates(readExistingFile(dest));
|
|
1448
|
-
}
|
|
1449
|
-
function trustSystemCertificates(io = {}) {
|
|
1564
|
+
function readText(path) {
|
|
1450
1565
|
try {
|
|
1451
|
-
|
|
1452
|
-
if (typeof api.getCACertificates !== "function" || typeof api.setDefaultCACertificates !== "function") {
|
|
1453
|
-
return false;
|
|
1454
|
-
}
|
|
1455
|
-
const current = api.getCACertificates("default");
|
|
1456
|
-
const system = api.getCACertificates("system");
|
|
1457
|
-
let extra = extraCertsFromBundle();
|
|
1458
|
-
if (system.length === 0 && extra.length === 0) {
|
|
1459
|
-
extra = splitPemCertificates(collectSystemCaPem(io));
|
|
1460
|
-
}
|
|
1461
|
-
if (system.length === 0 && extra.length === 0) return false;
|
|
1462
|
-
api.setDefaultCACertificates([...current, ...system, ...extra]);
|
|
1463
|
-
return true;
|
|
1566
|
+
return readFileSync3(path, "utf8");
|
|
1464
1567
|
} catch {
|
|
1465
|
-
return
|
|
1568
|
+
return "";
|
|
1466
1569
|
}
|
|
1467
1570
|
}
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
import { existsSync as existsSync3 } from "fs";
|
|
1471
|
-
import { join as join2 } from "path";
|
|
1472
|
-
function electronResourcesPath() {
|
|
1473
|
-
const resources = process.resourcesPath;
|
|
1474
|
-
if (typeof resources !== "string" || !resources) return null;
|
|
1475
|
-
return resources;
|
|
1476
|
-
}
|
|
1477
|
-
function packagedCursorRuntimeDir() {
|
|
1478
|
-
const resources = electronResourcesPath();
|
|
1479
|
-
if (!resources) return null;
|
|
1480
|
-
const dir = join2(resources, "cursor-runtime");
|
|
1481
|
-
if (!existsSync3(join2(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
|
|
1482
|
-
return dir;
|
|
1483
|
-
}
|
|
1484
|
-
function packagedCursorRunnerPath() {
|
|
1485
|
-
const dir = packagedCursorRuntimeDir();
|
|
1486
|
-
return dir ? join2(dir, "core-dist", "agents", "cursor-runner.js") : null;
|
|
1487
|
-
}
|
|
1488
|
-
function packagedMcpDir() {
|
|
1489
|
-
const resources = electronResourcesPath();
|
|
1490
|
-
if (!resources) return null;
|
|
1491
|
-
const dir = join2(resources, "sideboard-mcp");
|
|
1492
|
-
if (!existsSync3(join2(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
|
|
1493
|
-
return dir;
|
|
1571
|
+
function userCodexConfigPaths(home = homedir3()) {
|
|
1572
|
+
return [join6(home, ".codex", "config.toml"), join6(home, ".config", "codex", "config.toml")];
|
|
1494
1573
|
}
|
|
1495
|
-
function
|
|
1496
|
-
|
|
1497
|
-
|
|
1574
|
+
function userOpencodeConfigPaths(home = homedir3()) {
|
|
1575
|
+
return [
|
|
1576
|
+
join6(home, ".config", "opencode", "opencode.json"),
|
|
1577
|
+
join6(home, ".config", "opencode", "opencode.jsonc")
|
|
1578
|
+
];
|
|
1498
1579
|
}
|
|
1499
|
-
function
|
|
1500
|
-
const
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1580
|
+
function userMcpNamesToDisable(opts) {
|
|
1581
|
+
const keep = new Set(
|
|
1582
|
+
[...opts.injectedNames ?? []].map((n) => n.trim().toLowerCase()).filter(Boolean)
|
|
1583
|
+
);
|
|
1584
|
+
const out = [];
|
|
1585
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1586
|
+
for (const raw of opts.names) {
|
|
1587
|
+
const name = raw.trim();
|
|
1588
|
+
if (!name) continue;
|
|
1589
|
+
const key = name.toLowerCase();
|
|
1590
|
+
if (seen.has(key) || keep.has(key) || isInjectedOrchMcpName(name)) continue;
|
|
1591
|
+
seen.add(key);
|
|
1592
|
+
out.push(name);
|
|
1593
|
+
}
|
|
1594
|
+
return out;
|
|
1505
1595
|
}
|
|
1506
|
-
function
|
|
1507
|
-
const
|
|
1508
|
-
|
|
1509
|
-
|
|
1596
|
+
function listUserCodexMcpNames(home = homedir3()) {
|
|
1597
|
+
const names = [];
|
|
1598
|
+
for (const path of userCodexConfigPaths(home)) {
|
|
1599
|
+
if (!existsSync7(path)) continue;
|
|
1600
|
+
names.push(...listMcpNamesFromCodexToml(readText(path)));
|
|
1601
|
+
}
|
|
1602
|
+
return names;
|
|
1510
1603
|
}
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
const existing = (nodeOptions ?? "").trim();
|
|
1517
|
-
const match = MAX_OLD_SPACE_FLAG.exec(existing);
|
|
1518
|
-
if (match) {
|
|
1519
|
-
const current = match[2] ? Number(match[2]) : 0;
|
|
1520
|
-
if (Number.isFinite(current) && current >= heapMb) return existing;
|
|
1521
|
-
return existing.replace(MAX_OLD_SPACE_FLAG, ` --max-old-space-size=${heapMb}`).trim();
|
|
1604
|
+
function listUserOpencodeMcpNames(home = homedir3()) {
|
|
1605
|
+
const names = [];
|
|
1606
|
+
for (const path of userOpencodeConfigPaths(home)) {
|
|
1607
|
+
if (!existsSync7(path)) continue;
|
|
1608
|
+
names.push(...listMcpNamesFromJsonMap(readJsonObject(path), "mcp"));
|
|
1522
1609
|
}
|
|
1523
|
-
return
|
|
1610
|
+
return names;
|
|
1524
1611
|
}
|
|
1525
|
-
function
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
);
|
|
1530
|
-
applySystemCaEnv(env);
|
|
1612
|
+
function userClaudeMcpConfigObject(home = homedir3()) {
|
|
1613
|
+
const claudePath = home === homedir3() ? userClaudeMcpConfigPath() : join6(home, ".claude.json");
|
|
1614
|
+
if (!existsSync7(claudePath)) return {};
|
|
1615
|
+
return asObject(asObject(readJsonObject(claudePath)).mcpServers);
|
|
1531
1616
|
}
|
|
1532
|
-
function
|
|
1533
|
-
const
|
|
1534
|
-
|
|
1535
|
-
|
|
1617
|
+
function listUserClaudeMcpServerEntries(home = homedir3()) {
|
|
1618
|
+
const out = {};
|
|
1619
|
+
for (const [rawName, value] of Object.entries(userClaudeMcpConfigObject(home))) {
|
|
1620
|
+
const name = rawName.trim();
|
|
1621
|
+
if (!name || isInjectedOrchMcpName(name)) continue;
|
|
1622
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) continue;
|
|
1623
|
+
out[name] = value;
|
|
1624
|
+
}
|
|
1625
|
+
return out;
|
|
1536
1626
|
}
|
|
1537
|
-
function
|
|
1538
|
-
|
|
1539
|
-
|
|
1627
|
+
function toCodexDisableUserMcpArgs(names) {
|
|
1628
|
+
const args = [];
|
|
1629
|
+
for (const name of names) {
|
|
1630
|
+
if (!/^[A-Za-z0-9_-]+$/.test(name)) continue;
|
|
1631
|
+
args.push("-c", `mcp_servers.${name}.enabled=false`);
|
|
1632
|
+
}
|
|
1633
|
+
return args;
|
|
1540
1634
|
}
|
|
1541
|
-
function
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1635
|
+
function toCodexUnattendedAppsArgs() {
|
|
1636
|
+
return [
|
|
1637
|
+
"-c",
|
|
1638
|
+
"features.apps=false",
|
|
1639
|
+
"-c",
|
|
1640
|
+
"apps._default.enabled=false",
|
|
1641
|
+
"-c",
|
|
1642
|
+
"apps.posthog.enabled=false",
|
|
1643
|
+
"-c",
|
|
1644
|
+
"features.plugins=false"
|
|
1645
|
+
];
|
|
1546
1646
|
}
|
|
1547
|
-
|
|
1548
|
-
|
|
1647
|
+
|
|
1648
|
+
// src/agents/message-parts.ts
|
|
1649
|
+
function asRecord(input) {
|
|
1650
|
+
if (input && typeof input === "object" && !Array.isArray(input)) {
|
|
1651
|
+
return input;
|
|
1652
|
+
}
|
|
1653
|
+
return void 0;
|
|
1549
1654
|
}
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
const match = /^v?(\d+)/.exec(version.trim());
|
|
1553
|
-
if (!match) return null;
|
|
1554
|
-
const major = Number(match[1]);
|
|
1555
|
-
return Number.isInteger(major) ? major : null;
|
|
1655
|
+
function str(v) {
|
|
1656
|
+
return typeof v === "string" && v.trim() ? v : void 0;
|
|
1556
1657
|
}
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
if (
|
|
1561
|
-
|
|
1562
|
-
let score = 0;
|
|
1563
|
-
if (major % 2 === 0) {
|
|
1564
|
-
score += 1e3 + major * 10;
|
|
1565
|
-
} else {
|
|
1566
|
-
score += major;
|
|
1567
|
-
}
|
|
1568
|
-
if (/\/Cellar\/node\/\d/.test(posix) && !/\/Cellar\/node@\d+/.test(posix)) {
|
|
1569
|
-
score -= 50;
|
|
1570
|
-
}
|
|
1571
|
-
return score;
|
|
1658
|
+
var CHAT_DETAIL_MAX = 72;
|
|
1659
|
+
function clipChatLine(value, max = CHAT_DETAIL_MAX) {
|
|
1660
|
+
const line = value.trim().split(/\r?\n/, 1)[0] ?? "";
|
|
1661
|
+
if (line.length <= max) return line;
|
|
1662
|
+
return `${line.slice(0, Math.max(1, max - 1))}\u2026`;
|
|
1572
1663
|
}
|
|
1573
|
-
function
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
}
|
|
1664
|
+
function toolDetail(name, input) {
|
|
1665
|
+
if (!input) return void 0;
|
|
1666
|
+
const command = str(input.command) ?? str(input.cmd);
|
|
1667
|
+
if (command) return clipChatLine(command);
|
|
1668
|
+
const pattern = str(input.pattern) ?? str(input.glob) ?? str(input.glob_pattern);
|
|
1669
|
+
const isSearch = /grep|glob|search|ripgrep|findfiles|semsearch/i.test(name);
|
|
1670
|
+
if (isSearch && pattern) {
|
|
1671
|
+
return pattern.length > 80 ? `${pattern.slice(0, 77)}\u2026` : pattern;
|
|
1582
1672
|
}
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1673
|
+
const path = str(input.file_path) ?? str(input.path) ?? str(input.filePath) ?? str(input.filename);
|
|
1674
|
+
if (path) return path;
|
|
1675
|
+
if (pattern) return pattern.length > 80 ? `${pattern.slice(0, 77)}\u2026` : pattern;
|
|
1676
|
+
const query = str(input.query) ?? str(input.prompt);
|
|
1677
|
+
if (query) return query.length > 80 ? `${query.slice(0, 77)}\u2026` : query;
|
|
1587
1678
|
try {
|
|
1588
|
-
|
|
1679
|
+
const raw = JSON.stringify(input);
|
|
1680
|
+
return raw.length > 80 ? `${raw.slice(0, 77)}\u2026` : raw;
|
|
1589
1681
|
} catch {
|
|
1590
|
-
return
|
|
1682
|
+
return name;
|
|
1591
1683
|
}
|
|
1592
1684
|
}
|
|
1593
|
-
function
|
|
1594
|
-
const
|
|
1595
|
-
|
|
1596
|
-
)
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
"
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
)
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
for (const raw of paths) {
|
|
1624
|
-
const p = raw.trim();
|
|
1625
|
-
if (!p || !existsSync4(p) || isElectronLikeCommand(p)) continue;
|
|
1626
|
-
let key = p;
|
|
1627
|
-
try {
|
|
1628
|
-
key = realpathSync(p);
|
|
1629
|
-
} catch {
|
|
1630
|
-
continue;
|
|
1685
|
+
function toolDescription(name, input) {
|
|
1686
|
+
const n = name.replace(/^mcp__/, "").replace(/__/g, " \xB7 ");
|
|
1687
|
+
if (/^get_record_types$|recordTypes/i.test(name)) return "List record types";
|
|
1688
|
+
if (/connectedAgentRequest/i.test(name)) {
|
|
1689
|
+
return str(input?.agent_id) ? `Ask connected agent` : "Ask connected agent";
|
|
1690
|
+
}
|
|
1691
|
+
if (/present_artifact$/i.test(name)) {
|
|
1692
|
+
return str(input?.title) ? `Present ${str(input?.title)}` : "Present artifact";
|
|
1693
|
+
}
|
|
1694
|
+
if (/present_plan$/i.test(name)) {
|
|
1695
|
+
return str(input?.title) ? `Plan ${str(input?.title)}` : "Present plan";
|
|
1696
|
+
}
|
|
1697
|
+
if (/present_schema$/i.test(name)) {
|
|
1698
|
+
return str(input?.title) ? `Schema ${str(input?.title)}` : "Present schema";
|
|
1699
|
+
}
|
|
1700
|
+
if (/present_files$/i.test(name)) {
|
|
1701
|
+
return str(input?.title) ? `Files ${str(input?.title)}` : "Present files";
|
|
1702
|
+
}
|
|
1703
|
+
if (/wait_for_job$/i.test(name)) {
|
|
1704
|
+
return str(input?.id) ? `Wait for ${str(input?.id)}` : "Wait for job";
|
|
1705
|
+
}
|
|
1706
|
+
if (/stop_job$/i.test(name)) {
|
|
1707
|
+
return str(input?.id) ? `Stop ${str(input?.id)}` : "Stop job";
|
|
1708
|
+
}
|
|
1709
|
+
if (isSubagentToolName(name)) {
|
|
1710
|
+
const desc = str(input?.description);
|
|
1711
|
+
const sub = asRecord(input?.subagentType);
|
|
1712
|
+
const kind = str(sub?.name) ?? str(sub?.kind) ?? str(input?.subagent_type) ?? str(input?.subagentType);
|
|
1713
|
+
if (/^spawn_agent$/i.test(name)) {
|
|
1714
|
+
return str(input?.prompt) ?? desc ?? "Subagent";
|
|
1631
1715
|
}
|
|
1632
|
-
if (
|
|
1633
|
-
|
|
1634
|
-
|
|
1716
|
+
if (/connectedAgentRequest/i.test(name)) {
|
|
1717
|
+
return str(input?.agent_id) ? `Ask connected agent` : "Ask connected agent";
|
|
1718
|
+
}
|
|
1719
|
+
if (desc && kind) return `${kind}: ${desc}${subagentLiveSuffix(input)}`;
|
|
1720
|
+
if (desc) return `${desc}${subagentLiveSuffix(input)}`;
|
|
1721
|
+
return `Subagent${subagentLiveSuffix(input)}`;
|
|
1635
1722
|
}
|
|
1636
|
-
|
|
1637
|
-
}
|
|
1638
|
-
async function whichAllNode() {
|
|
1639
|
-
if (process.platform === "win32") {
|
|
1640
|
-
const located = await run("where", ["node"], { reject: false, timeoutMs: 5e3 });
|
|
1641
|
-
if (located.exitCode !== 0) return [];
|
|
1642
|
-
return located.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
1723
|
+
if (/^(create|update)_artifact$/i.test(name.replace(/^mcp__[^_]+__/, ""))) {
|
|
1724
|
+
return str(input?.title) ? `Artifact ${str(input?.title)}` : "Artifact";
|
|
1643
1725
|
}
|
|
1644
|
-
|
|
1645
|
-
if (
|
|
1646
|
-
|
|
1726
|
+
if (!input) return n;
|
|
1727
|
+
if (/bash|shell|terminal/i.test(name) && str(input.command)) {
|
|
1728
|
+
const cmd = str(input.command);
|
|
1729
|
+
if (/git\s+fetch/i.test(cmd)) return "Fetch latest from origin and check status";
|
|
1730
|
+
if (/git\s+status/i.test(cmd)) return "Check git status";
|
|
1731
|
+
if (/git\s+log/i.test(cmd)) return "Inspect recent commits";
|
|
1732
|
+
if (/git\s+branch/i.test(cmd)) return "List branches";
|
|
1733
|
+
if (/grep|rg\b/i.test(cmd)) return "Search repository";
|
|
1734
|
+
return "Run shell command";
|
|
1735
|
+
}
|
|
1736
|
+
if (/edit|write|apply/i.test(name)) {
|
|
1737
|
+
const path = str(input.file_path) ?? str(input.path);
|
|
1738
|
+
return path ? `Edit ${path.split("/").pop()}` : "Edit file";
|
|
1739
|
+
}
|
|
1740
|
+
if (/read/i.test(name)) {
|
|
1741
|
+
const path = str(input.file_path) ?? str(input.path);
|
|
1742
|
+
return path ? `Read ${path.split("/").pop()}` : "Read file";
|
|
1743
|
+
}
|
|
1744
|
+
if (/grep/i.test(name)) return "Search files";
|
|
1745
|
+
if (/glob/i.test(name)) return "Find files";
|
|
1746
|
+
const compact = n.replace(/[_-]/g, "");
|
|
1747
|
+
if (/^taskoutput$/i.test(compact)) {
|
|
1748
|
+
return str(input.task_id) ? `Wait for ${str(input.task_id)}` : "Wait for background task";
|
|
1749
|
+
}
|
|
1750
|
+
if (/^taskstop$/i.test(compact)) {
|
|
1751
|
+
return str(input.task_id) ? `Stop ${str(input.task_id)}` : "Stop background task";
|
|
1752
|
+
}
|
|
1753
|
+
if (/^monitor$/i.test(compact)) {
|
|
1754
|
+
const command = str(input.command);
|
|
1755
|
+
return command ? `Watch ${command.length > 48 ? `${command.slice(0, 45)}\u2026` : command}` : "Watch command";
|
|
1756
|
+
}
|
|
1757
|
+
return n;
|
|
1758
|
+
}
|
|
1759
|
+
function subagentLiveSuffix(input) {
|
|
1760
|
+
if (!input) return "";
|
|
1761
|
+
const bits = [];
|
|
1762
|
+
const status = str(input.live_status);
|
|
1763
|
+
if (status && !/^runn(ing)?$|^working$/i.test(status)) bits.push(status);
|
|
1764
|
+
if (typeof input.live_tool_uses === "number") bits.push(`${input.live_tool_uses} tools`);
|
|
1765
|
+
if (typeof input.live_duration_ms === "number") {
|
|
1766
|
+
bits.push(`${Math.max(0, Math.round(Number(input.live_duration_ms) / 1e3))}s`);
|
|
1647
1767
|
}
|
|
1648
|
-
const
|
|
1649
|
-
if (
|
|
1650
|
-
return
|
|
1768
|
+
const last = str(input.live_last_tool);
|
|
1769
|
+
if (last) bits.push(last);
|
|
1770
|
+
return bits.length ? ` \xB7 ${bits.join(" \xB7 ")}` : "";
|
|
1651
1771
|
}
|
|
1652
|
-
|
|
1653
|
-
const
|
|
1654
|
-
if (
|
|
1655
|
-
|
|
1656
|
-
return version || null;
|
|
1772
|
+
function isSubagentToolName(name) {
|
|
1773
|
+
const n = (name ?? "").trim();
|
|
1774
|
+
if (/^(task|agent|spawn_agent)$/i.test(n)) return true;
|
|
1775
|
+
return /connectedAgentRequest/i.test(n);
|
|
1657
1776
|
}
|
|
1658
|
-
|
|
1659
|
-
const
|
|
1660
|
-
|
|
1661
|
-
if (
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
const version = await probeNodeVersion(path);
|
|
1665
|
-
return version ? { path, version } : null;
|
|
1666
|
-
})
|
|
1667
|
-
);
|
|
1668
|
-
return pickPreferredNode(probed.filter((c) => c != null));
|
|
1777
|
+
function isInternalAgentStatusText(text) {
|
|
1778
|
+
const t = text.trim();
|
|
1779
|
+
if (!t) return false;
|
|
1780
|
+
if (/waiting for gate to pass/i.test(t)) return true;
|
|
1781
|
+
if (/^agent is running\b/i.test(t) && t.length < 160) return true;
|
|
1782
|
+
return false;
|
|
1669
1783
|
}
|
|
1670
|
-
function
|
|
1671
|
-
const
|
|
1672
|
-
|
|
1673
|
-
return {
|
|
1674
|
-
file: launch.file,
|
|
1675
|
-
args: readableArgs,
|
|
1676
|
-
env: envWithAgentHeap(launch.env)
|
|
1677
|
-
};
|
|
1678
|
-
}
|
|
1679
|
-
const wrapped = wrapElectronAsNodeLaunch(launch.file, readableArgs);
|
|
1680
|
-
if (process.platform === "win32") {
|
|
1681
|
-
return {
|
|
1682
|
-
file: wrapped.file,
|
|
1683
|
-
args: wrapped.args,
|
|
1684
|
-
env: envWithAgentHeap(launch.env)
|
|
1685
|
-
};
|
|
1686
|
-
}
|
|
1687
|
-
const env = envWithAgentHeap(launch.env);
|
|
1688
|
-
delete env.ELECTRON_RUN_AS_NODE;
|
|
1689
|
-
return { file: wrapped.file, args: wrapped.args, env };
|
|
1784
|
+
function isPollWrapperToolName(name) {
|
|
1785
|
+
const n = (name ?? "").replace(/[_-]/g, "");
|
|
1786
|
+
return /^(taskoutput|taskstop|sleep)$/i.test(n);
|
|
1690
1787
|
}
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
const node = await findSystemNode();
|
|
1699
|
-
if (node) {
|
|
1700
|
-
return { file: node.path, env: {}, nodeVersion: node.version };
|
|
1701
|
-
}
|
|
1788
|
+
function lastTextPart(parts, type) {
|
|
1789
|
+
for (let i = parts.length - 1; i >= 0; i--) {
|
|
1790
|
+
const p = parts[i];
|
|
1791
|
+
if (p.type !== type) continue;
|
|
1792
|
+
const text = p.text.trim();
|
|
1793
|
+
if (!text || isInternalAgentStatusText(text)) continue;
|
|
1794
|
+
return text;
|
|
1702
1795
|
}
|
|
1703
|
-
return
|
|
1704
|
-
file: process.execPath,
|
|
1705
|
-
env: { ELECTRON_RUN_AS_NODE: "1" }
|
|
1706
|
-
};
|
|
1796
|
+
return "";
|
|
1707
1797
|
}
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
var SIDEBOARD_MCP_ALLOWED_TOOLS = [
|
|
1711
|
-
"mcp__sideboard",
|
|
1712
|
-
"mcp__sideboard__*"
|
|
1713
|
-
];
|
|
1714
|
-
var SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS = [
|
|
1715
|
-
"mcp__sideboard__present_artifact",
|
|
1716
|
-
"mcp__sideboard__present_schema",
|
|
1717
|
-
"mcp__sideboard__present_files",
|
|
1718
|
-
"mcp__sideboard__ask_user",
|
|
1719
|
-
"mcp__sideboard__present_plan",
|
|
1720
|
-
"mcp__sideboard__wait_for_job",
|
|
1721
|
-
"mcp__sideboard__stop_job",
|
|
1722
|
-
"mcp__sideboard__get_viewer_context",
|
|
1723
|
-
"mcp__sideboard__update_viewer_context"
|
|
1724
|
-
];
|
|
1725
|
-
var SIDEBOARD_GITHUB_MCP_ALLOWED_TOOLS = ["mcp__sideboard__github_*"];
|
|
1726
|
-
var SIDEBOARD_LINEAR_MCP_ALLOWED_TOOLS = ["mcp__sideboard__linear_*"];
|
|
1727
|
-
var SIDEBOARD_ABLETIME_MCP_ALLOWED_TOOLS = ["mcp__sideboard__abletime_*"];
|
|
1728
|
-
function sideboardWorktreeAllowedTools(opts) {
|
|
1729
|
-
const out = [...SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS];
|
|
1730
|
-
if (opts?.github !== false) out.push(...SIDEBOARD_GITHUB_MCP_ALLOWED_TOOLS);
|
|
1731
|
-
if (opts?.linear) out.push(...SIDEBOARD_LINEAR_MCP_ALLOWED_TOOLS);
|
|
1732
|
-
if (opts?.abletime) out.push(...SIDEBOARD_ABLETIME_MCP_ALLOWED_TOOLS);
|
|
1733
|
-
return out;
|
|
1798
|
+
function toolLabel(tool) {
|
|
1799
|
+
return tool.description || toolDescription(tool.name, tool.input) || tool.name;
|
|
1734
1800
|
}
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
if (brightsyMcpCommandCache && now - brightsyMcpCommandCache.at < 6e4 && brightsyMcpCommandCache.command) {
|
|
1739
|
-
return brightsyMcpCommandCache.command;
|
|
1801
|
+
function liveActivitySummary(parts, opts) {
|
|
1802
|
+
if (opts?.queued && parts.length === 0) {
|
|
1803
|
+
return "Queued \u2014 waiting for a slot";
|
|
1740
1804
|
}
|
|
1741
|
-
const
|
|
1742
|
-
const
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1805
|
+
const tools = parts.filter((p) => p.type === "tool");
|
|
1806
|
+
const runningSubs = tools.filter(
|
|
1807
|
+
(t) => t.status === "running" && !t.parentId && isSubagentToolName(t.name)
|
|
1808
|
+
);
|
|
1809
|
+
const runningNested = [...tools].reverse().find((t) => t.status === "running" && t.parentId && !isPollWrapperToolName(t.name));
|
|
1810
|
+
const runningTop = [...tools].reverse().find(
|
|
1811
|
+
(t) => t.status === "running" && !t.parentId && !isPollWrapperToolName(t.name) && !isSubagentToolName(t.name)
|
|
1812
|
+
);
|
|
1813
|
+
const runningPoll = [...tools].reverse().find((t) => t.status === "running" && isPollWrapperToolName(t.name));
|
|
1814
|
+
const thinking = lastTextPart(parts, "thinking");
|
|
1815
|
+
const text = lastTextPart(parts, "text");
|
|
1816
|
+
if (runningSubs.length > 0) {
|
|
1817
|
+
const heads = runningSubs.map(toolLabel);
|
|
1818
|
+
const head = runningSubs.length === 1 ? heads[0] : `${runningSubs.length} subagents \xB7 ${heads.slice(0, 2).join(" \xB7 ")}`;
|
|
1819
|
+
if (runningNested) return `${head} \xB7 ${toolLabel(runningNested)}`;
|
|
1820
|
+
return head;
|
|
1752
1821
|
}
|
|
1822
|
+
if (runningTop) return toolLabel(runningTop);
|
|
1823
|
+
if (runningPoll) return toolLabel(runningPoll);
|
|
1824
|
+
if (thinking) return thinking.length > 96 ? `\u2026${thinking.slice(-96)}` : thinking;
|
|
1825
|
+
if (text) return "Writing reply\u2026";
|
|
1826
|
+
const last = [...tools].reverse().find((t) => !isPollWrapperToolName(t.name)) ?? tools.at(-1);
|
|
1827
|
+
if (last) {
|
|
1828
|
+
const label = toolLabel(last);
|
|
1829
|
+
return last.status === "running" ? label : `Finished ${label}`;
|
|
1830
|
+
}
|
|
1831
|
+
return "Working\u2026";
|
|
1753
1832
|
}
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
}
|
|
1758
|
-
|
|
1759
|
-
const n = name.toLowerCase();
|
|
1760
|
-
return n === "brightsy" || n.startsWith("mcp__brightsy") || n.startsWith("brightsy_");
|
|
1833
|
+
function messagePartParentId(part) {
|
|
1834
|
+
if ("parentId" in part && typeof part.parentId === "string" && part.parentId.trim()) {
|
|
1835
|
+
return part.parentId;
|
|
1836
|
+
}
|
|
1837
|
+
return void 0;
|
|
1761
1838
|
}
|
|
1762
|
-
function
|
|
1763
|
-
|
|
1764
|
-
return typeof ds === "string" && ds.toLowerCase() === "brightsy";
|
|
1839
|
+
function sameParentId(a, b) {
|
|
1840
|
+
return (a ?? "") === (b ?? "");
|
|
1765
1841
|
}
|
|
1766
|
-
function
|
|
1767
|
-
if (
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
if (isBrightsyMcpToolName(part.name)) return true;
|
|
1771
|
-
if (/present_(schema|files)$/i.test(part.name) && toolInputUsesBrightsyDatasource(part.input)) {
|
|
1772
|
-
return true;
|
|
1773
|
-
}
|
|
1842
|
+
function withEventParentId(event, parentId) {
|
|
1843
|
+
if (!parentId) return event;
|
|
1844
|
+
if (event.type === "stdout" || event.type === "thinking" || event.type === "tool_use" || event.type === "tool_result") {
|
|
1845
|
+
return { ...event, parentId: event.parentId ?? parentId };
|
|
1774
1846
|
}
|
|
1775
|
-
return
|
|
1847
|
+
return event;
|
|
1776
1848
|
}
|
|
1777
|
-
function
|
|
1778
|
-
|
|
1849
|
+
function toolFilePath(input) {
|
|
1850
|
+
if (!input) return void 0;
|
|
1851
|
+
return str(input.file_path) ?? str(input.path) ?? str(input.filePath) ?? str(input.filename);
|
|
1779
1852
|
}
|
|
1780
|
-
function
|
|
1781
|
-
if (!
|
|
1782
|
-
|
|
1783
|
-
const alwaysOn = opts?.alwaysOnWorktree ?? Boolean(loadAppSettings().brightsy?.injectWorktreeMcp);
|
|
1784
|
-
if (alwaysOn) return true;
|
|
1785
|
-
return threadRequestsBrightsyMcp(thread);
|
|
1853
|
+
function countLines(text) {
|
|
1854
|
+
if (!text) return 0;
|
|
1855
|
+
return text.split("\n").length;
|
|
1786
1856
|
}
|
|
1787
|
-
function
|
|
1788
|
-
if (
|
|
1789
|
-
|
|
1857
|
+
function diffFromInput(input) {
|
|
1858
|
+
if (!input) return {};
|
|
1859
|
+
const oldS = str(input.old_string) ?? str(input.oldString);
|
|
1860
|
+
const newS = str(input.new_string) ?? str(input.newString) ?? str(input.content);
|
|
1861
|
+
if (oldS != null || newS != null) {
|
|
1862
|
+
return {
|
|
1863
|
+
additions: countLines(newS),
|
|
1864
|
+
deletions: countLines(oldS)
|
|
1865
|
+
};
|
|
1790
1866
|
}
|
|
1791
|
-
return {
|
|
1792
|
-
name,
|
|
1793
|
-
command: "npx",
|
|
1794
|
-
args: ["-y", "@brightsy/mcp-server"],
|
|
1795
|
-
...env ? { env } : {}
|
|
1796
|
-
};
|
|
1867
|
+
return {};
|
|
1797
1868
|
}
|
|
1798
|
-
function
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1869
|
+
function parseDiffStat(result) {
|
|
1870
|
+
if (!result) return {};
|
|
1871
|
+
const paired = result.match(/\+(\d+)\s+-(\d+)/);
|
|
1872
|
+
if (paired) {
|
|
1873
|
+
return {
|
|
1874
|
+
additions: Number(paired[1]),
|
|
1875
|
+
deletions: Number(paired[2])
|
|
1876
|
+
};
|
|
1877
|
+
}
|
|
1878
|
+
const verbose = result.match(
|
|
1879
|
+
/(\d+)\s+insertions?(?:,\s*(\d+)\s+deletions?)?/i
|
|
1880
|
+
);
|
|
1881
|
+
if (verbose) {
|
|
1882
|
+
return {
|
|
1883
|
+
additions: Number(verbose[1]),
|
|
1884
|
+
deletions: verbose[2] != null ? Number(verbose[2]) : void 0
|
|
1885
|
+
};
|
|
1886
|
+
}
|
|
1887
|
+
return {};
|
|
1888
|
+
}
|
|
1889
|
+
var THINKING_PART_MAX_CHARS = 64e3;
|
|
1890
|
+
function clipThinkingForStore(text, max = THINKING_PART_MAX_CHARS) {
|
|
1891
|
+
if (text.length <= max) return text;
|
|
1892
|
+
const marker = "\u2026(earlier thinking trimmed)\n";
|
|
1893
|
+
return marker + text.slice(text.length - Math.max(1, max - marker.length));
|
|
1806
1894
|
}
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
return
|
|
1895
|
+
var STDOUT_EVENT_MAX_CHARS = 16e3;
|
|
1896
|
+
var STDERR_EVENT_MAX_CHARS = 4e3;
|
|
1897
|
+
function clipEventTail(text, max) {
|
|
1898
|
+
if (text.length <= max) return text;
|
|
1899
|
+
const marker = "\u2026(truncated)\n";
|
|
1900
|
+
return marker + text.slice(text.length - Math.max(1, max - marker.length));
|
|
1813
1901
|
}
|
|
1814
|
-
function
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
if (typeof url === "string" && url.length > 0) {
|
|
1820
|
-
return dirname2(fileURLToPath(url));
|
|
1821
|
-
}
|
|
1822
|
-
} catch {
|
|
1902
|
+
function clipAgentEventForPaint(event) {
|
|
1903
|
+
if (event.type === "tool_result" && event.content) {
|
|
1904
|
+
const content = clipToolResultForStore(event.content);
|
|
1905
|
+
if (content === event.content) return event;
|
|
1906
|
+
return { ...event, content };
|
|
1823
1907
|
}
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
return
|
|
1908
|
+
if (event.type === "thinking" && event.data.length > THINKING_PART_MAX_CHARS) {
|
|
1909
|
+
return { ...event, data: clipThinkingForStore(event.data) };
|
|
1910
|
+
}
|
|
1911
|
+
if (event.type === "stdout" && event.data.length > STDOUT_EVENT_MAX_CHARS) {
|
|
1912
|
+
return { ...event, data: clipEventTail(event.data, STDOUT_EVENT_MAX_CHARS) };
|
|
1913
|
+
}
|
|
1914
|
+
if (event.type === "stderr" && event.data.length > STDERR_EVENT_MAX_CHARS) {
|
|
1915
|
+
return { ...event, data: clipEventTail(event.data, STDERR_EVENT_MAX_CHARS) };
|
|
1829
1916
|
}
|
|
1917
|
+
return event;
|
|
1830
1918
|
}
|
|
1831
|
-
function
|
|
1832
|
-
const
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
const
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1919
|
+
function withPartTimes(next, prev) {
|
|
1920
|
+
const now = Date.now();
|
|
1921
|
+
const startedAt = prev && typeof prev.startedAt === "number" ? prev.startedAt : now;
|
|
1922
|
+
return { ...next, startedAt, updatedAt: now };
|
|
1923
|
+
}
|
|
1924
|
+
function applyAgentEvent(parts, event) {
|
|
1925
|
+
if (event.type === "stdout") {
|
|
1926
|
+
const data = event.data;
|
|
1927
|
+
if (!data) return parts;
|
|
1928
|
+
const next = [...parts];
|
|
1929
|
+
const last = next[next.length - 1];
|
|
1930
|
+
if (last?.type === "text" && sameParentId(last.parentId, event.parentId)) {
|
|
1931
|
+
next[next.length - 1] = withPartTimes(
|
|
1932
|
+
{
|
|
1933
|
+
type: "text",
|
|
1934
|
+
text: last.text + data,
|
|
1935
|
+
...event.parentId ? { parentId: event.parentId } : {}
|
|
1936
|
+
},
|
|
1937
|
+
last
|
|
1938
|
+
);
|
|
1939
|
+
} else {
|
|
1940
|
+
next.push(
|
|
1941
|
+
withPartTimes({
|
|
1942
|
+
type: "text",
|
|
1943
|
+
text: data,
|
|
1944
|
+
...event.parentId ? { parentId: event.parentId } : {}
|
|
1945
|
+
})
|
|
1946
|
+
);
|
|
1849
1947
|
}
|
|
1850
|
-
|
|
1851
|
-
if (parent === dir) break;
|
|
1852
|
-
dir = parent;
|
|
1948
|
+
return next;
|
|
1853
1949
|
}
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1950
|
+
if (event.type === "thinking") {
|
|
1951
|
+
const data = event.data;
|
|
1952
|
+
if (!data) return parts;
|
|
1953
|
+
const next = [...parts];
|
|
1954
|
+
if (event.replace) {
|
|
1955
|
+
for (let i = next.length - 1; i >= 0; i--) {
|
|
1956
|
+
const prev = next[i];
|
|
1957
|
+
if (prev?.type === "thinking" && sameParentId(prev.parentId, event.parentId)) {
|
|
1958
|
+
next[i] = withPartTimes(
|
|
1959
|
+
{
|
|
1960
|
+
type: "thinking",
|
|
1961
|
+
text: clipThinkingForStore(data),
|
|
1962
|
+
...event.parentId ? { parentId: event.parentId } : {}
|
|
1963
|
+
},
|
|
1964
|
+
prev
|
|
1965
|
+
);
|
|
1966
|
+
return next;
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
next.push(
|
|
1970
|
+
withPartTimes({
|
|
1971
|
+
type: "thinking",
|
|
1972
|
+
text: clipThinkingForStore(data),
|
|
1973
|
+
...event.parentId ? { parentId: event.parentId } : {}
|
|
1974
|
+
})
|
|
1975
|
+
);
|
|
1976
|
+
return next;
|
|
1977
|
+
}
|
|
1978
|
+
const last = next[next.length - 1];
|
|
1979
|
+
if (last?.type === "thinking" && sameParentId(last.parentId, event.parentId)) {
|
|
1980
|
+
next[next.length - 1] = withPartTimes(
|
|
1981
|
+
{
|
|
1982
|
+
type: "thinking",
|
|
1983
|
+
text: clipThinkingForStore(last.text + data),
|
|
1984
|
+
...event.parentId ? { parentId: event.parentId } : {}
|
|
1985
|
+
},
|
|
1986
|
+
last
|
|
1987
|
+
);
|
|
1988
|
+
} else {
|
|
1989
|
+
next.push(
|
|
1990
|
+
withPartTimes({
|
|
1991
|
+
type: "thinking",
|
|
1992
|
+
text: clipThinkingForStore(data),
|
|
1993
|
+
...event.parentId ? { parentId: event.parentId } : {}
|
|
1994
|
+
})
|
|
1995
|
+
);
|
|
1869
1996
|
}
|
|
1997
|
+
return next;
|
|
1870
1998
|
}
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1999
|
+
if (event.type === "tool_use") {
|
|
2000
|
+
const input = asRecord(event.input);
|
|
2001
|
+
const diff = diffFromInput(input);
|
|
2002
|
+
const existing = parts.findIndex((p) => p.type === "tool" && p.id === event.id);
|
|
2003
|
+
if (existing >= 0) {
|
|
2004
|
+
const prev = parts[existing];
|
|
2005
|
+
const next = [...parts];
|
|
2006
|
+
const mergedInput = {
|
|
2007
|
+
...prev.input ?? {},
|
|
2008
|
+
...input ?? {}
|
|
2009
|
+
};
|
|
2010
|
+
const mergedRecord = Object.keys(mergedInput).length > 0 ? mergedInput : void 0;
|
|
2011
|
+
next[existing] = withPartTimes(
|
|
2012
|
+
{
|
|
2013
|
+
...prev,
|
|
2014
|
+
name: event.name || prev.name,
|
|
2015
|
+
input: mergedRecord,
|
|
2016
|
+
description: toolDescription(event.name || prev.name, mergedRecord),
|
|
2017
|
+
detail: toolDetail(event.name || prev.name, mergedRecord) ?? prev.detail,
|
|
2018
|
+
filePath: toolFilePath(mergedRecord) ?? prev.filePath,
|
|
2019
|
+
additions: diff.additions ?? prev.additions,
|
|
2020
|
+
deletions: diff.deletions ?? prev.deletions,
|
|
2021
|
+
parentId: event.parentId ?? prev.parentId
|
|
2022
|
+
},
|
|
2023
|
+
prev
|
|
2024
|
+
);
|
|
2025
|
+
return next;
|
|
2026
|
+
}
|
|
2027
|
+
return [
|
|
2028
|
+
...parts,
|
|
2029
|
+
withPartTimes({
|
|
2030
|
+
type: "tool",
|
|
2031
|
+
id: event.id,
|
|
2032
|
+
name: event.name,
|
|
2033
|
+
input,
|
|
2034
|
+
description: toolDescription(event.name, input),
|
|
2035
|
+
detail: toolDetail(event.name, input),
|
|
2036
|
+
status: "running",
|
|
2037
|
+
filePath: toolFilePath(input),
|
|
2038
|
+
...event.parentId ? { parentId: event.parentId } : {},
|
|
2039
|
+
...diff
|
|
2040
|
+
})
|
|
2041
|
+
];
|
|
1874
2042
|
}
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
2043
|
+
if (event.type === "tool_result") {
|
|
2044
|
+
const existing = parts.findIndex((p) => p.type === "tool" && p.id === event.id);
|
|
2045
|
+
const fromResult = parseDiffStat(event.content);
|
|
2046
|
+
if (event.partial) {
|
|
2047
|
+
if (existing < 0) {
|
|
2048
|
+
return [
|
|
2049
|
+
...parts,
|
|
2050
|
+
withPartTimes({
|
|
2051
|
+
type: "tool",
|
|
2052
|
+
id: event.id,
|
|
2053
|
+
name: "tool",
|
|
2054
|
+
description: "tool",
|
|
2055
|
+
status: event.isError ? "error" : "running",
|
|
2056
|
+
result: clipToolResultForStore(event.content),
|
|
2057
|
+
...event.parentId ? { parentId: event.parentId } : {}
|
|
2058
|
+
})
|
|
2059
|
+
];
|
|
2060
|
+
}
|
|
2061
|
+
return parts.map((p, i) => {
|
|
2062
|
+
if (i !== existing || p.type !== "tool") return p;
|
|
2063
|
+
if (p.status === "done" || p.status === "error") return p;
|
|
2064
|
+
return withPartTimes(
|
|
2065
|
+
{
|
|
2066
|
+
...p,
|
|
2067
|
+
result: clipToolResultForStore(event.content) ?? p.result
|
|
2068
|
+
},
|
|
2069
|
+
p
|
|
2070
|
+
);
|
|
2071
|
+
});
|
|
2072
|
+
}
|
|
2073
|
+
if (existing < 0) {
|
|
2074
|
+
return [
|
|
2075
|
+
...parts,
|
|
2076
|
+
withPartTimes({
|
|
2077
|
+
type: "tool",
|
|
2078
|
+
id: event.id,
|
|
2079
|
+
name: "tool",
|
|
2080
|
+
description: "tool",
|
|
2081
|
+
status: event.isError ? "error" : "done",
|
|
2082
|
+
result: clipToolResultForStore(event.content),
|
|
2083
|
+
...event.parentId ? { parentId: event.parentId } : {},
|
|
2084
|
+
...fromResult.additions != null ? { additions: fromResult.additions } : {},
|
|
2085
|
+
...fromResult.deletions != null ? { deletions: fromResult.deletions } : {}
|
|
2086
|
+
})
|
|
2087
|
+
];
|
|
1890
2088
|
}
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
2089
|
+
return parts.map((p, i) => {
|
|
2090
|
+
if (i !== existing || p.type !== "tool") return p;
|
|
2091
|
+
return withPartTimes(
|
|
2092
|
+
{
|
|
2093
|
+
...p,
|
|
2094
|
+
status: event.isError ? "error" : "done",
|
|
2095
|
+
result: clipToolResultForStore(event.content),
|
|
2096
|
+
...fromResult.additions != null ? { additions: fromResult.additions } : {},
|
|
2097
|
+
...fromResult.deletions != null ? { deletions: fromResult.deletions } : {}
|
|
2098
|
+
},
|
|
2099
|
+
p
|
|
1895
2100
|
);
|
|
1896
|
-
}
|
|
1897
|
-
}
|
|
1898
|
-
applyAgentRunnerHeapEnv(sideboard.env);
|
|
1899
|
-
servers.push(sideboard);
|
|
1900
|
-
}
|
|
1901
|
-
if (opts.includeBrightsy && isBrightsyConnected()) {
|
|
1902
|
-
const cmd = await resolveBrightsyMcpCommand();
|
|
1903
|
-
const teams = await ensureConnectedBrightsyTeamTokens();
|
|
1904
|
-
if (teams.length > 0) {
|
|
1905
|
-
const used = /* @__PURE__ */ new Set();
|
|
1906
|
-
for (const team of teams) {
|
|
1907
|
-
let name = brightsyMcpServerName(team.slug);
|
|
1908
|
-
if (used.has(name)) name = `${name}_${team.id.slice(0, 8)}`;
|
|
1909
|
-
used.add(name);
|
|
1910
|
-
servers.push(mcpLaunch(cmd, name, teamEnv(team)));
|
|
1911
|
-
}
|
|
1912
|
-
} else {
|
|
1913
|
-
servers.push(mcpLaunch(cmd, "brightsy"));
|
|
1914
|
-
}
|
|
1915
|
-
}
|
|
1916
|
-
return servers;
|
|
1917
|
-
}
|
|
1918
|
-
function cursorSafeMcpLaunch(command, args) {
|
|
1919
|
-
if (process.platform === "win32") {
|
|
1920
|
-
return args && args.length > 0 ? { command, args } : { command };
|
|
2101
|
+
});
|
|
1921
2102
|
}
|
|
1922
|
-
|
|
1923
|
-
const file = unwrapped?.file ?? command;
|
|
1924
|
-
const fileArgs = unwrapped?.args ?? args ?? [];
|
|
1925
|
-
return fileArgs.length > 0 ? { command: file, args: fileArgs } : { command: file };
|
|
2103
|
+
return parts;
|
|
1926
2104
|
}
|
|
1927
|
-
function
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
delete out.ELECTRON_RUN_AS_NODE;
|
|
1932
|
-
return Object.keys(out).length > 0 ? out : void 0;
|
|
2105
|
+
function partsToAssistantText(parts) {
|
|
2106
|
+
return parts.filter(
|
|
2107
|
+
(p) => p.type === "text" && !messagePartParentId(p)
|
|
2108
|
+
).map((p) => p.text).join("").trim();
|
|
1933
2109
|
}
|
|
1934
|
-
function
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
...env ? { env } : {}
|
|
1944
|
-
};
|
|
1945
|
-
}
|
|
1946
|
-
return out;
|
|
2110
|
+
function stripBrightsyNdjsonNoise(text) {
|
|
2111
|
+
if (!text || !text.includes('"type"')) return text;
|
|
2112
|
+
let out = text;
|
|
2113
|
+
out = out.replace(
|
|
2114
|
+
/\{"type":"(?:tool_use|tool_result|tool|thinking|usage|done|error)"[\s\S]*?\}\s*(?=\{"type":"|$|(?=[A-Za-z*#]))/g,
|
|
2115
|
+
""
|
|
2116
|
+
);
|
|
2117
|
+
out = out.replace(/\{"type":"(?:tool_use|tool_result|tool)"[\s\S]*$/g, "");
|
|
2118
|
+
return out.trim();
|
|
1947
2119
|
}
|
|
1948
|
-
function
|
|
1949
|
-
const
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
args.push("-c", `${prefix}.command=${JSON.stringify(s.command)}`);
|
|
1953
|
-
if (s.args?.length) {
|
|
1954
|
-
args.push("-c", `${prefix}.args=${JSON.stringify(s.args)}`);
|
|
1955
|
-
}
|
|
1956
|
-
const env = mcpSpawnEnv(s.env);
|
|
1957
|
-
if (env) {
|
|
1958
|
-
for (const [key, value] of Object.entries(env)) {
|
|
1959
|
-
args.push("-c", `${prefix}.env.${key}=${JSON.stringify(value)}`);
|
|
1960
|
-
}
|
|
1961
|
-
}
|
|
1962
|
-
args.push("-c", `${prefix}.default_tools_approval_mode=${JSON.stringify("approve")}`);
|
|
1963
|
-
args.push("-c", `${prefix}.tool_timeout_sec=300`);
|
|
1964
|
-
args.push("-c", `${prefix}.startup_timeout_sec=30`);
|
|
1965
|
-
}
|
|
1966
|
-
return args;
|
|
2120
|
+
function isBrightsyNdjsonLine(line) {
|
|
2121
|
+
const t = line.trim();
|
|
2122
|
+
if (!t.startsWith("{")) return false;
|
|
2123
|
+
return /"type"\s*:\s*"(tool_use|tool_result|tool|thinking|usage|done|error|text)"/.test(t);
|
|
1967
2124
|
}
|
|
1968
|
-
function
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
mcp[s.name] = {
|
|
1973
|
-
type: "local",
|
|
1974
|
-
command: [s.command, ...s.args ?? []],
|
|
1975
|
-
enabled: true,
|
|
1976
|
-
...env ? { environment: env } : {}
|
|
1977
|
-
};
|
|
1978
|
-
}
|
|
1979
|
-
for (const name of opts?.disableNames ?? []) {
|
|
1980
|
-
const key = name.trim();
|
|
1981
|
-
if (!key || mcp[key]?.enabled === true) continue;
|
|
1982
|
-
mcp[key] = { ...mcp[key], enabled: false };
|
|
1983
|
-
}
|
|
1984
|
-
return JSON.stringify({ mcp });
|
|
2125
|
+
function finalizeParts(parts) {
|
|
2126
|
+
return parts.map(
|
|
2127
|
+
(p) => p.type === "tool" && p.status === "running" ? { ...p, status: "done" } : p
|
|
2128
|
+
);
|
|
1985
2129
|
}
|
|
1986
|
-
function
|
|
1987
|
-
if (
|
|
1988
|
-
|
|
1989
|
-
for (const s of servers) {
|
|
1990
|
-
const env = mcpSpawnEnv(s.env);
|
|
1991
|
-
mcpServers[s.name] = {
|
|
1992
|
-
command: s.command,
|
|
1993
|
-
...s.args ? { args: s.args } : {},
|
|
1994
|
-
...env ? { env } : {}
|
|
1995
|
-
};
|
|
1996
|
-
}
|
|
1997
|
-
const dir = mkdtempSync(join4(tmpdir(), "sideboard-mcp-"));
|
|
1998
|
-
const cfgPath = join4(dir, "mcp.json");
|
|
1999
|
-
writeFileSync2(cfgPath, JSON.stringify({ mcpServers }, null, 2));
|
|
2000
|
-
return cfgPath;
|
|
2130
|
+
function normalizeParseResult(parsed) {
|
|
2131
|
+
if (!parsed) return [];
|
|
2132
|
+
return Array.isArray(parsed) ? parsed : [parsed];
|
|
2001
2133
|
}
|
|
2002
2134
|
|
|
2003
2135
|
// src/agents/types.ts
|
|
@@ -2061,24 +2193,15 @@ var BASE_ALLOWED_TOOLS = [
|
|
|
2061
2193
|
"Skill"
|
|
2062
2194
|
];
|
|
2063
2195
|
var CLAUDE_PRINT_BG_WAIT_CEILING_MS = 72e5;
|
|
2196
|
+
function isLocalDevAppDataDir(dir = process.env.SIDEBOARD_APP_DATA) {
|
|
2197
|
+
return /[/\\]\.sideboard[/\\]dev-app-data(?:[/\\]|$)/.test(dir ?? "");
|
|
2198
|
+
}
|
|
2064
2199
|
var CLAUDE_CHROME_ALLOWED_TOOLS = [
|
|
2065
2200
|
"mcp__claude-in-chrome",
|
|
2066
2201
|
"mcp__claude-in-chrome__*",
|
|
2067
2202
|
"Skill(claude-in-chrome)"
|
|
2068
2203
|
];
|
|
2069
2204
|
var CLAUDE_PROMPT_ARG_MAX = 2e5;
|
|
2070
|
-
var mcpListCache = null;
|
|
2071
|
-
async function loadMcpServers() {
|
|
2072
|
-
if (mcpListCache && Date.now() - mcpListCache.at < 3e4) {
|
|
2073
|
-
return mcpListCache.servers;
|
|
2074
|
-
}
|
|
2075
|
-
const claude = resolveClaudeExecutable();
|
|
2076
|
-
const mcpText = await run(claude, ["mcp", "list"], { reject: false });
|
|
2077
|
-
const servers = parseMcpList(`${mcpText.stdout}
|
|
2078
|
-
${mcpText.stderr}`);
|
|
2079
|
-
mcpListCache = { at: Date.now(), servers };
|
|
2080
|
-
return servers;
|
|
2081
|
-
}
|
|
2082
2205
|
function usageFromClaude(usage) {
|
|
2083
2206
|
if (!usage) return null;
|
|
2084
2207
|
const inputTokens = Number(usage.input_tokens ?? 0);
|
|
@@ -2365,7 +2488,7 @@ var claudeAdapter = {
|
|
|
2365
2488
|
async detect() {
|
|
2366
2489
|
const claude = resolveClaudeExecutable();
|
|
2367
2490
|
if (claude !== "claude") {
|
|
2368
|
-
if (!
|
|
2491
|
+
if (!existsSync8(claude)) {
|
|
2369
2492
|
return {
|
|
2370
2493
|
agent: "claude",
|
|
2371
2494
|
installed: false,
|
|
@@ -2414,7 +2537,7 @@ var claudeAdapter = {
|
|
|
2414
2537
|
);
|
|
2415
2538
|
}
|
|
2416
2539
|
const mode = permissionMode(thread);
|
|
2417
|
-
const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-
|
|
2540
|
+
const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-QPSJEXGR.js");
|
|
2418
2541
|
const isOrchestrator = isOrchestratorThread2(thread);
|
|
2419
2542
|
const injectedServers = await buildInjectedMcpServers({
|
|
2420
2543
|
includeSideboard: true,
|
|
@@ -2425,6 +2548,7 @@ var claudeAdapter = {
|
|
|
2425
2548
|
});
|
|
2426
2549
|
const injectedBrightsyNames = injectedServers.filter((s) => s.name === "brightsy" || s.name.startsWith("brightsy_")).map((s) => s.name);
|
|
2427
2550
|
const chromeOn = claudeChromeEnabled();
|
|
2551
|
+
const userMcpEntries = isOrchestrator ? {} : listUserClaudeMcpServerEntries();
|
|
2428
2552
|
let allowedTools;
|
|
2429
2553
|
if (isOrchestrator) {
|
|
2430
2554
|
allowedTools = [
|
|
@@ -2433,10 +2557,9 @@ var claudeAdapter = {
|
|
|
2433
2557
|
...brightsyMcpAllowedTools(injectedBrightsyNames)
|
|
2434
2558
|
];
|
|
2435
2559
|
} else {
|
|
2436
|
-
const servers = await loadMcpServers();
|
|
2437
2560
|
allowedTools = [
|
|
2438
2561
|
...BASE_ALLOWED_TOOLS,
|
|
2439
|
-
...
|
|
2562
|
+
...mcpAllowToolsFromNames(Object.keys(userMcpEntries)),
|
|
2440
2563
|
...sideboardWorktreeAllowedTools({
|
|
2441
2564
|
github: true,
|
|
2442
2565
|
linear: isLinearConnected(),
|
|
@@ -2461,12 +2584,10 @@ var claudeAdapter = {
|
|
|
2461
2584
|
if (systemPrompt) {
|
|
2462
2585
|
args.push("--append-system-prompt", systemPrompt);
|
|
2463
2586
|
}
|
|
2464
|
-
const mcpConfigPath = writeMcpServersConfig(injectedServers);
|
|
2587
|
+
const mcpConfigPath = writeMcpServersConfig(injectedServers, userMcpEntries);
|
|
2465
2588
|
if (mcpConfigPath) {
|
|
2466
2589
|
args.push("--mcp-config", mcpConfigPath);
|
|
2467
|
-
|
|
2468
|
-
args.push("--strict-mcp-config");
|
|
2469
|
-
}
|
|
2590
|
+
args.push("--strict-mcp-config");
|
|
2470
2591
|
}
|
|
2471
2592
|
if (chromeOn) {
|
|
2472
2593
|
args.push("--chrome");
|
|
@@ -2498,8 +2619,10 @@ var claudeAdapter = {
|
|
|
2498
2619
|
CLAUDE_CODE_FORWARD_SUBAGENT_TEXT: "1",
|
|
2499
2620
|
CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS: process.env.CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS ?? String(CLAUDE_PRINT_BG_WAIT_CEILING_MS),
|
|
2500
2621
|
// `--strict-mcp-config` still fetches claude.ai connectors on some CLI
|
|
2501
|
-
// builds (anthropics/claude-code#60252). Coordinators
|
|
2502
|
-
|
|
2622
|
+
// builds (anthropics/claude-code#60252). Coordinators never need them.
|
|
2623
|
+
// Local `pnpm dev` also disables them: those HTTP connectors hang the
|
|
2624
|
+
// first worktree turn when Electron's cwd is this Sideboard repo.
|
|
2625
|
+
...isOrchestrator || isLocalDevAppDataDir() ? { ENABLE_CLAUDEAI_MCP_SERVERS: "false" } : {}
|
|
2503
2626
|
}
|
|
2504
2627
|
};
|
|
2505
2628
|
},
|
|
@@ -2650,115 +2773,6 @@ function parseIssuesJson(raw) {
|
|
|
2650
2773
|
import { existsSync as existsSync9, readFileSync as readFileSync4, statSync as statSync2 } from "fs";
|
|
2651
2774
|
import { homedir as homedir4 } from "os";
|
|
2652
2775
|
import { join as join7 } from "path";
|
|
2653
|
-
|
|
2654
|
-
// src/agents/orch-mcp-isolation.ts
|
|
2655
|
-
import { existsSync as existsSync8, readFileSync as readFileSync3 } from "fs";
|
|
2656
|
-
import { homedir as homedir3 } from "os";
|
|
2657
|
-
import { join as join6 } from "path";
|
|
2658
|
-
import { parse as parseToml } from "smol-toml";
|
|
2659
|
-
|
|
2660
|
-
// src/agents/user-mcp-config.ts
|
|
2661
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
2662
|
-
import { homedir as homedir2 } from "os";
|
|
2663
|
-
import { dirname as dirname3, join as join5 } from "path";
|
|
2664
|
-
|
|
2665
|
-
// src/agents/orch-mcp-isolation.ts
|
|
2666
|
-
function isInjectedOrchMcpName(name) {
|
|
2667
|
-
const n = name.trim().toLowerCase();
|
|
2668
|
-
return n === "sideboard" || n === "brightsy" || n.startsWith("brightsy_");
|
|
2669
|
-
}
|
|
2670
|
-
function asObject(value) {
|
|
2671
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
2672
|
-
return value;
|
|
2673
|
-
}
|
|
2674
|
-
function listMcpNamesFromJsonMap(raw, key) {
|
|
2675
|
-
return Object.keys(asObject(asObject(raw)[key])).filter((n) => n.trim());
|
|
2676
|
-
}
|
|
2677
|
-
function listMcpNamesFromCodexToml(text) {
|
|
2678
|
-
try {
|
|
2679
|
-
const parsed = parseToml(text);
|
|
2680
|
-
return Object.keys(asObject(parsed.mcp_servers)).filter((n) => n.trim());
|
|
2681
|
-
} catch {
|
|
2682
|
-
return [];
|
|
2683
|
-
}
|
|
2684
|
-
}
|
|
2685
|
-
function readJsonObject(path) {
|
|
2686
|
-
try {
|
|
2687
|
-
return JSON.parse(readFileSync3(path, "utf8"));
|
|
2688
|
-
} catch {
|
|
2689
|
-
return {};
|
|
2690
|
-
}
|
|
2691
|
-
}
|
|
2692
|
-
function readText(path) {
|
|
2693
|
-
try {
|
|
2694
|
-
return readFileSync3(path, "utf8");
|
|
2695
|
-
} catch {
|
|
2696
|
-
return "";
|
|
2697
|
-
}
|
|
2698
|
-
}
|
|
2699
|
-
function userCodexConfigPaths(home = homedir3()) {
|
|
2700
|
-
return [join6(home, ".codex", "config.toml"), join6(home, ".config", "codex", "config.toml")];
|
|
2701
|
-
}
|
|
2702
|
-
function userOpencodeConfigPaths(home = homedir3()) {
|
|
2703
|
-
return [
|
|
2704
|
-
join6(home, ".config", "opencode", "opencode.json"),
|
|
2705
|
-
join6(home, ".config", "opencode", "opencode.jsonc")
|
|
2706
|
-
];
|
|
2707
|
-
}
|
|
2708
|
-
function userMcpNamesToDisable(opts) {
|
|
2709
|
-
const keep = new Set(
|
|
2710
|
-
[...opts.injectedNames ?? []].map((n) => n.trim().toLowerCase()).filter(Boolean)
|
|
2711
|
-
);
|
|
2712
|
-
const out = [];
|
|
2713
|
-
const seen = /* @__PURE__ */ new Set();
|
|
2714
|
-
for (const raw of opts.names) {
|
|
2715
|
-
const name = raw.trim();
|
|
2716
|
-
if (!name) continue;
|
|
2717
|
-
const key = name.toLowerCase();
|
|
2718
|
-
if (seen.has(key) || keep.has(key) || isInjectedOrchMcpName(name)) continue;
|
|
2719
|
-
seen.add(key);
|
|
2720
|
-
out.push(name);
|
|
2721
|
-
}
|
|
2722
|
-
return out;
|
|
2723
|
-
}
|
|
2724
|
-
function listUserCodexMcpNames(home = homedir3()) {
|
|
2725
|
-
const names = [];
|
|
2726
|
-
for (const path of userCodexConfigPaths(home)) {
|
|
2727
|
-
if (!existsSync8(path)) continue;
|
|
2728
|
-
names.push(...listMcpNamesFromCodexToml(readText(path)));
|
|
2729
|
-
}
|
|
2730
|
-
return names;
|
|
2731
|
-
}
|
|
2732
|
-
function listUserOpencodeMcpNames(home = homedir3()) {
|
|
2733
|
-
const names = [];
|
|
2734
|
-
for (const path of userOpencodeConfigPaths(home)) {
|
|
2735
|
-
if (!existsSync8(path)) continue;
|
|
2736
|
-
names.push(...listMcpNamesFromJsonMap(readJsonObject(path), "mcp"));
|
|
2737
|
-
}
|
|
2738
|
-
return names;
|
|
2739
|
-
}
|
|
2740
|
-
function toCodexDisableUserMcpArgs(names) {
|
|
2741
|
-
const args = [];
|
|
2742
|
-
for (const name of names) {
|
|
2743
|
-
if (!/^[A-Za-z0-9_-]+$/.test(name)) continue;
|
|
2744
|
-
args.push("-c", `mcp_servers.${name}.enabled=false`);
|
|
2745
|
-
}
|
|
2746
|
-
return args;
|
|
2747
|
-
}
|
|
2748
|
-
function toCodexUnattendedAppsArgs() {
|
|
2749
|
-
return [
|
|
2750
|
-
"-c",
|
|
2751
|
-
"features.apps=false",
|
|
2752
|
-
"-c",
|
|
2753
|
-
"apps._default.enabled=false",
|
|
2754
|
-
"-c",
|
|
2755
|
-
"apps.posthog.enabled=false",
|
|
2756
|
-
"-c",
|
|
2757
|
-
"features.plugins=false"
|
|
2758
|
-
];
|
|
2759
|
-
}
|
|
2760
|
-
|
|
2761
|
-
// src/agents/codex.ts
|
|
2762
2776
|
var CODEX_PROMPT_ARG_MAX = 2e5;
|
|
2763
2777
|
var FALLBACK_CODEX_MODELS = [
|
|
2764
2778
|
{ id: "gpt-5.6-sol", displayName: "GPT-5.6 Sol" },
|
|
@@ -4755,6 +4769,9 @@ export {
|
|
|
4755
4769
|
adjustBrightsyTurnExit,
|
|
4756
4770
|
listBrightsyChatTargets,
|
|
4757
4771
|
brightsyAdapter,
|
|
4772
|
+
sideboardMcpProfile,
|
|
4773
|
+
packagedMcpDir,
|
|
4774
|
+
applyAgentRunnerHeapEnv,
|
|
4758
4775
|
toolDescription,
|
|
4759
4776
|
isInternalAgentStatusText,
|
|
4760
4777
|
isPollWrapperToolName,
|
|
@@ -4766,9 +4783,6 @@ export {
|
|
|
4766
4783
|
isBrightsyNdjsonLine,
|
|
4767
4784
|
finalizeParts,
|
|
4768
4785
|
normalizeParseResult,
|
|
4769
|
-
sideboardMcpProfile,
|
|
4770
|
-
packagedMcpDir,
|
|
4771
|
-
applyAgentRunnerHeapEnv,
|
|
4772
4786
|
PLAN_MODE_INSTRUCTION,
|
|
4773
4787
|
permissionMode,
|
|
4774
4788
|
mcpStatusThinkingFromClaudeInit,
|