@sideboard-ai/core 0.1.62 → 0.1.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agents-KF3J3C53.js → agents-OTBZVTZO.js} +27 -7
- package/dist/{agents-QLSFIQAO.js → agents-TS3EI2YI.js} +27 -7
- package/dist/{app-settings-LTSFG7QJ.js → app-settings-GJVZGU3M.js} +13 -3
- package/dist/{app-settings-HK4KAM4R.js → app-settings-ONKMFSEJ.js} +13 -3
- package/dist/{chunk-UGXSSBFJ.js → chunk-4BUCGNZS.js} +1 -1
- package/dist/chunk-4UIYN56C.js +173 -0
- package/dist/{chunk-NVU7EC2E.js → chunk-57WWNMFP.js} +2 -2
- package/dist/{chunk-A6FOKNOU.js → chunk-5HTTCYWA.js} +2 -2
- package/dist/{chunk-DXTGDXO2.js → chunk-7ZOQY4A7.js} +31 -6
- package/dist/{chunk-ZF5YJCXO.js → chunk-B4PRRKMA.js} +284 -93
- package/dist/{chunk-DDN3UF4R.js → chunk-BPOTVI5J.js} +115 -3
- package/dist/{chunk-MBAL5FE6.js → chunk-DB3I75FI.js} +4 -4
- package/dist/chunk-FGDJOJ2L.js +176 -0
- package/dist/{chunk-2FEA4LDA.js → chunk-JWZNK3CQ.js} +31 -6
- package/dist/{chunk-2MCNURQV.js → chunk-K7LM4CLD.js} +279 -93
- package/dist/{chunk-3KKNTHUC.js → chunk-LW5CMQGZ.js} +1 -1
- package/dist/{chunk-JB2H7E7V.js → chunk-M5V4QIWF.js} +1 -1
- package/dist/{chunk-6CUJQKTJ.js → chunk-MHR4OGZ4.js} +115 -3
- package/dist/{chunk-46KMKHSD.js → chunk-WAFIF22N.js} +2 -2
- package/dist/{chunk-27MAWNKY.js → chunk-ZRFAZVGL.js} +2 -2
- package/dist/{connected-teams-MKIYKOYA.js → connected-teams-OMDHTL6A.js} +2 -2
- package/dist/{connected-teams-RSL4VB3X.js → connected-teams-RUNMOCG5.js} +2 -2
- package/dist/{coordinator-prompt-N2R6FGZK.js → coordinator-prompt-3BSMKZL4.js} +4 -4
- package/dist/{coordinator-prompt-LKG3SHMI.js → coordinator-prompt-6HMTOX4G.js} +4 -4
- package/dist/{global-workspace-LALWQWRJ.js → global-workspace-QS7A23CB.js} +5 -6
- package/dist/{global-workspace-YOAUQCMA.js → global-workspace-YZ2NJVLL.js} +5 -6
- package/dist/index.cjs +1345 -933
- package/dist/index.d.cts +96 -1
- package/dist/index.d.ts +96 -1
- package/dist/index.js +750 -715
- package/dist/mcp/run-stdio.cjs +1293 -977
- package/dist/mcp/run-stdio.js +691 -748
- package/dist/{run-GPSVV5OH.js → run-JLD2Y52J.js} +1 -1
- package/dist/{run-HZTBWGQR.js → run-Y2MI3EVV.js} +1 -1
- package/dist/{workspaces-E75POJXP.js → workspaces-AIUYUXB7.js} +6 -7
- package/dist/{workspaces-VCAIHVIE.js → workspaces-EBFW7I7S.js} +6 -7
- package/dist/{worktree-MV4WRW6G.js → worktree-7NBPIVFZ.js} +2 -2
- package/dist/{worktree-LZEGVQSN.js → worktree-WMDJW2BL.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-73AT5K4A.js +0 -104
- package/dist/chunk-GI7E5733.js +0 -30
- package/dist/chunk-RIWUU7FO.js +0 -107
- package/dist/chunk-S2LL5HA4.js +0 -33
|
@@ -6,20 +6,30 @@ import {
|
|
|
6
6
|
ensureCliTeamTracked,
|
|
7
7
|
ensureConnectedBrightsyTeamTokens,
|
|
8
8
|
loadBrightsyConfig
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-M5V4QIWF.js";
|
|
10
10
|
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
isOrchestratorThread
|
|
12
|
+
} from "./chunk-JWZNK3CQ.js";
|
|
13
|
+
import {
|
|
14
|
+
enrichPathWithNpmGlobalBin,
|
|
15
|
+
isConductorBundledCli,
|
|
16
|
+
resolveCommandBinarySync,
|
|
17
|
+
run,
|
|
18
|
+
withExportedPath
|
|
19
|
+
} from "./chunk-FGDJOJ2L.js";
|
|
14
20
|
import {
|
|
15
21
|
claudeChromeEnabled,
|
|
16
22
|
loadAppSettings,
|
|
23
|
+
resolveAgentExecutable,
|
|
17
24
|
resolveClaudeExecutable
|
|
18
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-BPOTVI5J.js";
|
|
19
26
|
import {
|
|
20
27
|
appDataDir
|
|
21
28
|
} from "./chunk-7MV3RXSC.js";
|
|
22
29
|
|
|
30
|
+
// src/agents/brightsy.ts
|
|
31
|
+
import { existsSync } from "fs";
|
|
32
|
+
|
|
23
33
|
// src/agents/brightsy-targets.ts
|
|
24
34
|
function encodeBrightsyTarget(type, id, accountId) {
|
|
25
35
|
if (accountId) return `team:${accountId}:${type}:${id}`;
|
|
@@ -176,6 +186,11 @@ function normalizeTurnInput(input) {
|
|
|
176
186
|
if (typeof input === "string") return { prompt: input };
|
|
177
187
|
return { prompt: input.prompt, cachedPrefix: input.cachedPrefix?.trim() || void 0 };
|
|
178
188
|
}
|
|
189
|
+
function dropCachedPrefixOnResume(input, sessionId) {
|
|
190
|
+
const turn = normalizeTurnInput(input);
|
|
191
|
+
if (sessionId) return { prompt: turn.prompt };
|
|
192
|
+
return turn;
|
|
193
|
+
}
|
|
179
194
|
function flattenTurnInput(input) {
|
|
180
195
|
const { cachedPrefix, prompt } = normalizeTurnInput(input);
|
|
181
196
|
if (!cachedPrefix) return prompt;
|
|
@@ -315,9 +330,13 @@ async function fetchTeamChatTargets(team) {
|
|
|
315
330
|
};
|
|
316
331
|
}
|
|
317
332
|
async function listBrightsyChatTargetsViaCli() {
|
|
318
|
-
const listed = await run(
|
|
319
|
-
|
|
320
|
-
|
|
333
|
+
const listed = await run(
|
|
334
|
+
resolveAgentExecutable("brightsy"),
|
|
335
|
+
["chat", "--list-targets", "--json"],
|
|
336
|
+
{
|
|
337
|
+
reject: false
|
|
338
|
+
}
|
|
339
|
+
);
|
|
321
340
|
if (listed.exitCode !== 0 || !listed.stdout.trim()) {
|
|
322
341
|
throw new Error(
|
|
323
342
|
listed.stderr.trim() || "Failed to list Brightsy chat targets \u2014 is `brightsy` installed and logged in?"
|
|
@@ -404,18 +423,32 @@ async function syncCliForTarget(accountId) {
|
|
|
404
423
|
var brightsyAdapter = {
|
|
405
424
|
kind: "brightsy",
|
|
406
425
|
async detect() {
|
|
407
|
-
const
|
|
408
|
-
if (
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
426
|
+
const brightsy = resolveAgentExecutable("brightsy");
|
|
427
|
+
if (brightsy !== "brightsy") {
|
|
428
|
+
if (!existsSync(brightsy)) {
|
|
429
|
+
return {
|
|
430
|
+
agent: "brightsy",
|
|
431
|
+
installed: false,
|
|
432
|
+
authenticated: false,
|
|
433
|
+
linearMcp: false,
|
|
434
|
+
warnings: [],
|
|
435
|
+
reason: `Brightsy executable not found: ${brightsy}`
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
} else {
|
|
439
|
+
const which = await run("which", ["brightsy"], { reject: false });
|
|
440
|
+
if (which.exitCode !== 0) {
|
|
441
|
+
return {
|
|
442
|
+
agent: "brightsy",
|
|
443
|
+
installed: false,
|
|
444
|
+
authenticated: false,
|
|
445
|
+
linearMcp: false,
|
|
446
|
+
warnings: [],
|
|
447
|
+
reason: "brightsy CLI not found on PATH \u2014 npm i -g @brightsy/cli"
|
|
448
|
+
};
|
|
449
|
+
}
|
|
417
450
|
}
|
|
418
|
-
const who = await run(
|
|
451
|
+
const who = await run(brightsy, ["whoami"], { reject: false });
|
|
419
452
|
const authenticated = who.exitCode === 0 && /logged in as/i.test(who.stdout);
|
|
420
453
|
return {
|
|
421
454
|
agent: "brightsy",
|
|
@@ -440,7 +473,7 @@ var brightsyAdapter = {
|
|
|
440
473
|
target.id
|
|
441
474
|
];
|
|
442
475
|
return {
|
|
443
|
-
file: "brightsy",
|
|
476
|
+
file: resolveAgentExecutable("brightsy"),
|
|
444
477
|
args,
|
|
445
478
|
cwd: thread.worktreePath,
|
|
446
479
|
// Piped stdin becomes the message body (avoids ARG_MAX for long seeds).
|
|
@@ -457,12 +490,16 @@ var brightsyAdapter = {
|
|
|
457
490
|
const target = decodeBrightsyTarget(thread.model);
|
|
458
491
|
await syncCliForTarget(target.accountId);
|
|
459
492
|
const args = target.type === "model" ? ["chat", "--model", target.id] : ["chat", "--agent", target.id];
|
|
460
|
-
return {
|
|
493
|
+
return {
|
|
494
|
+
file: resolveAgentExecutable("brightsy"),
|
|
495
|
+
args,
|
|
496
|
+
cwd: thread.worktreePath
|
|
497
|
+
};
|
|
461
498
|
}
|
|
462
499
|
};
|
|
463
500
|
|
|
464
501
|
// src/agents/claude.ts
|
|
465
|
-
import { existsSync as
|
|
502
|
+
import { existsSync as existsSync3 } from "fs";
|
|
466
503
|
|
|
467
504
|
// src/agents/claude-mcp.ts
|
|
468
505
|
function parseMcpList(text) {
|
|
@@ -499,12 +536,18 @@ function mcpAllowTools(servers) {
|
|
|
499
536
|
}
|
|
500
537
|
|
|
501
538
|
// src/agents/injected-mcp.ts
|
|
502
|
-
import { existsSync, mkdtempSync, writeFileSync } from "fs";
|
|
539
|
+
import { existsSync as existsSync2, mkdtempSync, writeFileSync } from "fs";
|
|
503
540
|
import { createRequire } from "module";
|
|
504
541
|
import { tmpdir } from "os";
|
|
505
542
|
import { dirname, join } from "path";
|
|
506
543
|
import { fileURLToPath } from "url";
|
|
507
544
|
|
|
545
|
+
// src/mcp/profile.ts
|
|
546
|
+
var SIDEBOARD_MCP_PROFILE_ENV = "SIDEBOARD_MCP_PROFILE";
|
|
547
|
+
function sideboardMcpProfile(env = process.env) {
|
|
548
|
+
return env[SIDEBOARD_MCP_PROFILE_ENV]?.trim().toLowerCase() === "worktree" ? "worktree" : "orchestration";
|
|
549
|
+
}
|
|
550
|
+
|
|
508
551
|
// src/agents/node-launch.ts
|
|
509
552
|
function isAsarPath(filePath) {
|
|
510
553
|
return /\.asar([/\\]|$)/.test(filePath);
|
|
@@ -558,6 +601,39 @@ function isBrightsyConnected() {
|
|
|
558
601
|
return false;
|
|
559
602
|
}
|
|
560
603
|
}
|
|
604
|
+
var BRIGHTSY_WORD = /(?<![a-z0-9_-])brightsy(?![a-z0-9_-])/i;
|
|
605
|
+
function promptMentionsBrightsy(text) {
|
|
606
|
+
return BRIGHTSY_WORD.test(text ?? "");
|
|
607
|
+
}
|
|
608
|
+
function isBrightsyMcpToolName(name) {
|
|
609
|
+
const n = name.toLowerCase();
|
|
610
|
+
return n === "brightsy" || n.startsWith("mcp__brightsy") || n.startsWith("brightsy_");
|
|
611
|
+
}
|
|
612
|
+
function toolInputUsesBrightsyDatasource(input) {
|
|
613
|
+
const ds = input?.datasource;
|
|
614
|
+
return typeof ds === "string" && ds.toLowerCase() === "brightsy";
|
|
615
|
+
}
|
|
616
|
+
function messageUsedBrightsyMcp(msg) {
|
|
617
|
+
if (msg.role === "user" && promptMentionsBrightsy(msg.text)) return true;
|
|
618
|
+
for (const part of msg.parts ?? []) {
|
|
619
|
+
if (part.type !== "tool") continue;
|
|
620
|
+
if (isBrightsyMcpToolName(part.name)) return true;
|
|
621
|
+
if (/present_(schema|files)$/i.test(part.name) && toolInputUsesBrightsyDatasource(part.input)) {
|
|
622
|
+
return true;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
return false;
|
|
626
|
+
}
|
|
627
|
+
function threadRequestsBrightsyMcp(thread) {
|
|
628
|
+
return (thread?.messages ?? []).some(messageUsedBrightsyMcp);
|
|
629
|
+
}
|
|
630
|
+
function shouldInjectBrightsyMcp(thread, opts) {
|
|
631
|
+
if (!(opts?.connected ?? isBrightsyConnected())) return false;
|
|
632
|
+
if (opts?.orchestrator) return true;
|
|
633
|
+
const alwaysOn = opts?.alwaysOnWorktree ?? Boolean(loadAppSettings().brightsy?.injectWorktreeMcp);
|
|
634
|
+
if (alwaysOn) return true;
|
|
635
|
+
return threadRequestsBrightsyMcp(thread);
|
|
636
|
+
}
|
|
561
637
|
function mcpLaunch(cmd, name, env) {
|
|
562
638
|
if (cmd === "brightsy-mcp") {
|
|
563
639
|
return { name, command: "brightsy-mcp", ...env ? { env } : {} };
|
|
@@ -603,7 +679,7 @@ function corePackageDir() {
|
|
|
603
679
|
}
|
|
604
680
|
function findSideboardMcpJsEntry() {
|
|
605
681
|
const override = process.env.SIDEBOARD_MCP_ENTRY?.trim() || process.env.SIDEBOARD_CLI?.trim();
|
|
606
|
-
if (override &&
|
|
682
|
+
if (override && existsSync2(override)) return override;
|
|
607
683
|
let dir = corePackageDir();
|
|
608
684
|
for (let i = 0; i < 10; i++) {
|
|
609
685
|
const candidates = [
|
|
@@ -616,7 +692,7 @@ function findSideboardMcpJsEntry() {
|
|
|
616
692
|
join(dir, "cli/dist/index.js")
|
|
617
693
|
];
|
|
618
694
|
for (const p of candidates) {
|
|
619
|
-
if (
|
|
695
|
+
if (existsSync2(p)) return p;
|
|
620
696
|
}
|
|
621
697
|
const parent = dirname(dir);
|
|
622
698
|
if (parent === dir) break;
|
|
@@ -647,11 +723,13 @@ async function buildInjectedMcpServers(opts) {
|
|
|
647
723
|
const servers = [];
|
|
648
724
|
if (opts.includeSideboard) {
|
|
649
725
|
const sideboard = await resolveSideboardMcpServer();
|
|
726
|
+
const orchId = opts.orchestratorThreadId?.trim();
|
|
727
|
+
const profile = orchId ? "orchestration" : "worktree";
|
|
650
728
|
sideboard.env = {
|
|
651
729
|
...sideboard.env ?? {},
|
|
652
|
-
SIDEBOARD_APP_DATA: appDataDir()
|
|
730
|
+
SIDEBOARD_APP_DATA: appDataDir(),
|
|
731
|
+
[SIDEBOARD_MCP_PROFILE_ENV]: profile
|
|
653
732
|
};
|
|
654
|
-
const orchId = opts.orchestratorThreadId?.trim();
|
|
655
733
|
if (orchId) {
|
|
656
734
|
sideboard.env.SIDEBOARD_ORCHESTRATOR_THREAD_ID = orchId;
|
|
657
735
|
}
|
|
@@ -873,7 +951,7 @@ var claudeAdapter = {
|
|
|
873
951
|
async detect() {
|
|
874
952
|
const claude = resolveClaudeExecutable();
|
|
875
953
|
if (claude !== "claude") {
|
|
876
|
-
if (!
|
|
954
|
+
if (!existsSync3(claude)) {
|
|
877
955
|
return {
|
|
878
956
|
agent: "claude",
|
|
879
957
|
installed: false,
|
|
@@ -912,9 +990,8 @@ var claudeAdapter = {
|
|
|
912
990
|
},
|
|
913
991
|
async buildTurn(thread, input) {
|
|
914
992
|
const claude = resolveClaudeExecutable();
|
|
915
|
-
const turn = normalizeTurnInput(input);
|
|
916
993
|
const sessionId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
|
|
917
|
-
const effective = sessionId
|
|
994
|
+
const effective = dropCachedPrefixOnResume(input, sessionId);
|
|
918
995
|
const promptText = flattenTurnInput(effective);
|
|
919
996
|
const useStdin = promptText.length > CLAUDE_PROMPT_ARG_MAX;
|
|
920
997
|
if (process.env.SIDEBOARD_DEBUG_CLAUDE_TURN === "1") {
|
|
@@ -923,11 +1000,13 @@ var claudeAdapter = {
|
|
|
923
1000
|
);
|
|
924
1001
|
}
|
|
925
1002
|
const mode = permissionMode(thread);
|
|
926
|
-
const { isOrchestratorThread } = await import("./global-workspace-
|
|
927
|
-
const isOrchestrator =
|
|
1003
|
+
const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-YZ2NJVLL.js");
|
|
1004
|
+
const isOrchestrator = isOrchestratorThread2(thread);
|
|
928
1005
|
const injectedServers = await buildInjectedMcpServers({
|
|
929
1006
|
includeSideboard: true,
|
|
930
|
-
includeBrightsy:
|
|
1007
|
+
includeBrightsy: shouldInjectBrightsyMcp(thread, {
|
|
1008
|
+
orchestrator: isOrchestrator
|
|
1009
|
+
}),
|
|
931
1010
|
orchestratorThreadId: isOrchestrator ? thread.id : null
|
|
932
1011
|
});
|
|
933
1012
|
const injectedBrightsyNames = injectedServers.filter((s) => s.name === "brightsy" || s.name.startsWith("brightsy_")).map((s) => s.name);
|
|
@@ -1119,7 +1198,7 @@ function parseIssuesJson(raw) {
|
|
|
1119
1198
|
}
|
|
1120
1199
|
|
|
1121
1200
|
// src/agents/codex.ts
|
|
1122
|
-
import { existsSync as
|
|
1201
|
+
import { existsSync as existsSync4, readFileSync, statSync } from "fs";
|
|
1123
1202
|
import { homedir } from "os";
|
|
1124
1203
|
import { join as join2 } from "path";
|
|
1125
1204
|
var CODEX_PROMPT_ARG_MAX = 2e5;
|
|
@@ -1137,9 +1216,14 @@ async function listCodexModels() {
|
|
|
1137
1216
|
if (cachedCodexModels && now - cachedCodexModels.at < CODEX_MODEL_CACHE_MS) {
|
|
1138
1217
|
return cachedCodexModels.models;
|
|
1139
1218
|
}
|
|
1140
|
-
const
|
|
1141
|
-
if (
|
|
1142
|
-
|
|
1219
|
+
const codex = resolveAgentExecutable("codex");
|
|
1220
|
+
if (codex === "codex") {
|
|
1221
|
+
const which = await run("which", ["codex"], { reject: false });
|
|
1222
|
+
if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
|
|
1223
|
+
} else if (!existsSync4(codex)) {
|
|
1224
|
+
return FALLBACK_CODEX_MODELS;
|
|
1225
|
+
}
|
|
1226
|
+
const listed = await run(codex, ["debug", "models"], { reject: false });
|
|
1143
1227
|
if (listed.exitCode !== 0 || !listed.stdout.trim()) {
|
|
1144
1228
|
return cachedCodexModels?.models ?? FALLBACK_CODEX_MODELS;
|
|
1145
1229
|
}
|
|
@@ -1178,7 +1262,7 @@ function codexConfigHasNetworkAccess() {
|
|
|
1178
1262
|
join2(homedir(), ".config", "codex", "config.toml")
|
|
1179
1263
|
];
|
|
1180
1264
|
for (const path of candidates) {
|
|
1181
|
-
if (!
|
|
1265
|
+
if (!existsSync4(path)) continue;
|
|
1182
1266
|
const text = readFileSync(path, "utf8");
|
|
1183
1267
|
if (/network_access\s*=\s*true/.test(text)) return true;
|
|
1184
1268
|
}
|
|
@@ -1212,7 +1296,7 @@ function asRecord(value) {
|
|
|
1212
1296
|
}
|
|
1213
1297
|
function codexLooksAuthenticated() {
|
|
1214
1298
|
const authPath = join2(homedir(), ".codex", "auth.json");
|
|
1215
|
-
if (!
|
|
1299
|
+
if (!existsSync4(authPath)) return false;
|
|
1216
1300
|
try {
|
|
1217
1301
|
return statSync(authPath).size > 2;
|
|
1218
1302
|
} catch {
|
|
@@ -1222,16 +1306,30 @@ function codexLooksAuthenticated() {
|
|
|
1222
1306
|
var codexAdapter = {
|
|
1223
1307
|
kind: "codex",
|
|
1224
1308
|
async detect() {
|
|
1225
|
-
const
|
|
1226
|
-
if (
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1309
|
+
const codex = resolveAgentExecutable("codex");
|
|
1310
|
+
if (codex !== "codex") {
|
|
1311
|
+
if (!existsSync4(codex)) {
|
|
1312
|
+
return {
|
|
1313
|
+
agent: "codex",
|
|
1314
|
+
installed: false,
|
|
1315
|
+
authenticated: false,
|
|
1316
|
+
linearMcp: false,
|
|
1317
|
+
warnings: [],
|
|
1318
|
+
reason: `Codex executable not found: ${codex}`
|
|
1319
|
+
};
|
|
1320
|
+
}
|
|
1321
|
+
} else {
|
|
1322
|
+
const which = await run("which", ["codex"], { reject: false, timeoutMs: 3e3 });
|
|
1323
|
+
if (which.exitCode !== 0) {
|
|
1324
|
+
return {
|
|
1325
|
+
agent: "codex",
|
|
1326
|
+
installed: false,
|
|
1327
|
+
authenticated: false,
|
|
1328
|
+
linearMcp: false,
|
|
1329
|
+
warnings: [],
|
|
1330
|
+
reason: "codex CLI not found on PATH"
|
|
1331
|
+
};
|
|
1332
|
+
}
|
|
1235
1333
|
}
|
|
1236
1334
|
const authenticated = codexLooksAuthenticated();
|
|
1237
1335
|
const linearMcp = false;
|
|
@@ -1251,22 +1349,24 @@ var codexAdapter = {
|
|
|
1251
1349
|
};
|
|
1252
1350
|
},
|
|
1253
1351
|
async buildTurn(thread, input) {
|
|
1254
|
-
const prompt = flattenTurnInput(input);
|
|
1255
1352
|
const sessionId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
|
|
1353
|
+
const prompt = flattenTurnInput(dropCachedPrefixOnResume(input, sessionId));
|
|
1256
1354
|
const useStdin = prompt.length > CODEX_PROMPT_ARG_MAX;
|
|
1257
1355
|
const promptArg = useStdin ? "-" : prompt;
|
|
1258
1356
|
if (process.env.SIDEBOARD_DEBUG_CODEX_TURN === "1") {
|
|
1259
|
-
const { cachedPrefix } = normalizeTurnInput(input);
|
|
1260
1357
|
console.error(
|
|
1261
|
-
`[sideboard/codex] promptChars=${prompt.length} resumed=${Boolean(sessionId)} stdin=${useStdin} hasPrefix=${
|
|
1358
|
+
`[sideboard/codex] promptChars=${prompt.length} resumed=${Boolean(sessionId)} stdin=${useStdin} hasPrefix=${prompt.includes("Current request:")}`
|
|
1262
1359
|
);
|
|
1263
1360
|
}
|
|
1264
1361
|
const mode = permissionMode(thread);
|
|
1265
1362
|
const model = thread.model?.trim();
|
|
1363
|
+
const isOrchestrator = isOrchestratorThread(thread);
|
|
1266
1364
|
const injected = await buildInjectedMcpServers({
|
|
1267
1365
|
includeSideboard: true,
|
|
1268
|
-
includeBrightsy:
|
|
1269
|
-
|
|
1366
|
+
includeBrightsy: shouldInjectBrightsyMcp(thread, {
|
|
1367
|
+
orchestrator: isOrchestrator
|
|
1368
|
+
}),
|
|
1369
|
+
orchestratorThreadId: isOrchestrator ? thread.id : null
|
|
1270
1370
|
});
|
|
1271
1371
|
const mcpOverrides = toCodexMcpConfigArgs(injected);
|
|
1272
1372
|
const execOpts = [
|
|
@@ -1286,7 +1386,7 @@ var codexAdapter = {
|
|
|
1286
1386
|
];
|
|
1287
1387
|
const args = sessionId ? ["exec", ...execOpts, "resume", sessionId, promptArg] : ["exec", ...execOpts, promptArg];
|
|
1288
1388
|
return {
|
|
1289
|
-
file: "codex",
|
|
1389
|
+
file: resolveAgentExecutable("codex"),
|
|
1290
1390
|
args,
|
|
1291
1391
|
cwd: thread.worktreePath,
|
|
1292
1392
|
stdin: useStdin ? `${prompt}
|
|
@@ -1382,16 +1482,17 @@ var codexAdapter = {
|
|
|
1382
1482
|
return cached;
|
|
1383
1483
|
},
|
|
1384
1484
|
async buildAttach(thread) {
|
|
1485
|
+
const codex = resolveAgentExecutable("codex");
|
|
1385
1486
|
const sessionId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
|
|
1386
1487
|
if (sessionId) {
|
|
1387
1488
|
return {
|
|
1388
|
-
file:
|
|
1489
|
+
file: codex,
|
|
1389
1490
|
args: ["exec", "--cd", thread.worktreePath, "resume", sessionId],
|
|
1390
1491
|
cwd: thread.worktreePath
|
|
1391
1492
|
};
|
|
1392
1493
|
}
|
|
1393
1494
|
return {
|
|
1394
|
-
file:
|
|
1495
|
+
file: codex,
|
|
1395
1496
|
args: ["--cd", thread.worktreePath],
|
|
1396
1497
|
cwd: thread.worktreePath
|
|
1397
1498
|
};
|
|
@@ -1399,7 +1500,7 @@ var codexAdapter = {
|
|
|
1399
1500
|
async listLinearIssues(_repoPath) {
|
|
1400
1501
|
const prompt = "List my assigned Linear issues as JSON array only: id, identifier, title, url, labels.";
|
|
1401
1502
|
const { stdout, exitCode } = await run(
|
|
1402
|
-
"codex",
|
|
1503
|
+
resolveAgentExecutable("codex"),
|
|
1403
1504
|
[
|
|
1404
1505
|
"exec",
|
|
1405
1506
|
"--json",
|
|
@@ -1424,7 +1525,7 @@ var codexAdapter = {
|
|
|
1424
1525
|
};
|
|
1425
1526
|
|
|
1426
1527
|
// src/agents/cursor.ts
|
|
1427
|
-
import { existsSync as
|
|
1528
|
+
import { existsSync as existsSync5 } from "fs";
|
|
1428
1529
|
import { createRequire as createRequire2 } from "module";
|
|
1429
1530
|
import { dirname as dirname2, join as join3 } from "path";
|
|
1430
1531
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
@@ -1668,7 +1769,7 @@ function cursorRunnerPath() {
|
|
|
1668
1769
|
join3(root, "src", "agents", "cursor-runner.ts")
|
|
1669
1770
|
];
|
|
1670
1771
|
for (const candidate of candidates) {
|
|
1671
|
-
if (
|
|
1772
|
+
if (existsSync5(candidate)) return candidate;
|
|
1672
1773
|
}
|
|
1673
1774
|
return candidates[0];
|
|
1674
1775
|
}
|
|
@@ -1695,13 +1796,16 @@ var cursorAdapter = {
|
|
|
1695
1796
|
};
|
|
1696
1797
|
},
|
|
1697
1798
|
async buildTurn(thread, input) {
|
|
1698
|
-
const prompt = flattenTurnInput(input);
|
|
1699
1799
|
const agentId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
|
|
1800
|
+
const prompt = flattenTurnInput(dropCachedPrefixOnResume(input, agentId));
|
|
1700
1801
|
const apiKey = resolveCursorApiKey() || void 0;
|
|
1802
|
+
const isOrchestrator = isOrchestratorThread(thread);
|
|
1701
1803
|
const injected = await buildInjectedMcpServers({
|
|
1702
1804
|
includeSideboard: true,
|
|
1703
|
-
includeBrightsy:
|
|
1704
|
-
|
|
1805
|
+
includeBrightsy: shouldInjectBrightsyMcp(thread, {
|
|
1806
|
+
orchestrator: isOrchestrator
|
|
1807
|
+
}),
|
|
1808
|
+
orchestratorThreadId: isOrchestrator ? thread.id : null
|
|
1705
1809
|
});
|
|
1706
1810
|
const mcpServers = toCursorMcpServers(injected);
|
|
1707
1811
|
const req = {
|
|
@@ -1747,6 +1851,7 @@ var cursorAdapter = {
|
|
|
1747
1851
|
};
|
|
1748
1852
|
|
|
1749
1853
|
// src/agents/opencode.ts
|
|
1854
|
+
import { existsSync as existsSync6 } from "fs";
|
|
1750
1855
|
var FALLBACK_OPENCODE_MODELS = [
|
|
1751
1856
|
{ id: "opencode/big-pickle", displayName: "opencode \xB7 big-pickle" },
|
|
1752
1857
|
{
|
|
@@ -1783,9 +1888,14 @@ async function listOpencodeModels() {
|
|
|
1783
1888
|
if (cachedOpencodeModels && now - cachedOpencodeModels.at < OPENCODE_MODEL_CACHE_MS) {
|
|
1784
1889
|
return cachedOpencodeModels.models;
|
|
1785
1890
|
}
|
|
1786
|
-
const
|
|
1787
|
-
if (
|
|
1788
|
-
|
|
1891
|
+
const opencode = resolveAgentExecutable("opencode");
|
|
1892
|
+
if (opencode === "opencode") {
|
|
1893
|
+
const which = await run("which", ["opencode"], { reject: false });
|
|
1894
|
+
if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
|
|
1895
|
+
} else if (!existsSync6(opencode)) {
|
|
1896
|
+
return FALLBACK_OPENCODE_MODELS;
|
|
1897
|
+
}
|
|
1898
|
+
const listed = await run(opencode, ["models"], { reject: false });
|
|
1789
1899
|
if (listed.exitCode !== 0 || !listed.stdout.trim()) {
|
|
1790
1900
|
return cachedOpencodeModels?.models ?? FALLBACK_OPENCODE_MODELS;
|
|
1791
1901
|
}
|
|
@@ -1815,20 +1925,34 @@ function usageFromOpencode(tokens) {
|
|
|
1815
1925
|
var opencodeAdapter = {
|
|
1816
1926
|
kind: "opencode",
|
|
1817
1927
|
async detect() {
|
|
1818
|
-
const
|
|
1819
|
-
if (
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1928
|
+
const opencode = resolveAgentExecutable("opencode");
|
|
1929
|
+
if (opencode !== "opencode") {
|
|
1930
|
+
if (!existsSync6(opencode)) {
|
|
1931
|
+
return {
|
|
1932
|
+
agent: "opencode",
|
|
1933
|
+
installed: false,
|
|
1934
|
+
authenticated: false,
|
|
1935
|
+
linearMcp: false,
|
|
1936
|
+
warnings: [],
|
|
1937
|
+
reason: `OpenCode executable not found: ${opencode}`
|
|
1938
|
+
};
|
|
1939
|
+
}
|
|
1940
|
+
} else {
|
|
1941
|
+
const which = await run("which", ["opencode"], { reject: false });
|
|
1942
|
+
if (which.exitCode !== 0) {
|
|
1943
|
+
return {
|
|
1944
|
+
agent: "opencode",
|
|
1945
|
+
installed: false,
|
|
1946
|
+
authenticated: false,
|
|
1947
|
+
linearMcp: false,
|
|
1948
|
+
warnings: [],
|
|
1949
|
+
reason: "opencode CLI not found on PATH"
|
|
1950
|
+
};
|
|
1951
|
+
}
|
|
1828
1952
|
}
|
|
1829
|
-
const auth = await run(
|
|
1953
|
+
const auth = await run(opencode, ["auth", "list"], { reject: false });
|
|
1830
1954
|
const authenticated = auth.exitCode === 0 && auth.stdout.trim().length > 0;
|
|
1831
|
-
const mcp = await run(
|
|
1955
|
+
const mcp = await run(opencode, ["mcp", "list"], { reject: false });
|
|
1832
1956
|
const linearMcp = /linear/i.test(mcp.stdout + mcp.stderr);
|
|
1833
1957
|
return {
|
|
1834
1958
|
agent: "opencode",
|
|
@@ -1840,8 +1964,8 @@ var opencodeAdapter = {
|
|
|
1840
1964
|
};
|
|
1841
1965
|
},
|
|
1842
1966
|
async buildTurn(thread, input) {
|
|
1843
|
-
const prompt = flattenTurnInput(input);
|
|
1844
1967
|
const sessionId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
|
|
1968
|
+
const prompt = flattenTurnInput(dropCachedPrefixOnResume(input, sessionId));
|
|
1845
1969
|
const mode = permissionMode(thread);
|
|
1846
1970
|
const model = thread.model?.trim();
|
|
1847
1971
|
const args = [
|
|
@@ -1857,14 +1981,17 @@ var opencodeAdapter = {
|
|
|
1857
1981
|
if (model) {
|
|
1858
1982
|
args.push("--model", model);
|
|
1859
1983
|
}
|
|
1984
|
+
const isOrchestrator = isOrchestratorThread(thread);
|
|
1860
1985
|
const injected = await buildInjectedMcpServers({
|
|
1861
1986
|
includeSideboard: true,
|
|
1862
|
-
includeBrightsy:
|
|
1863
|
-
|
|
1987
|
+
includeBrightsy: shouldInjectBrightsyMcp(thread, {
|
|
1988
|
+
orchestrator: isOrchestrator
|
|
1989
|
+
}),
|
|
1990
|
+
orchestratorThreadId: isOrchestrator ? thread.id : null
|
|
1864
1991
|
});
|
|
1865
1992
|
const mcpContent = injected.length > 0 ? toOpencodeMcpConfigContent(injected) : null;
|
|
1866
1993
|
return {
|
|
1867
|
-
file: "opencode",
|
|
1994
|
+
file: resolveAgentExecutable("opencode"),
|
|
1868
1995
|
args,
|
|
1869
1996
|
cwd: thread.worktreePath,
|
|
1870
1997
|
// `opencode run` treats non-TTY stdin as the message body when no positional
|
|
@@ -1940,7 +2067,7 @@ var opencodeAdapter = {
|
|
|
1940
2067
|
async resolveSessionId(worktreePath, cached) {
|
|
1941
2068
|
const cachedId = cached?.trim() || null;
|
|
1942
2069
|
const listed = await run(
|
|
1943
|
-
"opencode",
|
|
2070
|
+
resolveAgentExecutable("opencode"),
|
|
1944
2071
|
["session", "list", "--format", "json"],
|
|
1945
2072
|
{ cwd: worktreePath, reject: false }
|
|
1946
2073
|
);
|
|
@@ -1971,7 +2098,7 @@ var opencodeAdapter = {
|
|
|
1971
2098
|
const args = ["--dir", thread.worktreePath];
|
|
1972
2099
|
if (sessionId) args.push("--session", sessionId);
|
|
1973
2100
|
return {
|
|
1974
|
-
file: "opencode",
|
|
2101
|
+
file: resolveAgentExecutable("opencode"),
|
|
1975
2102
|
args,
|
|
1976
2103
|
cwd: thread.worktreePath,
|
|
1977
2104
|
env: {
|
|
@@ -1982,7 +2109,7 @@ var opencodeAdapter = {
|
|
|
1982
2109
|
async listLinearIssues(_repoPath) {
|
|
1983
2110
|
const prompt = "List my assigned Linear issues as JSON array only: id, identifier, title, url, labels.";
|
|
1984
2111
|
const { stdout, exitCode } = await run(
|
|
1985
|
-
"opencode",
|
|
2112
|
+
resolveAgentExecutable("opencode"),
|
|
1986
2113
|
["run", prompt, "--format", "json"],
|
|
1987
2114
|
{
|
|
1988
2115
|
reject: false,
|
|
@@ -2237,15 +2364,48 @@ var SETUP = {
|
|
|
2237
2364
|
npmPackage: "@brightsy/cli"
|
|
2238
2365
|
}
|
|
2239
2366
|
};
|
|
2367
|
+
var CLI_BIN = {
|
|
2368
|
+
claude: "claude",
|
|
2369
|
+
codex: "codex",
|
|
2370
|
+
opencode: "opencode",
|
|
2371
|
+
brightsy: "brightsy"
|
|
2372
|
+
};
|
|
2240
2373
|
function getAgentSetupInfo(agent) {
|
|
2241
2374
|
return SETUP[agent];
|
|
2242
2375
|
}
|
|
2243
2376
|
function listAgentSetupInfo() {
|
|
2244
2377
|
return Object.values(SETUP);
|
|
2245
2378
|
}
|
|
2246
|
-
|
|
2247
|
-
|
|
2379
|
+
var CLI_LOGIN_AGENTS = /* @__PURE__ */ new Set([
|
|
2380
|
+
"claude",
|
|
2381
|
+
"codex",
|
|
2382
|
+
"opencode",
|
|
2383
|
+
"brightsy"
|
|
2384
|
+
]);
|
|
2385
|
+
function resolveLoginCommand(agent) {
|
|
2386
|
+
const info = getAgentSetupInfo(agent);
|
|
2387
|
+
if (!info.loginCommand) return null;
|
|
2388
|
+
if (!CLI_LOGIN_AGENTS.has(agent)) return info.loginCommand;
|
|
2389
|
+
const exe = resolveAgentExecutable(agent);
|
|
2390
|
+
return info.loginCommand.replace(/^\S+/, exe);
|
|
2391
|
+
}
|
|
2392
|
+
async function prepareTerminalCommand(command) {
|
|
2393
|
+
enrichPathWithNpmGlobalBin();
|
|
2248
2394
|
const trimmed = command.trim();
|
|
2395
|
+
if (!trimmed) return trimmed;
|
|
2396
|
+
if (/^(export\s+PATH=|PATH=)/.test(trimmed)) return trimmed;
|
|
2397
|
+
const match = /^(\S+)(\s[\s\S]*)?$/.exec(trimmed);
|
|
2398
|
+
const bin = match?.[1];
|
|
2399
|
+
let whichPath = null;
|
|
2400
|
+
if (bin && !bin.includes("/") && !bin.includes("\\")) {
|
|
2401
|
+
const which = await run("which", [bin], { reject: false, timeoutMs: 3e3 });
|
|
2402
|
+
whichPath = which.exitCode === 0 ? which.stdout.trim() : null;
|
|
2403
|
+
}
|
|
2404
|
+
const resolved = resolveCommandBinarySync(trimmed, whichPath);
|
|
2405
|
+
return withExportedPath(resolved, process.env.PATH ?? "");
|
|
2406
|
+
}
|
|
2407
|
+
async function openInSystemTerminal(command) {
|
|
2408
|
+
const trimmed = (await prepareTerminalCommand(command)).trim();
|
|
2249
2409
|
if (!trimmed) throw new Error("Command is empty");
|
|
2250
2410
|
if (process.platform === "darwin") {
|
|
2251
2411
|
const escaped = trimmed.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
@@ -2286,6 +2446,11 @@ async function openInSystemTerminal(command) {
|
|
|
2286
2446
|
`No terminal found to run: ${trimmed}. Install gnome-terminal (or similar), or run the command manually.`
|
|
2287
2447
|
);
|
|
2288
2448
|
}
|
|
2449
|
+
async function whichCli(bin) {
|
|
2450
|
+
const which = await run("which", [bin], { reject: false, timeoutMs: 3e3 });
|
|
2451
|
+
if (which.exitCode !== 0) return null;
|
|
2452
|
+
return which.stdout.trim().split(/\r?\n/).find(Boolean) ?? null;
|
|
2453
|
+
}
|
|
2289
2454
|
async function installAgent(agent) {
|
|
2290
2455
|
const info = getAgentSetupInfo(agent);
|
|
2291
2456
|
if (info.kind === "bundled-sdk" || info.kind === "api-key") {
|
|
@@ -2306,7 +2471,18 @@ async function installAgent(agent) {
|
|
|
2306
2471
|
message: `Opened Terminal to run: ${info.installCommand}`
|
|
2307
2472
|
};
|
|
2308
2473
|
}
|
|
2309
|
-
|
|
2474
|
+
enrichPathWithNpmGlobalBin();
|
|
2475
|
+
const cliBin = agent === "cursor" ? null : CLI_BIN[agent];
|
|
2476
|
+
if (cliBin) {
|
|
2477
|
+
const existing = await whichCli(cliBin);
|
|
2478
|
+
if (existing) {
|
|
2479
|
+
return {
|
|
2480
|
+
ok: true,
|
|
2481
|
+
command: existing,
|
|
2482
|
+
message: isConductorBundledCli(existing) ? `Using Conductor\u2019s ${cliBin} at ${existing}. No extra install \u2014 Log in only if auth is missing.` : `Already on PATH: ${existing}`
|
|
2483
|
+
};
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2310
2486
|
const result = await run("npm", ["install", "-g", info.npmPackage], { reject: false });
|
|
2311
2487
|
const ok = result.exitCode === 0;
|
|
2312
2488
|
if (!ok) {
|
|
@@ -2332,29 +2508,36 @@ async function installAgent(agent) {
|
|
|
2332
2508
|
};
|
|
2333
2509
|
}
|
|
2334
2510
|
}
|
|
2511
|
+
enrichPathWithNpmGlobalBin();
|
|
2512
|
+
let binPath = null;
|
|
2513
|
+
if (cliBin) {
|
|
2514
|
+
binPath = await whichCli(cliBin);
|
|
2515
|
+
}
|
|
2335
2516
|
return {
|
|
2336
2517
|
ok: true,
|
|
2337
2518
|
command: info.installCommand,
|
|
2338
2519
|
exitCode: 0,
|
|
2339
2520
|
stdout: result.stdout,
|
|
2340
2521
|
stderr: result.stderr,
|
|
2341
|
-
message: `Installed ${info.npmPackage}`
|
|
2522
|
+
message: binPath ? `Installed ${info.npmPackage} \u2192 ${binPath}` : `Installed ${info.npmPackage} (CLI not yet on PATH \u2014 Log in still exports Electron\u2019s PATH into Terminal)`
|
|
2342
2523
|
};
|
|
2343
2524
|
}
|
|
2344
2525
|
async function loginAgent(agent) {
|
|
2345
2526
|
const info = getAgentSetupInfo(agent);
|
|
2346
|
-
|
|
2527
|
+
const loginCommand = resolveLoginCommand(agent);
|
|
2528
|
+
if (!loginCommand) {
|
|
2347
2529
|
return {
|
|
2348
2530
|
ok: true,
|
|
2349
2531
|
message: info.kind === "bundled-sdk" || info.kind === "api-key" ? info.summary : `No login command for ${agent}`
|
|
2350
2532
|
};
|
|
2351
2533
|
}
|
|
2352
|
-
await
|
|
2534
|
+
const prepared = await prepareTerminalCommand(loginCommand);
|
|
2535
|
+
await openInSystemTerminal(prepared);
|
|
2353
2536
|
return {
|
|
2354
2537
|
ok: true,
|
|
2355
2538
|
openedTerminal: true,
|
|
2356
|
-
command:
|
|
2357
|
-
message: `Opened Terminal to run: ${
|
|
2539
|
+
command: prepared,
|
|
2540
|
+
message: `Opened Terminal to run: ${prepared}`
|
|
2358
2541
|
};
|
|
2359
2542
|
}
|
|
2360
2543
|
|
|
@@ -2386,6 +2569,7 @@ export {
|
|
|
2386
2569
|
parseBrightsyCliLine,
|
|
2387
2570
|
listBrightsyChatTargets,
|
|
2388
2571
|
brightsyAdapter,
|
|
2572
|
+
sideboardMcpProfile,
|
|
2389
2573
|
PLAN_MODE_INSTRUCTION,
|
|
2390
2574
|
permissionMode,
|
|
2391
2575
|
claudeAdapter,
|
|
@@ -2406,6 +2590,8 @@ export {
|
|
|
2406
2590
|
resolveQuotaFallbackAgent,
|
|
2407
2591
|
getAgentSetupInfo,
|
|
2408
2592
|
listAgentSetupInfo,
|
|
2593
|
+
resolveLoginCommand,
|
|
2594
|
+
prepareTerminalCommand,
|
|
2409
2595
|
openInSystemTerminal,
|
|
2410
2596
|
installAgent,
|
|
2411
2597
|
loginAgent,
|