@sideboard-ai/core 0.1.30 → 0.1.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -4538,6 +4538,35 @@ var init_claude = __esm({
4538
4538
  });
4539
4539
 
4540
4540
  // src/agents/codex.ts
4541
+ async function listCodexModels() {
4542
+ const now = Date.now();
4543
+ if (cachedCodexModels && now - cachedCodexModels.at < CODEX_MODEL_CACHE_MS) {
4544
+ return cachedCodexModels.models;
4545
+ }
4546
+ const which = await run("which", ["codex"], { reject: false });
4547
+ if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
4548
+ const listed = await run("codex", ["debug", "models"], { reject: false });
4549
+ if (listed.exitCode !== 0 || !listed.stdout.trim()) {
4550
+ return cachedCodexModels?.models ?? FALLBACK_CODEX_MODELS;
4551
+ }
4552
+ try {
4553
+ const parsed = JSON.parse(listed.stdout);
4554
+ const rows = Array.isArray(parsed.models) ? parsed.models : [];
4555
+ const preferred = rows.filter((m) => (m.visibility ?? "list") === "list");
4556
+ const source = preferred.length > 0 ? preferred : rows;
4557
+ const models = source.map((m) => ({
4558
+ id: (m.slug || "").trim(),
4559
+ displayName: (m.display_name || m.slug || "").trim(),
4560
+ description: m.description,
4561
+ priority: typeof m.priority === "number" ? m.priority : 999
4562
+ })).filter((m) => m.id).sort((a, b) => a.priority - b.priority).map(({ id, displayName, description }) => ({ id, displayName, description }));
4563
+ if (models.length === 0) return FALLBACK_CODEX_MODELS;
4564
+ cachedCodexModels = { at: now, models };
4565
+ return models;
4566
+ } catch {
4567
+ return cachedCodexModels?.models ?? FALLBACK_CODEX_MODELS;
4568
+ }
4569
+ }
4541
4570
  function usageFromCodex(usage) {
4542
4571
  if (!usage) return null;
4543
4572
  const inputTokens = Number(usage.input_tokens ?? 0);
@@ -4561,7 +4590,7 @@ function codexConfigHasNetworkAccess() {
4561
4590
  }
4562
4591
  return false;
4563
4592
  }
