@sideboard-ai/core 0.1.45 → 0.1.49

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/cursor-runner.cjs +11 -4
  2. package/dist/agents/cursor-runner.js +11 -4
  3. package/dist/{agents-JSHCAZUZ.js → agents-3P4N6KHC.js} +12 -2
  4. package/dist/agents-LUB3Q773.js +82 -0
  5. package/dist/app-settings-7XVDQJ7F.js +80 -0
  6. package/dist/{app-settings-LYGVDGZY.js → app-settings-LZP632KI.js} +1 -1
  7. package/dist/{chunk-U3EQKJHA.js → chunk-3NAS4MWH.js} +1 -1
  8. package/dist/{chunk-ZNSM2DDD.js → chunk-5WYEJ3F3.js} +6 -2
  9. package/dist/chunk-7MV3RXSC.js +277 -0
  10. package/dist/chunk-DF5VQQKA.js +191 -0
  11. package/dist/chunk-E35APBHV.js +269 -0
  12. package/dist/chunk-EOYDCKQC.js +172 -0
  13. package/dist/chunk-GI7E5733.js +30 -0
  14. package/dist/chunk-GZXBYHJC.js +148 -0
  15. package/dist/chunk-HBJSHRY2.js +494 -0
  16. package/dist/chunk-ISY4EGF6.js +77 -0
  17. package/dist/chunk-KGZBYWZ3.js +23 -0
  18. package/dist/chunk-RQI4TOXK.js +2232 -0
  19. package/dist/chunk-S2LL5HA4.js +33 -0
  20. package/dist/{chunk-ANZ566Z5.js → chunk-SS34TVSY.js} +66 -7
  21. package/dist/{chunk-WYY3J7GR.js → chunk-T5QQVXK3.js} +6 -3
  22. package/dist/chunk-V4JRXYYU.js +122 -0
  23. package/dist/{chunk-6NAPN2N5.js → chunk-ZQCQIWIP.js} +1 -1
  24. package/dist/chunk-ZVV5EEQN.js +1892 -0
  25. package/dist/connected-teams-UBXHZGO4.js +24 -0
  26. package/dist/{coordinator-prompt-2XFYG3C5.js → coordinator-prompt-SPGDT7J5.js} +1 -1
  27. package/dist/coordinator-prompt-VG4BZ5JL.js +25 -0
  28. package/dist/cursor-recover-NNK7JPQM.js +44 -0
  29. package/dist/{global-workspace-YFOQUGWD.js → global-workspace-KSR3E63K.js} +3 -2
  30. package/dist/global-workspace-OJF4ENH4.js +40 -0
  31. package/dist/index.cjs +377 -30
  32. package/dist/index.d.cts +70 -11
  33. package/dist/index.d.ts +70 -11
  34. package/dist/index.js +5779 -193
  35. package/dist/mcp/run-stdio.cjs +331 -32
  36. package/dist/mcp/run-stdio.js +5618 -14
  37. package/dist/paths-2OFB7UJG.js +28 -0
  38. package/dist/run-HMRSRG3U.js +12 -0
  39. package/dist/thread-store-XICUWFNM.js +32 -0
  40. package/dist/title-4WAKWZRF.js +27 -0
  41. package/dist/workspaces-OZE7LRDO.js +24 -0
  42. package/dist/{workspaces-TIKLNDW3.js → workspaces-UJX7JIGH.js} +4 -3
  43. package/dist/worktree-XG5PCLZY.js +94 -0
  44. package/package.json +2 -2
  45. package/dist/chunk-I6QGZOOS.js +0 -5667
