@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
@@ -1,10 +1,13 @@
1
+ import {
2
+ isOrchestratorThread
3
+ } from "./chunk-7ZOQY4A7.js";
1
4
  import {
2
5
  applyConnectedTeamToCli,
3
6
  brightsyMcpServerName,
4
7
  ensureCliTeamTracked,
5
8
  ensureConnectedBrightsyTeamTokens,
6
9
  loadBrightsyConfig
7
- } from "./chunk-MBAL5FE6.js";
10
+ } from "./chunk-DB3I75FI.js";
8
11
  import {
9
12
  extractJsonErrorMessage,
10
13
  formatUnknownDetail,
@@ -14,15 +17,22 @@ import {
14
17
  import {
15
18
  claudeChromeEnabled,
16
19
  loadAppSettings,
20
+ resolveAgentExecutable,
17
21
  resolveClaudeExecutable
18
- } from "./chunk-6CUJQKTJ.js";
22
+ } from "./chunk-MHR4OGZ4.js";
19
23
  import {
20
24
  appDataDir
21
25
  } from "./chunk-M37RITA6.js";
22
26
  import {
23
- ensureAgentPath,
24
- run
25
- } from "./chunk-73AT5K4A.js";
27
+ enrichPathWithNpmGlobalBin,
28
+ isConductorBundledCli,
29
+ resolveCommandBinarySync,
30
+ run,
31
+ withExportedPath
32
+ } from "./chunk-4UIYN56C.js";
33
+
34
+ // src/agents/brightsy.ts
35
+ import { existsSync } from "fs";
26
36
 
27
37
  // src/agents/brightsy-targets.ts
