@sideboard-ai/core 0.1.88 → 0.1.92

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 (31) hide show
  1. package/dist/agents/cursor-runner.cjs +176 -15
  2. package/dist/agents/cursor-runner.js +11 -2
  3. package/dist/{agents-LMUFTGKF.js → agents-JXQ5QHDU.js} +4 -4
  4. package/dist/{agents-ODBP7J6E.js → agents-TUV4NH7S.js} +5 -5
  5. package/dist/{chunk-RJLBSYUO.js → chunk-35LKGGOC.js} +45 -77
  6. package/dist/{chunk-WANQFU3S.js → chunk-6XBXVXX2.js} +2 -2
  7. package/dist/{chunk-7D27DD2X.js → chunk-CIRXAYWS.js} +260 -61
  8. package/dist/{chunk-B2KIO2SD.js → chunk-CLGO7TLO.js} +2 -2
  9. package/dist/{chunk-JE75QW2I.js → chunk-GJ2HJQIU.js} +236 -96
  10. package/dist/{chunk-CBJSPTBG.js → chunk-GXSYI7FH.js} +206 -5
  11. package/dist/chunk-MMI4RJ5I.js +46 -0
  12. package/dist/{chunk-UHTNJKZX.js → chunk-NR6APJLD.js} +2 -2
  13. package/dist/{chunk-6EZRSCIT.js → chunk-QKYO6BHB.js} +2 -2
  14. package/dist/{chunk-ZXYWWSHZ.js → chunk-R7BQBSDT.js} +254 -61
  15. package/dist/{chunk-OB6IRIFV.js → chunk-XH2GS2LO.js} +2 -2
  16. package/dist/{chunk-VZ2L4AEJ.js → chunk-XUWDLRAE.js} +2 -2
  17. package/dist/{coordinator-prompt-UK5LYFN5.js → coordinator-prompt-AKEY4WSO.js} +2 -2
  18. package/dist/{coordinator-prompt-CI5SHONJ.js → coordinator-prompt-OQOOD5ET.js} +2 -2
  19. package/dist/{global-workspace-2YZ2V4I5.js → global-workspace-3GNPQCLE.js} +3 -3
  20. package/dist/{global-workspace-JQQLPJM5.js → global-workspace-M3OMVDDH.js} +3 -3
  21. package/dist/index.cjs +998 -463
  22. package/dist/index.d.cts +77 -19
  23. package/dist/index.d.ts +77 -19
  24. package/dist/index.js +181 -50
  25. package/dist/mcp/run-stdio.cjs +872 -436
  26. package/dist/mcp/run-stdio.js +132 -48
  27. package/dist/{workspaces-YWCC3WV4.js → workspaces-ERZC7ULY.js} +4 -4
  28. package/dist/{workspaces-FDO5L4NI.js → workspaces-J4WG6UFR.js} +4 -4
  29. package/dist/{worktree-7YNSJ224.js → worktree-DA4BOV7G.js} +7 -1
  30. package/dist/{worktree-4555QBQ7.js → worktree-EO5QAGJU.js} +7 -1
  31. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  listWorkspaces,
5
5
  removeWorkspace,
6
6
  syncWorkspacesFromThreads
