@sideboard-ai/core 0.1.45 → 0.1.46

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.
@@ -2753,7 +2753,7 @@ function normalizeAdvanced(raw) {
2753
2753
  if (source.orchestrationQuotaOnLimit === "switch_agent" || source.orchestrationQuotaOnLimit === "wait_reset") {
2754
2754
  out.orchestrationQuotaOnLimit = source.orchestrationQuotaOnLimit;
2755
2755
  }
2756
- if (typeof source.orchestrationQuotaFallbackAgent === "string" && DEFAULT_AGENTS.has(source.orchestrationQuotaFallbackAgent)) {
2756
+ if (typeof source.orchestrationQuotaFallbackAgent === "string" && DEFAULT_AGENTS.has(source.orchestrationQuotaFallbackAgent) && source.orchestrationQuotaFallbackAgent !== "brightsy") {
2757
2757
  out.orchestrationQuotaFallbackAgent = source.orchestrationQuotaFallbackAgent;
2758
2758
  }
2759
2759
  return out;
@@ -2993,7 +2993,7 @@ function updateAdvancedSettings(patch) {
2993
2993
  if (patch.orchestrationQuotaOnLimit === "switch_agent" || patch.orchestrationQuotaOnLimit === "wait_reset") {
2994
2994
  advanced.orchestrationQuotaOnLimit = patch.orchestrationQuotaOnLimit;
2995
2995
  }
2996
- if (typeof patch.orchestrationQuotaFallbackAgent === "string" && DEFAULT_AGENTS.has(patch.orchestrationQuotaFallbackAgent)) {
2996
+ if (typeof patch.orchestrationQuotaFallbackAgent === "string" && DEFAULT_AGENTS.has(patch.orchestrationQuotaFallbackAgent) && patch.orchestrationQuotaFallbackAgent !== "brightsy") {
2997
2997
  advanced.orchestrationQuotaFallbackAgent = patch.orchestrationQuotaFallbackAgent;
2998
2998
  }
2999
2999
  return saveAppSettings({ ...current, advanced });
@@ -3021,7 +3021,10 @@ function orchestrationQuotaOnLimit(settings = loadAppSettings()) {
3021
3021
  }
3022
3022
  function orchestrationQuotaFallbackAgent(settings = loadAppSettings()) {
3023
3023
  const preferred = settings.advanced.orchestrationQuotaFallbackAgent;
3024
- return preferred && DEFAULT_AGENTS.has(preferred) ? preferred : "cursor";
3024
+ if (preferred && DEFAULT_AGENTS.has(preferred) && preferred !== "brightsy") {
3025
+ return preferred;
3026
+ }
3027
+ return "cursor";
3025
3028
  }
3026
3029
  function maxConcurrentAgents(settings = loadAppSettings()) {
3027
3030
  const n = settings.advanced.maxConcurrent;
@@ -3129,6 +3132,36 @@ var init_cloud_connect_constants = __esm({
3129
3132
  }
3130
3133
  });
3131
3134
 
3135
+ // src/agents/orchestrator-capable.ts
3136
+ function isOrchestratorCapableAgent(agent) {
3137
+ return Boolean(
3138
+ agent && ORCHESTRATOR_AGENT_KINDS.includes(agent)
3139
+ );
3140
+ }
3141
+ function assertOrchestratorCapableAgent(agent, context = "orchestration") {
3142
+ if (!isOrchestratorCapableAgent(agent)) {
3143
+ throw new Error(
3144
+ `${agent} cannot run ${context} \u2014 it does not support Sideboard MCP. Use Claude, Cursor, Codex, or OpenCode.`
3145
+ );
3146
+ }
3147
+ return agent;
3148
+ }
3149
+ function coerceOrchestratorAgent(agent, fallback = "claude") {
3150
+ return isOrchestratorCapableAgent(agent) ? agent : fallback;
3151
+ }
3152
+ var ORCHESTRATOR_AGENT_KINDS;
3153
+ var init_orchestrator_capable = __esm({
3154
+ "src/agents/orchestrator-capable.ts"() {
3155
+ "use strict";
3156
+ ORCHESTRATOR_AGENT_KINDS = [
3157
+ "claude",
3158
+ "codex",
3159
+ "opencode",
3160
+ "cursor"
3161
+ ];
3162
+ }
3163
+ });
3164
+
3132
3165
  // src/orchestrator/coordinator-prompt.ts
3133
3166
  var coordinator_prompt_exports = {};
3134
3167
  __export(coordinator_prompt_exports, {
@@ -3355,6 +3388,7 @@ function createGlobalChat(opts) {
3355
3388
  const explicit = opts.title?.trim();
3356
3389
  const title = explicit && explicit !== CLOUD_ORCHESTRATOR_GOAL ? explicit : allocateTeamName(takenTeamSlugsForOrchestration()).name;
3357
3390
  const sourceRef = opts.sourceRef?.trim() || (isCloud ? CLOUD_ORCHESTRATOR_GOAL : title);
3391
+ const agent = assertOrchestratorCapableAgent(opts.agent);
3358
3392
  const thread = createEmptyThread({
3359
3393
  title,
3360
3394
  // Stick nicknames the same way chat tabs do (avoid later sync overwrites).
@@ -3364,7 +3398,7 @@ function createGlobalChat(opts) {
3364
3398
  branchName: "global",
3365
3399
  worktreePath: globalAgentCwd(),
3366
3400
  repoPath: GLOBAL_WORKSPACE_ID,
3367
- agent: opts.agent,
3401
+ agent,
3368
3402
  autonomy: opts.autonomy ?? "default",
3369
3403
  model: opts.model ?? null,
3370
3404
  effort: opts.effort ?? "high",
@@ -3426,6 +3460,7 @@ var init_global_workspace = __esm({
3426
3460
  "src/store/global-workspace.ts"() {
3427
3461
  "use strict";
3428
3462
  init_cloud_connect_constants();
3463
+ init_orchestrator_capable();
3429
3464
  init_teams();
3430
3465
  init_coordinator_prompt();
3431
3466
  init_paths();
@@ -4158,6 +4193,45 @@ async function buildInjectedMcpServers(opts) {
4158
4193
  }
4159
4194
  return servers;
4160
4195
  }
4196
+ function toCursorMcpServers(servers) {
4197
+ const out = {};
4198
+ for (const s of servers) {
4199
+ out[s.name] = {
4200
+ command: s.command,
4201
+ ...s.args ? { args: s.args } : {},
4202
+ ...s.env ? { env: s.env } : {}
4203
+ };
4204
+ }
4205
+ return out;
4206
+ }
4207
+ function toCodexMcpConfigArgs(servers) {
4208
+ const args = [];
4209
+ for (const s of servers) {
4210
+ const prefix = `mcp_servers.${s.name}`;
4211
+ args.push("-c", `${prefix}.command=${JSON.stringify(s.command)}`);
4212
+ if (s.args?.length) {
4213
+ args.push("-c", `${prefix}.args=${JSON.stringify(s.args)}`);
4214
+ }
4215
+ if (s.env) {
4216
+ for (const [key, value] of Object.entries(s.env)) {
4217
+ args.push("-c", `${prefix}.env.${key}=${JSON.stringify(value)}`);
4218
+ }
4219
+ }
4220
+ }
4221
+ return args;
4222
+ }
4223
+ function toOpencodeMcpConfigContent(servers) {
4224
+ const mcp = {};
4225
+ for (const s of servers) {
4226
+ mcp[s.name] = {
4227
+ type: "local",
4228
+ command: [s.command, ...s.args ?? []],
4229
+ enabled: true,
4230
+ ...s.env && Object.keys(s.env).length > 0 ? { environment: s.env } : {}
4231
+ };
4232
+ }
4233
+ return JSON.stringify({ mcp });
4234
+ }
4161
4235
  function writeMcpServersConfig(servers) {
4162
4236
  if (servers.length === 0) return null;
4163
4237
  const mcpServers = {};
@@ -4658,6 +4732,7 @@ var init_codex = __esm({
4658
4732
  import_node_path11 = require("path");
4659
4733
  init_run();
4660
4734
  init_error_detail();
4735
+ init_injected_mcp();
4661
4736
  init_turn_input();
4662
4737
  init_types();
4663
4738
  CODEX_PROMPT_ARG_MAX = 2e5;
@@ -4716,6 +4791,11 @@ var init_codex = __esm({
4716
4791
  }
4717
4792
  const mode = permissionMode(thread);
4718
4793
  const model = thread.model?.trim();
4794
+ const injected = await buildInjectedMcpServers({
4795
+ includeSideboard: true,
4796
+ includeBrightsy: isBrightsyConnected()
4797
+ });
4798
+ const mcpOverrides = toCodexMcpConfigArgs(injected);
4719
4799
  const args = [
4720
4800
  "exec",
4721
4801
  ...sessionId ? ["resume", sessionId] : [],
@@ -4727,7 +4807,8 @@ var init_codex = __esm({
4727
4807
  mode.codexSandbox,
4728
4808
  "--ask-for-approval",
4729
4809
  "never",
4730
- ...model ? ["--model", model] : []
4810
+ ...model ? ["--model", model] : [],
4811
+ ...mcpOverrides
4731
4812
  ];
4732
4813
  return {
4733
4814
  file: "codex",
@@ -5012,6 +5093,7 @@ var init_cursor = __esm({
5012
5093
  init_run();
5013
5094
  init_app_settings();
5014
5095
  init_cursor_events();
5096
+ init_injected_mcp();
5015
5097
  init_node_launch();
5016
5098
  init_turn_input();
5017
5099
  init_cursor_events();
@@ -5062,6 +5144,11 @@ var init_cursor = __esm({
5062
5144
  const prompt = flattenTurnInput(input);
5063
5145
  const agentId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
5064
5146
  const apiKey = resolveCursorApiKey() || void 0;
5147
+ const injected = await buildInjectedMcpServers({
5148
+ includeSideboard: true,
5149
+ includeBrightsy: isBrightsyConnected()
5150
+ });
5151
+ const mcpServers = toCursorMcpServers(injected);
5065
5152
  const req = {
5066
5153
  prompt,
5067
5154
  cwd: thread.worktreePath,
@@ -5070,7 +5157,8 @@ var init_cursor = __esm({
5070
5157
  effort: thread.effort,
5071
5158
  fast: thread.fast,
5072
5159
  planMode: thread.planMode,
5073
- apiKey
5160
+ apiKey,
5161
+ ...Object.keys(mcpServers).length > 0 ? { mcpServers } : {}
5074
5162
  };
5075
5163
  const runner = cursorRunnerPath();
5076
5164
  const isTs = runner.endsWith(".ts");
@@ -5164,6 +5252,7 @@ var init_opencode = __esm({
5164
5252
  "use strict";
5165
5253
  init_run();
5166
5254
  init_error_detail();
5255
+ init_injected_mcp();
5167
5256
  init_turn_input();
5168
5257
  init_types();
5169
5258
  FALLBACK_OPENCODE_MODELS = [
@@ -5224,6 +5313,11 @@ var init_opencode = __esm({
5224
5313
  if (model) {
5225
5314
  args.push("--model", model);
5226
5315
  }
5316
+ const injected = await buildInjectedMcpServers({
5317
+ includeSideboard: true,
5318
+ includeBrightsy: isBrightsyConnected()
5319
+ });
5320
+ const mcpContent = injected.length > 0 ? toOpencodeMcpConfigContent(injected) : null;
5227
5321
  return {
5228
5322
  file: "opencode",
5229
5323
  args,
@@ -5232,7 +5326,8 @@ var init_opencode = __esm({
5232
5326
  // message is given (see resolveRunInput in opencode's run.ts).
5233
5327
  stdin: prompt,
5234
5328
  env: {
5235
- OPENCODE_PERMISSION: mode.opencodePermission
5329
+ OPENCODE_PERMISSION: mode.opencodePermission,
5330
+ ...mcpContent ? { OPENCODE_CONFIG_CONTENT: mcpContent } : {}
5236
5331
  }
5237
5332
  };
5238
5333
  },
@@ -5528,7 +5623,10 @@ function zonedWallTimeToUtc(day, hour, minute, timeZone) {
5528
5623
  }
5529
5624
  }
5530
5625
  function resolveQuotaFallbackAgent(current, preferred) {
5531
- const ordered = preferred ? [preferred, ...FALLBACK_ORDER.filter((a) => a !== preferred)] : FALLBACK_ORDER;
5626
+ const ordered = [
5627
+ ...preferred && preferred !== "brightsy" ? [preferred] : [],
5628
+ ...FALLBACK_ORDER.filter((a) => a !== preferred)
5629
+ ];
5532
5630
  return ordered.find((a) => a !== current) ?? (current === "cursor" ? "codex" : "cursor");
5533
5631
  }
5534
5632
  var FALLBACK_ORDER;
@@ -5539,7 +5637,6 @@ var init_session_quota = __esm({
5539
5637
  "cursor",
5540
5638
  "codex",
5541
5639
  "opencode",
5542
- "brightsy",
5543
5640
  "claude"
5544
5641
  ];
5545
5642
  }
@@ -5726,11 +5823,14 @@ var init_install = __esm({
5726
5823
  var agents_exports = {};
5727
5824
  __export(agents_exports, {
5728
5825
  CLAUDE_MODEL_CATALOG: () => CLAUDE_MODEL_CATALOG,
5826
+ ORCHESTRATOR_AGENT_KINDS: () => ORCHESTRATOR_AGENT_KINDS,
5729
5827
  PLAN_MODE_INSTRUCTION: () => PLAN_MODE_INSTRUCTION,
5730
5828
  allAdapters: () => allAdapters,
5829
+ assertOrchestratorCapableAgent: () => assertOrchestratorCapableAgent,
5731
5830
  brightsyAdapter: () => brightsyAdapter,
5732
5831
  claudeAdapter: () => claudeAdapter,
5733
5832
  codexAdapter: () => codexAdapter,
5833
+ coerceOrchestratorAgent: () => coerceOrchestratorAgent,
5734
5834
  cursorAdapter: () => cursorAdapter,
5735
5835
  cursorSdkMessageToEvents: () => cursorSdkMessageToEvents,
5736
5836
  decodeBrightsyTarget: () => decodeBrightsyTarget,
@@ -5740,6 +5840,7 @@ __export(agents_exports, {
5740
5840
  getAgentSetupInfo: () => getAgentSetupInfo,
5741
5841
  installAgent: () => installAgent,
5742
5842
  isCursorAutoModel: () => isCursorAutoModel,
5843
+ isOrchestratorCapableAgent: () => isOrchestratorCapableAgent,
5743
5844
  isSessionQuotaLimit: () => isSessionQuotaLimit,
5744
5845
  listAgentSetupInfo: () => listAgentSetupInfo,
5745
5846
  listBrightsyChatTargets: () => listBrightsyChatTargets,
@@ -5782,6 +5883,7 @@ var init_agents = __esm({
5782
5883
  init_opencode();
5783
5884
  init_list_models();
5784
5885
  init_session_quota();
5886
+ init_orchestrator_capable();
5785
5887
  init_path();
5786
5888
  init_install();
5787
5889
  adapters = {
@@ -5979,6 +6081,7 @@ init_app_settings();
5979
6081
  init_global_workspace();
5980
6082
  init_brightsy();
5981
6083
  init_agents();
6084
+ init_orchestrator_capable();
5982
6085
 
5983
6086
  // src/agents/message-parts.ts
5984
6087
  function asRecord(input) {
@@ -6220,6 +6323,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
6220
6323
  const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
6221
6324
  ensureGlobalCoordinatorCwd2();
6222
6325
  }
6326
+ if (isOrchestratorThread(thread)) {
6327
+ assertOrchestratorCapableAgent(thread.agent);
6328
+ }
6223
6329
  const adapter = getAdapter(thread.agent);
6224
6330
  const cmd = await adapter.buildTurn(thread, input);
6225
6331
  if (cmd.cwd !== thread.worktreePath) {
@@ -7038,6 +7144,9 @@ async function listLinearIssues(agent, repoPath) {
7038
7144
  return adapter.listLinearIssues(repoPath);
7039
7145
  }
7040
7146
 
7147
+ // src/orchestrator/orchestrator.ts
7148
+ init_orchestrator_capable();
7149
+
7041
7150
  // src/threads/chat-tabs.ts
7042
7151
  var import_node_crypto2 = require("crypto");
7043
7152
 
@@ -7319,6 +7428,7 @@ async function maybeCompactContext(thread, thresholds = {}, summarize = summariz
7319
7428
  init_teams();
7320
7429
  init_worktree_labels();
7321
7430
  init_global_workspace();
7431
+ init_orchestrator_capable();
7322
7432
  init_thread_store();
7323
7433
  init_worktree_labels();
7324
7434
  function sameWorktreePath(a, b) {
@@ -7382,6 +7492,10 @@ function createChatTab(input) {
7382
7492
  const binding = worktreeBindingFrom(from);
7383
7493
  const explicitTitle = input.title?.trim();
7384
7494
  const title = explicitTitle || allocateTeamName(takenTeamSlugsForChatTab(binding.worktreePath)).name;
7495
+ const nextAgent = input.agent ?? from.agent;
7496
+ if (isOrchestratorThread(from) || binding.sourceType === "orchestration") {
7497
+ assertOrchestratorCapableAgent(nextAgent);
7498
+ }
7385
7499
  const thread = createEmptyThread({
7386
7500
  title,
7387
7501
  // Chat-tab nicknames (soccer team or explicit) must stick. Post-turn
@@ -7389,7 +7503,7 @@ function createChatTab(input) {
7389
7503
  // shared worktree folder name (e.g. fork "Arsenal" → "Monaco").
7390
7504
  userSetTitle: true,
7391
7505
  ...binding,
7392
- agent: input.agent ?? from.agent,
7506
+ agent: nextAgent,
7393
7507
  model: input.model !== void 0 ? input.model : input.agent && input.agent !== from.agent ? null : from.model,
7394
7508
  effort: input.effort !== void 0 ? input.effort : from.effort,
7395
7509
  fast: input.fast !== void 0 ? Boolean(input.fast) : from.fast,
@@ -10349,6 +10463,9 @@ var Orchestrator = class {
10349
10463
  `Cannot switch agent provider mid-chat (${thread.agent} \u2192 ${patch.agent}). Start a new chat tab instead.`
10350
10464
  );
10351
10465
  }
10466
+ if (isOrchestratorThread(thread)) {
10467
+ assertOrchestratorCapableAgent(patch.agent);
10468
+ }
10352
10469
  next.agent = patch.agent;
10353
10470
  if (patch.agent !== "claude" && patch.model === void 0) next.model = null;
10354
10471
  next.sessionId = null;
@@ -11114,7 +11231,7 @@ async function startMcpServer() {
11114
11231
  );
11115
11232
  server.tool(
11116
11233
  "fork_chat",
11117
- "Fork a chat into a NEW tab on the SAME workspace: worktree agent \u2192 same worktree tab; Global orchestration chat \u2192 new orchestration chat (same synthetic home). Seeds a transcript; optional agent override. Leave model unset for Auto unless you have a reason. Remote coordinators use this to continue an orchestration chat on another agent after session limits. Then send_to_thread / wait_for_turn on the returned id. Use fork_worktree only for worktree agents that need a new git worktree.",
11234
+ "Fork a chat into a NEW tab on the SAME workspace: worktree agent \u2192 same worktree tab; Global orchestration chat \u2192 new orchestration chat (same synthetic home). Seeds a transcript; optional agent override. Leave model unset for Auto unless you have a reason. Orchestration forks require an MCP-capable agent (claude, cursor, codex, opencode \u2014 not brightsy). Remote coordinators use this to continue an orchestration chat on another agent after session limits. Then send_to_thread / wait_for_turn on the returned id. Use fork_worktree only for worktree agents that need a new git worktree.",
11118
11235
  {
11119
11236
  ref: import_zod.z.string().describe("Thread id/ref to fork (worktree agent or orchestration chat)"),
11120
11237
  through_index: import_zod.z.number().optional().describe("Inclusive message index to include in the transcript (default: all)"),
@@ -1,14 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  startMcpServer
4
- } from "../chunk-I6QGZOOS.js";
5
- import "../chunk-U3EQKJHA.js";
6
- import "../chunk-ZNSM2DDD.js";
4
+ } from "../chunk-7DTJFP4D.js";
5
+ import "../chunk-SZAKJ4TR.js";
6
+ import "../chunk-SPCU3MFY.js";
7
7
  import "../chunk-6NAPN2N5.js";
8
- import "../chunk-ANZ566Z5.js";
8
+ import "../chunk-TQK2OYPU.js";
9
+ import "../chunk-GI7E5733.js";
9
10
  import "../chunk-ILQK4P5R.js";
10
11
  import "../chunk-J5JTEJ5O.js";
11
- import "../chunk-WYY3J7GR.js";
12
+ import "../chunk-T5QQVXK3.js";
12
13
  import "../chunk-FV6FN6V5.js";
13
14
  import "../chunk-O6W3P7V3.js";
14
15
  import "../chunk-77WWLBCI.js";
@@ -4,9 +4,10 @@ import {
4
4
  listWorkspaces,
5
5
  removeWorkspace,
6
6
  syncWorkspacesFromThreads
7
- } from "./chunk-U3EQKJHA.js";
8
- import "./chunk-ZNSM2DDD.js";
7
+ } from "./chunk-SZAKJ4TR.js";
8
+ import "./chunk-SPCU3MFY.js";
9
9
  import "./chunk-6NAPN2N5.js";
10
+ import "./chunk-GI7E5733.js";
10
11
  import "./chunk-FV6FN6V5.js";
11
12
  import "./chunk-O6W3P7V3.js";
12
13
  import "./chunk-77WWLBCI.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sideboard-ai/core",
3
- "version": "0.1.45",
3
+ "version": "0.1.46",
4
4
  "description": "Sideboard core — orchestration, agents, git worktrees, MCP server",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",