28
38
  function encodeBrightsyTarget(type, id, accountId) {
@@ -59,6 +69,11 @@ function normalizeTurnInput(input) {
59
69
  if (typeof input === "string") return { prompt: input };
60
70
  return { prompt: input.prompt, cachedPrefix: input.cachedPrefix?.trim() || void 0 };
61
71
  }
72
+ function dropCachedPrefixOnResume(input, sessionId) {
73
+ const turn = normalizeTurnInput(input);
74
+ if (sessionId) return { prompt: turn.prompt };
75
+ return turn;
76
+ }
62
77
  function flattenTurnInput(input) {
63
78
  const { cachedPrefix, prompt } = normalizeTurnInput(input);
64
79
  if (!cachedPrefix) return prompt;
@@ -241,9 +256,13 @@ async function fetchTeamChatTargets(team) {
241
256
  };
242
257
  }
243
258
  async function listBrightsyChatTargetsViaCli() {
244
- const listed = await run("brightsy", ["chat", "--list-targets", "--json"], {
245
- reject: false
246
- });
259
+ const listed = await run(
260
+ resolveAgentExecutable("brightsy"),
261
+ ["chat", "--list-targets", "--json"],
262
+ {
263
+ reject: false
264
+ }
265
+ );
247
266
  if (listed.exitCode !== 0 || !listed.stdout.trim()) {
248
267
  throw new Error(
249
268
  listed.stderr.trim() || "Failed to list Brightsy chat targets \u2014 is `brightsy` installed and logged in?"
@@ -330,18 +349,32 @@ async function syncCliForTarget(accountId) {
330
349
  var brightsyAdapter = {
331
350
  kind: "brightsy",
332
351
  async detect() {
333
- const which = await run("which", ["brightsy"], { reject: false });
334
- if (which.exitCode !== 0) {
335
- return {
336
- agent: "brightsy",
337
- installed: false,
338
- authenticated: false,
339
- linearMcp: false,
340
- warnings: [],
341
- reason: "brightsy CLI not found on PATH \u2014 npm i -g @brightsy/cli"
342
- };
352
+ const brightsy = resolveAgentExecutable("brightsy");
353
+ if (brightsy !== "brightsy") {
354
+ if (!existsSync(brightsy)) {
355
+ return {
356
+ agent: "brightsy",
357
+ installed: false,
358
+ authenticated: false,
359
+ linearMcp: false,
360
+ warnings: [],
361
+ reason: `Brightsy executable not found: ${brightsy}`
362
+ };
363
+ }
364
+ } else {
365
+ const which = await run("which", ["brightsy"], { reject: false });
366
+ if (which.exitCode !== 0) {
367
+ return {
368
+ agent: "brightsy",
369
+ installed: false,
370
+ authenticated: false,
371
+ linearMcp: false,
372
+ warnings: [],
373
+ reason: "brightsy CLI not found on PATH \u2014 npm i -g @brightsy/cli"
374
+ };
375
+ }
343
376
  }
344
- const who = await run("brightsy", ["whoami"], { reject: false });
377
+ const who = await run(brightsy, ["whoami"], { reject: false });
345
378
  const authenticated = who.exitCode === 0 && /logged in as/i.test(who.stdout);
346
379
  return {
347
380
  agent: "brightsy",
@@ -366,7 +399,7 @@ var brightsyAdapter = {
366
399
  target.id
367
400
  ];
368
401
  return {
369
- file: "brightsy",
402
+ file: resolveAgentExecutable("brightsy"),
370
403
  args,
371
404
  cwd: thread.worktreePath,
372
405
  // Piped stdin becomes the message body (avoids ARG_MAX for long seeds).
@@ -383,12 +416,16 @@ var brightsyAdapter = {
383
416
  const target = decodeBrightsyTarget(thread.model);
384
417
  await syncCliForTarget(target.accountId);
385
418
  const args = target.type === "model" ? ["chat", "--model", target.id] : ["chat", "--agent", target.id];
386
- return { file: "brightsy", args, cwd: thread.worktreePath };
419
+ return {
420
+ file: resolveAgentExecutable("brightsy"),
421
+ args,
422
+ cwd: thread.worktreePath
423
+ };
387
424
  }
388
425
  };
389
426
 
390
427
  // src/agents/claude.ts
391
- import { existsSync as existsSync2 } from "fs";
428
+ import { existsSync as existsSync3 } from "fs";
392
429
 
393
430
  // src/agents/claude-mcp.ts
394
431
  function parseMcpList(text) {
@@ -432,12 +469,18 @@ function mcpAuthWarnings(servers) {
432
469
  }
433
470
 
434
471
  // src/agents/injected-mcp.ts
435
- import { existsSync, mkdtempSync, writeFileSync } from "fs";
472
+ import { existsSync as existsSync2, mkdtempSync, writeFileSync } from "fs";
436
473
  import { createRequire } from "module";
437
474
  import { tmpdir } from "os";
438
475
  import { dirname, join } from "path";
439
476
  import { fileURLToPath } from "url";
440
477
 
478
+ // src/mcp/profile.ts
479
+ var SIDEBOARD_MCP_PROFILE_ENV = "SIDEBOARD_MCP_PROFILE";
480
+ function sideboardMcpProfile(env = process.env) {
481
+ return env[SIDEBOARD_MCP_PROFILE_ENV]?.trim().toLowerCase() === "worktree" ? "worktree" : "orchestration";
482
+ }
483
+
441
484
  // src/agents/node-launch.ts
442
485
  function isAsarPath(filePath) {
443
486
  return /\.asar([/\\]|$)/.test(filePath);
@@ -495,6 +538,39 @@ function isBrightsyConnected() {
495
538
  return false;
496
539
  }
497
540
  }
541
+ var BRIGHTSY_WORD = /(?<![a-z0-9_-])brightsy(?![a-z0-9_-])/i;
542
+ function promptMentionsBrightsy(text) {
543
+ return BRIGHTSY_WORD.test(text ?? "");
544
+ }
545
+ function isBrightsyMcpToolName(name) {
546
+ const n = name.toLowerCase();
547
+ return n === "brightsy" || n.startsWith("mcp__brightsy") || n.startsWith("brightsy_");
548
+ }
549
+ function toolInputUsesBrightsyDatasource(input) {
550
+ const ds = input?.datasource;
551
+ return typeof ds === "string" && ds.toLowerCase() === "brightsy";
552
+ }
553
+ function messageUsedBrightsyMcp(msg) {
554
+ if (msg.role === "user" && promptMentionsBrightsy(msg.text)) return true;
555
+ for (const part of msg.parts ?? []) {
556
+ if (part.type !== "tool") continue;
557
+ if (isBrightsyMcpToolName(part.name)) return true;
558
+ if (/present_(schema|files)$/i.test(part.name) && toolInputUsesBrightsyDatasource(part.input)) {
559
+ return true;
560
+ }
561
+ }
562
+ return false;
563
+ }
564
+ function threadRequestsBrightsyMcp(thread) {
565
+ return (thread?.messages ?? []).some(messageUsedBrightsyMcp);
566
+ }
567
+ function shouldInjectBrightsyMcp(thread, opts) {
568
+ if (!(opts?.connected ?? isBrightsyConnected())) return false;
569
+ if (opts?.orchestrator) return true;
570
+ const alwaysOn = opts?.alwaysOnWorktree ?? Boolean(loadAppSettings().brightsy?.injectWorktreeMcp);
571
+ if (alwaysOn) return true;
572
+ return threadRequestsBrightsyMcp(thread);
573
+ }
498
574
  function mcpLaunch(cmd, name, env) {
499
575
  if (cmd === "brightsy-mcp") {
500
576
  return { name, command: "brightsy-mcp", ...env ? { env } : {} };
@@ -540,7 +616,7 @@ function corePackageDir() {
540
616
  }
541
617
  function findSideboardMcpJsEntry() {
542
618
  const override = process.env.SIDEBOARD_MCP_ENTRY?.trim() || process.env.SIDEBOARD_CLI?.trim();
543
- if (override && existsSync(override)) return override;
619
+ if (override && existsSync2(override)) return override;
544
620
  let dir = corePackageDir();
545
621
  for (let i = 0; i < 10; i++) {
546
622
  const candidates = [
@@ -553,7 +629,7 @@ function findSideboardMcpJsEntry() {
553
629
  join(dir, "cli/dist/index.js")
554
630
  ];
555
631
  for (const p of candidates) {
556
- if (existsSync(p)) return p;
632
+ if (existsSync2(p)) return p;
557
633
  }
558
634
  const parent = dirname(dir);
559
635
  if (parent === dir) break;
@@ -584,11 +660,13 @@ async function buildInjectedMcpServers(opts) {
584
660
  const servers = [];
585
661
  if (opts.includeSideboard) {
586
662
  const sideboard = await resolveSideboardMcpServer();
663
+ const orchId = opts.orchestratorThreadId?.trim();
664
+ const profile = orchId ? "orchestration" : "worktree";
587
665
  sideboard.env = {
588
666
  ...sideboard.env ?? {},
589
- SIDEBOARD_APP_DATA: appDataDir()
667
+ SIDEBOARD_APP_DATA: appDataDir(),
668
+ [SIDEBOARD_MCP_PROFILE_ENV]: profile
590
669
  };
591
- const orchId = opts.orchestratorThreadId?.trim();
592
670
  if (orchId) {
593
671
  sideboard.env.SIDEBOARD_ORCHESTRATOR_THREAD_ID = orchId;
594
672
  }
@@ -813,7 +891,7 @@ var claudeAdapter = {
813
891
  async detect() {
814
892
  const claude = resolveClaudeExecutable();
815
893
  if (claude !== "claude") {
816
- if (!existsSync2(claude)) {
894
+ if (!existsSync3(claude)) {
817
895
  return {
818
896
  agent: "claude",
819
897
  installed: false,
@@ -852,9 +930,8 @@ var claudeAdapter = {
852
930
  },
853
931
  async buildTurn(thread, input) {
854
932
  const claude = resolveClaudeExecutable();
855
- const turn = normalizeTurnInput(input);
856
933
  const sessionId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
857
- const effective = sessionId ? { prompt: turn.prompt } : turn;
934
+ const effective = dropCachedPrefixOnResume(input, sessionId);
858
935
  const promptText = flattenTurnInput(effective);
859
936
  const useStdin = promptText.length > CLAUDE_PROMPT_ARG_MAX;
860
937
  if (process.env.SIDEBOARD_DEBUG_CLAUDE_TURN === "1") {
@@ -863,11 +940,13 @@ var claudeAdapter = {
863
940
  );
864
941
  }
865
942
  const mode = permissionMode(thread);
866
- const { isOrchestratorThread } = await import("./global-workspace-LALWQWRJ.js");
867
- const isOrchestrator = isOrchestratorThread(thread);
943
+ const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-QS7A23CB.js");
944
+ const isOrchestrator = isOrchestratorThread2(thread);
868
945
  const injectedServers = await buildInjectedMcpServers({
869
946
  includeSideboard: true,
870
- includeBrightsy: isBrightsyConnected(),
947
+ includeBrightsy: shouldInjectBrightsyMcp(thread, {
948
+ orchestrator: isOrchestrator
949
+ }),
871
950
  orchestratorThreadId: isOrchestrator ? thread.id : null
872
951
  });
873
952
  const injectedBrightsyNames = injectedServers.filter((s) => s.name === "brightsy" || s.name.startsWith("brightsy_")).map((s) => s.name);
@@ -1059,7 +1138,7 @@ function parseIssuesJson(raw) {
1059
1138
  }
1060
1139
 
1061
1140
  // src/agents/codex.ts
1062
- import { existsSync as existsSync3, readFileSync, statSync } from "fs";
1141
+ import { existsSync as existsSync4, readFileSync, statSync } from "fs";
1063
1142
  import { homedir } from "os";
1064
1143
  import { join as join2 } from "path";
1065
1144
  var CODEX_PROMPT_ARG_MAX = 2e5;
@@ -1077,9 +1156,14 @@ async function listCodexModels() {
1077
1156
  if (cachedCodexModels && now - cachedCodexModels.at < CODEX_MODEL_CACHE_MS) {
1078
1157
  return cachedCodexModels.models;
1079
1158
  }
1080
- const which = await run("which", ["codex"], { reject: false });
1081
- if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
1082
- const listed = await run("codex", ["debug", "models"], { reject: false });
1159
+ const codex = resolveAgentExecutable("codex");
1160
+ if (codex === "codex") {
1161
+ const which = await run("which", ["codex"], { reject: false });
1162
+ if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
1163
+ } else if (!existsSync4(codex)) {
1164
+ return FALLBACK_CODEX_MODELS;
1165
+ }
1166
+ const listed = await run(codex, ["debug", "models"], { reject: false });
1083
1167
  if (listed.exitCode !== 0 || !listed.stdout.trim()) {
1084
1168
  return cachedCodexModels?.models ?? FALLBACK_CODEX_MODELS;
1085
1169
  }
@@ -1118,7 +1202,7 @@ function codexConfigHasNetworkAccess() {
1118
1202
  join2(homedir(), ".config", "codex", "config.toml")
1119
1203
  ];
1120
1204
  for (const path of candidates) {
1121
- if (!existsSync3(path)) continue;
1205
+ if (!existsSync4(path)) continue;
1122
1206
  const text = readFileSync(path, "utf8");
1123
1207
  if (/network_access\s*=\s*true/.test(text)) return true;
1124
1208
  }
@@ -1152,7 +1236,7 @@ function asRecord(value) {
1152
1236
  }
1153
1237
  function codexLooksAuthenticated() {
1154
1238
  const authPath = join2(homedir(), ".codex", "auth.json");
1155
- if (!existsSync3(authPath)) return false;
1239
+ if (!existsSync4(authPath)) return false;
1156
1240
  try {
1157
1241
  return statSync(authPath).size > 2;
1158
1242
  } catch {
@@ -1162,16 +1246,30 @@ function codexLooksAuthenticated() {
1162
1246
  var codexAdapter = {
1163
1247
  kind: "codex",
1164
1248
  async detect() {
1165
- const which = await run("which", ["codex"], { reject: false, timeoutMs: 3e3 });
1166
- if (which.exitCode !== 0) {
1167
- return {
1168
- agent: "codex",
1169
- installed: false,
1170
- authenticated: false,
1171
- linearMcp: false,
1172
- warnings: [],
1173
- reason: "codex CLI not found on PATH"
1174
- };
1249
+ const codex = resolveAgentExecutable("codex");
1250
+ if (codex !== "codex") {
1251
+ if (!existsSync4(codex)) {
1252
+ return {
1253
+ agent: "codex",
1254
+ installed: false,
1255
+ authenticated: false,
1256
+ linearMcp: false,
1257
+ warnings: [],
1258
+ reason: `Codex executable not found: ${codex}`
1259
+ };
1260
+ }
1261
+ } else {
1262
+ const which = await run("which", ["codex"], { reject: false, timeoutMs: 3e3 });
1263
+ if (which.exitCode !== 0) {
1264
+ return {
1265
+ agent: "codex",
1266
+ installed: false,
1267
+ authenticated: false,
1268
+ linearMcp: false,
1269
+ warnings: [],
1270
+ reason: "codex CLI not found on PATH"
1271
+ };
1272
+ }
1175
1273
  }
1176
1274
  const authenticated = codexLooksAuthenticated();
1177
1275
  const linearMcp = false;
@@ -1191,22 +1289,24 @@ var codexAdapter = {
1191
1289
  };
1192
1290
  },
1193
1291
  async buildTurn(thread, input) {
1194
- const prompt = flattenTurnInput(input);
1195
1292
  const sessionId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
1293
+ const prompt = flattenTurnInput(dropCachedPrefixOnResume(input, sessionId));
1196
1294
  const useStdin = prompt.length > CODEX_PROMPT_ARG_MAX;
1197
1295
  const promptArg = useStdin ? "-" : prompt;
1198
1296
  if (process.env.SIDEBOARD_DEBUG_CODEX_TURN === "1") {
1199
- const { cachedPrefix } = normalizeTurnInput(input);
1200
1297
  console.error(
1201
- `[sideboard/codex] promptChars=${prompt.length} resumed=${Boolean(sessionId)} stdin=${useStdin} hasPrefix=${Boolean(cachedPrefix)}`
1298
+ `[sideboard/codex] promptChars=${prompt.length} resumed=${Boolean(sessionId)} stdin=${useStdin} hasPrefix=${prompt.includes("Current request:")}`
1202
1299
  );
1203
1300
  }
1204
1301
  const mode = permissionMode(thread);
1205
1302
  const model = thread.model?.trim();
1303
+ const isOrchestrator = isOrchestratorThread(thread);
1206
1304
  const injected = await buildInjectedMcpServers({
1207
1305
  includeSideboard: true,
1208
- includeBrightsy: isBrightsyConnected(),
1209
- orchestratorThreadId: thread.sourceType === "orchestration" ? thread.id : null
1306
+ includeBrightsy: shouldInjectBrightsyMcp(thread, {
1307
+ orchestrator: isOrchestrator
1308
+ }),
1309
+ orchestratorThreadId: isOrchestrator ? thread.id : null
1210
1310
  });
1211
1311
  const mcpOverrides = toCodexMcpConfigArgs(injected);
1212
1312
  const execOpts = [
@@ -1226,7 +1326,7 @@ var codexAdapter = {
1226
1326
  ];
1227
1327
  const args = sessionId ? ["exec", ...execOpts, "resume", sessionId, promptArg] : ["exec", ...execOpts, promptArg];
1228
1328
  return {
1229
- file: "codex",
1329
+ file: resolveAgentExecutable("codex"),
1230
1330
  args,
1231
1331
  cwd: thread.worktreePath,
1232
1332
  stdin: useStdin ? `${prompt}
@@ -1322,16 +1422,17 @@ var codexAdapter = {
1322
1422
  return cached;
1323
1423
  },
1324
1424
  async buildAttach(thread) {
1425
+ const codex = resolveAgentExecutable("codex");
1325
1426
  const sessionId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
1326
1427
  if (sessionId) {
1327
1428
  return {
1328
- file: "codex",
1429
+ file: codex,
1329
1430
  args: ["exec", "--cd", thread.worktreePath, "resume", sessionId],
1330
1431
  cwd: thread.worktreePath
1331
1432
  };
1332
1433
  }
1333
1434
  return {
1334
- file: "codex",
1435
+ file: codex,
1335
1436
  args: ["--cd", thread.worktreePath],
1336
1437
  cwd: thread.worktreePath
1337
1438
  };
@@ -1339,7 +1440,7 @@ var codexAdapter = {
1339
1440
  async listLinearIssues(_repoPath) {
1340
1441
  const prompt = "List my assigned Linear issues as JSON array only: id, identifier, title, url, labels.";
1341
1442
  const { stdout, exitCode } = await run(
1342
- "codex",
1443
+ resolveAgentExecutable("codex"),
1343
1444
  [
1344
1445
  "exec",
1345
1446
  "--json",
@@ -1364,7 +1465,7 @@ var codexAdapter = {
1364
1465
  };
1365
1466
 
1366
1467
  // src/agents/cursor.ts
1367
- import { existsSync as existsSync4 } from "fs";
1468
+ import { existsSync as existsSync5 } from "fs";
1368
1469
  import { createRequire as createRequire2 } from "module";
1369
1470
  import { dirname as dirname2, join as join3 } from "path";
1370
1471
  import { fileURLToPath as fileURLToPath2 } from "url";
@@ -1437,7 +1538,7 @@ function cursorRunnerPath() {
1437
1538
  join3(root, "src", "agents", "cursor-runner.ts")
1438
1539
  ];
1439
1540
  for (const candidate of candidates) {
1440
- if (existsSync4(candidate)) return candidate;
1541
+ if (existsSync5(candidate)) return candidate;
1441
1542
  }
1442
1543
  return candidates[0];
1443
1544
  }
@@ -1464,13 +1565,16 @@ var cursorAdapter = {
1464
1565
  };
1465
1566
  },
1466
1567
  async buildTurn(thread, input) {
1467
- const prompt = flattenTurnInput(input);
1468
1568
  const agentId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
1569
+ const prompt = flattenTurnInput(dropCachedPrefixOnResume(input, agentId));
1469
1570
  const apiKey = resolveCursorApiKey() || void 0;
1571
+ const isOrchestrator = isOrchestratorThread(thread);
1470
1572
  const injected = await buildInjectedMcpServers({
1471
1573
  includeSideboard: true,
1472
- includeBrightsy: isBrightsyConnected(),
1473
- orchestratorThreadId: thread.sourceType === "orchestration" ? thread.id : null
1574
+ includeBrightsy: shouldInjectBrightsyMcp(thread, {
1575
+ orchestrator: isOrchestrator
1576
+ }),
1577
+ orchestratorThreadId: isOrchestrator ? thread.id : null
1474
1578
  });
1475
1579
  const mcpServers = toCursorMcpServers(injected);
1476
1580
  const req = {
@@ -1516,6 +1620,7 @@ var cursorAdapter = {
1516
1620
  };
1517
1621
 
1518
1622
  // src/agents/opencode.ts
1623
+ import { existsSync as existsSync6 } from "fs";
1519
1624
  var FALLBACK_OPENCODE_MODELS = [
1520
1625
  { id: "opencode/big-pickle", displayName: "opencode \xB7 big-pickle" },
1521
1626
  {
@@ -1552,9 +1657,14 @@ async function listOpencodeModels() {
1552
1657
  if (cachedOpencodeModels && now - cachedOpencodeModels.at < OPENCODE_MODEL_CACHE_MS) {
1553
1658
  return cachedOpencodeModels.models;
1554
1659
  }
1555
- const which = await run("which", ["opencode"], { reject: false });
1556
- if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
1557
- const listed = await run("opencode", ["models"], { reject: false });
1660
+ const opencode = resolveAgentExecutable("opencode");
1661
+ if (opencode === "opencode") {
1662
+ const which = await run("which", ["opencode"], { reject: false });
1663
+ if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
1664
+ } else if (!existsSync6(opencode)) {
1665
+ return FALLBACK_OPENCODE_MODELS;
1666
+ }
1667
+ const listed = await run(opencode, ["models"], { reject: false });
1558
1668
  if (listed.exitCode !== 0 || !listed.stdout.trim()) {
1559
1669
  return cachedOpencodeModels?.models ?? FALLBACK_OPENCODE_MODELS;
1560
1670
  }
@@ -1584,20 +1694,34 @@ function usageFromOpencode(tokens) {
1584
1694
  var opencodeAdapter = {
1585
1695
  kind: "opencode",
1586
1696
  async detect() {
1587
- const which = await run("which", ["opencode"], { reject: false });
1588
- if (which.exitCode !== 0) {
1589
- return {
1590
- agent: "opencode",
1591
- installed: false,
1592
- authenticated: false,
1593
- linearMcp: false,
1594
- warnings: [],
1595
- reason: "opencode CLI not found on PATH"
1596
- };
1697
+ const opencode = resolveAgentExecutable("opencode");
1698
+ if (opencode !== "opencode") {
1699
+ if (!existsSync6(opencode)) {
1700
+ return {
1701
+ agent: "opencode",
1702
+ installed: false,
1703
+ authenticated: false,
1704
+ linearMcp: false,
1705
+ warnings: [],
1706
+ reason: `OpenCode executable not found: ${opencode}`
1707
+ };
1708
+ }
1709
+ } else {
1710
+ const which = await run("which", ["opencode"], { reject: false });
1711
+ if (which.exitCode !== 0) {
1712
+ return {
1713
+ agent: "opencode",
1714
+ installed: false,
1715
+ authenticated: false,
1716
+ linearMcp: false,
1717
+ warnings: [],
1718
+ reason: "opencode CLI not found on PATH"
1719
+ };
1720
+ }
1597
1721
  }
1598
- const auth = await run("opencode", ["auth", "list"], { reject: false });
1722
+ const auth = await run(opencode, ["auth", "list"], { reject: false });
1599
1723
  const authenticated = auth.exitCode === 0 && auth.stdout.trim().length > 0;
1600
- const mcp = await run("opencode", ["mcp", "list"], { reject: false });
1724
+ const mcp = await run(opencode, ["mcp", "list"], { reject: false });
1601
1725
  const linearMcp = /linear/i.test(mcp.stdout + mcp.stderr);
1602
1726
  return {
1603
1727
  agent: "opencode",
@@ -1609,8 +1733,8 @@ var opencodeAdapter = {
1609
1733
  };
1610
1734
  },
1611
1735
  async buildTurn(thread, input) {
1612
- const prompt = flattenTurnInput(input);
1613
1736
  const sessionId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
1737
+ const prompt = flattenTurnInput(dropCachedPrefixOnResume(input, sessionId));
1614
1738
  const mode = permissionMode(thread);
1615
1739
  const model = thread.model?.trim();
1616
1740
  const args = [
@@ -1626,14 +1750,17 @@ var opencodeAdapter = {
1626
1750
  if (model) {
1627
1751
  args.push("--model", model);
1628
1752
  }
1753
+ const isOrchestrator = isOrchestratorThread(thread);
1629
1754
  const injected = await buildInjectedMcpServers({
1630
1755
  includeSideboard: true,
1631
- includeBrightsy: isBrightsyConnected(),
1632
- orchestratorThreadId: thread.sourceType === "orchestration" ? thread.id : null
1756
+ includeBrightsy: shouldInjectBrightsyMcp(thread, {
1757
+ orchestrator: isOrchestrator
1758
+ }),
1759
+ orchestratorThreadId: isOrchestrator ? thread.id : null
1633
1760
  });
1634
1761
  const mcpContent = injected.length > 0 ? toOpencodeMcpConfigContent(injected) : null;
1635
1762
  return {
1636
- file: "opencode",
1763
+ file: resolveAgentExecutable("opencode"),
1637
1764
  args,
1638
1765
  cwd: thread.worktreePath,
1639
1766
  // `opencode run` treats non-TTY stdin as the message body when no positional
@@ -1709,7 +1836,7 @@ var opencodeAdapter = {
1709
1836
  async resolveSessionId(worktreePath, cached) {
1710
1837
  const cachedId = cached?.trim() || null;
1711
1838
  const listed = await run(
1712
- "opencode",
1839
+ resolveAgentExecutable("opencode"),
1713
1840
  ["session", "list", "--format", "json"],
1714
1841
  { cwd: worktreePath, reject: false }
1715
1842
  );
@@ -1740,7 +1867,7 @@ var opencodeAdapter = {
1740
1867
  const args = ["--dir", thread.worktreePath];
1741
1868
  if (sessionId) args.push("--session", sessionId);
1742
1869
  return {
1743
- file: "opencode",
1870
+ file: resolveAgentExecutable("opencode"),
1744
1871
  args,
1745
1872
  cwd: thread.worktreePath,
1746
1873
  env: {
@@ -1751,7 +1878,7 @@ var opencodeAdapter = {
1751
1878
  async listLinearIssues(_repoPath) {
1752
1879
  const prompt = "List my assigned Linear issues as JSON array only: id, identifier, title, url, labels.";
1753
1880
  const { stdout, exitCode } = await run(
1754
- "opencode",
1881
+ resolveAgentExecutable("opencode"),
1755
1882
  ["run", prompt, "--format", "json"],
1756
1883
  {
1757
1884
  reject: false,
@@ -2006,15 +2133,48 @@ var SETUP = {
2006
2133
  npmPackage: "@brightsy/cli"
2007
2134
  }
2008
2135
  };
2136
+ var CLI_BIN = {
2137
+ claude: "claude",
2138
+ codex: "codex",
2139
+ opencode: "opencode",
2140
+ brightsy: "brightsy"
2141
+ };
2009
2142
  function getAgentSetupInfo(agent) {
2010
2143
  return SETUP[agent];
2011
2144
  }
2012
2145
  function listAgentSetupInfo() {
2013
2146
  return Object.values(SETUP);
2014
2147
  }
2015
- async function openInSystemTerminal(command) {
2016
- ensureAgentPath();
2148
+ var CLI_LOGIN_AGENTS = /* @__PURE__ */ new Set([
2149
+ "claude",
2150
+ "codex",
2151
+ "opencode",
2152
+ "brightsy"
2153
+ ]);
2154
+ function resolveLoginCommand(agent) {
2155
+ const info = getAgentSetupInfo(agent);
2156
+ if (!info.loginCommand) return null;
2157
+ if (!CLI_LOGIN_AGENTS.has(agent)) return info.loginCommand;
2158
+ const exe = resolveAgentExecutable(agent);
2159
+ return info.loginCommand.replace(/^\S+/, exe);
2160
+ }
2161
+ async function prepareTerminalCommand(command) {
2162
+ enrichPathWithNpmGlobalBin();
2017
2163
  const trimmed = command.trim();
2164
+ if (!trimmed) return trimmed;
2165
+ if (/^(export\s+PATH=|PATH=)/.test(trimmed)) return trimmed;
2166
+ const match = /^(\S+)(\s[\s\S]*)?$/.exec(trimmed);
2167
+ const bin = match?.[1];
2168
+ let whichPath = null;
2169
+ if (bin && !bin.includes("/") && !bin.includes("\\")) {
2170
+ const which = await run("which", [bin], { reject: false, timeoutMs: 3e3 });
2171
+ whichPath = which.exitCode === 0 ? which.stdout.trim() : null;
2172
+ }
2173
+ const resolved = resolveCommandBinarySync(trimmed, whichPath);
2174
+ return withExportedPath(resolved, process.env.PATH ?? "");
2175
+ }
2176
+ async function openInSystemTerminal(command) {
2177
+ const trimmed = (await prepareTerminalCommand(command)).trim();
2018
2178
  if (!trimmed) throw new Error("Command is empty");
2019
2179
  if (process.platform === "darwin") {
2020
2180
  const escaped = trimmed.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
@@ -2055,6 +2215,11 @@ async function openInSystemTerminal(command) {
2055
2215
  `No terminal found to run: ${trimmed}. Install gnome-terminal (or similar), or run the command manually.`
2056
2216
  );
2057
2217
  }
2218
+ async function whichCli(bin) {
2219
+ const which = await run("which", [bin], { reject: false, timeoutMs: 3e3 });
2220
+ if (which.exitCode !== 0) return null;
2221
+ return which.stdout.trim().split(/\r?\n/).find(Boolean) ?? null;
2222
+ }
2058
2223
  async function installAgent(agent) {
2059
2224
  const info = getAgentSetupInfo(agent);
2060
2225
  if (info.kind === "bundled-sdk" || info.kind === "api-key") {
@@ -2075,7 +2240,18 @@ async function installAgent(agent) {
2075
2240
  message: `Opened Terminal to run: ${info.installCommand}`
2076
2241
  };
2077
2242
  }
2078
- ensureAgentPath();
2243
+ enrichPathWithNpmGlobalBin();
2244
+ const cliBin = agent === "cursor" ? null : CLI_BIN[agent];
2245
+ if (cliBin) {
2246
+ const existing = await whichCli(cliBin);
2247
+ if (existing) {
2248
+ return {
2249
+ ok: true,
2250
+ command: existing,
2251
+ message: isConductorBundledCli(existing) ? `Using Conductor\u2019s ${cliBin} at ${existing}. No extra install \u2014 Log in only if auth is missing.` : `Already on PATH: ${existing}`
2252
+ };
2253
+ }
2254
+ }
2079
2255
  const result = await run("npm", ["install", "-g", info.npmPackage], { reject: false });
2080
2256
  const ok = result.exitCode === 0;
2081
2257
  if (!ok) {
@@ -2101,29 +2277,36 @@ async function installAgent(agent) {
2101
2277
  };
2102
2278
  }
2103
2279
  }
2280
+ enrichPathWithNpmGlobalBin();
2281
+ let binPath = null;
2282
+ if (cliBin) {
2283
+ binPath = await whichCli(cliBin);
2284
+ }
2104
2285
  return {
2105
2286
  ok: true,
2106
2287
  command: info.installCommand,
2107
2288
  exitCode: 0,
2108
2289
  stdout: result.stdout,
2109
2290
  stderr: result.stderr,
2110
- message: `Installed ${info.npmPackage}`
2291
+ 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)`
2111
2292
  };
2112
2293
  }
2113
2294
  async function loginAgent(agent) {
2114
2295
  const info = getAgentSetupInfo(agent);
2115
- if (!info.loginCommand) {
2296
+ const loginCommand = resolveLoginCommand(agent);
2297
+ if (!loginCommand) {
2116
2298
  return {
2117
2299
  ok: true,
2118
2300
  message: info.kind === "bundled-sdk" || info.kind === "api-key" ? info.summary : `No login command for ${agent}`
2119
2301
  };
2120
2302
  }
2121
- await openInSystemTerminal(info.loginCommand);
2303
+ const prepared = await prepareTerminalCommand(loginCommand);
2304
+ await openInSystemTerminal(prepared);
2122
2305
  return {
2123
2306
  ok: true,
2124
2307
  openedTerminal: true,
2125
- command: info.loginCommand,
2126
- message: `Opened Terminal to run: ${info.loginCommand}`
2308
+ command: prepared,
2309
+ message: `Opened Terminal to run: ${prepared}`
2127
2310
  };
2128
2311
  }
2129
2312
 
@@ -2146,6 +2329,7 @@ export {
2146
2329
  encodeBrightsyTarget,
2147
2330
  decodeBrightsyTarget,
2148
2331
  normalizeTurnInput,
2332
+ dropCachedPrefixOnResume,
2149
2333
  flattenTurnInput,
2150
2334
  buildCachedUserContent,
2151
2335
  buildClaudeStreamJsonUserMessage,
@@ -2159,9 +2343,14 @@ export {
2159
2343
  sanitizeMcpServerName,
2160
2344
  mcpAllowTools,
2161
2345
  mcpAuthWarnings,
2346
+ SIDEBOARD_MCP_PROFILE_ENV,
2347
+ sideboardMcpProfile,
2162
2348
  SIDEBOARD_MCP_ALLOWED_TOOLS,
2163
2349
  BRIGHTSY_MCP_ALLOWED_TOOLS,
2164
2350
  isBrightsyConnected,
2351
+ promptMentionsBrightsy,
2352
+ threadRequestsBrightsyMcp,
2353
+ shouldInjectBrightsyMcp,
2165
2354
  brightsyMcpAllowedTools,
2166
2355
  writeInjectedMcpConfig,
2167
2356
  PLAN_MODE_INSTRUCTION,
@@ -2182,6 +2371,8 @@ export {
2182
2371
  resolveQuotaFallbackAgent,
2183
2372
  getAgentSetupInfo,
2184
2373
  listAgentSetupInfo,
2374
+ resolveLoginCommand,
2375
+ prepareTerminalCommand,
2185
2376
  openInSystemTerminal,
2186
2377
  installAgent,
2187
2378
  loginAgent,