package/dist/index.cjs CHANGED
@@ -528,7 +528,7 @@ function normalizeAdvanced(raw) {
528
528
  if (source.orchestrationQuotaOnLimit === "switch_agent" || source.orchestrationQuotaOnLimit === "wait_reset") {
529
529
  out.orchestrationQuotaOnLimit = source.orchestrationQuotaOnLimit;
530
530
  }
531
- if (typeof source.orchestrationQuotaFallbackAgent === "string" && DEFAULT_AGENTS.has(source.orchestrationQuotaFallbackAgent)) {
531
+ if (typeof source.orchestrationQuotaFallbackAgent === "string" && DEFAULT_AGENTS.has(source.orchestrationQuotaFallbackAgent) && source.orchestrationQuotaFallbackAgent !== "brightsy") {
532
532
  out.orchestrationQuotaFallbackAgent = source.orchestrationQuotaFallbackAgent;
533
533
  }
534
534
  return out;
@@ -768,7 +768,7 @@ function updateAdvancedSettings(patch) {
768
768
  if (patch.orchestrationQuotaOnLimit === "switch_agent" || patch.orchestrationQuotaOnLimit === "wait_reset") {
769
769
  advanced.orchestrationQuotaOnLimit = patch.orchestrationQuotaOnLimit;
770
770
  }
771
- if (typeof patch.orchestrationQuotaFallbackAgent === "string" && DEFAULT_AGENTS.has(patch.orchestrationQuotaFallbackAgent)) {
771
+ if (typeof patch.orchestrationQuotaFallbackAgent === "string" && DEFAULT_AGENTS.has(patch.orchestrationQuotaFallbackAgent) && patch.orchestrationQuotaFallbackAgent !== "brightsy") {
772
772
  advanced.orchestrationQuotaFallbackAgent = patch.orchestrationQuotaFallbackAgent;
773
773
  }
774
774
  return saveAppSettings({ ...current, advanced });
@@ -796,7 +796,10 @@ function orchestrationQuotaOnLimit(settings = loadAppSettings()) {
796
796
  }
797
797
  function orchestrationQuotaFallbackAgent(settings = loadAppSettings()) {
798
798
  const preferred = settings.advanced.orchestrationQuotaFallbackAgent;
799
- return preferred && DEFAULT_AGENTS.has(preferred) ? preferred : "cursor";
799
+ if (preferred && DEFAULT_AGENTS.has(preferred) && preferred !== "brightsy") {
800
+ return preferred;
801
+ }
802
+ return "cursor";
800
803
  }
801
804
  function maxConcurrentAgents(settings = loadAppSettings()) {
802
805
  const n = settings.advanced.maxConcurrent;
@@ -1075,6 +1078,36 @@ var init_cloud_connect_constants = __esm({
1075
1078
  }
1076
1079
  });
1077
1080
 
1081
+ // src/agents/orchestrator-capable.ts
1082
+ function isOrchestratorCapableAgent(agent) {
1083
+ return Boolean(
1084
+ agent && ORCHESTRATOR_AGENT_KINDS.includes(agent)
1085
+ );
1086
+ }
1087
+ function assertOrchestratorCapableAgent(agent, context = "orchestration") {
1088
+ if (!isOrchestratorCapableAgent(agent)) {
1089
+ throw new Error(
1090
+ `${agent} cannot run ${context} \u2014 it does not support Sideboard MCP. Use Claude, Cursor, Codex, or OpenCode.`
1091
+ );
1092
+ }
1093
+ return agent;
1094
+ }
1095
+ function coerceOrchestratorAgent(agent, fallback = "claude") {
1096
+ return isOrchestratorCapableAgent(agent) ? agent : fallback;
1097
+ }
1098
+ var ORCHESTRATOR_AGENT_KINDS;
1099
+ var init_orchestrator_capable = __esm({
1100
+ "src/agents/orchestrator-capable.ts"() {
1101
+ "use strict";
1102
+ ORCHESTRATOR_AGENT_KINDS = [
1103
+ "claude",
1104
+ "codex",
1105
+ "opencode",
1106
+ "cursor"
1107
+ ];
1108
+ }
1109
+ });
1110
+
1078
1111
  // src/git/team-meta.ts
1079
1112
  var SOCCER_TEAM_META;
1080
1113
  var init_team_meta = __esm({
@@ -3224,7 +3257,7 @@ var init_coordinator_prompt = __esm({
3224
3257
  "- list_run_scripts / run_dev_script / stop_dev_script \u2014 start/stop named run scripts",
3225
3258
  "Inspect / review / PRs:",
3226
3259
  "- get_diff \u2014 compact diff summary",
3227
- "- request_review \u2014 open a Review chat tab on a worktree thread (merge-readiness recommendation); then wait_for_turn / get_turn_result on the returned id",
3260
+ '- request_review \u2014 open a Review chat tab on a worktree thread (attaches .sideboard/review.md when present, else local guidelines; sends "Review."); then wait_for_turn / get_turn_result on the returned id',
3228
3261
  "- Ask the worktree agent via send_to_thread to open a draft PR with `gh pr create --draft -R <origin-owner/name>` (workspace `github:` slug / that worktree's origin \u2014 never upstream). Do not open PRs from the orchestrator yourself.",
3229
3262
  "Human-only (do not attempt): merge, ready-for-review land, purge_thread.",
3230
3263
  "Thread links in replies: when mentioning a chat/thread for the user, include a markdown link `[Title](sideboard://thread/<id>)` using the full id (or the link field from create_thread / list_threads). Sideboard renders these as clickable opens.",
@@ -3312,6 +3345,7 @@ function createGlobalChat(opts) {
3312
3345
  const explicit = opts.title?.trim();
3313
3346
  const title = explicit && explicit !== CLOUD_ORCHESTRATOR_GOAL ? explicit : allocateTeamName(takenTeamSlugsForOrchestration()).name;
3314
3347
  const sourceRef = opts.sourceRef?.trim() || (isCloud ? CLOUD_ORCHESTRATOR_GOAL : title);
3348
+ const agent = assertOrchestratorCapableAgent(opts.agent);
3315
3349
  const thread = createEmptyThread({
3316
3350
  title,
3317
3351
  // Stick nicknames the same way chat tabs do (avoid later sync overwrites).
@@ -3321,7 +3355,7 @@ function createGlobalChat(opts) {
3321
3355
  branchName: "global",
3322
3356
  worktreePath: globalAgentCwd(),
3323
3357
  repoPath: GLOBAL_WORKSPACE_ID,
3324
- agent: opts.agent,
3358
+ agent,
3325
3359
  autonomy: opts.autonomy ?? "default",
3326
3360
  model: opts.model ?? null,
3327
3361
  effort: opts.effort ?? "high",
@@ -3383,6 +3417,7 @@ var init_global_workspace = __esm({
3383
3417
  "src/store/global-workspace.ts"() {
3384
3418
  "use strict";
3385
3419
  init_cloud_connect_constants();
3420
+ init_orchestrator_capable();
3386
3421
  init_teams();
3387
3422
  init_coordinator_prompt();
3388
3423
  init_paths();
@@ -4538,6 +4573,45 @@ async function buildInjectedMcpServers(opts) {
4538
4573
  }
4539
4574
  return servers;
4540
4575
  }
4576
+ function toCursorMcpServers(servers) {
4577
+ const out = {};
4578
+ for (const s of servers) {
4579
+ out[s.name] = {
4580
+ command: s.command,
4581
+ ...s.args ? { args: s.args } : {},
4582
+ ...s.env ? { env: s.env } : {}
4583
+ };
4584
+ }
4585
+ return out;
4586
+ }
4587
+ function toCodexMcpConfigArgs(servers) {
4588
+ const args = [];
4589
+ for (const s of servers) {
4590
+ const prefix = `mcp_servers.${s.name}`;
4591
+ args.push("-c", `${prefix}.command=${JSON.stringify(s.command)}`);
4592
+ if (s.args?.length) {
4593
+ args.push("-c", `${prefix}.args=${JSON.stringify(s.args)}`);
4594
+ }
4595
+ if (s.env) {
4596
+ for (const [key, value] of Object.entries(s.env)) {
4597
+ args.push("-c", `${prefix}.env.${key}=${JSON.stringify(value)}`);
4598
+ }
4599
+ }
4600
+ }
4601
+ return args;
4602
+ }
4603
+ function toOpencodeMcpConfigContent(servers) {
4604
+ const mcp = {};
4605
+ for (const s of servers) {
4606
+ mcp[s.name] = {
4607
+ type: "local",
4608
+ command: [s.command, ...s.args ?? []],
4609
+ enabled: true,
4610
+ ...s.env && Object.keys(s.env).length > 0 ? { environment: s.env } : {}
4611
+ };
4612
+ }
4613
+ return JSON.stringify({ mcp });
4614
+ }
4541
4615
  function writeMcpServersConfig(servers) {
4542
4616
  if (servers.length === 0) return null;
4543
4617
  const mcpServers = {};
@@ -5045,6 +5119,7 @@ var init_codex = __esm({
5045
5119
  import_node_path12 = require("path");
5046
5120
  init_run();
5047
5121
  init_error_detail();
5122
+ init_injected_mcp();
5048
5123
  init_turn_input();
5049
5124
  init_types();
5050
5125
  CODEX_PROMPT_ARG_MAX = 2e5;
@@ -5103,6 +5178,11 @@ var init_codex = __esm({
5103
5178
  }
5104
5179
  const mode = permissionMode(thread);
5105
5180
  const model = thread.model?.trim();
5181
+ const injected = await buildInjectedMcpServers({
5182
+ includeSideboard: true,
5183
+ includeBrightsy: isBrightsyConnected()
5184
+ });
5185
+ const mcpOverrides = toCodexMcpConfigArgs(injected);
5106
5186
  const args = [
5107
5187
  "exec",
5108
5188
  ...sessionId ? ["resume", sessionId] : [],
@@ -5114,7 +5194,8 @@ var init_codex = __esm({
5114
5194
  mode.codexSandbox,
5115
5195
  "--ask-for-approval",
5116
5196
  "never",
5117
- ...model ? ["--model", model] : []
5197
+ ...model ? ["--model", model] : [],
5198
+ ...mcpOverrides
5118
5199
  ];
5119
5200
  return {
5120
5201
  file: "codex",
@@ -5399,6 +5480,7 @@ var init_cursor = __esm({
5399
5480
  init_run();
5400
5481
  init_app_settings();
5401
5482
  init_cursor_events();
5483
+ init_injected_mcp();
5402
5484
  init_node_launch();
5403
5485
  init_turn_input();
5404
5486
  init_cursor_events();
@@ -5449,6 +5531,11 @@ var init_cursor = __esm({
5449
5531
  const prompt = flattenTurnInput(input);
5450
5532
  const agentId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
5451
5533
  const apiKey = resolveCursorApiKey() || void 0;
5534
+ const injected = await buildInjectedMcpServers({
5535
+ includeSideboard: true,
5536
+ includeBrightsy: isBrightsyConnected()
5537
+ });
5538
+ const mcpServers = toCursorMcpServers(injected);
5452
5539
  const req = {
5453
5540
  prompt,
5454
5541
  cwd: thread.worktreePath,
@@ -5457,7 +5544,8 @@ var init_cursor = __esm({
5457
5544
  effort: thread.effort,
5458
5545
  fast: thread.fast,
5459
5546
  planMode: thread.planMode,
5460
- apiKey
5547
+ apiKey,
5548
+ ...Object.keys(mcpServers).length > 0 ? { mcpServers } : {}
5461
5549
  };
5462
5550
  const runner = cursorRunnerPath();
5463
5551
  const isTs = runner.endsWith(".ts");
@@ -5551,6 +5639,7 @@ var init_opencode = __esm({
5551
5639
  "use strict";
5552
5640
  init_run();
5553
5641
  init_error_detail();
5642
+ init_injected_mcp();
5554
5643
  init_turn_input();
5555
5644
  init_types();
5556
5645
  FALLBACK_OPENCODE_MODELS = [
@@ -5611,6 +5700,11 @@ var init_opencode = __esm({
5611
5700
  if (model) {
5612
5701
  args.push("--model", model);
5613
5702
  }
5703
+ const injected = await buildInjectedMcpServers({
5704
+ includeSideboard: true,
5705
+ includeBrightsy: isBrightsyConnected()
5706
+ });
5707
+ const mcpContent = injected.length > 0 ? toOpencodeMcpConfigContent(injected) : null;
5614
5708
  return {
5615
5709
  file: "opencode",
5616
5710
  args,
@@ -5619,7 +5713,8 @@ var init_opencode = __esm({
5619
5713
  // message is given (see resolveRunInput in opencode's run.ts).
5620
5714
  stdin: prompt,
5621
5715
  env: {
5622
- OPENCODE_PERMISSION: mode.opencodePermission
5716
+ OPENCODE_PERMISSION: mode.opencodePermission,
5717
+ ...mcpContent ? { OPENCODE_CONFIG_CONTENT: mcpContent } : {}
5623
5718
  }
5624
5719
  };
5625
5720
  },
@@ -5915,7 +6010,10 @@ function zonedWallTimeToUtc(day, hour, minute, timeZone) {
5915
6010
  }
5916
6011
  }
5917
6012
  function resolveQuotaFallbackAgent(current, preferred) {
5918
- const ordered = preferred ? [preferred, ...FALLBACK_ORDER.filter((a) => a !== preferred)] : FALLBACK_ORDER;
6013
+ const ordered = [
6014
+ ...preferred && preferred !== "brightsy" ? [preferred] : [],
6015
+ ...FALLBACK_ORDER.filter((a) => a !== preferred)
6016
+ ];
5919
6017
  return ordered.find((a) => a !== current) ?? (current === "cursor" ? "codex" : "cursor");
5920
6018
  }
5921
6019
  var FALLBACK_ORDER;
@@ -5926,7 +6024,6 @@ var init_session_quota = __esm({
5926
6024
  "cursor",
5927
6025
  "codex",
5928
6026
  "opencode",
5929
- "brightsy",
5930
6027
  "claude"
5931
6028
  ];
5932
6029
  }
@@ -6113,11 +6210,14 @@ var init_install = __esm({
6113
6210
  var agents_exports = {};
6114
6211
  __export(agents_exports, {
6115
6212
  CLAUDE_MODEL_CATALOG: () => CLAUDE_MODEL_CATALOG,
6213
+ ORCHESTRATOR_AGENT_KINDS: () => ORCHESTRATOR_AGENT_KINDS,
6116
6214
  PLAN_MODE_INSTRUCTION: () => PLAN_MODE_INSTRUCTION,
6117
6215
  allAdapters: () => allAdapters,
6216
+ assertOrchestratorCapableAgent: () => assertOrchestratorCapableAgent,
6118
6217
  brightsyAdapter: () => brightsyAdapter,
6119
6218
  claudeAdapter: () => claudeAdapter,
6120
6219
  codexAdapter: () => codexAdapter,
6220
+ coerceOrchestratorAgent: () => coerceOrchestratorAgent,
6121
6221
  cursorAdapter: () => cursorAdapter,
6122
6222
  cursorSdkMessageToEvents: () => cursorSdkMessageToEvents,
6123
6223
  decodeBrightsyTarget: () => decodeBrightsyTarget,
@@ -6127,6 +6227,7 @@ __export(agents_exports, {
6127
6227
  getAgentSetupInfo: () => getAgentSetupInfo,
6128
6228
  installAgent: () => installAgent,
6129
6229
  isCursorAutoModel: () => isCursorAutoModel,
6230
+ isOrchestratorCapableAgent: () => isOrchestratorCapableAgent,
6130
6231
  isSessionQuotaLimit: () => isSessionQuotaLimit,
6131
6232
  listAgentSetupInfo: () => listAgentSetupInfo,
6132
6233
  listBrightsyChatTargets: () => listBrightsyChatTargets,
@@ -6169,6 +6270,7 @@ var init_agents = __esm({
6169
6270
  init_opencode();
6170
6271
  init_list_models();
6171
6272
  init_session_quota();
6273
+ init_orchestrator_capable();
6172
6274
  init_path();
6173
6275
  init_install();
6174
6276
  adapters = {
@@ -6278,10 +6380,13 @@ __export(index_exports, {
6278
6380
  GLOBAL_WORKSPACE_ID: () => GLOBAL_WORKSPACE_ID,
6279
6381
  HARNESS_ENV_KEYS: () => HARNESS_ENV_KEYS,
6280
6382
  MAX_ANTHROPIC_CACHE_CONTROL_BLOCKS: () => MAX_ANTHROPIC_CACHE_CONTROL_BLOCKS,
6383
+ ORCHESTRATOR_AGENT_KINDS: () => ORCHESTRATOR_AGENT_KINDS,
6281
6384
  Orchestrator: () => Orchestrator,
6282
6385
  PASTE_ATTACH_MIN_CHARS: () => PASTE_ATTACH_MIN_CHARS,
6283
6386
  PASTE_ATTACH_MIN_LINES: () => PASTE_ATTACH_MIN_LINES,
6284
6387
  PLAN_MODE_INSTRUCTION: () => PLAN_MODE_INSTRUCTION,
6388
+ REPO_REVIEW_NAME: () => REPO_REVIEW_NAME,
6389
+ REPO_REVIEW_PATH: () => REPO_REVIEW_PATH,
6285
6390
  REVIEW_REQUEST_NAME: () => REVIEW_REQUEST_NAME,
6286
6391
  REVIEW_REQUEST_PATH: () => REVIEW_REQUEST_PATH,
6287
6392
  REVIEW_REQUEST_PREFILL: () => REVIEW_REQUEST_PREFILL,
@@ -6302,6 +6407,7 @@ __export(index_exports, {
6302
6407
  applyAppEnvironment: () => applyAppEnvironment,
6303
6408
  applyCompaction: () => applyCompaction,
6304
6409
  applyThreadIntoMain: () => applyThreadIntoMain,
6410
+ assertOrchestratorCapableAgent: () => assertOrchestratorCapableAgent,
6305
6411
  attachmentFromAbsolutePath: () => attachmentFromAbsolutePath,
6306
6412
  attachmentsFromBuffers: () => attachmentsFromBuffers,
6307
6413
  attachmentsFromWorktreePaths: () => attachmentsFromWorktreePaths,
@@ -6334,6 +6440,7 @@ __export(index_exports, {
6334
6440
  cleanupOrphanWorktrees: () => cleanupOrphanWorktrees,
6335
6441
  cloneRepoIntoSideboard: () => cloneRepoIntoSideboard,
6336
6442
  codexAdapter: () => codexAdapter,
6443
+ coerceOrchestratorAgent: () => coerceOrchestratorAgent,
6337
6444
  collectTakenTeamSlugs: () => collectTakenTeamSlugs,
6338
6445
  commitAll: () => commitAll,
6339
6446
  conductorDbPath: () => conductorDbPath,
@@ -6365,6 +6472,7 @@ __export(index_exports, {
6365
6472
  ensureCloudCoordinator: () => ensureCloudCoordinator,
6366
6473
  ensureGhPreferOrigin: () => ensureGhPreferOrigin,
6367
6474
  ensureGlobalCoordinatorCwd: () => ensureGlobalCoordinatorCwd,
6475
+ ensureReviewRequestFile: () => ensureReviewRequestFile,
6368
6476
  ensureWorkspace: () => ensureWorkspace,
6369
6477
  estimateMessageChars: () => estimateMessageChars,
6370
6478
  estimateThreadChars: () => estimateThreadChars,
@@ -6438,6 +6546,7 @@ __export(index_exports, {
6438
6546
  isGlobalThread: () => isGlobalThread,
6439
6547
  isImageFilePath: () => isImageFilePath,
6440
6548
  isLinearConnected: () => isLinearConnected,
6549
+ isOrchestratorCapableAgent: () => isOrchestratorCapableAgent,
6441
6550
  isOrchestratorThread: () => isOrchestratorThread,
6442
6551
  isPidAlive: () => isPidAlive,
6443
6552
  isPlaceholderBranch: () => isPlaceholderBranch,
@@ -6527,6 +6636,7 @@ __export(index_exports, {
6527
6636
  resolvePrSelector: () => resolvePrSelector,
6528
6637
  resolveQuotaFallbackAgent: () => resolveQuotaFallbackAgent,
6529
6638
  resolveRepoRoot: () => resolveRepoRoot,
6639
+ resolveReviewGuidelines: () => resolveReviewGuidelines,
6530
6640
  resolveThreadDefaults: () => resolveThreadDefaults,
6531
6641
  resolveThreadEffort: () => resolveThreadEffort,
6532
6642
  resolveWorktreeStartPoint: () => resolveWorktreeStartPoint,
@@ -6542,6 +6652,7 @@ __export(index_exports, {
6542
6652
  settingsSourceLabel: () => settingsSourceLabel,
6543
6653
  shouldAttachPastedText: () => shouldAttachPastedText,
6544
6654
  shouldCompactContext: () => shouldCompactContext,
6655
+ shouldRefreshReviewRequestTemplate: () => shouldRefreshReviewRequestTemplate,
6545
6656
  shouldRunWorktreeCleanup: () => shouldRunWorktreeCleanup,
6546
6657
  sideboardHomeDir: () => sideboardHomeDir,
6547
6658
  sideboardReposDir: () => sideboardReposDir,
@@ -6790,6 +6901,7 @@ init_app_settings();
6790
6901
  init_global_workspace();
6791
6902
  init_brightsy();
6792
6903
  init_agents();
6904
+ init_orchestrator_capable();
6793
6905
 
6794
6906
  // src/agents/message-parts.ts
6795
6907
  function asRecord(input) {
@@ -7034,6 +7146,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
7034
7146
  const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
7035
7147
  ensureGlobalCoordinatorCwd2();
7036
7148
  }
7149
+ if (isOrchestratorThread(thread)) {
7150
+ assertOrchestratorCapableAgent(thread.agent);
7151
+ }
7037
7152
  const adapter = getAdapter(thread.agent);
7038
7153
  const cmd = await adapter.buildTurn(thread, input);
7039
7154
  if (cmd.cwd !== thread.worktreePath) {
@@ -9326,6 +9441,7 @@ var import_node_crypto4 = require("crypto");
9326
9441
  init_teams();
9327
9442
  init_worktree_labels();
9328
9443
  init_global_workspace();
9444
+ init_orchestrator_capable();
9329
9445
  init_thread_store();
9330
9446
  init_worktree_labels();
9331
9447
  function sameWorktreePath(a, b) {
@@ -9389,6 +9505,10 @@ function createChatTab(input) {
9389
9505
  const binding = worktreeBindingFrom(from);
9390
9506
  const explicitTitle = input.title?.trim();
9391
9507
  const title = explicitTitle || allocateTeamName(takenTeamSlugsForChatTab(binding.worktreePath)).name;
9508
+ const nextAgent = input.agent ?? from.agent;
9509
+ if (isOrchestratorThread(from) || binding.sourceType === "orchestration") {
9510
+ assertOrchestratorCapableAgent(nextAgent);
9511
+ }
9392
9512
  const thread = createEmptyThread({
9393
9513
  title,
9394
9514
  // Chat-tab nicknames (soccer team or explicit) must stick. Post-turn
@@ -9396,7 +9516,7 @@ function createChatTab(input) {
9396
9516
  // shared worktree folder name (e.g. fork "Arsenal" → "Monaco").
9397
9517
  userSetTitle: true,
9398
9518
  ...binding,
9399
- agent: input.agent ?? from.agent,
9519
+ agent: nextAgent,
9400
9520
  model: input.model !== void 0 ? input.model : input.agent && input.agent !== from.agent ? null : from.model,
9401
9521
  effort: input.effort !== void 0 ? input.effort : from.effort,
9402
9522
  fast: input.fast !== void 0 ? Boolean(input.fast) : from.fast,
@@ -9999,6 +10119,7 @@ async function cloneRepoIntoSideboard(opts) {
9999
10119
 
10000
10120
  // src/orchestrator/orchestrator.ts
10001
10121
  init_thread_store();
10122
+ init_orchestrator_capable();
10002
10123
 
10003
10124
  // src/review/request-review.ts
10004
10125
  var import_node_crypto5 = require("crypto");
@@ -10006,22 +10127,149 @@ var import_node_fs24 = require("fs");
10006
10127
  var import_node_path23 = require("path");
10007
10128
  init_global_workspace();
10008
10129
  init_thread_store();
10130
+
10131
+ // src/review/review-request-template.ts
10132
+ var REVIEW_REQUEST_TEMPLATE = `# Review guidelines:
10133
+
10134
+ You are reviewing a proposed code change so a human can decide whether it is **ready to merge / land**. Findings matter, but the primary deliverable is a clear readiness recommendation \u2014 not a laundry list of style notes.
10135
+
10136
+ ## Required outcome
10137
+
10138
+ Start your reply with a **Recommendation** section using exactly one of:
10139
+
10140
+ - **Approve** \u2014 ready to merge as-is (or with only trivial nits the author can ignore).
10141
+ - **Approve with nits** \u2014 ready to merge; list only optional polish that should not block.
10142
+ - **Request changes** \u2014 not ready; blocking issues must be fixed first.
10143
+ - **Needs more information** \u2014 cannot judge readiness yet (missing context, incomplete diff, unclear intent).
10144
+
10145
+ In 1\u20133 sentences, say **why** \u2014 grounded in correctness, risk, test coverage, and scope \u2014 not vibes. If you request changes, name the blockers explicitly.
10146
+
10147
+ People running this review are asking \u201Ccan we ship this?\u201D Treat that as the question you answer first.
10148
+
10149
+ ## Findings
10150
+
10151
+ Below are guidelines for determining whether an issue is worth flagging to the original author.
10152
+
10153
+ These are not the final word. More specific guidelines elsewhere (developer message, user message, a file, etc.) override these.
10154
+
10155
+ Flag something as a bug / blocking finding only when:
10156
+
10157
+ 1. It meaningfully impacts the accuracy, performance, security, or maintainability of the code.
10158
+ 2. The bug is discrete and actionable (not a vague codebase-wide complaint or a bundle of unrelated issues).
10159
+ 3. Fixing it does not demand rigor absent from the rest of the codebase.
10160
+ 4. The issue was introduced by this change (do not flag pre-existing bugs unless they are newly exposed by this PR).
10161
+ 5. The author would likely fix it if made aware.
10162
+ 6. It does not rely on unstated assumptions about the codebase or author intent.
10163
+ 7. Speculative breakage is not enough \u2014 identify the other code that is provably affected.
10164
+ 8. It is clearly not just an intentional change by the author.
10165
+
10166
+ When flagging an issue, include a short accompanying comment:
10167
+
10168
+ 1. Clear about why it is a problem.
10169
+ 2. Severity must match reality \u2014 do not inflate.
10170
+ 3. Brief: at most one paragraph; avoid unnecessary line breaks in prose.
10171
+ 4. No code chunks longer than 3 lines; wrap code in inline ticks or a fenced block.
10172
+ 5. Call out scenarios / environments / inputs needed to hit the bug when severity depends on them.
10173
+ 6. Matter-of-fact tone \u2014 helpful assistant, not accusatory or effusive.
10174
+ 7. Skimmable on first read.
10175
+ 8. No empty flattery (\u201CGreat job\u2026\u201D, \u201CThanks for\u2026\u201D).
10176
+
10177
+ HOW MANY FINDINGS TO RETURN:
10178
+
10179
+ List every finding the author would fix if they knew about it. If nothing qualifies, say so and still give the Recommendation. Do not stop at the first finding.
10180
+
10181
+ GUIDELINES:
10182
+
10183
+ - Ignore trivial style unless it obscures meaning or violates documented standards.
10184
+ - One comment per distinct issue (or a short multi-line range if needed).
10185
+ - Use \`\`\`suggestion blocks ONLY for concrete replacement code (minimal lines; no commentary inside the block).
10186
+ - In every \`\`\`suggestion block, preserve the exact leading whitespace of the replaced lines (spaces vs tabs, number of spaces).
10187
+ - Do NOT introduce or remove outer indentation levels unless that is the actual fix.
10188
+ - Separate **blocking** findings from **nits**. Only blocking findings should drive Request changes.
10189
+
10190
+ The report appears in chat (and can become Sideboard diff comments). Avoid unnecessary location chatter in the body; keep line ranges as short as possible (prefer \u22645\u201310 lines).
10191
+
10192
+ ## Getting the diff
10193
+
10194
+ Use Sideboard's diff for this thread's worktree. Prefer the \`get_diff\` MCP tool (pass this thread's ref) for a compact summary, then read specific files with Read/Glob as needed. In the Sideboard desktop app, the Changes panel shows the same worktree diff.
10195
+
10196
+ If the user asks you to address or read line comments they added in the Changes / file diff UI, those arrive as \`diff-comment\` attachments on the next turn \u2014 follow them precisely.
10197
+
10198
+ ## Fallback: if you don't have access to the Sideboard diff tool
10199
+
10200
+ If you don't have access to \`get_diff\`, use the following git commands to get the diff:
10201
+
10202
+ \`\`\`bash
10203
+ # Get the merge base between this branch and the target
10204
+ MERGE_BASE=$(git merge-base origin/main HEAD)
10205
+
10206
+ # Get the committed diff against the merge base
10207
+ git diff $MERGE_BASE HEAD
10208
+
10209
+ # Get any uncommitted changes (staged and unstaged)
10210
+ git diff HEAD
10211
+ \`\`\`
10212
+
10213
+ Review the combination of both outputs: the first shows all committed changes on this branch relative to the target, and the second shows any uncommitted work in progress.
10214
+
10215
+ No need to mention in your report whether or not you used one of the fallback strategies; it's usually irrelevant.
10216
+
10217
+ ## Output format
10218
+
10219
+ **1. Recommendation first** (required), then **2. Findings** (may be empty).
10220
+
10221
+ Only report ONE finding per unique issue.
10222
+
10223
+ <example>
10224
+ ## Recommendation
10225
+
10226
+ **Request changes** \u2014 The empty-input crash on load will break first-run users; fix that before merge. The unused helper is a nit and can wait.
10227
+
10228
+ ## Findings
10229
+
10230
+ ### **#1 Empty input causes crash** (blocking)
10231
+
10232
+ If the input field is empty when the page loads, the app will crash.
10233
+
10234
+ File: src/client/frontends/desktop/ui/Input.tsx
10235
+
10236
+ ### **#2 Dead code** (nit)
10237
+
10238
+ The getUserData function is now unused. It should be deleted.
10239
+
10240
+ File: src/client/frontends/desktop/core/UserData.ts
10241
+ </example>
10242
+
10243
+ <example>
10244
+ ## Recommendation
10245
+
10246
+ **Approve** \u2014 Diff is scoped, behavior looks correct, and there are no blocking issues. Safe to merge.
10247
+ </example>
10248
+ `;
10249
+
10250
+ // src/review/request-review.ts
10251
+ var REPO_REVIEW_PATH = ".sideboard/review.md";
10252
+ var REPO_REVIEW_NAME = "review.md";
10009
10253
  var REVIEW_REQUEST_PATH = ".sideboard/attachments/Review request.md";
10010
10254
  var REVIEW_REQUEST_NAME = "Review request.md";
10011
- var REVIEW_REQUEST_PREFILL = `Please review the changes in this workspace and recommend whether they are ready to merge.
10012
-
10013
- Start with a **Recommendation**: Approve, Approve with nits, Request changes, or Needs more information \u2014 and say why in 1\u20133 sentences. Then list blocking findings vs nits (findings may be empty).`;
10014
- function buildReviewRequestAttachment(content) {
10015
- return {
10016
- id: (0, import_node_crypto5.randomUUID)(),
10017
- name: REVIEW_REQUEST_NAME,
10018
- kind: "file",
10019
- path: REVIEW_REQUEST_PATH,
10020
- content
10021
- };
10255
+ var REVIEW_REQUEST_PREFILL = "Review.";
10256
+ var ATTACHMENTS_GITIGNORE2 = `# Sideboard review / composer attachments (local only)
10257
+ *
10258
+ !.gitignore
10259
+ `;
10260
+ var LEGACY_REVIEW_TEMPLATE_MARKERS = [
10261
+ "You are acting as a reviewer for a proposed code change made by another engineer.",
10262
+ "HOW MANY FINDINGS TO RETURN:"
10263
+ ];
10264
+ function shouldRefreshReviewRequestTemplate(content) {
10265
+ const trimmed = content.trim();
10266
+ if (!trimmed) return true;
10267
+ if (/##\s*Recommendation|ready to merge|Approve with nits|Request changes/i.test(trimmed)) {
10268
+ return false;
10269
+ }
10270
+ return LEGACY_REVIEW_TEMPLATE_MARKERS.every((m) => trimmed.includes(m));
10022
10271
  }
10023
- function readExistingReviewRequestFile(worktreePath) {
10024
- const abs = (0, import_node_path23.join)(worktreePath, REVIEW_REQUEST_PATH);
10272
+ function readTextIfPresent(abs) {
10025
10273
  if (!(0, import_node_fs24.existsSync)(abs)) return null;
10026
10274
  try {
10027
10275
  const content = (0, import_node_fs24.readFileSync)(abs, "utf8");
@@ -10030,6 +10278,87 @@ function readExistingReviewRequestFile(worktreePath) {
10030
10278
  return null;
10031
10279
  }
10032
10280
  }
10281
+ function ensureAttachmentsGitignore(worktreePath) {
10282
+ const gitignoreAbs = (0, import_node_path23.join)(worktreePath, ".sideboard", "attachments", ".gitignore");
10283
+ if ((0, import_node_fs24.existsSync)(gitignoreAbs)) return;
10284
+ (0, import_node_fs24.mkdirSync)((0, import_node_path23.dirname)(gitignoreAbs), { recursive: true });
10285
+ (0, import_node_fs24.writeFileSync)(gitignoreAbs, ATTACHMENTS_GITIGNORE2, "utf8");
10286
+ }
10287
+ function resolveReviewGuidelines(worktreePath) {
10288
+ const repoAbs = (0, import_node_path23.join)(worktreePath, REPO_REVIEW_PATH);
10289
+ const repoContent = readTextIfPresent(repoAbs);
10290
+ if (repoContent) {
10291
+ return {
10292
+ path: REPO_REVIEW_PATH,
10293
+ name: REPO_REVIEW_NAME,
10294
+ content: repoContent,
10295
+ source: "repo"
10296
+ };
10297
+ }
10298
+ const localAbs = (0, import_node_path23.join)(worktreePath, REVIEW_REQUEST_PATH);
10299
+ const localContent = readTextIfPresent(localAbs);
10300
+ if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
10301
+ return {
10302
+ path: REVIEW_REQUEST_PATH,
10303
+ name: REVIEW_REQUEST_NAME,
10304
+ content: localContent,
10305
+ source: "local"
10306
+ };
10307
+ }
10308
+ ensureAttachmentsGitignore(worktreePath);
10309
+ (0, import_node_fs24.mkdirSync)((0, import_node_path23.dirname)(localAbs), { recursive: true });
10310
+ (0, import_node_fs24.writeFileSync)(localAbs, REVIEW_REQUEST_TEMPLATE, "utf8");
10311
+ return {
10312
+ path: REVIEW_REQUEST_PATH,
10313
+ name: REVIEW_REQUEST_NAME,
10314
+ content: REVIEW_REQUEST_TEMPLATE,
10315
+ source: "stock"
10316
+ };
10317
+ }
10318
+ function ensureReviewRequestFile(worktreePath) {
10319
+ const repoAbs = (0, import_node_path23.join)(worktreePath, REPO_REVIEW_PATH);
10320
+ const repoContent = readTextIfPresent(repoAbs);
10321
+ if (repoContent) {
10322
+ return {
10323
+ path: REPO_REVIEW_PATH,
10324
+ name: REPO_REVIEW_NAME,
10325
+ content: repoContent,
10326
+ source: "repo"
10327
+ };
10328
+ }
10329
+ const localAbs = (0, import_node_path23.join)(worktreePath, REVIEW_REQUEST_PATH);
10330
+ const localContent = readTextIfPresent(localAbs);
10331
+ if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
10332
+ return {
10333
+ path: REVIEW_REQUEST_PATH,
10334
+ name: REVIEW_REQUEST_NAME,
10335
+ content: localContent,
10336
+ source: "local"
10337
+ };
10338
+ }
10339
+ (0, import_node_fs24.mkdirSync)((0, import_node_path23.dirname)(repoAbs), { recursive: true });
10340
+ (0, import_node_fs24.writeFileSync)(repoAbs, REVIEW_REQUEST_TEMPLATE, "utf8");
10341
+ return {
10342
+ path: REPO_REVIEW_PATH,
10343
+ name: REPO_REVIEW_NAME,
10344
+ content: REVIEW_REQUEST_TEMPLATE,
10345
+ source: "repo"
10346
+ };
10347
+ }
10348
+ function buildReviewRequestAttachment(content, opts) {
10349
+ const path = opts?.path ?? REVIEW_REQUEST_PATH;
10350
+ const name = opts?.name ?? (path === REPO_REVIEW_PATH ? REPO_REVIEW_NAME : REVIEW_REQUEST_NAME);
10351
+ return {
10352
+ id: (0, import_node_crypto5.randomUUID)(),
10353
+ name,
10354
+ kind: "file",
10355
+ path,
10356
+ content
10357
+ };
10358
+ }
10359
+ function readExistingReviewRequestFile(worktreePath) {
10360
+ return readTextIfPresent((0, import_node_path23.join)(worktreePath, REPO_REVIEW_PATH)) ?? readTextIfPresent((0, import_node_path23.join)(worktreePath, REVIEW_REQUEST_PATH));
10361
+ }
10033
10362
  async function requestReview(threadRef, send) {
10034
10363
  const from = findThreadByRef(threadRef);
10035
10364
  if (!from) throw new Error(`Thread not found: ${threadRef}`);
@@ -10041,12 +10370,16 @@ async function requestReview(threadRef, send) {
10041
10370
  if (from.status === "archived") {
10042
10371
  throw new Error(`Thread is archived: ${from.id}`);
10043
10372
  }
10044
- const existing = readExistingReviewRequestFile(from.worktreePath);
10045
- const attachments = existing ? [buildReviewRequestAttachment(existing)] : [];
10373
+ const guidelines = resolveReviewGuidelines(from.worktreePath);
10046
10374
  const tab = createChatTab({
10047
10375
  fromThreadId: from.id,
10048
10376
  title: "Review",
10049
- attachments
10377
+ attachments: [
10378
+ buildReviewRequestAttachment(guidelines.content, {
10379
+ path: guidelines.path,
10380
+ name: guidelines.name
10381
+ })
10382
+ ]
10050
10383
  });
10051
10384
  const started = await send(tab.id, REVIEW_REQUEST_PREFILL);
10052
10385
  return { tab: started, from };
@@ -10626,9 +10959,11 @@ var Orchestrator = class {
10626
10959
  this.emit({ type: "error", threadId, message: `context compact failed: ${message}` });
10627
10960
  thread = this.requireThread(threadId);
10628
10961
  }
10962
+ const sentAttachments = thread.attachments.length > 0 ? [...thread.attachments] : void 0;
10629
10963
  appendMessage(threadId, {
10630
10964
  role: "user",
10631
10965
  text: prompt,
10966
+ ...sentAttachments ? { attachments: sentAttachments } : {},
10632
10967
  ts: (/* @__PURE__ */ new Date()).toISOString()
10633
10968
  });
10634
10969
  thread = this.requireThread(threadId);
@@ -10636,7 +10971,7 @@ var Orchestrator = class {
10636
10971
  thread.worktreePath,
10637
10972
  prompt,
10638
10973
  {
10639
- attachments: thread.attachments
10974
+ attachments: sentAttachments ?? thread.attachments
10640
10975
  }
10641
10976
  );
10642
10977
  const orchestrationReminder = isOrchestratorThread(thread) ? coordinatorTurnReminder({
@@ -11320,6 +11655,9 @@ var Orchestrator = class {
11320
11655
  `Cannot switch agent provider mid-chat (${thread.agent} \u2192 ${patch.agent}). Start a new chat tab instead.`
11321
11656
  );
11322
11657
  }
11658
+ if (isOrchestratorThread(thread)) {
11659
+ assertOrchestratorCapableAgent(patch.agent);
11660
+ }
11323
11661
  next.agent = patch.agent;
11324
11662
  if (patch.agent !== "claude" && patch.model === void 0) next.model = null;
11325
11663
  next.sessionId = null;
@@ -11937,7 +12275,7 @@ async function startMcpServer() {
11937
12275
  );
11938
12276
  server.tool(
11939
12277
  "request_review",
11940
- "Start a merge-readiness Review on a worktree agent thread (same as the desktop Review button). Opens a new Review chat tab, optionally attaches .sideboard/attachments/Review request.md when present, and asks for Approve / Approve with nits / Request changes / Needs more information. Pass a worktree thread ref \u2014 not the orchestrator. Then wait_for_turn / get_turn_result on the returned review tab id.",
12278
+ 'Start a merge-readiness Review on a worktree agent thread (same as the desktop Review button). Opens a new Review chat tab, attaches .sideboard/review.md when present (else local Review request.md / stock template), and sends "Review." Expect Approve / Approve with nits / Request changes / Needs more information. Pass a worktree thread ref \u2014 not the orchestrator. Then wait_for_turn / get_turn_result on the returned review tab id.',
11941
12279
  { ref: import_zod.z.string().describe("Worktree thread id/ref to review") },
11942
12280
  async ({ ref }) => {
11943
12281
  try {
@@ -12029,7 +12367,7 @@ async function startMcpServer() {
12029
12367
  );
12030
12368
  server.tool(
12031
12369
  "fork_chat",
12032
- "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.",
12370
+ "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.",
12033
12371
  {
12034
12372
  ref: import_zod.z.string().describe("Thread id/ref to fork (worktree agent or orchestration chat)"),
12035
12373
  through_index: import_zod.z.number().optional().describe("Inclusive message index to include in the transcript (default: all)"),
@@ -12617,10 +12955,13 @@ init_injected_mcp();
12617
12955
  GLOBAL_WORKSPACE_ID,
12618
12956
  HARNESS_ENV_KEYS,
12619
12957
  MAX_ANTHROPIC_CACHE_CONTROL_BLOCKS,
12958
+ ORCHESTRATOR_AGENT_KINDS,
12620
12959
  Orchestrator,
12621
12960
  PASTE_ATTACH_MIN_CHARS,
12622
12961
  PASTE_ATTACH_MIN_LINES,
12623
12962
  PLAN_MODE_INSTRUCTION,
12963
+ REPO_REVIEW_NAME,
12964
+ REPO_REVIEW_PATH,
12624
12965
  REVIEW_REQUEST_NAME,
12625
12966
  REVIEW_REQUEST_PATH,
12626
12967
  REVIEW_REQUEST_PREFILL,
@@ -12641,6 +12982,7 @@ init_injected_mcp();
12641
12982
  applyAppEnvironment,
12642
12983
  applyCompaction,
12643
12984
  applyThreadIntoMain,
12985
+ assertOrchestratorCapableAgent,
12644
12986
  attachmentFromAbsolutePath,
12645
12987
  attachmentsFromBuffers,
12646
12988
  attachmentsFromWorktreePaths,
@@ -12673,6 +13015,7 @@ init_injected_mcp();
12673
13015
  cleanupOrphanWorktrees,
12674
13016
  cloneRepoIntoSideboard,
12675
13017
  codexAdapter,
13018
+ coerceOrchestratorAgent,
12676
13019
  collectTakenTeamSlugs,
12677
13020
  commitAll,
12678
13021
  conductorDbPath,
@@ -12704,6 +13047,7 @@ init_injected_mcp();
12704
13047
  ensureCloudCoordinator,
12705
13048
  ensureGhPreferOrigin,
12706
13049
  ensureGlobalCoordinatorCwd,
13050
+ ensureReviewRequestFile,
12707
13051
  ensureWorkspace,
12708
13052
  estimateMessageChars,
12709
13053
  estimateThreadChars,
@@ -12777,6 +13121,7 @@ init_injected_mcp();
12777
13121
  isGlobalThread,
12778
13122
  isImageFilePath,
12779
13123
  isLinearConnected,
13124
+ isOrchestratorCapableAgent,
12780
13125
  isOrchestratorThread,
12781
13126
  isPidAlive,
12782
13127
  isPlaceholderBranch,
@@ -12866,6 +13211,7 @@ init_injected_mcp();
12866
13211
  resolvePrSelector,
12867
13212
  resolveQuotaFallbackAgent,
12868
13213
  resolveRepoRoot,
13214
+ resolveReviewGuidelines,
12869
13215
  resolveThreadDefaults,
12870
13216
  resolveThreadEffort,
12871
13217
  resolveWorktreeStartPoint,
@@ -12881,6 +13227,7 @@ init_injected_mcp();
12881
13227
  settingsSourceLabel,
12882
13228
  shouldAttachPastedText,
12883
13229
  shouldCompactContext,
13230
+ shouldRefreshReviewRequestTemplate,
12884
13231
  shouldRunWorktreeCleanup,
12885
13232
  sideboardHomeDir,
12886
13233
  sideboardReposDir,