@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.
Files changed (43) hide show
  1. package/dist/{agents-KF3J3C53.js → agents-OTBZVTZO.js} +27 -7
  2. package/dist/{agents-QLSFIQAO.js → agents-TS3EI2YI.js} +27 -7
  3. package/dist/{app-settings-LTSFG7QJ.js → app-settings-GJVZGU3M.js} +13 -3
  4. package/dist/{app-settings-HK4KAM4R.js → app-settings-ONKMFSEJ.js} +13 -3
  5. package/dist/{chunk-UGXSSBFJ.js → chunk-4BUCGNZS.js} +1 -1
  6. package/dist/chunk-4UIYN56C.js +173 -0
  7. package/dist/{chunk-NVU7EC2E.js → chunk-57WWNMFP.js} +2 -2
  8. package/dist/{chunk-A6FOKNOU.js → chunk-5HTTCYWA.js} +2 -2
  9. package/dist/{chunk-DXTGDXO2.js → chunk-7ZOQY4A7.js} +31 -6
  10. package/dist/{chunk-ZF5YJCXO.js → chunk-B4PRRKMA.js} +284 -93
  11. package/dist/{chunk-DDN3UF4R.js → chunk-BPOTVI5J.js} +115 -3
  12. package/dist/{chunk-MBAL5FE6.js → chunk-DB3I75FI.js} +4 -4
  13. package/dist/chunk-FGDJOJ2L.js +176 -0
  14. package/dist/{chunk-2FEA4LDA.js → chunk-JWZNK3CQ.js} +31 -6
  15. package/dist/{chunk-2MCNURQV.js → chunk-K7LM4CLD.js} +279 -93
  16. package/dist/{chunk-3KKNTHUC.js → chunk-LW5CMQGZ.js} +1 -1
  17. package/dist/{chunk-JB2H7E7V.js → chunk-M5V4QIWF.js} +1 -1
  18. package/dist/{chunk-6CUJQKTJ.js → chunk-MHR4OGZ4.js} +115 -3
  19. package/dist/{chunk-46KMKHSD.js → chunk-WAFIF22N.js} +2 -2
  20. package/dist/{chunk-27MAWNKY.js → chunk-ZRFAZVGL.js} +2 -2
  21. package/dist/{connected-teams-MKIYKOYA.js → connected-teams-OMDHTL6A.js} +2 -2
  22. package/dist/{connected-teams-RSL4VB3X.js → connected-teams-RUNMOCG5.js} +2 -2
  23. package/dist/{coordinator-prompt-N2R6FGZK.js → coordinator-prompt-3BSMKZL4.js} +4 -4
  24. package/dist/{coordinator-prompt-LKG3SHMI.js → coordinator-prompt-6HMTOX4G.js} +4 -4
  25. package/dist/{global-workspace-LALWQWRJ.js → global-workspace-QS7A23CB.js} +5 -6
  26. package/dist/{global-workspace-YOAUQCMA.js → global-workspace-YZ2NJVLL.js} +5 -6
  27. package/dist/index.cjs +1345 -933
  28. package/dist/index.d.cts +96 -1
  29. package/dist/index.d.ts +96 -1
  30. package/dist/index.js +750 -715
  31. package/dist/mcp/run-stdio.cjs +1293 -977
  32. package/dist/mcp/run-stdio.js +691 -748
  33. package/dist/{run-GPSVV5OH.js → run-JLD2Y52J.js} +1 -1
  34. package/dist/{run-HZTBWGQR.js → run-Y2MI3EVV.js} +1 -1
  35. package/dist/{workspaces-E75POJXP.js → workspaces-AIUYUXB7.js} +6 -7
  36. package/dist/{workspaces-VCAIHVIE.js → workspaces-EBFW7I7S.js} +6 -7
  37. package/dist/{worktree-MV4WRW6G.js → worktree-7NBPIVFZ.js} +2 -2
  38. package/dist/{worktree-LZEGVQSN.js → worktree-WMDJW2BL.js} +2 -2
  39. package/package.json +1 -1
  40. package/dist/chunk-73AT5K4A.js +0 -104
  41. package/dist/chunk-GI7E5733.js +0 -30
  42. package/dist/chunk-RIWUU7FO.js +0 -107
  43. package/dist/chunk-S2LL5HA4.js +0 -33
