@sideboard-ai/core 0.1.61 → 0.1.66

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 (45) hide show
  1. package/dist/{agents-B2723EOF.js → agents-EWFD765A.js} +23 -7
  2. package/dist/{agents-EADRAAPG.js → agents-MD7SCFYX.js} +23 -7
  3. package/dist/{app-settings-YBNZ4XSR.js → app-settings-GJVZGU3M.js} +15 -3
  4. package/dist/{app-settings-TBHTJWLQ.js → app-settings-ONKMFSEJ.js} +15 -3
  5. package/dist/{chunk-RIWUU7FO.js → chunk-5AG5BUQN.js} +61 -3
  6. package/dist/{chunk-HLEX5AQ6.js → chunk-7FD7COKE.js} +4 -0
  7. package/dist/{chunk-XWPKLRB3.js → chunk-AKPEXIKK.js} +2 -2
  8. package/dist/{chunk-MX7UH5AT.js → chunk-BBEH2CJE.js} +264 -93
  9. package/dist/{chunk-FGNBTFRD.js → chunk-BPOTVI5J.js} +125 -3
  10. package/dist/{chunk-CHGOMFTA.js → chunk-DNPP7QMK.js} +32 -7
  11. package/dist/{chunk-MBAL5FE6.js → chunk-DZYMNW2A.js} +4 -4
  12. package/dist/{chunk-JB2H7E7V.js → chunk-EVD4KNKR.js} +1 -1
  13. package/dist/{chunk-TSRXOSVD.js → chunk-FWJYLBO6.js} +4 -0
  14. package/dist/{chunk-QJBC4BRK.js → chunk-HTOTTJJX.js} +2 -2
  15. package/dist/{chunk-MFGGIRUA.js → chunk-I2KGRAXC.js} +2 -2
  16. package/dist/{chunk-ZXDOI6IH.js → chunk-IFAU2DEY.js} +269 -93
  17. package/dist/{chunk-NTYRBRE7.js → chunk-LRBRQFBU.js} +2 -2
  18. package/dist/{chunk-75QR74KM.js → chunk-MHR4OGZ4.js} +125 -3
  19. package/dist/{chunk-2P2UK7E7.js → chunk-PESJDZTB.js} +2 -2
  20. package/dist/{chunk-P7EQUFB6.js → chunk-R7GUDEPY.js} +2 -2
  21. package/dist/{chunk-73AT5K4A.js → chunk-TXQ6K2GR.js} +61 -3
  22. package/dist/{chunk-MLAST5BB.js → chunk-YTNLOJPK.js} +32 -7
  23. package/dist/{connected-teams-RSL4VB3X.js → connected-teams-CHXO5FFA.js} +2 -2
  24. package/dist/{connected-teams-MKIYKOYA.js → connected-teams-GJTESSTX.js} +2 -2
  25. package/dist/{coordinator-prompt-4P23VVFC.js → coordinator-prompt-E5UGSJES.js} +5 -5
  26. package/dist/{coordinator-prompt-LNWHZ64D.js → coordinator-prompt-ILSULI7C.js} +5 -5
  27. package/dist/{global-workspace-TMMAVRVW.js → global-workspace-44UG64NA.js} +6 -7
  28. package/dist/{global-workspace-BHT4XUAA.js → global-workspace-5PM5LA6E.js} +6 -7
  29. package/dist/index.cjs +1433 -944
  30. package/dist/index.d.cts +117 -2
  31. package/dist/index.d.ts +117 -2
  32. package/dist/index.js +859 -736
  33. package/dist/mcp/run-stdio.cjs +1388 -993
  34. package/dist/mcp/run-stdio.js +798 -765
  35. package/dist/{run-HZTBWGQR.js → run-74S2NZWB.js} +1 -1
  36. package/dist/{run-GPSVV5OH.js → run-JLN5JK7Q.js} +1 -1
  37. package/dist/{thread-store-GHOADGL2.js → thread-store-BUBR24YA.js} +1 -1
  38. package/dist/{thread-store-UJIGMI5J.js → thread-store-XTPFCJAI.js} +1 -1
  39. package/dist/{workspaces-3GO3EDQG.js → workspaces-OVBCSS5Y.js} +7 -8
  40. package/dist/{workspaces-GFPGDGCS.js → workspaces-RXFXQRRF.js} +7 -8
  41. package/dist/{worktree-GBLHEFHR.js → worktree-K2JB53R5.js} +3 -3
  42. package/dist/{worktree-3L2G6PCM.js → worktree-S2N63FLV.js} +3 -3
  43. package/package.json +1 -1
  44. package/dist/chunk-GI7E5733.js +0 -30
  45. package/dist/chunk-S2LL5HA4.js +0 -33