4564
- var import_node_fs12, import_node_os7, import_node_path12, CODEX_PROMPT_ARG_MAX, codexAdapter;
4593
+ var import_node_fs12, import_node_os7, import_node_path12, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
4565
4594
  var init_codex = __esm({
4566
4595
  "src/agents/codex.ts"() {
4567
4596
  "use strict";
@@ -4572,6 +4601,15 @@ var init_codex = __esm({
4572
4601
  init_turn_input();
4573
4602
  init_types();
4574
4603
  CODEX_PROMPT_ARG_MAX = 2e5;
4604
+ FALLBACK_CODEX_MODELS = [
4605
+ { id: "gpt-5.6-sol", displayName: "GPT-5.6 Sol" },
4606
+ { id: "gpt-5.6-terra", displayName: "GPT-5.6 Terra" },
4607
+ { id: "gpt-5.6-luna", displayName: "GPT-5.6 Luna" },
4608
+ { id: "gpt-5.5", displayName: "GPT-5.5" },
4609
+ { id: "gpt-5.2", displayName: "GPT-5.2" }
4610
+ ];
4611
+ cachedCodexModels = null;
4612
+ CODEX_MODEL_CACHE_MS = 5 * 60 * 1e3;
4575
4613
  codexAdapter = {
4576
4614
  kind: "codex",
4577
4615
  async detect() {
@@ -4617,6 +4655,7 @@ var init_codex = __esm({
4617
4655
  );
4618
4656
  }
4619
4657
  const mode = permissionMode(thread);
4658
+ const model = thread.model?.trim();
4620
4659
  const args = [
4621
4660
  "exec",
4622
4661
  ...sessionId ? ["resume", sessionId] : [],
@@ -4627,7 +4666,8 @@ var init_codex = __esm({
4627
4666
  "--sandbox",
4628
4667
  mode.codexSandbox,
4629
4668
  "--ask-for-approval",
4630
- "never"
4669
+ "never",
4670
+ ...model ? ["--model", model] : []
4631
4671
  ];
4632
4672
  return {
4633
4673
  file: "codex",
@@ -4808,6 +4848,35 @@ function resolveCursorApiKey() {
4808
4848
  if (fromEnv) return fromEnv;
4809
4849
  return (loadAppSettings().environment.CURSOR_API_KEY || "").trim();
4810
4850
  }
4851
+ function isCursorAutoModel(model) {
4852
+ const id = (model ?? "").trim().toLowerCase();
4853
+ return !id || id === "default" || id === "auto";
4854
+ }
4855
+ function resolveCursorModelId(model) {
4856
+ if (isCursorAutoModel(model)) return "default";
4857
+ return model.trim();
4858
+ }
4859
+ async function listCursorModels() {
4860
+ const now = Date.now();
4861
+ if (cachedModels && now - cachedModels.at < MODEL_CACHE_MS) {
4862
+ return cachedModels.models;
4863
+ }
4864
+ const apiKey = resolveCursorApiKey();
4865
+ if (!apiKey) return FALLBACK_CURSOR_MODELS;
4866
+ try {
4867
+ const listed = await import_sdk.Cursor.models.list({ apiKey });
4868
+ const models = listed.map((m) => ({
4869
+ id: m.id,
4870
+ displayName: m.displayName || m.id,
4871
+ description: m.description
4872
+ })).filter((m) => Boolean(m.id));
4873
+ if (models.length === 0) return FALLBACK_CURSOR_MODELS;
4874
+ cachedModels = { at: now, models };
4875
+ return models;
4876
+ } catch {
4877
+ return cachedModels?.models ?? FALLBACK_CURSOR_MODELS;
4878
+ }
4879
+ }
4811
4880
  function entryDir() {
4812
4881
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
4813
4882
  if (cjsDir) return cjsDir;
@@ -4839,7 +4908,7 @@ function cursorRunnerPath() {
4839
4908
  }
4840
4909
  return candidates[0];
4841
4910
  }
4842
- var import_node_fs13, import_node_module2, import_node_path13, import_node_url2, import_sdk, import_meta2, cursorAdapter;
4911
+ var import_node_fs13, import_node_module2, import_node_path13, import_node_url2, import_sdk, import_meta2, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
4843
4912
  var init_cursor = __esm({
4844
4913
  "src/agents/cursor.ts"() {
4845
4914
  "use strict";
@@ -4854,6 +4923,13 @@ var init_cursor = __esm({
4854
4923
  init_turn_input();
4855
4924
  init_cursor_events();
4856
4925
  import_meta2 = {};
4926
+ FALLBACK_CURSOR_MODELS = [
4927
+ { id: "default", displayName: "Auto" },
4928
+ { id: "composer-2.5", displayName: "Composer 2.5" },
4929
+ { id: "composer-2", displayName: "Composer 2" }
4930
+ ];
4931
+ cachedModels = null;
4932
+ MODEL_CACHE_MS = 5 * 60 * 1e3;
4857
4933
  cursorAdapter = {
4858
4934
  kind: "cursor",
4859
4935
  async detect() {
@@ -4904,12 +4980,16 @@ var init_cursor = __esm({
4904
4980
  };
4905
4981
  const runner = cursorRunnerPath();
4906
4982
  const isTs = runner.endsWith(".ts");
4983
+ const whichNode = await run("which", ["node"], { reject: false });
4984
+ const nodeBin = whichNode.exitCode === 0 && whichNode.stdout.trim() ? whichNode.stdout.trim() : null;
4985
+ const file = nodeBin || process.execPath;
4907
4986
  return {
4908
- file: process.execPath,
4987
+ file,
4909
4988
  args: isTs ? ["--import", "tsx", runner] : [runner],
4910
4989
  cwd: thread.worktreePath,
4911
4990
  stdin: JSON.stringify(req),
4912
4991
  env: {
4992
+ ...nodeBin ? {} : { ELECTRON_RUN_AS_NODE: "1" },
4913
4993
  ...apiKey ? { CURSOR_API_KEY: apiKey } : {}
4914
4994
  }
4915
4995
  };
@@ -4934,6 +5014,46 @@ var init_cursor = __esm({
4934
5014
  });
4935
5015
 
4936
5016
  // src/agents/opencode.ts
5017
+ function displayNameFromOpencodeId(id) {
5018
+ const slash = id.indexOf("/");
5019
+ if (slash <= 0) return id;
5020
+ const provider = id.slice(0, slash);
5021
+ const name = id.slice(slash + 1);
5022
+ return `${provider} \xB7 ${name}`;
5023
+ }
5024
+ function sortOpencodeModelIds(ids) {
5025
+ return [...ids].sort((a, b) => {
5026
+ const aLatest = /latest|~/.test(a) ? 0 : 1;
5027
+ const bLatest = /latest|~/.test(b) ? 0 : 1;
5028
+ if (aLatest !== bLatest) return aLatest - bLatest;
5029
+ const aOc = a.startsWith("opencode/") ? 0 : 1;
5030
+ const bOc = b.startsWith("opencode/") ? 0 : 1;
5031
+ if (aOc !== bOc) return aOc - bOc;
5032
+ return a.localeCompare(b);
5033
+ });
5034
+ }
5035
+ async function listOpencodeModels() {
5036
+ const now = Date.now();
5037
+ if (cachedOpencodeModels && now - cachedOpencodeModels.at < OPENCODE_MODEL_CACHE_MS) {
5038
+ return cachedOpencodeModels.models;
5039
+ }
5040
+ const which = await run("which", ["opencode"], { reject: false });
5041
+ if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
5042
+ const listed = await run("opencode", ["models"], { reject: false });
5043
+ if (listed.exitCode !== 0 || !listed.stdout.trim()) {
5044
+ return cachedOpencodeModels?.models ?? FALLBACK_OPENCODE_MODELS;
5045
+ }
5046
+ const ids = listed.stdout.split("\n").map((l) => l.trim()).filter((l) => /^[\w.~@+-]+\/[\w.~@+/-]+$/.test(l));
5047
+ const unique = [...new Set(ids)];
5048
+ if (unique.length === 0) return FALLBACK_OPENCODE_MODELS;
5049
+ const OPENCODE_PICKER_LIMIT = 60;
5050
+ const models = sortOpencodeModelIds(unique).slice(0, OPENCODE_PICKER_LIMIT).map((id) => ({
5051
+ id,
5052
+ displayName: displayNameFromOpencodeId(id)
5053
+ }));
5054
+ cachedOpencodeModels = { at: now, models };
5055
+ return models;
5056
+ }
4937
5057
  function usageFromOpencode(tokens) {
4938
5058
  if (!tokens) return null;
4939
5059
  const inputTokens = Number(tokens.input ?? 0);
@@ -4946,13 +5066,26 @@ function usageFromOpencode(tokens) {
4946
5066
  cacheWriteTokens: tokens.cache?.write ? Number(tokens.cache.write) : void 0
4947
5067
  };
4948
5068
  }
4949
- var opencodeAdapter;
5069
+ var FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
4950
5070
  var init_opencode = __esm({
4951
5071
  "src/agents/opencode.ts"() {
4952
5072
  "use strict";
4953
5073
  init_run();
4954
5074
  init_turn_input();
4955
5075
  init_types();
5076
+ FALLBACK_OPENCODE_MODELS = [
5077
+ { id: "opencode/big-pickle", displayName: "opencode \xB7 big-pickle" },
5078
+ {
5079
+ id: "openrouter/~anthropic/claude-sonnet-latest",
5080
+ displayName: "openrouter \xB7 claude-sonnet-latest"
5081
+ },
5082
+ {
5083
+ id: "openrouter/~openai/gpt-latest",
5084
+ displayName: "openrouter \xB7 gpt-latest"
5085
+ }
5086
+ ];
5087
+ cachedOpencodeModels = null;
5088
+ OPENCODE_MODEL_CACHE_MS = 5 * 60 * 1e3;
4956
5089
  opencodeAdapter = {
4957
5090
  kind: "opencode",
4958
5091
  async detect() {
@@ -4984,6 +5117,7 @@ var init_opencode = __esm({
4984
5117
  const prompt = flattenTurnInput(input);
4985
5118
  const sessionId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
4986
5119
  const mode = permissionMode(thread);
5120
+ const model = thread.model?.trim();
4987
5121
  const args = [
4988
5122
  "run",
4989
5123
  "--dir",
@@ -4994,6 +5128,9 @@ var init_opencode = __esm({
4994
5128
  if (sessionId) {
4995
5129
  args.push("--session", sessionId);
4996
5130
  }
5131
+ if (model) {
5132
+ args.push("--model", model);
5133
+ }
4997
5134
  return {
4998
5135
  file: "opencode",
4999
5136
  args,
@@ -5121,6 +5258,183 @@ var init_opencode = __esm({
5121
5258
  }
5122
5259
  });
5123
5260
 
5261
+ // src/agents/install.ts
5262
+ function getAgentSetupInfo(agent) {
5263
+ return SETUP[agent];
5264
+ }
5265
+ function listAgentSetupInfo() {
5266
+ return Object.values(SETUP);
5267
+ }
5268
+ async function openInSystemTerminal(command) {
5269
+ ensureAgentPath();
5270
+ const trimmed = command.trim();
5271
+ if (!trimmed) throw new Error("Command is empty");
5272
+ if (process.platform === "darwin") {
5273
+ const escaped = trimmed.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
5274
+ const script = `tell application "Terminal" to do script "${escaped}"`;
5275
+ const result = await run("osascript", ["-e", script], { reject: false });
5276
+ if (result.exitCode !== 0) {
5277
+ throw new Error(result.stderr.trim() || result.stdout.trim() || "Failed to open Terminal");
5278
+ }
5279
+ await run("osascript", ["-e", 'tell application "Terminal" to activate'], {
5280
+ reject: false
5281
+ });
5282
+ return;
5283
+ }
5284
+ if (process.platform === "win32") {
5285
+ const result = await run(
5286
+ "cmd.exe",
5287
+ ["/c", "start", "cmd.exe", "/k", trimmed],
5288
+ { reject: false }
5289
+ );
5290
+ if (result.exitCode !== 0) {
5291
+ throw new Error(result.stderr.trim() || result.stdout.trim() || "Failed to open cmd");
5292
+ }
5293
+ return;
5294
+ }
5295
+ const candidates = [
5296
+ { file: "gnome-terminal", args: ["--", "bash", "-lc", `${trimmed}; exec bash`] },
5297
+ { file: "x-terminal-emulator", args: ["-e", "bash", "-lc", `${trimmed}; exec bash`] },
5298
+ { file: "konsole", args: ["-e", "bash", "-lc", `${trimmed}; exec bash`] },
5299
+ { file: "xterm", args: ["-e", "bash", "-lc", `${trimmed}; exec bash`] }
5300
+ ];
5301
+ for (const c of candidates) {
5302
+ const which = await run("which", [c.file], { reject: false });
5303
+ if (which.exitCode !== 0 || !which.stdout.trim()) continue;
5304
+ const result = await run(c.file, c.args, { reject: false });
5305
+ if (result.exitCode === 0) return;
5306
+ }
5307
+ throw new Error(
5308
+ `No terminal found to run: ${trimmed}. Install gnome-terminal (or similar), or run the command manually.`
5309
+ );
5310
+ }
5311
+ async function installAgent(agent) {
5312
+ const info = getAgentSetupInfo(agent);
5313
+ if (info.kind === "bundled-sdk" || info.kind === "api-key") {
5314
+ return {
5315
+ ok: true,
5316
+ message: info.summary
5317
+ };
5318
+ }
5319
+ if (!info.installCommand) {
5320
+ return { ok: false, message: `No install command for ${agent}` };
5321
+ }
5322
+ if (/curl\s| \|\s*bash/.test(info.installCommand) || !info.npmPackage) {
5323
+ await openInSystemTerminal(info.installCommand);
5324
+ return {
5325
+ ok: true,
5326
+ openedTerminal: true,
5327
+ command: info.installCommand,
5328
+ message: `Opened Terminal to run: ${info.installCommand}`
5329
+ };
5330
+ }
5331
+ ensureAgentPath();
5332
+ const result = await run("npm", ["install", "-g", info.npmPackage], { reject: false });
5333
+ const ok = result.exitCode === 0;
5334
+ if (!ok) {
5335
+ try {
5336
+ await openInSystemTerminal(info.installCommand);
5337
+ return {
5338
+ ok: false,
5339
+ openedTerminal: true,
5340
+ command: info.installCommand,
5341
+ exitCode: result.exitCode,
5342
+ stdout: result.stdout,
5343
+ stderr: result.stderr,
5344
+ message: `npm install failed (exit ${result.exitCode}). Opened Terminal with: ${info.installCommand}`
5345
+ };
5346
+ } catch {
5347
+ return {
5348
+ ok: false,
5349
+ command: info.installCommand,
5350
+ exitCode: result.exitCode,
5351
+ stdout: result.stdout,
5352
+ stderr: result.stderr,
5353
+ message: result.stderr.trim() || result.stdout.trim() || `npm install failed (exit ${result.exitCode})`
5354
+ };
5355
+ }
5356
+ }
5357
+ return {
5358
+ ok: true,
5359
+ command: info.installCommand,
5360
+ exitCode: 0,
5361
+ stdout: result.stdout,
5362
+ stderr: result.stderr,
5363
+ message: `Installed ${info.npmPackage}`
5364
+ };
5365
+ }
5366
+ async function loginAgent(agent) {
5367
+ const info = getAgentSetupInfo(agent);
5368
+ if (!info.loginCommand) {
5369
+ return {
5370
+ ok: true,
5371
+ message: info.kind === "bundled-sdk" || info.kind === "api-key" ? info.summary : `No login command for ${agent}`
5372
+ };
5373
+ }
5374
+ await openInSystemTerminal(info.loginCommand);
5375
+ return {
5376
+ ok: true,
5377
+ openedTerminal: true,
5378
+ command: info.loginCommand,
5379
+ message: `Opened Terminal to run: ${info.loginCommand}`
5380
+ };
5381
+ }
5382
+ var SETUP;
5383
+ var init_install = __esm({
5384
+ "src/agents/install.ts"() {
5385
+ "use strict";
5386
+ init_run();
5387
+ init_path();
5388
+ SETUP = {
5389
+ claude: {
5390
+ agent: "claude",
5391
+ kind: "cli",
5392
+ summary: "Install the Claude Code CLI, then complete login in a terminal.",
5393
+ docsUrl: "https://code.claude.com/docs/en/install",
5394
+ installCommand: "npm install -g @anthropic-ai/claude-code",
5395
+ loginCommand: "claude auth login",
5396
+ npmPackage: "@anthropic-ai/claude-code"
5397
+ },
5398
+ codex: {
5399
+ agent: "codex",
5400
+ kind: "cli",
5401
+ summary: "Install the Codex CLI, then run login in a terminal.",
5402
+ docsUrl: "https://github.com/openai/codex",
5403
+ installCommand: "npm install -g @openai/codex",
5404
+ loginCommand: "codex login",
5405
+ npmPackage: "@openai/codex"
5406
+ },
5407
+ opencode: {
5408
+ agent: "opencode",
5409
+ kind: "cli",
5410
+ summary: "Install OpenCode (curl installer or npm), then authenticate providers.",
5411
+ docsUrl: "https://opencode.ai/docs",
5412
+ // Prefer the official installer; npm package name is opencode-ai.
5413
+ installCommand: "curl -fsSL https://opencode.ai/install | bash",
5414
+ loginCommand: "opencode auth login",
5415
+ npmPackage: "opencode-ai@latest"
5416
+ },
5417
+ cursor: {
5418
+ agent: "cursor",
5419
+ kind: "bundled-sdk",
5420
+ summary: "No CLI install \u2014 Sideboard ships the Cursor SDK. Add a CURSOR_API_KEY from the Cursor dashboard.",
5421
+ docsUrl: "https://cursor.com/dashboard/integrations",
5422
+ installCommand: null,
5423
+ loginCommand: null
5424
+ },
5425
+ brightsy: {
5426
+ agent: "brightsy",
5427
+ kind: "cli",
5428
+ summary: "Install the Brightsy CLI, then run `brightsy login`.",
5429
+ docsUrl: "https://www.npmjs.com/package/@brightsy/cli",
5430
+ installCommand: "npm install -g @brightsy/cli",
5431
+ loginCommand: "brightsy login",
5432
+ npmPackage: "@brightsy/cli"
5433
+ }
5434
+ };
5435
+ }
5436
+ });
5437
+
5124
5438
  // src/agents/index.ts
5125
5439
  var agents_exports = {};
5126
5440
  __export(agents_exports, {
@@ -5135,10 +5449,20 @@ __export(agents_exports, {
5135
5449
  encodeBrightsyTarget: () => encodeBrightsyTarget,
5136
5450
  ensureAgentPath: () => ensureAgentPath,
5137
5451
  getAdapter: () => getAdapter,
5452
+ getAgentSetupInfo: () => getAgentSetupInfo,
5453
+ installAgent: () => installAgent,
5454
+ isCursorAutoModel: () => isCursorAutoModel,
5455
+ listAgentSetupInfo: () => listAgentSetupInfo,
5138
5456
  listBrightsyChatTargets: () => listBrightsyChatTargets,
5457
+ listCodexModels: () => listCodexModels,
5458
+ listCursorModels: () => listCursorModels,
5459
+ listOpencodeModels: () => listOpencodeModels,
5460
+ loginAgent: () => loginAgent,
5461
+ openInSystemTerminal: () => openInSystemTerminal,
5139
5462
  opencodeAdapter: () => opencodeAdapter,
5140
5463
  parseCursorRunnerLine: () => parseCursorRunnerLine,
5141
- permissionMode: () => permissionMode
5464
+ permissionMode: () => permissionMode,
5465
+ resolveCursorModelId: () => resolveCursorModelId
5142
5466
  });
5143
5467
  function getAdapter(kind) {
5144
5468
  return adapters[kind];
@@ -5162,8 +5486,10 @@ var init_agents = __esm({
5162
5486
  init_codex();
5163
5487
  init_cursor();
5164
5488
  init_cursor_events();
5489
+ init_cursor();
5165
5490
  init_opencode();
5166
5491
  init_path();
5492
+ init_install();
5167
5493
  adapters = {
5168
5494
  claude: claudeAdapter,
5169
5495
  codex: codexAdapter,
@@ -5329,6 +5655,7 @@ __export(index_exports, {
5329
5655
  formatWorkspaceInventory: () => formatWorkspaceInventory,
5330
5656
  formatWorktreeDirective: () => formatWorktreeDirective,
5331
5657
  getAdapter: () => getAdapter,
5658
+ getAgentSetupInfo: () => getAgentSetupInfo,
5332
5659
  getBrightsySession: () => getBrightsySession,
5333
5660
  getDefaultRunScript: () => getDefaultRunScript,
5334
5661
  getDiff: () => getDiff,
@@ -5359,9 +5686,11 @@ __export(index_exports, {
5359
5686
  importConductorWorkspaceAsync: () => importConductorWorkspaceAsync,
5360
5687
  initializeGitRepository: () => initializeGitRepository,
5361
5688
  inspectGitWorktree: () => inspectGitWorktree,
5689
+ installAgent: () => installAgent,
5362
5690
  isBrightsyConnected: () => isBrightsyConnected,
5363
5691
  isBrightsyNdjsonLine: () => isBrightsyNdjsonLine,
5364
5692
  isCloudCoordinatorThread: () => isCloudCoordinatorThread,
5693
+ isCursorAutoModel: () => isCursorAutoModel,
5365
5694
  isDirty: () => isDirty,
5366
5695
  isGhRateLimitError: () => isGhRateLimitError,
5367
5696
  isGlobalRepoPath: () => isGlobalRepoPath,
@@ -5370,17 +5699,21 @@ __export(index_exports, {
5370
5699
  isLinearConnected: () => isLinearConnected,
5371
5700
  isOrchestratorThread: () => isOrchestratorThread,
5372
5701
  isPlaceholderBranch: () => isPlaceholderBranch,
5702
+ listAgentSetupInfo: () => listAgentSetupInfo,
5373
5703
  listBranchCommits: () => listBranchCommits,
5374
5704
  listBranches: () => listBranches,
5375
5705
  listBrightsyAccounts: () => listBrightsyAccounts,
5376
5706
  listBrightsyChatTargets: () => listBrightsyChatTargets,
5707
+ listCodexModels: () => listCodexModels,
5377
5708
  listConductorWorkspaces: () => listConductorWorkspaces,
5378
5709
  listConnectedBrightsyTeams: () => listConnectedBrightsyTeams,
5710
+ listCursorModels: () => listCursorModels,
5379
5711
  listGitHubIssues: () => listGitHubIssues,
5380
5712
  listGlobalThreads: () => listGlobalThreads,
5381
5713
  listIssues: () => listIssues,
5382
5714
  listLinearIssues: () => listLinearIssues,
5383
5715
  listLinearIssuesDirect: () => listLinearIssuesDirect,
5716
+ listOpencodeModels: () => listOpencodeModels,
5384
5717
  listPrs: () => listPrs,
5385
5718
  listRunScripts: () => listRunScripts,
5386
5719
  listThreads: () => listThreads,
@@ -5394,6 +5727,7 @@ __export(index_exports, {
5394
5727
  loadRepoSettings: () => loadRepoSettings,
5395
5728
  loadWorkspaceSettings: () => loadWorkspaceSettings,
5396
5729
  locksDir: () => locksDir,
5730
+ loginAgent: () => loginAgent,
5397
5731
  lookupSoccerTeam: () => lookupSoccerTeam,
5398
5732
  maxConcurrentAgents: () => maxConcurrentAgents,
5399
5733
  maybeCompactContext: () => maybeCompactContext,
@@ -5405,6 +5739,7 @@ __export(index_exports, {
5405
5739
  normalizeThread: () => normalizeThread,
5406
5740
  normalizeTurnInput: () => normalizeTurnInput,
5407
5741
  normalizeWorktreePath: () => normalizeWorktreePath,
5742
+ openInSystemTerminal: () => openInSystemTerminal,
5408
5743
  opencodeAdapter: () => opencodeAdapter,
5409
5744
  orchestrationTitleNeedsSoccerNickname: () => orchestrationTitleNeedsSoccerNickname,
5410
5745
  orchestratorSessionPoisonedByBuiltins: () => orchestratorSessionPoisonedByBuiltins,
@@ -5429,6 +5764,7 @@ __export(index_exports, {
5429
5764
  requireAgent: () => requireAgent,
5430
5765
  resolveClaudeExecutable: () => resolveClaudeExecutable,
5431
5766
  resolveConductorCursorAgentId: () => resolveConductorCursorAgentId,
5767
+ resolveCursorModelId: () => resolveCursorModelId,
5432
5768
  resolveDefaultBranch: () => resolveDefaultBranch,
5433
5769
  resolveDiffBaseRef: () => resolveDiffBaseRef,
5434
5770
  resolveEffectiveIssueSource: () => resolveEffectiveIssueSource,
@@ -8187,10 +8523,10 @@ function createChatTab(input) {
8187
8523
  userSetTitle: true,
8188
8524
  ...binding,
8189
8525
  agent: input.agent ?? from.agent,
8190
- model: input.agent && input.agent !== from.agent ? null : from.model,
8526
+ model: input.model !== void 0 ? input.model : input.agent && input.agent !== from.agent ? null : from.model,
8191
8527
  fast: from.fast,
8192
8528
  planMode: from.planMode,
8193
- autonomy: from.autonomy,
8529
+ autonomy: input.autonomy ?? from.autonomy,
8194
8530
  attachments: input.attachments ?? [],
8195
8531
  status: "idle"
8196
8532
  });
@@ -9113,6 +9449,7 @@ var Orchestrator = class {
9113
9449
  ...fresh.agent === "claude" && fresh.sessionId ? [] : [instructions, seed]
9114
9450
  ].filter(Boolean).join("\n\n---\n\n");
9115
9451
  try {
9452
+ let lastStderr = "";
9116
9453
  const handle = await spawnAgentTurn(
9117
9454
  fresh,
9118
9455
  { cachedPrefix, prompt: agentPrompt },
@@ -9121,6 +9458,9 @@ var Orchestrator = class {
9121
9458
  if (event.type === "session_id") {
9122
9459
  updateThread(threadId, { sessionId: event.data });
9123
9460
  }
9461
+ if (event.type === "stderr" && typeof event.data === "string" && event.data.trim()) {
9462
+ lastStderr = event.data.trim();
9463
+ }
9124
9464
  }
9125
9465
  );
9126
9466
  this.activeTurns.set(threadId, handle);
@@ -9166,7 +9506,12 @@ var Orchestrator = class {
9166
9506
  this.emit({ type: "status_changed", threadId, status: "stopped" });
9167
9507
  this.emit({ type: "turn_finished", threadId, exitCode: result.exitCode });
9168
9508
  } else {
9169
- setStatus(threadId, result.exitCode === 0 ? "idle" : "error", result.exitCode === 0 ? null : `exit ${result.exitCode}`);
9509
+ const failDetail = lastStderr ? `exit ${result.exitCode}: ${lastStderr.slice(0, 500)}` : `exit ${result.exitCode}`;
9510
+ setStatus(
9511
+ threadId,
9512
+ result.exitCode === 0 ? "idle" : "error",
9513
+ result.exitCode === 0 ? null : failDetail
9514
+ );
9170
9515
  this.emit({
9171
9516
  type: "status_changed",
9172
9517
  threadId,
@@ -9640,9 +9985,16 @@ var Orchestrator = class {
9640
9985
  if (patch.planMode !== void 0) next.planMode = patch.planMode;
9641
9986
  if (patch.model !== void 0) next.model = patch.model;
9642
9987
  if (patch.agent !== void 0) {
9643
- next.agent = patch.agent;
9644
- if (patch.agent !== "claude" && patch.model === void 0) next.model = null;
9645
- next.sessionId = null;
9988
+ if (patch.agent !== thread.agent) {
9989
+ if (thread.messages.length > 0) {
9990
+ throw new Error(
9991
+ `Cannot switch agent provider mid-chat (${thread.agent} \u2192 ${patch.agent}). Start a new chat tab instead.`
9992
+ );
9993
+ }
9994
+ next.agent = patch.agent;
9995
+ if (patch.agent !== "claude" && patch.model === void 0) next.model = null;
9996
+ next.sessionId = null;
9997
+ }
9646
9998
  }
9647
9999
  return updateThread(thread.id, next);
9648
10000
  }
@@ -10882,6 +11234,7 @@ init_injected_mcp();
10882
11234
  formatWorkspaceInventory,
10883
11235
  formatWorktreeDirective,
10884
11236
  getAdapter,
11237
+ getAgentSetupInfo,
10885
11238
  getBrightsySession,
10886
11239
  getDefaultRunScript,
10887
11240
  getDiff,
@@ -10912,9 +11265,11 @@ init_injected_mcp();
10912
11265
  importConductorWorkspaceAsync,
10913
11266
  initializeGitRepository,
10914
11267
  inspectGitWorktree,
11268
+ installAgent,
10915
11269
  isBrightsyConnected,
10916
11270
  isBrightsyNdjsonLine,
10917
11271
  isCloudCoordinatorThread,
11272
+ isCursorAutoModel,
10918
11273
  isDirty,
10919
11274
  isGhRateLimitError,
10920
11275
  isGlobalRepoPath,
@@ -10923,17 +11278,21 @@ init_injected_mcp();
10923
11278
  isLinearConnected,
10924
11279
  isOrchestratorThread,
10925
11280
  isPlaceholderBranch,
11281
+ listAgentSetupInfo,
10926
11282
  listBranchCommits,
10927
11283
  listBranches,
10928
11284
  listBrightsyAccounts,
10929
11285
  listBrightsyChatTargets,
11286
+ listCodexModels,
10930
11287
  listConductorWorkspaces,
10931
11288
  listConnectedBrightsyTeams,
11289
+ listCursorModels,
10932
11290
  listGitHubIssues,
10933
11291
  listGlobalThreads,
10934
11292
  listIssues,
10935
11293
  listLinearIssues,
10936
11294
  listLinearIssuesDirect,
11295
+ listOpencodeModels,
10937
11296
  listPrs,
10938
11297
  listRunScripts,
10939
11298
  listThreads,
@@ -10947,6 +11306,7 @@ init_injected_mcp();
10947
11306
  loadRepoSettings,
10948
11307
  loadWorkspaceSettings,
10949
11308
  locksDir,
11309
+ loginAgent,
10950
11310
  lookupSoccerTeam,
10951
11311
  maxConcurrentAgents,
10952
11312
  maybeCompactContext,
@@ -10958,6 +11318,7 @@ init_injected_mcp();
10958
11318
  normalizeThread,
10959
11319
  normalizeTurnInput,
10960
11320
  normalizeWorktreePath,
11321
+ openInSystemTerminal,
10961
11322
  opencodeAdapter,
10962
11323
  orchestrationTitleNeedsSoccerNickname,
10963
11324
  orchestratorSessionPoisonedByBuiltins,
@@ -10982,6 +11343,7 @@ init_injected_mcp();
10982
11343
  requireAgent,
10983
11344
  resolveClaudeExecutable,
10984
11345
  resolveConductorCursorAgentId,
11346
+ resolveCursorModelId,
10985
11347
  resolveDefaultBranch,
10986
11348
  resolveDiffBaseRef,
10987
11349
  resolveEffectiveIssueSource,