@@ -6,20 +6,30 @@ import {
6
6
  ensureCliTeamTracked,
7
7
  ensureConnectedBrightsyTeamTokens,
8
8
  loadBrightsyConfig
9
- } from "./chunk-JB2H7E7V.js";
9
+ } from "./chunk-M5V4QIWF.js";
10
10
  import {
11
- ensureAgentPath,
12
- run
13
- } from "./chunk-RIWUU7FO.js";
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-DDN3UF4R.js";
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("brightsy", ["chat", "--list-targets", "--json"], {
319
- reject: false
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 which = await run("which", ["brightsy"], { reject: false });
408
- if (which.exitCode !== 0) {
409
- return {
410
- agent: "brightsy",
411
- installed: false,
412
- authenticated: false,
413
- linearMcp: false,
414
- warnings: [],
415
- reason: "brightsy CLI not found on PATH \u2014 npm i -g @brightsy/cli"
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("brightsy", ["whoami"], { reject: false });
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 { file: "brightsy", args, cwd: thread.worktreePath };
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 existsSync2 } from "fs";
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 && existsSync(override)) return 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 (existsSync(p)) return p;
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 (!existsSync2(claude)) {
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 ? { prompt: turn.prompt } : turn;
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-YOAUQCMA.js");
927
- const isOrchestrator = isOrchestratorThread(thread);
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: isBrightsyConnected(),
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 existsSync3, readFileSync, statSync } from "fs";
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 which = await run("which", ["codex"], { reject: false });
1141
- if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
1142
- const listed = await run("codex", ["debug", "models"], { reject: false });
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 (!existsSync3(path)) continue;
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 (!existsSync3(authPath)) return false;
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 which = await run("which", ["codex"], { reject: false, timeoutMs: 3e3 });
1226
- if (which.exitCode !== 0) {
1227
- return {
1228
- agent: "codex",
1229
- installed: false,
1230
- authenticated: false,
1231
- linearMcp: false,
1232
- warnings: [],
1233
- reason: "codex CLI not found on PATH"
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=${Boolean(cachedPrefix)}`
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: isBrightsyConnected(),
1269
- orchestratorThreadId: thread.sourceType === "orchestration" ? thread.id : null
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: "codex",
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: "codex",
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 existsSync4 } from "fs";
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 (existsSync4(candidate)) return candidate;
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: isBrightsyConnected(),
1704
- orchestratorThreadId: thread.sourceType === "orchestration" ? thread.id : null
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 which = await run("which", ["opencode"], { reject: false });
1787
- if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
1788
- const listed = await run("opencode", ["models"], { reject: false });
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 which = await run("which", ["opencode"], { reject: false });
1819
- if (which.exitCode !== 0) {
1820
- return {
1821
- agent: "opencode",
1822
- installed: false,
1823
- authenticated: false,
1824
- linearMcp: false,
1825
- warnings: [],
1826
- reason: "opencode CLI not found on PATH"
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("opencode", ["auth", "list"], { reject: false });
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("opencode", ["mcp", "list"], { reject: false });
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: isBrightsyConnected(),
1863
- orchestratorThreadId: thread.sourceType === "orchestration" ? thread.id : null
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
- async function openInSystemTerminal(command) {
2247
- ensureAgentPath();
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
- ensureAgentPath();
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
- if (!info.loginCommand) {
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 openInSystemTerminal(info.loginCommand);
2534
+ const prepared = await prepareTerminalCommand(loginCommand);
2535
+ await openInSystemTerminal(prepared);
2353
2536
  return {
2354
2537
  ok: true,
2355
2538
  openedTerminal: true,
2356
- command: info.loginCommand,
2357
- message: `Opened Terminal to run: ${info.loginCommand}`
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,