7
- } from "./chunk-6EZRSCIT.js";
7
+ } from "./chunk-QKYO6BHB.js";
8
8
  import {
9
9
  BRIGHTSY_MCP_ALLOWED_TOOLS,
10
10
  CLAUDE_MODEL_CATALOG,
@@ -58,13 +58,14 @@ import {
58
58
  resolveCursorModelId,
59
59
  resolveLoginCommand,
60
60
  resolveQuotaFallbackAgent,
61
+ resolveSideboardMcpServer,
61
62
  sanitizeMcpServerName,
62
63
  shouldInjectBrightsyMcp,
63
64
  sideboardMcpProfile,
64
65
  threadRequestsBrightsyMcp,
65
66
  totalTokens,
66
67
  writeInjectedMcpConfig
67
- } from "./chunk-RJLBSYUO.js";
68
+ } from "./chunk-35LKGGOC.js";
68
69
  import {
69
70
  CLOUD_COORDINATOR_BUSY_REPLY,
70
71
  CLOUD_COORDINATOR_STOPPED_REPLY,
@@ -91,7 +92,7 @@ import {
91
92
  parseForceStopMessage,
92
93
  slackCoordinatorSourceRef,
93
94
  takenTeamSlugsForOrchestration
94
- } from "./chunk-B2KIO2SD.js";
95
+ } from "./chunk-CLGO7TLO.js";
95
96
  import {
96
97
  COORDINATOR_TOOL_PLAYBOOK,
97
98
  SLACK_REPLY_FORMATTING,
@@ -100,7 +101,7 @@ import {
100
101
  enrichWorkspacesWithGithub,
101
102
  ensureGlobalCoordinatorCwd,
102
103
  formatWorkspaceInventory
103
- } from "./chunk-VZ2L4AEJ.js";
104
+ } from "./chunk-XUWDLRAE.js";
104
105
  import {
105
106
  brightsyConfigPath,
106
107
  brightsyMcpServerName,
@@ -124,6 +125,9 @@ import {
124
125
  resolvePlanMarkdown,
125
126
  writePlanFile
126
127
  } from "./chunk-QTUESPAW.js";
128
+ import {
129
+ createAgentStreamCoalescer
130
+ } from "./chunk-MMI4RJ5I.js";
127
131
  import {
128
132
  cursorSdkMessageToEvents,
129
133
  fallbackTurnFailDetail,
@@ -134,7 +138,7 @@ import {
134
138
  parseCursorRunnerLine,
135
139
  pushTurnStderr,
136
140
  summarizeTurnStderr
137
- } from "./chunk-CBJSPTBG.js";
141
+ } from "./chunk-GXSYI7FH.js";
138
142
  import {
139
143
  caffeinateHoldPath,
140
144
  getCaffeinateHold,
@@ -151,6 +155,7 @@ import {
151
155
  applyGithubGitAuthEnv,
152
156
  branchDisplayLabel,
153
157
  checkoutPrStackLayer,
158
+ codexSandboxWritableRootsArgs,
154
159
  codexUnattendedGitConfigArgs,
155
160
  collectTakenTeamSlugs,
156
161
  commitAll,
@@ -171,12 +176,14 @@ import {
171
176
  getPr,
172
177
  getPrChecks,
173
178
  getPrDetails,
179
+ getPrForHeadBranch,
174
180
  getPrMeta,
175
181
  getPrStack,
176
182
  ghHeadRef,
177
183
  ghRepoSelectArgs,
178
184
  githubAgentGitEnv,
179
185
  initPrStack,
186
+ isDefaultishSourceRef,
180
187
  isDirty,
181
188
  isGhRateLimitError,
182
189
  isInPrStack,
@@ -187,6 +194,7 @@ import {
187
194
  listPrs,
188
195
  listWorktrees,
189
196
  lookupSoccerTeam,
197
+ mergeAgentGitAuthEnv,
190
198
  mergePr,
191
199
  mergePrStack,
192
200
  nonInteractiveGitProcessEnv,
@@ -197,24 +205,29 @@ import {
197
205
  pushBranch,
198
206
  removeWorktree,
199
207
  resetGhStackDetectCache,
208
+ resetGithubAgentTokenMemo,
200
209
  resolveAgentGitAuthEnv,
210
+ resolveCodexGitWritableRoots,
201
211
  resolveDefaultBranch,
202
212
  resolveDiffBaseRef,
203
213
  resolveGithubAgentToken,
204
214
  resolveGithubRepoSlug,
205
215
  resolvePrSelector,
216
+ resolvePrSelectors,
206
217
  resolveRepoRoot,
207
218
  resolveWorktreeStartPoint,
219
+ scrubGithubTokensFromChildEnv,
208
220
  slugify,
209
221
  stackMergeReadiness,
210
222
  submitPrStack,
211
223
  suggestSlug,
212
224
  takenSlugsFromThread,
213
225
  threadDisplayLabel,
226
+ warmGithubAgentAuth,
214
227
  worktreeDisplayLabel,
215
228
  worktreeDisplayLabelForGroup,
216
229
  worktreeNameFromPath
217
- } from "./chunk-7D27DD2X.js";
230
+ } from "./chunk-CIRXAYWS.js";
218
231
  import {
219
232
  ATTACHMENTS_DIR,
220
233
  LEGACY_ATTACHMENTS_DIR,
@@ -1325,9 +1338,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
1325
1338
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
1326
1339
  );
1327
1340
  }
1328
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-JQQLPJM5.js");
1341
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-M3OMVDDH.js");
1329
1342
  if (isGlobalThread2(thread)) {
1330
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-UK5LYFN5.js");
1343
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-AKEY4WSO.js");
1331
1344
  ensureGlobalCoordinatorCwd2(
1332
1345
  isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
1333
1346
  );
@@ -1345,10 +1358,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
1345
1358
  const env = childEnvWithAppSettings(cmd.env);
1346
1359
  try {
1347
1360
  if (isOrchestratorThread(thread)) {
1348
- Object.assign(env, await resolveAgentGitAuthEnv(env));
1361
+ mergeAgentGitAuthEnv(env, await resolveAgentGitAuthEnv(env));
1349
1362
  } else {
1350
- const originEnv = await originGhRepoEnv(thread.worktreePath, { env });
1351
- Object.assign(env, originEnv);
1363
+ mergeAgentGitAuthEnv(env, await originGhRepoEnv(thread.worktreePath, { env }));
1352
1364
  }
1353
1365
  } catch (err) {
1354
1366
  const detail = err instanceof Error ? err.message : String(err);
@@ -1372,12 +1384,13 @@ async function spawnAgentTurn(thread, input, onEvent) {
1372
1384
  let assistantText = "";
1373
1385
  let parts = [];
1374
1386
  let usage = null;
1387
+ const outbound = createAgentStreamCoalescer(onEvent);
1375
1388
  const consume = (stream, kind) => {
1376
1389
  if (!stream) return;
1377
1390
  const rl = createInterface({ input: stream, crlfDelay: Infinity });
1378
1391
  rl.on("line", (line) => {
1379
1392
  if (kind === "stderr") {
1380
- onEvent({ type: "stderr", data: line });
1393
+ outbound.push({ type: "stderr", data: line });
1381
1394
  return;
1382
1395
  }
1383
1396
  let events = normalizeParseResult(adapter.parseEvent(line));
@@ -1392,12 +1405,12 @@ async function spawnAgentTurn(thread, input, onEvent) {
1392
1405
  for (const parsed of events) {
1393
1406
  if (parsed.type === "session_id") {
1394
1407
  sessionId = parsed.data;
1395
- onEvent(parsed);
1408
+ outbound.push(parsed);
1396
1409
  continue;
1397
1410
  }
1398
1411
  if (parsed.type === "usage") {
1399
1412
  usage = applyTurnUsage(usage, parsed.data, parsed.scope ?? "request");
1400
- onEvent(parsed);
1413
+ outbound.push(parsed);
1401
1414
  continue;
1402
1415
  }
1403
1416
  if (parsed.type === "stdout") {
@@ -1410,13 +1423,14 @@ async function spawnAgentTurn(thread, input, onEvent) {
1410
1423
  assistantText += parsed.data;
1411
1424
  }
1412
1425
  parts = applyAgentEvent(parts, parsed);
1413
- onEvent(parsed);
1426
+ outbound.push(parsed);
1414
1427
  }
1415
1428
  });
1416
1429
  };
1417
1430
  consume(child.stdout, "stdout");
1418
1431
  consume(child.stderr, "stderr");
1419
1432
  const done = child.then((result) => {
1433
+ outbound.flush();
1420
1434
  const exitCode = result.exitCode ?? null;
1421
1435
  onEvent({ type: "exit", data: exitCode });
1422
1436
  const finalized = finalizeParts(parts);
@@ -1569,9 +1583,10 @@ function formatArtifactDirective() {
1569
1583
  "Files / media browser (CMS file manager column):",
1570
1584
  "4) Call Sideboard MCP `present_files` with optional title, path, and datasource (brightsy|memory).",
1571
1585
  " Opens the Files column for browse/upload/pick. Do NOT say a file manager UI is missing.",
1572
- "Multiple-choice questions (any mode \u2014 not only Plan):",
1573
- "5) Call Sideboard MCP `ask_user` when the user should pick from predefined options (approach forks, requirements, which API). First write a short chat message that explains the decision and what each option means (tradeoffs, when to pick it). Include a description on every option. After calling, stop and wait for their next message with answers. Do not ask multiple-choice questions as plain chat bullets \u2014 use ask_user so Sideboard shows the composer picker.",
1574
- "Never say artifacts, CMS UI, or the Files column are unavailable. Prefer present_schema for list/edit/publish; present_files for storage UI; html fences for standalone pages; ask_user for predefined-option questions."
1586
+ "Multiple-choice questions:",
1587
+ "5) Call Sideboard MCP `ask_user` only when work is blocked on choosing among a few concrete options (approach forks, which API, auth vs cookies). First write a short chat message that explains the decision and what each option means (tradeoffs, when to pick it). Include a description on every option. After calling, stop and wait for their next message with answers. If you are asking a real multiple-choice, use ask_user rather than chat bullets so Sideboard shows the composer picker.",
1588
+ "Do not call ask_user for greetings, check-ins, \u201Chello\u201D, open-ended how-can-I-help, or to invent a menu of possible next tasks \u2014 reply in chat. If one option is the obvious default, proceed without asking.",
1589
+ "Never say artifacts, CMS UI, or the Files column are unavailable. Prefer present_schema for list/edit/publish; present_files for storage UI; html fences for standalone pages; ask_user only for those blocked predefined-option questions."
1575
1590
  ].join("\n");
1576
1591
  }
1577
1592
  function formatUiReminder() {
@@ -1582,7 +1597,7 @@ function formatUiReminder() {
1582
1597
  "CMS forms/tables: MCP present_schema (Brightsy resource_id or inline schema+schemaUi).",
1583
1598
  "Files column: MCP present_files (brightsy account storage or memory).",
1584
1599
  "Do not say artifacts/CMS UI are unavailable.",
1585
- "Multiple-choice questions: MCP ask_user (composer picker, any mode). Explain options in chat first, then wait for answers."
1600
+ "ask_user: only when blocked on a real multiple-choice (approach fork, which API). Never for hellos, check-ins, or \u201Cwhat next?\u201D menus \u2014 reply in chat."
1586
1601
  ].join(" ");
1587
1602
  }
1588
1603
  var FILES_BY_AGENT = {
@@ -1869,7 +1884,10 @@ async function spawnWorkspaceScript(command, opts) {
1869
1884
  loginEnv
1870
1885
  );
1871
1886
  try {
1872
- Object.assign(env, await resolveAgentGitAuthEnv(env, { cwd: opts.worktreePath }));
1887
+ mergeAgentGitAuthEnv(
1888
+ env,
1889
+ await resolveAgentGitAuthEnv(env, { cwd: opts.worktreePath })
1890
+ );
1873
1891
  } catch {
1874
1892
  }
1875
1893
  const shell = process.platform === "darwin" ? "zsh" : "bash";
@@ -3754,6 +3772,7 @@ async function createThread(input, _onSetupLine) {
3754
3772
  let sourceRef = input.sourceRef;
3755
3773
  let sourceIsFork = false;
3756
3774
  let prUrl = null;
3775
+ let prTitle = null;
3757
3776
  if (input.sourceType === "pr") {
3758
3777
  const num = Number(input.sourceRef.replace(/^#/, ""));
3759
3778
  if (!Number.isFinite(num)) throw new Error(`Invalid PR number: ${input.sourceRef}`);
@@ -3769,6 +3788,12 @@ async function createThread(input, _onSetupLine) {
3769
3788
  } else if (input.sourceType === "branch") {
3770
3789
  if (!sourceRef || sourceRef === "HEAD" || sourceRef === "default") {
3771
3790
  sourceRef = await resolveDefaultBranch(repoPath);
3791
+ } else {
3792
+ const existing = await getPrForHeadBranch(repoPath, sourceRef);
3793
+ if (existing?.url) {
3794
+ prUrl = existing.url;
3795
+ prTitle = existing.title;
3796
+ }
3772
3797
  }
3773
3798
  } else if (input.sourceType === "adopt") {
3774
3799
  throw new Error("Use adoptThread() for adopt sources");
@@ -3799,14 +3824,15 @@ async function createThread(input, _onSetupLine) {
3799
3824
  sourceIsFork,
3800
3825
  parentThreadId: input.parentThreadId ?? null,
3801
3826
  status: "idle",
3802
- prUrl
3827
+ prUrl,
3828
+ prTitle
3803
3829
  });
3804
3830
  writeThread(thread);
3805
3831
  await ensureWorkspace(repoPath);
3806
3832
  return readThread(thread.id) ?? thread;
3807
3833
  }
3808
3834
  async function listLinearIssues(agent, repoPath) {
3809
- const { getAdapter: getAdapter2 } = await import("./agents-ODBP7J6E.js");
3835
+ const { getAdapter: getAdapter2 } = await import("./agents-TUV4NH7S.js");
3810
3836
  await requireAgent(agent, { requireLinear: true });
3811
3837
  const adapter = getAdapter2(agent);
3812
3838
  if (!adapter.listLinearIssues) {
@@ -4272,7 +4298,7 @@ import {
4272
4298
  } from "fs";
4273
4299
  import { tmpdir } from "os";
4274
4300
  import { join as join6 } from "path";
4275
- import Database from "better-sqlite3";
4301
+ import { createRequire } from "module";
4276
4302
  var CONDUCTOR_APP_SUPPORT = join6(
4277
4303
  process.env.HOME ?? "",
4278
4304
  "Library",
@@ -4281,6 +4307,11 @@ var CONDUCTOR_APP_SUPPORT = join6(
4281
4307
  );
4282
4308
  var CONDUCTOR_DB = join6(CONDUCTOR_APP_SUPPORT, "conductor.db");
4283
4309
  var CURSOR_SDK_STORE = join6(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
4310
+ function openReadonlySqlite(file) {
4311
+ const req = createRequire(import.meta.url);
4312
+ const Database = req("better-sqlite3");
4313
+ return new Database(file, { readonly: true, fileMustExist: true });
4314
+ }
4284
4315
  function mapAgentType(raw) {
4285
4316
  if (!raw) return null;
4286
4317
  const v = raw.toLowerCase();
@@ -4349,7 +4380,7 @@ async function adoptThread(input) {
4349
4380
  messages: input.messages ?? []
4350
4381
  });
4351
4382
  writeThread(thread);
4352
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-YWCC3WV4.js");
4383
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-ERZC7ULY.js");
4353
4384
  await ensureWorkspace2(repoPath);
4354
4385
  return thread;
4355
4386
  }
@@ -4373,7 +4404,7 @@ function listConductorWorkspaces() {
4373
4404
  }
4374
4405
  }
4375
4406
  }
4376
- const db = new Database(snapshot, { readonly: true, fileMustExist: true });
4407
+ const db = openReadonlySqlite(snapshot);
4377
4408
  try {
4378
4409
  const tables = db.prepare(`SELECT name FROM sqlite_master WHERE type='table'`).all();
4379
4410
  const names = new Set(tables.map((t) => t.name));
@@ -4464,7 +4495,7 @@ function importConductorWorkspace(workspaceId) {
4464
4495
  }
4465
4496
  }
4466
4497
  }
4467
- const db = new Database(snapshot, { readonly: true, fileMustExist: true });
4498
+ const db = openReadonlySqlite(snapshot);
4468
4499
  try {
4469
4500
  const row = db.prepare(
4470
4501
  `SELECT
@@ -6354,10 +6385,12 @@ var Orchestrator = class {
6354
6385
  if (event.type === "stderr" && typeof event.data === "string") {
6355
6386
  pushTurnStderr(stderrTail, event.data);
6356
6387
  }
6357
- const live = readThread(threadId);
6358
- if (live?.lastError?.includes("reconciled on startup") && (this.activeTurns.has(threadId) || this.startingTurns.has(threadId))) {
6359
- setStatus(threadId, "running");
6360
- this.emit({ type: "status_changed", threadId, status: "running" });
6388
+ if (event.type !== "stdout" && event.type !== "thinking") {
6389
+ const live = readThread(threadId);
6390
+ if (live?.lastError?.includes("reconciled on startup") && (this.activeTurns.has(threadId) || this.startingTurns.has(threadId))) {
6391
+ setStatus(threadId, "running");
6392
+ this.emit({ type: "status_changed", threadId, status: "running" });
6393
+ }
6361
6394
  }
6362
6395
  }
6363
6396
  );
@@ -6941,8 +6974,9 @@ var Orchestrator = class {
6941
6974
  return result;
6942
6975
  }
6943
6976
  async mergePr(threadRef) {
6944
- const { thread, selector, cwd } = await this.withPrSelector(threadRef);
6977
+ const { thread, selectors, cwd } = await this.withPrSelector(threadRef);
6945
6978
  this.assertNotGlobal(thread, "Merge PR");
6979
+ const selector = selectors[0];
6946
6980
  if (!selector) throw new Error("No pull request linked to this thread");
6947
6981
  const result = await mergePr(cwd, selector);
6948
6982
  const state = normalizePrState(result.state) || "MERGED";
@@ -6962,29 +6996,34 @@ var Orchestrator = class {
6962
6996
  await this.persistPrMetaAndMaybeArchive(thread, metaLike);
6963
6997
  return { url: metaLike.url, state };
6964
6998
  }
6965
- /** Resolve PR selector and optionally persist `prUrl` when found. */
6999
+ /** Resolve PR selectors and optionally persist `prUrl` when found. */
6966
7000
  async withPrSelector(threadRef) {
6967
7001
  const thread = this.requireThread(threadRef);
6968
- const selector = resolvePrSelector(thread);
7002
+ const selectors = resolvePrSelectors(thread);
6969
7003
  const cwd = thread.worktreePath;
6970
7004
  if (!cwd?.trim()) {
6971
7005
  throw new Error(`Thread ${threadRef} has no worktreePath`);
6972
7006
  }
6973
- return { thread, selector, cwd };
7007
+ return { thread, selectors, cwd };
6974
7008
  }
6975
7009
  async getPrChecks(threadRef) {
6976
- const { selector, cwd } = await this.withPrSelector(threadRef);
6977
- if (!selector) return null;
6978
- return getPrChecks(cwd, selector);
7010
+ const { selectors, cwd } = await this.withPrSelector(threadRef);
7011
+ for (const selector of selectors) {
7012
+ const checks = await getPrChecks(cwd, selector);
7013
+ if (checks) return checks;
7014
+ }
7015
+ return null;
6979
7016
  }
6980
7017
  async getPrMeta(threadRef) {
6981
- const { thread, selector, cwd } = await this.withPrSelector(threadRef);
6982
- if (!selector) return null;
6983
- const meta = await getPrMeta(cwd, selector);
6984
- if (meta) {
6985
- await this.persistPrMetaAndMaybeArchive(thread, meta);
7018
+ const { thread, selectors, cwd } = await this.withPrSelector(threadRef);
7019
+ for (const selector of selectors) {
7020
+ const meta = await getPrMeta(cwd, selector);
7021
+ if (meta) {
7022
+ await this.persistPrMetaAndMaybeArchive(thread, meta);
7023
+ return meta;
7024
+ }
6986
7025
  }
6987
- return meta;
7026
+ return null;
6988
7027
  }
6989
7028
  /**
6990
7029
  * Persist PR URL/title/state and Conductor-style auto-archive when the PR
@@ -7108,9 +7147,12 @@ var Orchestrator = class {
7108
7147
  return { stack: result.stack, threads: result.threads };
7109
7148
  }
7110
7149
  async getPrDetails(threadRef) {
7111
- const { thread, selector, cwd } = await this.withPrSelector(threadRef);
7112
- if (!selector) return null;
7113
- const details = await getPrDetails(cwd, selector);
7150
+ const { thread, selectors, cwd } = await this.withPrSelector(threadRef);
7151
+ let details = null;
7152
+ for (const selector of selectors) {
7153
+ details = await getPrDetails(cwd, selector);
7154
+ if (details) break;
7155
+ }
7114
7156
  if (details) {
7115
7157
  const patch = {};
7116
7158
  if (details.url && details.url !== thread.prUrl) patch.prUrl = details.url;
@@ -7295,7 +7337,7 @@ var Orchestrator = class {
7295
7337
  this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
7296
7338
  if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
7297
7339
  try {
7298
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-YWCC3WV4.js");
7340
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-ERZC7ULY.js");
7299
7341
  await ensureWorkspace2(thread.repoPath);
7300
7342
  } catch {
7301
7343
  }
@@ -7338,7 +7380,7 @@ var Orchestrator = class {
7338
7380
  return restored2;
7339
7381
  }
7340
7382
  if (!existsSync14(thread.worktreePath)) {
7341
- const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-7YNSJ224.js");
7383
+ const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-DA4BOV7G.js");
7342
7384
  const { execa: execa5 } = await import("execa");
7343
7385
  const slug = thread.worktreePath.split("/").pop();
7344
7386
  const dest = thread.worktreePath;
@@ -7447,7 +7489,7 @@ async function startOrchestration(opts) {
7447
7489
  sourceRef: "default",
7448
7490
  ...createOpts
7449
7491
  }).catch(async () => {
7450
- const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-7YNSJ224.js");
7492
+ const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-DA4BOV7G.js");
7451
7493
  const repo = await resolveRepoRoot2(repoPath);
7452
7494
  const def = await resolveDefaultBranch2(repo);
7453
7495
  return orch.createThread({
@@ -8198,6 +8240,14 @@ function withTimeout(promise, ms, label) {
8198
8240
  }
8199
8241
  async function startMcpServer() {
8200
8242
  const orch = getOrchestrator();
8243
+ try {
8244
+ await warmGithubAgentAuth();
8245
+ } catch (err) {
8246
+ console.error(
8247
+ "[sideboard-mcp] GitHub agent auth warm skipped:",
8248
+ err instanceof Error ? err.message : err
8249
+ );
8250
+ }
8201
8251
  try {
8202
8252
  const { maxConcurrentAgents: maxConcurrentAgents2 } = await import("./app-settings-BRF7VKTQ.js");
8203
8253
  orch.setMaxConcurrent(maxConcurrentAgents2());
@@ -8304,7 +8354,7 @@ async function startMcpServer() {
8304
8354
  );
8305
8355
  server.tool(
8306
8356
  "ask_user",
8307
- "Ask the user clarifying multiple-choice questions in Sideboard\u2019s composer (any mode \u2014 not only Plan). Before calling, write a short chat message explaining the decision and what each option means. Include a description on every option. Use when the user should pick from predefined options (approach forks, requirements, which API) \u2014 not for \u201Cis the plan ready?\u201D. After calling, stop and wait for their next message with answers.",
8357
+ "Ask the user a clarifying multiple-choice question in Sideboard\u2019s composer. Call only when work is blocked on choosing among a few concrete options (approach fork, which API, auth vs cookies). Do not call for greetings, check-ins, \u201Chello\u201D, open-ended how-can-I-help, or to invent a menu of possible next tasks \u2014 reply in chat instead. If one option is the obvious default, proceed without asking. Before calling, write a short chat message explaining the decision and what each option means. Include a description on every option. After calling, stop and wait for answers. Not for \u201Cis the plan ready?\u201D.",
8308
8358
  {
8309
8359
  questions: z3.array(
8310
8360
  z3.object({
@@ -9533,6 +9583,74 @@ async function runCloudConnect(opts) {
9533
9583
  }
9534
9584
  }
9535
9585
 
9586
+ // src/agents/user-mcp-config.ts
9587
+ import { existsSync as existsSync15, mkdirSync as mkdirSync5, readFileSync as readFileSync10, writeFileSync as writeFileSync4 } from "fs";
9588
+ import { homedir as homedir2 } from "os";
9589
+ import { dirname as dirname4, join as join13 } from "path";
9590
+ function userCursorMcpConfigPath() {
9591
+ return join13(homedir2(), ".cursor", "mcp.json");
9592
+ }
9593
+ function userClaudeMcpConfigPath() {
9594
+ return join13(homedir2(), ".claude.json");
9595
+ }
9596
+ function asObject(value) {
9597
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
9598
+ return { ...value };
9599
+ }
9600
+ function stripElectronSpawnEnv(env) {
9601
+ if (!env) return void 0;
9602
+ const next = { ...env };
9603
+ delete next.ELECTRON_RUN_AS_NODE;
9604
+ delete next.ELECTRON_RUN_AS_NODE;
9605
+ return Object.keys(next).length > 0 ? next : void 0;
9606
+ }
9607
+ function mergeSideboardIntoMcpServersJson(existing, sideboard) {
9608
+ const root = asObject(existing);
9609
+ const servers = asObject(root.mcpServers);
9610
+ const env = stripElectronSpawnEnv(sideboard.env);
9611
+ servers.sideboard = {
9612
+ command: sideboard.command,
9613
+ ...sideboard.args && sideboard.args.length > 0 ? { args: sideboard.args } : {},
9614
+ ...env ? { env } : {}
9615
+ };
9616
+ return { ...root, mcpServers: servers };
9617
+ }
9618
+ function writeMergedMcpServersJson(configPath, sideboard) {
9619
+ let existing = {};
9620
+ if (existsSync15(configPath)) {
9621
+ try {
9622
+ existing = JSON.parse(readFileSync10(configPath, "utf8"));
9623
+ } catch {
9624
+ existing = {};
9625
+ }
9626
+ }
9627
+ const next = mergeSideboardIntoMcpServersJson(existing, sideboard);
9628
+ mkdirSync5(dirname4(configPath), { recursive: true });
9629
+ writeFileSync4(configPath, `${JSON.stringify(next, null, 2)}
9630
+ `);
9631
+ }
9632
+ function launchFromResolved(server) {
9633
+ return {
9634
+ command: server.command,
9635
+ args: server.args,
9636
+ env: {
9637
+ ...server.env ?? {},
9638
+ SIDEBOARD_APP_DATA: appDataDir()
9639
+ }
9640
+ };
9641
+ }
9642
+ async function registerPackagedUserMcpClients() {
9643
+ const launch = launchFromResolved(await resolveSideboardMcpServer());
9644
+ const cursor = userCursorMcpConfigPath();
9645
+ writeMergedMcpServersJson(cursor, launch);
9646
+ const claude = userClaudeMcpConfigPath();
9647
+ if (existsSync15(claude)) {
9648
+ writeMergedMcpServersJson(claude, launch);
9649
+ return { cursor, claude };
9650
+ }
9651
+ return { cursor };
9652
+ }
9653
+
9536
9654
  // src/slack/oauth.ts
9537
9655
  import { randomBytes as randomBytes2 } from "crypto";
9538
9656
 
@@ -11231,6 +11349,7 @@ export {
11231
11349
  cleanupOrphanWorktrees,
11232
11350
  cloneRepoIntoSideboard,
11233
11351
  codexAdapter,
11352
+ codexSandboxWritableRootsArgs,
11234
11353
  codexUnattendedGitConfigArgs,
11235
11354
  coerceOrchestratorAgent,
11236
11355
  collectTakenTeamSlugs,
@@ -11347,6 +11466,7 @@ export {
11347
11466
  getPr,
11348
11467
  getPrChecks,
11349
11468
  getPrDetails,
11469
+ getPrForHeadBranch,
11350
11470
  getPrMeta,
11351
11471
  getPrStack,
11352
11472
  getRepoSetupInfo,
@@ -11383,6 +11503,7 @@ export {
11383
11503
  isCloudCoordinatorThread,
11384
11504
  isConductorBundledCli,
11385
11505
  isCursorAutoModel,
11506
+ isDefaultishSourceRef,
11386
11507
  isDirty,
11387
11508
  isGhRateLimitError,
11388
11509
  isGlobalRepoPath,
@@ -11449,8 +11570,10 @@ export {
11449
11570
  maybeCompactContext,
11450
11571
  mcpAllowTools,
11451
11572
  mcpAuthWarnings,
11573
+ mergeAgentGitAuthEnv,
11452
11574
  mergePr,
11453
11575
  mergePrStack,
11576
+ mergeSideboardIntoMcpServersJson,
11454
11577
  mergeUsage,
11455
11578
  nextPastedTextName,
11456
11579
  nextThinkingEffort,
@@ -11501,6 +11624,7 @@ export {
11501
11624
  recordSlackOutboundWatch,
11502
11625
  refreshGitHubAuth,
11503
11626
  refreshSlackReplyBadges,
11627
+ registerPackagedUserMcpClients,
11504
11628
  releaseCaffeinateHoldForThread,
11505
11629
  removeWorkspace,
11506
11630
  removeWorktree,
@@ -11509,9 +11633,11 @@ export {
11509
11633
  requestReview,
11510
11634
  requireAgent,
11511
11635
  resetGhStackDetectCache,
11636
+ resetGithubAgentTokenMemo,
11512
11637
  resolveAgentExecutable,
11513
11638
  resolveAgentGitAuthEnv,
11514
11639
  resolveClaudeExecutable,
11640
+ resolveCodexGitWritableRoots,
11515
11641
  resolveCommandBinarySync,
11516
11642
  resolveConductorCursorAgentId,
11517
11643
  resolveCursorModelId,
@@ -11528,6 +11654,7 @@ export {
11528
11654
  resolveNewThreadOptions,
11529
11655
  resolvePlanMarkdown,
11530
11656
  resolvePrSelector,
11657
+ resolvePrSelectors,
11531
11658
  resolveQuotaFallbackAgent,
11532
11659
  resolveRepoRoot,
11533
11660
  resolveReviewGuidelines,
@@ -11550,6 +11677,7 @@ export {
11550
11677
  sanitizeMcpServerName,
11551
11678
  saveAppSettings,
11552
11679
  saveLinearOAuth,
11680
+ scrubGithubTokensFromChildEnv,
11553
11681
  secureFileUnlocksWith,
11554
11682
  setCaffeinateHold,
11555
11683
  setHttpFetchImpl,
@@ -11620,7 +11748,10 @@ export {
11620
11748
  updateLinearIssue,
11621
11749
  updateOpencodeSettings,
11622
11750
  updateThread,
11751
+ userClaudeMcpConfigPath,
11752
+ userCursorMcpConfigPath,
11623
11753
  validateLinearApiKey,
11754
+ warmGithubAgentAuth,
11624
11755
  withAgentInstructions,
11625
11756
  withExportedPath,
11626
11757
  withThreadLock,