@@ -1,10 +1,13 @@
1
+ import {
2
+ isOrchestratorThread
3
+ } from "./chunk-YTNLOJPK.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-DZYMNW2A.js";
8
11
  import {
9
12
  extractJsonErrorMessage,
10
13
  formatUnknownDetail,
@@ -14,15 +17,21 @@ import {
14
17
  import {
15
18
  claudeChromeEnabled,
16
19
  loadAppSettings,
20
+ resolveAgentExecutable,
17
21
  resolveClaudeExecutable
18
- } from "./chunk-75QR74KM.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
+ resolveCommandBinarySync,
29
+ run,
30
+ withExportedPath
31
+ } from "./chunk-TXQ6K2GR.js";
32
+
33
+ // src/agents/brightsy.ts
34
+ import { existsSync } from "fs";
26
35
 
27
36
  // src/agents/brightsy-targets.ts
28
37
  function encodeBrightsyTarget(type, id, accountId) {
@@ -59,6 +68,11 @@ function normalizeTurnInput(input) {
59
68
  if (typeof input === "string") return { prompt: input };
60
69
  return { prompt: input.prompt, cachedPrefix: input.cachedPrefix?.trim() || void 0 };
61
70
  }
71
+ function dropCachedPrefixOnResume(input, sessionId) {
72
+ const turn = normalizeTurnInput(input);
73
+ if (sessionId) return { prompt: turn.prompt };
74
+ return turn;
75
+ }
62
76
  function flattenTurnInput(input) {
63
77
  const { cachedPrefix, prompt } = normalizeTurnInput(input);
64
78
  if (!cachedPrefix) return prompt;
@@ -241,9 +255,13 @@ async function fetchTeamChatTargets(team) {
241
255
  };
242
256
  }
243
257
  async function listBrightsyChatTargetsViaCli() {
244
- const listed = await run("brightsy", ["chat", "--list-targets", "--json"], {
245
- reject: false
246
- });
258
+ const listed = await run(
259
+ resolveAgentExecutable("brightsy"),
260
+ ["chat", "--list-targets", "--json"],
261
+ {
262
+ reject: false
263
+ }
264
+ );
247
265
  if (listed.exitCode !== 0 || !listed.stdout.trim()) {
248
266
  throw new Error(
249
267
  listed.stderr.trim() || "Failed to list Brightsy chat targets \u2014 is `brightsy` installed and logged in?"
@@ -330,18 +348,32 @@ async function syncCliForTarget(accountId) {
330
348
  var brightsyAdapter = {
331
349
  kind: "brightsy",
332
350
  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
- };
351
+ const brightsy = resolveAgentExecutable("brightsy");
352
+ if (brightsy !== "brightsy") {
353
+ if (!existsSync(brightsy)) {
354
+ return {
355
+ agent: "brightsy",
356
+ installed: false,
357
+ authenticated: false,
358
+ linearMcp: false,
359
+ warnings: [],
360
+ reason: `Brightsy executable not found: ${brightsy}`
361
+ };
362
+ }
363
+ } else {
364
+ const which = await run("which", ["brightsy"], { reject: false });
365
+ if (which.exitCode !== 0) {
366
+ return {
367
+ agent: "brightsy",
368
+ installed: false,
369
+ authenticated: false,
370
+ linearMcp: false,
371
+ warnings: [],
372
+ reason: "brightsy CLI not found on PATH \u2014 npm i -g @brightsy/cli"
373
+ };
374
+ }
343
375
  }
344
- const who = await run("brightsy", ["whoami"], { reject: false });
376
+ const who = await run(brightsy, ["whoami"], { reject: false });
345
377
  const authenticated = who.exitCode === 0 && /logged in as/i.test(who.stdout);
346
378
  return {
347
379
  agent: "brightsy",
@@ -366,7 +398,7 @@ var brightsyAdapter = {
366
398
  target.id
367
399
  ];
368
400
  return {
369
- file: "brightsy",
401
+ file: resolveAgentExecutable("brightsy"),
370
402
  args,
371
403
  cwd: thread.worktreePath,
372
404
  // Piped stdin becomes the message body (avoids ARG_MAX for long seeds).
@@ -383,12 +415,16 @@ var brightsyAdapter = {
383
415
  const target = decodeBrightsyTarget(thread.model);
384
416
  await syncCliForTarget(target.accountId);
385
417
  const args = target.type === "model" ? ["chat", "--model", target.id] : ["chat", "--agent", target.id];
386
- return { file: "brightsy", args, cwd: thread.worktreePath };
418
+ return {
419
+ file: resolveAgentExecutable("brightsy"),
420
+ args,
421
+ cwd: thread.worktreePath
422
+ };
387
423
  }
388
424
  };
389
425
 
390
426
  // src/agents/claude.ts
391
- import { existsSync as existsSync2 } from "fs";
427
+ import { existsSync as existsSync3 } from "fs";
392
428
 
393
429
  // src/agents/claude-mcp.ts
394
430
  function parseMcpList(text) {
@@ -432,12 +468,18 @@ function mcpAuthWarnings(servers) {
432
468
  }
433
469
 
434
470
  // src/agents/injected-mcp.ts
435
- import { existsSync, mkdtempSync, writeFileSync } from "fs";
471
+ import { existsSync as existsSync2, mkdtempSync, writeFileSync } from "fs";
436
472
  import { createRequire } from "module";
437
473
  import { tmpdir } from "os";
438
474
  import { dirname, join } from "path";
439
475
  import { fileURLToPath } from "url";
440
476
 
477
+ // src/mcp/profile.ts
478
+ var SIDEBOARD_MCP_PROFILE_ENV = "SIDEBOARD_MCP_PROFILE";
479
+ function sideboardMcpProfile(env = process.env) {
480
+ return env[SIDEBOARD_MCP_PROFILE_ENV]?.trim().toLowerCase() === "worktree" ? "worktree" : "orchestration";
481
+ }
482
+
441
483
  // src/agents/node-launch.ts
442
484
  function isAsarPath(filePath) {
443
485
  return /\.asar([/\\]|$)/.test(filePath);
@@ -495,6 +537,39 @@ function isBrightsyConnected() {
495
537
  return false;
496
538
  }
497
539
  }
540
+ var BRIGHTSY_WORD = /(?<![a-z0-9_-])brightsy(?![a-z0-9_-])/i;
541
+ function promptMentionsBrightsy(text) {
542
+ return BRIGHTSY_WORD.test(text ?? "");
543
+ }
544
+ function isBrightsyMcpToolName(name) {
545
+ const n = name.toLowerCase();
546
+ return n === "brightsy" || n.startsWith("mcp__brightsy") || n.startsWith("brightsy_");
547
+ }
548
+ function toolInputUsesBrightsyDatasource(input) {
549
+ const ds = input?.datasource;
550
+ return typeof ds === "string" && ds.toLowerCase() === "brightsy";
551
+ }
552
+ function messageUsedBrightsyMcp(msg) {
553
+ if (msg.role === "user" && promptMentionsBrightsy(msg.text)) return true;
554
+ for (const part of msg.parts ?? []) {
555
+ if (part.type !== "tool") continue;
556
+ if (isBrightsyMcpToolName(part.name)) return true;
557
+ if (/present_(schema|files)$/i.test(part.name) && toolInputUsesBrightsyDatasource(part.input)) {
558
+ return true;
559
+ }
560
+ }
561
+ return false;
562
+ }
563
+ function threadRequestsBrightsyMcp(thread) {
564
+ return (thread?.messages ?? []).some(messageUsedBrightsyMcp);
565
+ }
566
+ function shouldInjectBrightsyMcp(thread, opts) {
567
+ if (!(opts?.connected ?? isBrightsyConnected())) return false;
568
+ if (opts?.orchestrator) return true;
569
+ const alwaysOn = opts?.alwaysOnWorktree ?? Boolean(loadAppSettings().brightsy?.injectWorktreeMcp);
570
+ if (alwaysOn) return true;
571
+ return threadRequestsBrightsyMcp(thread);
572
+ }
498
573
  function mcpLaunch(cmd, name, env) {
499
574
  if (cmd === "brightsy-mcp") {
500
575
  return { name, command: "brightsy-mcp", ...env ? { env } : {} };
@@ -540,7 +615,7 @@ function corePackageDir() {
540
615
  }
541
616
  function findSideboardMcpJsEntry() {
542
617
  const override = process.env.SIDEBOARD_MCP_ENTRY?.trim() || process.env.SIDEBOARD_CLI?.trim();
543
- if (override && existsSync(override)) return override;
618
+ if (override && existsSync2(override)) return override;
544
619
  let dir = corePackageDir();
545
620
  for (let i = 0; i < 10; i++) {
546
621
  const candidates = [
@@ -553,7 +628,7 @@ function findSideboardMcpJsEntry() {
553
628
  join(dir, "cli/dist/index.js")
554
629
  ];
555
630
  for (const p of candidates) {
556
- if (existsSync(p)) return p;
631
+ if (existsSync2(p)) return p;
557
632
  }
558
633
  const parent = dirname(dir);
559
634
  if (parent === dir) break;
@@ -584,11 +659,13 @@ async function buildInjectedMcpServers(opts) {
584
659
  const servers = [];
585
660
  if (opts.includeSideboard) {
586
661
  const sideboard = await resolveSideboardMcpServer();
662
+ const orchId = opts.orchestratorThreadId?.trim();
663
+ const profile = orchId ? "orchestration" : "worktree";
587
664
  sideboard.env = {
588
665
  ...sideboard.env ?? {},
589
- SIDEBOARD_APP_DATA: appDataDir()
666
+ SIDEBOARD_APP_DATA: appDataDir(),
667
+ [SIDEBOARD_MCP_PROFILE_ENV]: profile
590
668
  };
591
- const orchId = opts.orchestratorThreadId?.trim();
592
669
  if (orchId) {
593
670
  sideboard.env.SIDEBOARD_ORCHESTRATOR_THREAD_ID = orchId;
594
671
  }
@@ -813,7 +890,7 @@ var claudeAdapter = {
813
890
  async detect() {
814
891
  const claude = resolveClaudeExecutable();
815
892
  if (claude !== "claude") {
816
- if (!existsSync2(claude)) {
893
+ if (!existsSync3(claude)) {
817
894
  return {
818
895
  agent: "claude",
819
896
  installed: false,
@@ -852,9 +929,8 @@ var claudeAdapter = {
852
929
  },
853
930
  async buildTurn(thread, input) {
854
931
  const claude = resolveClaudeExecutable();
855
- const turn = normalizeTurnInput(input);
856
932
  const sessionId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
857
- const effective = sessionId ? { prompt: turn.prompt } : turn;
933
+ const effective = dropCachedPrefixOnResume(input, sessionId);
858
934
  const promptText = flattenTurnInput(effective);
859
935
  const useStdin = promptText.length > CLAUDE_PROMPT_ARG_MAX;
860
936
  if (process.env.SIDEBOARD_DEBUG_CLAUDE_TURN === "1") {
@@ -863,11 +939,13 @@ var claudeAdapter = {
863
939
  );
864
940
  }
865
941
  const mode = permissionMode(thread);
866
- const { isOrchestratorThread } = await import("./global-workspace-TMMAVRVW.js");
867
- const isOrchestrator = isOrchestratorThread(thread);
942
+ const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-44UG64NA.js");
943
+ const isOrchestrator = isOrchestratorThread2(thread);
868
944
  const injectedServers = await buildInjectedMcpServers({
869
945
  includeSideboard: true,
870
- includeBrightsy: isBrightsyConnected(),
946
+ includeBrightsy: shouldInjectBrightsyMcp(thread, {
947
+ orchestrator: isOrchestrator
948
+ }),
871
949
  orchestratorThreadId: isOrchestrator ? thread.id : null
872
950
  });
873
951
  const injectedBrightsyNames = injectedServers.filter((s) => s.name === "brightsy" || s.name.startsWith("brightsy_")).map((s) => s.name);
@@ -1059,7 +1137,7 @@ function parseIssuesJson(raw) {
1059
1137
  }
1060
1138
 
1061
1139
  // src/agents/codex.ts
1062
- import { existsSync as existsSync3, readFileSync, statSync } from "fs";
1140
+ import { existsSync as existsSync4, readFileSync, statSync } from "fs";
1063
1141
  import { homedir } from "os";
1064
1142
  import { join as join2 } from "path";
1065
1143
  var CODEX_PROMPT_ARG_MAX = 2e5;
@@ -1077,9 +1155,14 @@ async function listCodexModels() {
1077
1155
  if (cachedCodexModels && now - cachedCodexModels.at < CODEX_MODEL_CACHE_MS) {
1078
1156
  return cachedCodexModels.models;
1079
1157
  }
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 });
1158
+ const codex = resolveAgentExecutable("codex");
1159
+ if (codex === "codex") {
1160
+ const which = await run("which", ["codex"], { reject: false });
1161
+ if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
1162
+ } else if (!existsSync4(codex)) {
1163
+ return FALLBACK_CODEX_MODELS;
1164
+ }
1165
+ const listed = await run(codex, ["debug", "models"], { reject: false });
1083
1166
  if (listed.exitCode !== 0 || !listed.stdout.trim()) {
1084
1167
  return cachedCodexModels?.models ?? FALLBACK_CODEX_MODELS;
1085
1168
  }
@@ -1118,7 +1201,7 @@ function codexConfigHasNetworkAccess() {
1118
1201
  join2(homedir(), ".config", "codex", "config.toml")
1119
1202
  ];
1120
1203
  for (const path of candidates) {
1121
- if (!existsSync3(path)) continue;
1204
+ if (!existsSync4(path)) continue;
1122
1205
  const text = readFileSync(path, "utf8");
1123
1206
  if (/network_access\s*=\s*true/.test(text)) return true;
1124
1207
  }
@@ -1152,7 +1235,7 @@ function asRecord(value) {
1152
1235
  }
1153
1236
  function codexLooksAuthenticated() {
1154
1237
  const authPath = join2(homedir(), ".codex", "auth.json");
1155
- if (!existsSync3(authPath)) return false;
1238
+ if (!existsSync4(authPath)) return false;
1156
1239
  try {
1157
1240
  return statSync(authPath).size > 2;
1158
1241
  } catch {
@@ -1162,16 +1245,30 @@ function codexLooksAuthenticated() {
1162
1245
  var codexAdapter = {
1163
1246
  kind: "codex",
1164
1247
  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
- };
1248
+ const codex = resolveAgentExecutable("codex");
1249
+ if (codex !== "codex") {
1250
+ if (!existsSync4(codex)) {
1251
+ return {
1252
+ agent: "codex",
1253
+ installed: false,
1254
+ authenticated: false,
1255
+ linearMcp: false,
1256
+ warnings: [],
1257
+ reason: `Codex executable not found: ${codex}`
1258
+ };
1259
+ }
1260
+ } else {
1261
+ const which = await run("which", ["codex"], { reject: false, timeoutMs: 3e3 });
1262
+ if (which.exitCode !== 0) {
1263
+ return {
1264
+ agent: "codex",
1265
+ installed: false,
1266
+ authenticated: false,
1267
+ linearMcp: false,
1268
+ warnings: [],
1269
+ reason: "codex CLI not found on PATH"
1270
+ };
1271
+ }
1175
1272
  }
1176
1273
  const authenticated = codexLooksAuthenticated();
1177
1274
  const linearMcp = false;
@@ -1191,22 +1288,24 @@ var codexAdapter = {
1191
1288
  };
1192
1289
  },
1193
1290
  async buildTurn(thread, input) {
1194
- const prompt = flattenTurnInput(input);
1195
1291
  const sessionId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
1292
+ const prompt = flattenTurnInput(dropCachedPrefixOnResume(input, sessionId));
1196
1293
  const useStdin = prompt.length > CODEX_PROMPT_ARG_MAX;
1197
1294
  const promptArg = useStdin ? "-" : prompt;
1198
1295
  if (process.env.SIDEBOARD_DEBUG_CODEX_TURN === "1") {
1199
- const { cachedPrefix } = normalizeTurnInput(input);
1200
1296
  console.error(
1201
- `[sideboard/codex] promptChars=${prompt.length} resumed=${Boolean(sessionId)} stdin=${useStdin} hasPrefix=${Boolean(cachedPrefix)}`
1297
+ `[sideboard/codex] promptChars=${prompt.length} resumed=${Boolean(sessionId)} stdin=${useStdin} hasPrefix=${prompt.includes("Current request:")}`
1202
1298
  );
1203
1299
  }
1204
1300
  const mode = permissionMode(thread);
1205
1301
  const model = thread.model?.trim();
1302
+ const isOrchestrator = isOrchestratorThread(thread);
1206
1303
  const injected = await buildInjectedMcpServers({
1207
1304
  includeSideboard: true,
1208
- includeBrightsy: isBrightsyConnected(),
1209
- orchestratorThreadId: thread.sourceType === "orchestration" ? thread.id : null
1305
+ includeBrightsy: shouldInjectBrightsyMcp(thread, {
1306
+ orchestrator: isOrchestrator
1307
+ }),
1308
+ orchestratorThreadId: isOrchestrator ? thread.id : null
1210
1309
  });
1211
1310
  const mcpOverrides = toCodexMcpConfigArgs(injected);
1212
1311
  const execOpts = [
@@ -1226,7 +1325,7 @@ var codexAdapter = {
1226
1325
  ];
1227
1326
  const args = sessionId ? ["exec", ...execOpts, "resume", sessionId, promptArg] : ["exec", ...execOpts, promptArg];
1228
1327
  return {
1229
- file: "codex",
1328
+ file: resolveAgentExecutable("codex"),
1230
1329
  args,
1231
1330
  cwd: thread.worktreePath,
1232
1331
  stdin: useStdin ? `${prompt}
@@ -1322,16 +1421,17 @@ var codexAdapter = {
1322
1421
  return cached;
1323
1422
  },
1324
1423
  async buildAttach(thread) {
1424
+ const codex = resolveAgentExecutable("codex");
1325
1425
  const sessionId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
1326
1426
  if (sessionId) {
1327
1427
  return {
1328
- file: "codex",
1428
+ file: codex,
1329
1429
  args: ["exec", "--cd", thread.worktreePath, "resume", sessionId],
1330
1430
  cwd: thread.worktreePath
1331
1431
  };
1332
1432
  }
1333
1433
  return {
1334
- file: "codex",
1434
+ file: codex,
1335
1435
  args: ["--cd", thread.worktreePath],
1336
1436
  cwd: thread.worktreePath
1337
1437
  };
@@ -1339,7 +1439,7 @@ var codexAdapter = {
1339
1439
  async listLinearIssues(_repoPath) {
1340
1440
  const prompt = "List my assigned Linear issues as JSON array only: id, identifier, title, url, labels.";
1341
1441
  const { stdout, exitCode } = await run(
1342
- "codex",
1442
+ resolveAgentExecutable("codex"),
1343
1443
  [
1344
1444
  "exec",
1345
1445
  "--json",
@@ -1364,7 +1464,7 @@ var codexAdapter = {
1364
1464
  };
1365
1465
 
1366
1466
  // src/agents/cursor.ts
1367
- import { existsSync as existsSync4 } from "fs";
1467
+ import { existsSync as existsSync5 } from "fs";
1368
1468
  import { createRequire as createRequire2 } from "module";
1369
1469
  import { dirname as dirname2, join as join3 } from "path";
1370
1470
  import { fileURLToPath as fileURLToPath2 } from "url";
@@ -1437,7 +1537,7 @@ function cursorRunnerPath() {
1437
1537
  join3(root, "src", "agents", "cursor-runner.ts")
1438
1538
  ];
1439
1539
  for (const candidate of candidates) {
1440
- if (existsSync4(candidate)) return candidate;
1540
+ if (existsSync5(candidate)) return candidate;
1441
1541
  }
1442
1542
  return candidates[0];
1443
1543
  }
@@ -1464,13 +1564,16 @@ var cursorAdapter = {
1464
1564
  };
1465
1565
  },
1466
1566
  async buildTurn(thread, input) {
1467
- const prompt = flattenTurnInput(input);
1468
1567
  const agentId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
1568
+ const prompt = flattenTurnInput(dropCachedPrefixOnResume(input, agentId));
1469
1569
  const apiKey = resolveCursorApiKey() || void 0;
1570
+ const isOrchestrator = isOrchestratorThread(thread);
1470
1571
  const injected = await buildInjectedMcpServers({
1471
1572
  includeSideboard: true,
1472
- includeBrightsy: isBrightsyConnected(),
1473
- orchestratorThreadId: thread.sourceType === "orchestration" ? thread.id : null
1573
+ includeBrightsy: shouldInjectBrightsyMcp(thread, {
1574
+ orchestrator: isOrchestrator
1575
+ }),
1576
+ orchestratorThreadId: isOrchestrator ? thread.id : null
1474
1577
  });
1475
1578
  const mcpServers = toCursorMcpServers(injected);
1476
1579
  const req = {
@@ -1516,6 +1619,7 @@ var cursorAdapter = {
1516
1619
  };
1517
1620
 
1518
1621
  // src/agents/opencode.ts
1622
+ import { existsSync as existsSync6 } from "fs";
1519
1623
  var FALLBACK_OPENCODE_MODELS = [
1520
1624
  { id: "opencode/big-pickle", displayName: "opencode \xB7 big-pickle" },
1521
1625
  {
@@ -1552,9 +1656,14 @@ async function listOpencodeModels() {
1552
1656
  if (cachedOpencodeModels && now - cachedOpencodeModels.at < OPENCODE_MODEL_CACHE_MS) {
1553
1657
  return cachedOpencodeModels.models;
1554
1658
  }
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 });
1659
+ const opencode = resolveAgentExecutable("opencode");
1660
+ if (opencode === "opencode") {
1661
+ const which = await run("which", ["opencode"], { reject: false });
1662
+ if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
1663
+ } else if (!existsSync6(opencode)) {
1664
+ return FALLBACK_OPENCODE_MODELS;
1665
+ }
1666
+ const listed = await run(opencode, ["models"], { reject: false });
1558
1667
  if (listed.exitCode !== 0 || !listed.stdout.trim()) {
1559
1668
  return cachedOpencodeModels?.models ?? FALLBACK_OPENCODE_MODELS;
1560
1669
  }
@@ -1584,20 +1693,34 @@ function usageFromOpencode(tokens) {
1584
1693
  var opencodeAdapter = {
1585
1694
  kind: "opencode",
1586
1695
  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
- };
1696
+ const opencode = resolveAgentExecutable("opencode");
1697
+ if (opencode !== "opencode") {
1698
+ if (!existsSync6(opencode)) {
1699
+ return {
1700
+ agent: "opencode",
1701
+ installed: false,
1702
+ authenticated: false,
1703
+ linearMcp: false,
1704
+ warnings: [],
1705
+ reason: `OpenCode executable not found: ${opencode}`
1706
+ };
1707
+ }
1708
+ } else {
1709
+ const which = await run("which", ["opencode"], { reject: false });
1710
+ if (which.exitCode !== 0) {
1711
+ return {
1712
+ agent: "opencode",
1713
+ installed: false,
1714
+ authenticated: false,
1715
+ linearMcp: false,
1716
+ warnings: [],
1717
+ reason: "opencode CLI not found on PATH"
1718
+ };
1719
+ }
1597
1720
  }
1598
- const auth = await run("opencode", ["auth", "list"], { reject: false });
1721
+ const auth = await run(opencode, ["auth", "list"], { reject: false });
1599
1722
  const authenticated = auth.exitCode === 0 && auth.stdout.trim().length > 0;
1600
- const mcp = await run("opencode", ["mcp", "list"], { reject: false });
1723
+ const mcp = await run(opencode, ["mcp", "list"], { reject: false });
1601
1724
  const linearMcp = /linear/i.test(mcp.stdout + mcp.stderr);
1602
1725
  return {
1603
1726
  agent: "opencode",
@@ -1609,8 +1732,8 @@ var opencodeAdapter = {
1609
1732
  };
1610
1733
  },
1611
1734
  async buildTurn(thread, input) {
1612
- const prompt = flattenTurnInput(input);
1613
1735
  const sessionId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
1736
+ const prompt = flattenTurnInput(dropCachedPrefixOnResume(input, sessionId));
1614
1737
  const mode = permissionMode(thread);
1615
1738
  const model = thread.model?.trim();
1616
1739
  const args = [
@@ -1626,14 +1749,17 @@ var opencodeAdapter = {
1626
1749
  if (model) {
1627
1750
  args.push("--model", model);
1628
1751
  }
1752
+ const isOrchestrator = isOrchestratorThread(thread);
1629
1753
  const injected = await buildInjectedMcpServers({
1630
1754
  includeSideboard: true,
1631
- includeBrightsy: isBrightsyConnected(),
1632
- orchestratorThreadId: thread.sourceType === "orchestration" ? thread.id : null
1755
+ includeBrightsy: shouldInjectBrightsyMcp(thread, {
1756
+ orchestrator: isOrchestrator
1757
+ }),
1758
+ orchestratorThreadId: isOrchestrator ? thread.id : null
1633
1759
  });
1634
1760
  const mcpContent = injected.length > 0 ? toOpencodeMcpConfigContent(injected) : null;
1635
1761
  return {
1636
- file: "opencode",
1762
+ file: resolveAgentExecutable("opencode"),
1637
1763
  args,
1638
1764
  cwd: thread.worktreePath,
1639
1765
  // `opencode run` treats non-TTY stdin as the message body when no positional
@@ -1709,7 +1835,7 @@ var opencodeAdapter = {
1709
1835
  async resolveSessionId(worktreePath, cached) {
1710
1836
  const cachedId = cached?.trim() || null;
1711
1837
  const listed = await run(
1712
- "opencode",
1838
+ resolveAgentExecutable("opencode"),
1713
1839
  ["session", "list", "--format", "json"],
1714
1840
  { cwd: worktreePath, reject: false }
1715
1841
  );
@@ -1740,7 +1866,7 @@ var opencodeAdapter = {
1740
1866
  const args = ["--dir", thread.worktreePath];
1741
1867
  if (sessionId) args.push("--session", sessionId);
1742
1868
  return {
1743
- file: "opencode",
1869
+ file: resolveAgentExecutable("opencode"),
1744
1870
  args,
1745
1871
  cwd: thread.worktreePath,
1746
1872
  env: {
@@ -1751,7 +1877,7 @@ var opencodeAdapter = {
1751
1877
  async listLinearIssues(_repoPath) {
1752
1878
  const prompt = "List my assigned Linear issues as JSON array only: id, identifier, title, url, labels.";
1753
1879
  const { stdout, exitCode } = await run(
1754
- "opencode",
1880
+ resolveAgentExecutable("opencode"),
1755
1881
  ["run", prompt, "--format", "json"],
1756
1882
  {
1757
1883
  reject: false,
@@ -2006,15 +2132,48 @@ var SETUP = {
2006
2132
  npmPackage: "@brightsy/cli"
2007
2133
  }
2008
2134
  };
2135
+ var CLI_BIN = {
2136
+ claude: "claude",
2137
+ codex: "codex",
2138
+ opencode: "opencode",
2139
+ brightsy: "brightsy"
2140
+ };
2009
2141
  function getAgentSetupInfo(agent) {
2010
2142
  return SETUP[agent];
2011
2143
  }
2012
2144
  function listAgentSetupInfo() {
2013
2145
  return Object.values(SETUP);
2014
2146
  }
2015
- async function openInSystemTerminal(command) {
2016
- ensureAgentPath();
2147
+ var CLI_LOGIN_AGENTS = /* @__PURE__ */ new Set([
2148
+ "claude",
2149
+ "codex",
2150
+ "opencode",
2151
+ "brightsy"
2152
+ ]);
2153
+ function resolveLoginCommand(agent) {
2154
+ const info = getAgentSetupInfo(agent);
2155
+ if (!info.loginCommand) return null;
2156
+ if (!CLI_LOGIN_AGENTS.has(agent)) return info.loginCommand;
2157
+ const exe = resolveAgentExecutable(agent);
2158
+ return info.loginCommand.replace(/^\S+/, exe);
2159
+ }
2160
+ async function prepareTerminalCommand(command) {
2161
+ enrichPathWithNpmGlobalBin();
2017
2162
  const trimmed = command.trim();
2163
+ if (!trimmed) return trimmed;
2164
+ if (/^(export\s+PATH=|PATH=)/.test(trimmed)) return trimmed;
2165
+ const match = /^(\S+)(\s[\s\S]*)?$/.exec(trimmed);
2166
+ const bin = match?.[1];
2167
+ let whichPath = null;
2168
+ if (bin && !bin.includes("/") && !bin.includes("\\")) {
2169
+ const which = await run("which", [bin], { reject: false, timeoutMs: 3e3 });
2170
+ whichPath = which.exitCode === 0 ? which.stdout.trim() : null;
2171
+ }
2172
+ const resolved = resolveCommandBinarySync(trimmed, whichPath);
2173
+ return withExportedPath(resolved, process.env.PATH ?? "");
2174
+ }
2175
+ async function openInSystemTerminal(command) {
2176
+ const trimmed = (await prepareTerminalCommand(command)).trim();
2018
2177
  if (!trimmed) throw new Error("Command is empty");
2019
2178
  if (process.platform === "darwin") {
2020
2179
  const escaped = trimmed.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
@@ -2075,7 +2234,7 @@ async function installAgent(agent) {
2075
2234
  message: `Opened Terminal to run: ${info.installCommand}`
2076
2235
  };
2077
2236
  }
2078
- ensureAgentPath();
2237
+ enrichPathWithNpmGlobalBin();
2079
2238
  const result = await run("npm", ["install", "-g", info.npmPackage], { reject: false });
2080
2239
  const ok = result.exitCode === 0;
2081
2240
  if (!ok) {
@@ -2101,29 +2260,38 @@ async function installAgent(agent) {
2101
2260
  };
2102
2261
  }
2103
2262
  }
2263
+ enrichPathWithNpmGlobalBin();
2264
+ const cliBin = agent === "cursor" ? null : CLI_BIN[agent];
2265
+ let binPath = null;
2266
+ if (cliBin) {
2267
+ const which = await run("which", [cliBin], { reject: false, timeoutMs: 3e3 });
2268
+ binPath = which.exitCode === 0 ? which.stdout.trim().split(/\r?\n/).find(Boolean) ?? null : null;
2269
+ }
2104
2270
  return {
2105
2271
  ok: true,
2106
2272
  command: info.installCommand,
2107
2273
  exitCode: 0,
2108
2274
  stdout: result.stdout,
2109
2275
  stderr: result.stderr,
2110
- message: `Installed ${info.npmPackage}`
2276
+ 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
2277
  };
2112
2278
  }
2113
2279
  async function loginAgent(agent) {
2114
2280
  const info = getAgentSetupInfo(agent);
2115
- if (!info.loginCommand) {
2281
+ const loginCommand = resolveLoginCommand(agent);
2282
+ if (!loginCommand) {
2116
2283
  return {
2117
2284
  ok: true,
2118
2285
  message: info.kind === "bundled-sdk" || info.kind === "api-key" ? info.summary : `No login command for ${agent}`
2119
2286
  };
2120
2287
  }
2121
- await openInSystemTerminal(info.loginCommand);
2288
+ const prepared = await prepareTerminalCommand(loginCommand);
2289
+ await openInSystemTerminal(prepared);
2122
2290
  return {
2123
2291
  ok: true,
2124
2292
  openedTerminal: true,
2125
- command: info.loginCommand,
2126
- message: `Opened Terminal to run: ${info.loginCommand}`
2293
+ command: prepared,
2294
+ message: `Opened Terminal to run: ${prepared}`
2127
2295
  };
2128
2296
  }
2129
2297
 
@@ -2146,6 +2314,7 @@ export {
2146
2314
  encodeBrightsyTarget,
2147
2315
  decodeBrightsyTarget,
2148
2316
  normalizeTurnInput,
2317
+ dropCachedPrefixOnResume,
2149
2318
  flattenTurnInput,
2150
2319
  buildCachedUserContent,
2151
2320
  buildClaudeStreamJsonUserMessage,
@@ -2159,9 +2328,14 @@ export {
2159
2328
  sanitizeMcpServerName,
2160
2329
  mcpAllowTools,
2161
2330
  mcpAuthWarnings,
2331
+ SIDEBOARD_MCP_PROFILE_ENV,
2332
+ sideboardMcpProfile,
2162
2333
  SIDEBOARD_MCP_ALLOWED_TOOLS,
2163
2334
  BRIGHTSY_MCP_ALLOWED_TOOLS,
2164
2335
  isBrightsyConnected,
2336
+ promptMentionsBrightsy,
2337
+ threadRequestsBrightsyMcp,
2338
+ shouldInjectBrightsyMcp,
2165
2339
  brightsyMcpAllowedTools,
2166
2340
  writeInjectedMcpConfig,
2167
2341
  PLAN_MODE_INSTRUCTION,
@@ -2182,6 +2356,8 @@ export {
2182
2356
  resolveQuotaFallbackAgent,
2183
2357
  getAgentSetupInfo,
2184
2358
  listAgentSetupInfo,
2359
+ resolveLoginCommand,
2360
+ prepareTerminalCommand,
2185
2361
  openInSystemTerminal,
2186
2362
  installAgent,
2187
2363
  loginAgent,