@sideboard-ai/core 0.1.257 → 0.1.261

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 (66) hide show
  1. package/dist/{abletime-IDQJI2KW.js → abletime-CDGINDXG.js} +6 -5
  2. package/dist/{abletime-OGQR4LIL.js → abletime-OQ4PC52L.js} +7 -6
  3. package/dist/{abletime-oauth-ZQUIY4EM.js → abletime-oauth-5A5EOH2A.js} +5 -4
  4. package/dist/{abletime-oauth-MBAG5MYU.js → abletime-oauth-KX2TDFTE.js} +6 -5
  5. package/dist/{abletime-rest-WEJERY4O.js → abletime-rest-PUGKYTRR.js} +6 -5
  6. package/dist/{abletime-rest-JZIIT5W3.js → abletime-rest-UEHOBLXD.js} +5 -4
  7. package/dist/agents/cursor-runner.cjs +274 -12
  8. package/dist/agents/cursor-runner.js +156 -13
  9. package/dist/{agents-HZP7YEKC.js → agents-IKVUGW5H.js} +12 -9
  10. package/dist/{agents-FSUI5MET.js → agents-J2P4KNEY.js} +21 -18
  11. package/dist/{app-settings-CLARFJUX.js → app-settings-OM7H64YM.js} +12 -3
  12. package/dist/{app-settings-ONYJ36XH.js → app-settings-VQEUCONM.js} +11 -2
  13. package/dist/chunk-3HO2OY5T.js +159 -0
  14. package/dist/{chunk-F7ANS66U.js → chunk-4F7J6UWD.js} +75 -33
  15. package/dist/{chunk-WDDUIGFK.js → chunk-4GK32AYX.js} +1 -1
  16. package/dist/{chunk-ZC3TVLY6.js → chunk-5OKJDCBK.js} +5 -5
  17. package/dist/{chunk-KJM3E3NF.js → chunk-6PFZ6XO7.js} +65 -6
  18. package/dist/{title-4A2ATYNY.js → chunk-7H655NEW.js} +1 -0
  19. package/dist/{chunk-R4DWUBOL.js → chunk-ABPNIYRS.js} +78 -37
  20. package/dist/{chunk-XIEDFRBP.js → chunk-B6XFBNYM.js} +2 -2
  21. package/dist/chunk-CEMNIGQH.js +161 -0
  22. package/dist/{chunk-66LAOKLK.js → chunk-D554YCHG.js} +2 -2
  23. package/dist/{chunk-HCNCZPDL.js → chunk-FSZ7YYFQ.js} +119 -63
  24. package/dist/{chunk-4723RAO3.js → chunk-FWNL62VA.js} +3 -1
  25. package/dist/{chunk-Y7CS2WGJ.js → chunk-GIZQAOHZ.js} +247 -109
  26. package/dist/chunk-HHEKVR6C.js +72 -0
  27. package/dist/{chunk-IFHHPPSL.js → chunk-J6ONZP74.js} +5 -5
  28. package/dist/{chunk-PJK24CN3.js → chunk-JTNY5CK4.js} +10 -10
  29. package/dist/{chunk-CPEIHTG7.js → chunk-KVQX62XI.js} +3 -3
  30. package/dist/{chunk-5F4YFGHL.js → chunk-LDXSAVWO.js} +7 -7
  31. package/dist/{title-4WAKWZRF.js → chunk-LX5R5JOR.js} +1 -0
  32. package/dist/{chunk-D6JWYJ4P.js → chunk-N2WW62LF.js} +1 -0
  33. package/dist/{chunk-RTQOCFIV.js → chunk-S7VDDJ34.js} +3 -3
  34. package/dist/{chunk-RJC2MKXN.js → chunk-TJ673EZT.js} +3 -1
  35. package/dist/{chunk-63YSFXLT.js → chunk-U3AOJLH3.js} +126 -70
  36. package/dist/{chunk-452Y24PW.js → chunk-VIC6TDYT.js} +68 -9
  37. package/dist/{chunk-553IEH7O.js → chunk-W5PWGEKS.js} +241 -104
  38. package/dist/{chunk-VVHHBOIA.js → chunk-WV7KJH2E.js} +5 -3
  39. package/dist/{chunk-BYRZS2S2.js → chunk-X2OTZ36G.js} +4 -4
  40. package/dist/{chunk-FGWUZOZN.js → chunk-YFTO7U2A.js} +3 -3
  41. package/dist/connected-teams-7CENZDWU.js +1 -1
  42. package/dist/{connected-teams-Z5GOIC5I.js → connected-teams-RU6VATCM.js} +2 -2
  43. package/dist/{coordinator-prompt-HZUWK3NP.js → coordinator-prompt-TU6656OK.js} +9 -8
  44. package/dist/{coordinator-prompt-Y6S6USNS.js → coordinator-prompt-VQHQ3RIX.js} +8 -7
  45. package/dist/{global-workspace-4JCITHB6.js → global-workspace-47NZVA44.js} +8 -7
  46. package/dist/{global-workspace-YA7U4M2N.js → global-workspace-PHF2MOGW.js} +9 -8
  47. package/dist/index.cjs +1443 -856
  48. package/dist/index.d.cts +118 -37
  49. package/dist/index.d.ts +118 -37
  50. package/dist/index.js +148 -64
  51. package/dist/managed-accounts-2AK5RIAF.js +39 -0
  52. package/dist/managed-accounts-4BLTJKAN.js +41 -0
  53. package/dist/mcp/run-stdio.cjs +2722 -2248
  54. package/dist/mcp/run-stdio.js +136 -50
  55. package/dist/{orchestrator-LWADJQTN.js → orchestrator-OCG4QVA5.js} +13 -11
  56. package/dist/{orchestrator-VHJZEVGA.js → orchestrator-VLTO5JBR.js} +13 -11
  57. package/dist/{plan-file-CKXUFTQ2.js → plan-file-VAHV5WBB.js} +2 -2
  58. package/dist/{thread-store-HDQ4CH54.js → thread-store-FJ5CDX2M.js} +1 -1
  59. package/dist/{thread-store-ZDR3Z5UG.js → thread-store-SHCUBWB3.js} +1 -1
  60. package/dist/title-ERD6D3C3.js +8 -0
  61. package/dist/title-Z7WAJN57.js +6 -0
  62. package/dist/{workspaces-IXZD7EC4.js → workspaces-2XTDS7N2.js} +9 -8
  63. package/dist/{workspaces-4KHEUPEX.js → workspaces-I7TWFTJM.js} +8 -7
  64. package/dist/{worktree-DAAF64UU.js → worktree-DDDF3WHV.js} +8 -7
  65. package/dist/{worktree-S3FOMEQ2.js → worktree-YASFE65H.js} +7 -6
  66. package/package.json +1 -1
@@ -4,7 +4,7 @@ import {
4
4
  extractPresentedPlan,
5
5
  readPlanFile,
6
6
  writePlanFile
7
- } from "./chunk-WDDUIGFK.js";
7
+ } from "./chunk-4GK32AYX.js";
8
8
  import {
9
9
  releaseCaffeinateHoldForThread
10
10
  } from "./chunk-QN5DL2QO.js";
@@ -44,7 +44,7 @@ import {
44
44
  summarizeTurnStderr,
45
45
  toolDescription,
46
46
  turnFailChatText
47
- } from "./chunk-F7ANS66U.js";
47
+ } from "./chunk-4F7J6UWD.js";
48
48
  import {
49
49
  SLACK_REPLY_FORMATTING,
50
50
  addWorkspace,
@@ -67,9 +67,10 @@ import {
67
67
  stageAbsolutePathsAsAttachments,
68
68
  stageBuffersAsAttachments,
69
69
  syncWorkspacesFromThreads
70
- } from "./chunk-PJK24CN3.js";
70
+ } from "./chunk-JTNY5CK4.js";
71
71
  import {
72
72
  addPrStackLayer,
73
+ agentNicknameFromWorktreePath,
73
74
  allocateTeamName,
74
75
  allocateTeamSlug,
75
76
  canonicalizeRepoPath,
@@ -97,6 +98,7 @@ import {
97
98
  isDirty,
98
99
  isPlaceholderBranch,
99
100
  isSideboardScratchPath,
101
+ isWorktreeIdentityTitle,
100
102
  listWorktrees,
101
103
  markPrReady,
102
104
  mergeAgentGitAuthEnv,
@@ -112,31 +114,23 @@ import {
112
114
  resolveRepoRoot,
113
115
  switchWorktreeBranch,
114
116
  takenSlugsFromThread,
115
- threadDisplayLabel,
117
+ teamSlugFromName,
116
118
  ticketSlugForBranch,
117
119
  withRepoGitLock,
118
120
  worktreeDisplayLabelForGroup,
121
+ worktreeIdentityTitles,
119
122
  worktreeNameFromPath,
120
123
  worktreeSlugForTicket
121
- } from "./chunk-HCNCZPDL.js";
124
+ } from "./chunk-FSZ7YYFQ.js";
122
125
  import {
123
126
  ATTACHMENTS_DIR,
124
127
  DETACHED_JOBS_DIR,
125
128
  LEGACY_ATTACHMENTS_DIR,
126
129
  LEGACY_DETACHED_JOBS_DIR
127
- } from "./chunk-D6JWYJ4P.js";
130
+ } from "./chunk-N2WW62LF.js";
128
131
  import {
129
- appendMessage,
130
- createEmptyThread,
131
- deleteThreadRecord,
132
- findThreadByRef,
133
- listThreads,
134
- readThread,
135
- setStatus,
136
- updateThread,
137
- withThreadLock,
138
- writeThread
139
- } from "./chunk-RJC2MKXN.js";
132
+ titleFromPrompt
133
+ } from "./chunk-LX5R5JOR.js";
140
134
  import {
141
135
  ensureWorktreeSideboardIgnored
142
136
  } from "./chunk-DD67JWTN.js";
@@ -178,10 +172,35 @@ import {
178
172
  sumUsageList,
179
173
  updateAdvancedSettings,
180
174
  usageOnLimit
181
- } from "./chunk-452Y24PW.js";
175
+ } from "./chunk-VIC6TDYT.js";
182
176
  import {
183
177
  writePrivateFile
184
178
  } from "./chunk-NSTQ6QKD.js";
179
+ import {
180
+ stripNestedElectronEnv
181
+ } from "./chunk-WWUABK6B.js";
182
+ import {
183
+ examplePrefixedBranch,
184
+ sanitizeGitBranchPrefix
185
+ } from "./chunk-FJZWM2ON.js";
186
+ import {
187
+ accountIdToPin,
188
+ applyManagedAccountEnv,
189
+ nextManagedAccount,
190
+ resolveAccountForThread
191
+ } from "./chunk-CEMNIGQH.js";
192
+ import {
193
+ appendMessage,
194
+ createEmptyThread,
195
+ deleteThreadRecord,
196
+ findThreadByRef,
197
+ listThreads,
198
+ readThread,
199
+ setStatus,
200
+ updateThread,
201
+ withThreadLock,
202
+ writeThread
203
+ } from "./chunk-TJ673EZT.js";
185
204
  import {
186
205
  annotateDevAccessRuns,
187
206
  appDataDir,
@@ -196,13 +215,6 @@ import {
196
215
  workspaceSettingsSourceLabel,
197
216
  worktreesRoot
198
217
  } from "./chunk-Z2LGMV6C.js";
199
- import {
200
- stripNestedElectronEnv
201
- } from "./chunk-WWUABK6B.js";
202
- import {
203
- examplePrefixedBranch,
204
- sanitizeGitBranchPrefix
205
- } from "./chunk-FJZWM2ON.js";
206
218
 
207
219
  // src/orchestrator/orchestrator.ts
208
220
  import { EventEmitter } from "events";
@@ -493,9 +505,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
493
505
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
494
506
  );
495
507
  }
496
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-YA7U4M2N.js");
508
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-PHF2MOGW.js");
497
509
  if (isGlobalThread2(thread)) {
498
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-HZUWK3NP.js");
510
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-TU6656OK.js");
499
511
  ensureGlobalCoordinatorCwd2(
500
512
  isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
501
513
  );
@@ -523,6 +535,17 @@ async function spawnAgentTurn(thread, input, onEvent) {
523
535
  );
524
536
  }
525
537
  const env = childEnvWithAppSettings(cmd.env);
538
+ const accounts = loadAppSettings().accounts;
539
+ const pin = accountIdToPin(thread, accounts);
540
+ if (pin !== void 0 && thread.accountId !== pin) {
541
+ try {
542
+ updateThread(thread.id, { accountId: pin });
543
+ thread = { ...thread, accountId: pin };
544
+ } catch {
545
+ thread = { ...thread, accountId: pin };
546
+ }
547
+ }
548
+ applyManagedAccountEnv(env, thread.agent, resolveAccountForThread(thread, accounts));
526
549
  sanitizeAgentHostEnv(env, cmd.cwd);
527
550
  ensureAgentPath(env);
528
551
  applyPromptCacheTtlEnv(thread.agent, env);
@@ -1443,6 +1466,7 @@ function createChatTab(input) {
1443
1466
  autonomy: input.autonomy ?? from.autonomy,
1444
1467
  attachments: input.attachments ?? [],
1445
1468
  status: "idle",
1469
+ ...input.accountId !== void 0 ? { accountId: input.accountId } : {},
1446
1470
  ...mergeWorktreeActiveRuns(threadsSharingWorktree(binding.worktreePath))
1447
1471
  });
1448
1472
  writeThread(thread);
@@ -1467,6 +1491,32 @@ function forkChatTab(input) {
1467
1491
  return tab;
1468
1492
  }
1469
1493
 
1494
+ // src/review/review-write-gate.ts
1495
+ var REVIEW_TAB_TITLE = "Review";
1496
+ function hasLiveReviewSibling(thread, siblings = []) {
1497
+ const selfId = thread.id;
1498
+ return siblings.some(
1499
+ (t) => t.id !== selfId && t.status !== "archived" && t.title.trim() === REVIEW_TAB_TITLE
1500
+ );
1501
+ }
1502
+ function isReviewWriteGatedThread(thread, siblings) {
1503
+ if (thread.sourceType === "pr" || thread.title.trim() === REVIEW_TAB_TITLE) {
1504
+ return true;
1505
+ }
1506
+ return hasLiveReviewSibling(thread, siblings);
1507
+ }
1508
+ function formatReviewWriteGateDirective() {
1509
+ return [
1510
+ "Review writes are public. The PR or ticket author sees GitHub/Linear/AbleTime comments, ticket updates, and submitted reviews immediately \u2014 a draft will confuse them.",
1511
+ "Write the recommendation in chat so the user can work through the feedback first. Do not call github_comment, linear_comment, abletime_comment, github_update_issue, linear_update_issue, abletime_update_task, or run `gh pr review` / `gh pr comment`, until they type a next step that asks you to post.",
1512
+ "After the review is in chat, stop. Do not call ask_user. The user needs time to read and will type the next steps. If they already asked you to post a specific comment or update in this turn, that is confirmation.",
1513
+ "Do not request reviewers, change labels, or assign yourself unless they asked \u2014 those also notify the author."
1514
+ ].join("\n");
1515
+ }
1516
+ function formatReviewWriteGateReminder() {
1517
+ return "Review writes: keep the review in chat. Do not ask_user after it \u2014 they read and type next steps. Do not github_comment / linear_comment / *_update_* / `gh pr review` on the PR or ticket until they ask. Authors see those immediately.";
1518
+ }
1519
+
1470
1520
  // src/review/review-request-template.ts
1471
1521
  var REVIEW_REQUEST_TEMPLATE = `# Review guidelines:
1472
1522
 
@@ -1709,6 +1759,22 @@ function buildReviewRequestAttachment(content, opts) {
1709
1759
  content
1710
1760
  };
1711
1761
  }
1762
+ function canReuseIdleWorktreeAgentForReview(from, siblings) {
1763
+ const live = siblings.filter((t) => t.status !== "archived");
1764
+ if (live.length !== 1) return false;
1765
+ const only = live[0];
1766
+ if (only.id !== from.id) return false;
1767
+ if (from.status !== "idle") return false;
1768
+ if ((from.queue?.length ?? 0) > 0) return false;
1769
+ return (from.messages?.length ?? 0) === 0 && (only.messages?.length ?? 0) === 0;
1770
+ }
1771
+ function reviewGuidelinesAttachment(from) {
1772
+ const guidelines = resolveReviewGuidelines(from.worktreePath, from.repoPath);
1773
+ return buildReviewRequestAttachment(guidelines.content, {
1774
+ path: guidelines.path,
1775
+ name: guidelines.name
1776
+ });
1777
+ }
1712
1778
  async function requestReview(threadRef, send) {
1713
1779
  const from = findThreadByRef(threadRef);
1714
1780
  if (!from) throw new Error(`Thread not found: ${threadRef}`);
@@ -1720,16 +1786,21 @@ async function requestReview(threadRef, send) {
1720
1786
  if (from.status === "archived") {
1721
1787
  throw new Error(`Thread is archived: ${from.id}`);
1722
1788
  }
1723
- const guidelines = resolveReviewGuidelines(from.worktreePath, from.repoPath);
1789
+ const attachment = reviewGuidelinesAttachment(from);
1790
+ const siblings = threadsSharingWorktree(from.worktreePath);
1791
+ if (canReuseIdleWorktreeAgentForReview(from, siblings)) {
1792
+ const reused = updateThread(from.id, {
1793
+ title: REVIEW_TAB_TITLE,
1794
+ userSetTitle: true,
1795
+ attachments: [...from.attachments ?? [], attachment]
1796
+ });
1797
+ const started2 = await send(reused.id, REVIEW_REQUEST_PREFILL);
1798
+ return { tab: started2, from: reused };
1799
+ }
1724
1800
  const tab = createChatTab({
1725
1801
  fromThreadId: from.id,
1726
- title: "Review",
1727
- attachments: [
1728
- buildReviewRequestAttachment(guidelines.content, {
1729
- path: guidelines.path,
1730
- name: guidelines.name
1731
- })
1732
- ]
1802
+ title: REVIEW_TAB_TITLE,
1803
+ attachments: [attachment]
1733
1804
  });
1734
1805
  const started = await send(tab.id, REVIEW_REQUEST_PREFILL);
1735
1806
  return { tab: started, from };
@@ -3401,6 +3472,32 @@ function notifyParentOfChildHalt(child, status, send) {
3401
3472
  return true;
3402
3473
  }
3403
3474
 
3475
+ // src/threads/agent-purpose-title.ts
3476
+ function agentPurposeStamp(input) {
3477
+ if (input.autoContinue) return null;
3478
+ if (input.thread.sourceType === "orchestration") return null;
3479
+ if (input.thread.title.trim() === REVIEW_TAB_TITLE) return null;
3480
+ const identities = worktreeIdentityTitles(input.thread);
3481
+ const titled = input.thread.title?.trim() || "";
3482
+ const nickname = agentNicknameFromWorktreePath(input.thread.worktreePath);
3483
+ const soccerTitle = Boolean(teamSlugFromName(titled));
3484
+ const identityTitle = isWorktreeIdentityTitle(titled, identities);
3485
+ if (input.thread.userSetTitle && !soccerTitle && !identityTitle) return null;
3486
+ const userTurns = (input.thread.messages ?? []).filter(
3487
+ (m) => m.role === "user" && m.origin !== "continue" && m.text?.trim()
3488
+ ).length;
3489
+ if (userTurns <= 1) {
3490
+ const purpose = titleFromPrompt(input.prompt);
3491
+ if (purpose && !isWorktreeIdentityTitle(purpose, identities)) {
3492
+ return { title: purpose };
3493
+ }
3494
+ }
3495
+ if (isWorktreeIdentityTitle(titled, identities) && nickname && !isWorktreeIdentityTitle(nickname, identities)) {
3496
+ return { title: nickname };
3497
+ }
3498
+ return null;
3499
+ }
3500
+
3404
3501
  // src/threads/create.ts
3405
3502
  import { existsSync as existsSync9 } from "fs";
3406
3503
 
@@ -3972,7 +4069,7 @@ async function createThread(input, _onSetupLine) {
3972
4069
  });
3973
4070
  await requireAgent(resolved.agent);
3974
4071
  if (input.cowboy) {
3975
- const { cowboyModeEnabled } = await import("./app-settings-CLARFJUX.js");
4072
+ const { cowboyModeEnabled } = await import("./app-settings-OM7H64YM.js");
3976
4073
  if (!cowboyModeEnabled()) {
3977
4074
  throw new Error(
3978
4075
  "Cowboy mode is off. Enable it in Settings \u2192 Advanced."
@@ -4030,7 +4127,7 @@ async function createThread(input, _onSetupLine) {
4030
4127
  let sourceIsFork = false;
4031
4128
  if (!input.cowboy && sourceType === "branch" && (!sourceRef || sourceRef === "HEAD" || sourceRef === "default")) {
4032
4129
  if (isAbleTimeConnected() && getIssueSource() === "abletime") {
4033
- const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-OGQR4LIL.js");
4130
+ const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-OQ4PC52L.js");
4034
4131
  const task = await ensureAbleTimeTask({
4035
4132
  title: title?.trim() || "Untitled work",
4036
4133
  description: input.prompt?.trim() || void 0
@@ -4376,6 +4473,9 @@ async function forkThreadWorktree(input, onSetupLine) {
4376
4473
 
4377
4474
  // src/orchestrator/quota-failover.ts
4378
4475
  import { randomUUID as randomUUID3 } from "crypto";
4476
+ function managedKindForAgent(agent) {
4477
+ return agent === "claude" || agent === "codex" ? agent : null;
4478
+ }
4379
4479
  function planOrchestrationQuotaFailover(thread, limitText, opts) {
4380
4480
  if (!isSessionQuotaLimit(limitText)) return null;
4381
4481
  const onLimit = opts?.onLimit ?? usageOnLimit();
@@ -4388,7 +4488,7 @@ function planOrchestrationQuotaFailover(thread, limitText, opts) {
4388
4488
  };
4389
4489
  }
4390
4490
  if (thread.quotaContinuedFromId) {
4391
- if (onLimit === "switch_agent" && resumeAt) {
4491
+ if ((onLimit === "switch_agent" || onLimit === "switch_account") && resumeAt) {
4392
4492
  return {
4393
4493
  action: "wait_reset",
4394
4494
  reason: "Already continued once; waiting for quota reset instead.",
@@ -4417,6 +4517,32 @@ function planOrchestrationQuotaFailover(thread, limitText, opts) {
4417
4517
  resumeAt
4418
4518
  };
4419
4519
  }
4520
+ if (onLimit === "switch_account") {
4521
+ const kind = managedKindForAgent(thread.agent);
4522
+ if (!kind) {
4523
+ return {
4524
+ action: "none",
4525
+ reason: `switch_account configured but ${thread.agent} has no managed accounts.`,
4526
+ limitText
4527
+ };
4528
+ }
4529
+ const accounts = opts?.accounts ?? loadAppSettings().accounts;
4530
+ const next = nextManagedAccount(kind, thread.accountId ?? null, accounts);
4531
+ if (!next) {
4532
+ return {
4533
+ action: "none",
4534
+ reason: "switch_account configured but no other Claude/Codex account is available.",
4535
+ limitText
4536
+ };
4537
+ }
4538
+ return {
4539
+ action: "switch_account",
4540
+ reason: `Continue on ${kind} account \u201C${next.label}\u201D after session limit.`,
4541
+ limitText,
4542
+ fallbackAccountId: next.accountId,
4543
+ fallbackAccountLabel: next.label
4544
+ };
4545
+ }
4420
4546
  const preferred = opts?.fallbackAgent ?? orchestrationQuotaFallbackAgent();
4421
4547
  const fallbackAgent = resolveQuotaFallbackAgent(thread.agent, preferred);
4422
4548
  return {
@@ -4476,6 +4602,10 @@ var QUOTA_CONTINUE_PROMPT = (fromAgent, fallback) => [
4476
4602
  `${fromAgent} hit a session/usage limit. Continue this chat on ${fallback} using the attached handoff.`,
4477
4603
  "Proceed with the goal. Leave model Auto unless needed."
4478
4604
  ].join(" ");
4605
+ var QUOTA_CONTINUE_ACCOUNT_PROMPT = (fromAgent, accountLabel) => [
4606
+ `${fromAgent} hit a session/usage limit. Continue this chat on ${fromAgent} account \u201C${accountLabel}\u201D using the attached handoff.`,
4607
+ "Proceed with the goal. Leave model Auto unless needed."
4608
+ ].join(" ");
4479
4609
  var QUOTA_RESUME_PROMPT = "Session/usage limit window should have reset. Continue this chat from where you left off.";
4480
4610
  async function isolateQuotaFailover(run2) {
4481
4611
  try {
@@ -4484,13 +4614,14 @@ async function isolateQuotaFailover(run2) {
4484
4614
  return true;
4485
4615
  }
4486
4616
  }
4487
- function createQuotaFailoverChat(from, fallbackAgent, limitText) {
4617
+ function createQuotaFailoverChat(from, fallbackAgent, limitText, opts) {
4488
4618
  const handoff = buildQuotaHandoffAttachment(from, limitText, fallbackAgent);
4489
4619
  const tab = createChatTab({
4490
4620
  fromThreadId: from.id,
4491
4621
  agent: fallbackAgent,
4492
4622
  model: null,
4493
- attachments: [handoff]
4623
+ attachments: [handoff],
4624
+ ...opts && "accountId" in opts ? { accountId: opts.accountId } : {}
4494
4625
  });
4495
4626
  const patch = {
4496
4627
  quotaContinuedFromId: from.id,
@@ -4601,7 +4732,7 @@ async function adoptThread(input) {
4601
4732
  messages: input.messages ?? []
4602
4733
  });
4603
4734
  writeThread(thread);
4604
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-IXZD7EC4.js");
4735
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-2XTDS7N2.js");
4605
4736
  await ensureWorkspace2(repoPath);
4606
4737
  const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-5N2KTYIT.js");
4607
4738
  await ensureWorktreeSideboardIgnored2(input.worktreePath);
@@ -6714,32 +6845,6 @@ function formatUiReminder() {
6714
6845
  return "Sideboard UI: markdown table is enough to read data; present_schema if they ask to edit/filter (even after markdown); present_files for the file manager. html fence or present_artifact, not both for the same document. type=log appends (same artifact_id, new lines only). ask_user only for a real multiple-choice (not hellos, \u201Cwhat next?\u201D, or after a review) \u2014 reply in chat. ask_user wakes the parent orchestrator; notify_orchestrator if blocked without a picker. Do not say artifacts/CMS UI are unavailable. Dev / preview: run_dev_script (same as the Dev button) returns {url, port, preview} (SIDEBOARD_PORT \u2014 never guess :3000). preview=url \u2192 open url; preview=window \u2192 Electron window is the app, url is renderer/HMR only. list_run_scripts active[].url if already running; get_run_log for the Run-tab terminal; stop_dev_script to stop.";
6715
6846
  }
6716
6847
 
6717
- // src/review/review-write-gate.ts
6718
- var REVIEW_TAB_TITLE = "Review";
6719
- function hasLiveReviewSibling(thread, siblings = []) {
6720
- const selfId = thread.id;
6721
- return siblings.some(
6722
- (t) => t.id !== selfId && t.status !== "archived" && t.title.trim() === REVIEW_TAB_TITLE
6723
- );
6724
- }
6725
- function isReviewWriteGatedThread(thread, siblings) {
6726
- if (thread.sourceType === "pr" || thread.title.trim() === REVIEW_TAB_TITLE) {
6727
- return true;
6728
- }
6729
- return hasLiveReviewSibling(thread, siblings);
6730
- }
6731
- function formatReviewWriteGateDirective() {
6732
- return [
6733
- "Review writes are public. The PR or ticket author sees GitHub/Linear/AbleTime comments, ticket updates, and submitted reviews immediately \u2014 a draft will confuse them.",
6734
- "Write the recommendation in chat so the user can work through the feedback first. Do not call github_comment, linear_comment, abletime_comment, github_update_issue, linear_update_issue, abletime_update_task, or run `gh pr review` / `gh pr comment`, until they type a next step that asks you to post.",
6735
- "After the review is in chat, stop. Do not call ask_user. The user needs time to read and will type the next steps. If they already asked you to post a specific comment or update in this turn, that is confirmation.",
6736
- "Do not request reviewers, change labels, or assign yourself unless they asked \u2014 those also notify the author."
6737
- ].join("\n");
6738
- }
6739
- function formatReviewWriteGateReminder() {
6740
- return "Review writes: keep the review in chat. Do not ask_user after it \u2014 they read and type next steps. Do not github_comment / linear_comment / *_update_* / `gh pr review` on the PR or ticket until they ask. Authors see those immediately.";
6741
- }
6742
-
6743
6848
  // src/integrations/optional-services.ts
6744
6849
  var OPTIONAL_SERVICES = [
6745
6850
  {
@@ -6856,19 +6961,9 @@ async function syncThreadBranchFromGit(threadId) {
6856
6961
  const branch = stdout.trim();
6857
6962
  if (!branch || branch === "HEAD") return;
6858
6963
  const siblings = threadsSharingWorktree(thread.worktreePath);
6859
- const canonicalId = siblings[0]?.id ?? null;
6860
6964
  for (const sibling of siblings) {
6861
- const patch = {};
6862
- if (sibling.branchName !== branch) patch.branchName = branch;
6863
- if (sibling.id === canonicalId && !sibling.userSetTitle) {
6864
- const nextTitle = threadDisplayLabel({
6865
- ...sibling,
6866
- branchName: branch
6867
- });
6868
- if (sibling.title !== nextTitle) patch.title = nextTitle;
6869
- }
6870
- if (Object.keys(patch).length > 0) {
6871
- updateThread(sibling.id, patch);
6965
+ if (sibling.branchName !== branch) {
6966
+ updateThread(sibling.id, { branchName: branch });
6872
6967
  }
6873
6968
  }
6874
6969
  }
@@ -7124,7 +7219,7 @@ function formatScheduledPrompt(name, prompt) {
7124
7219
  ${prompt}`;
7125
7220
  }
7126
7221
  async function defaultDeps() {
7127
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-VHJZEVGA.js");
7222
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-VLTO5JBR.js");
7128
7223
  const orch = getOrchestrator2();
7129
7224
  return {
7130
7225
  findThread: (id) => findThreadByRef(id),
@@ -7442,7 +7537,7 @@ var Orchestrator = class {
7442
7537
  orphans: orphans.map((o) => ({ path: o.path, repoPath: o.repoPath }))
7443
7538
  });
7444
7539
  }
7445
- const { autoCleanupOrphansEnabled } = await import("./app-settings-CLARFJUX.js");
7540
+ const { autoCleanupOrphansEnabled } = await import("./app-settings-OM7H64YM.js");
7446
7541
  if (autoCleanupOrphansEnabled() && shouldRunWorktreeCleanup() && orphans.length > 0) {
7447
7542
  await cleanupOrphanWorktrees({ repoPaths });
7448
7543
  }
@@ -7638,6 +7733,48 @@ var Orchestrator = class {
7638
7733
  }
7639
7734
  return true;
7640
7735
  }
7736
+ if (plan.action === "switch_account" && plan.fallbackAccountLabel) {
7737
+ this.haltDrain.add(threadId);
7738
+ let next;
7739
+ try {
7740
+ next = createQuotaFailoverChat(thread, thread.agent, plan.limitText, {
7741
+ accountId: plan.fallbackAccountId ?? null,
7742
+ accountLabel: plan.fallbackAccountLabel
7743
+ });
7744
+ } catch {
7745
+ return false;
7746
+ }
7747
+ this.clearQuotaResumeTimer(threadId);
7748
+ try {
7749
+ updateThread(threadId, { quotaResumeAt: null });
7750
+ } catch {
7751
+ }
7752
+ try {
7753
+ appendMessage(threadId, {
7754
+ role: "agent",
7755
+ text: `Session limit on ${thread.agent}. Sideboard continued on account \u201C${plan.fallbackAccountLabel}\u201D in [${next.title}](sideboard://thread/${next.id}).`,
7756
+ ts: (/* @__PURE__ */ new Date()).toISOString()
7757
+ });
7758
+ this.emit({
7759
+ type: "quota_failover",
7760
+ threadId,
7761
+ action: "switch_account",
7762
+ toThreadId: next.id,
7763
+ message: plan.reason
7764
+ });
7765
+ this.emit({
7766
+ type: "status_changed",
7767
+ threadId: next.id,
7768
+ status: next.status
7769
+ });
7770
+ } catch {
7771
+ }
7772
+ void this.send(
7773
+ next.id,
7774
+ QUOTA_CONTINUE_ACCOUNT_PROMPT(thread.agent, plan.fallbackAccountLabel)
7775
+ );
7776
+ return true;
7777
+ }
7641
7778
  if (plan.action === "switch_agent" && plan.fallbackAgent) {
7642
7779
  this.haltDrain.add(threadId);
7643
7780
  let next;
@@ -7789,7 +7926,7 @@ var Orchestrator = class {
7789
7926
  }
7790
7927
  await setup;
7791
7928
  if (skipSetup) return;
7792
- const { autoRunAfterSetupEnabled } = await import("./app-settings-CLARFJUX.js");
7929
+ const { autoRunAfterSetupEnabled } = await import("./app-settings-OM7H64YM.js");
7793
7930
  if (autoRunAfterSetupEnabled()) {
7794
7931
  try {
7795
7932
  await this.startDev(threadId);
@@ -8066,6 +8203,15 @@ var Orchestrator = class {
8066
8203
  ...autoContinue ? { origin: "continue" } : {},
8067
8204
  ts: (/* @__PURE__ */ new Date()).toISOString()
8068
8205
  });
8206
+ if (!autoContinue) {
8207
+ const live = this.requireThread(threadId);
8208
+ const stamp = agentPurposeStamp({
8209
+ thread: live,
8210
+ prompt: promptText,
8211
+ autoContinue: false
8212
+ });
8213
+ if (stamp) updateThread(threadId, stamp);
8214
+ }
8069
8215
  traceTurn("runTurn.afterUserMessage", {
8070
8216
  threadId,
8071
8217
  agent: thread.agent,
@@ -8159,7 +8305,7 @@ var Orchestrator = class {
8159
8305
  }
8160
8306
  const isBrightsy = fresh.agent === "brightsy";
8161
8307
  const isOrchestration = isOrchestratorThread(fresh);
8162
- const { autoRenameBranchEnabled, getGithubGitAuthMode, gitBranchPrefixSetting } = await import("./app-settings-CLARFJUX.js");
8308
+ const { autoRenameBranchEnabled, getGithubGitAuthMode, gitBranchPrefixSetting } = await import("./app-settings-OM7H64YM.js");
8163
8309
  const gitAuthMode = getGithubGitAuthMode();
8164
8310
  const worktreeDirective = isBrightsy || isOrchestration ? null : formatWorktreeDirective(fresh, {
8165
8311
  githubSlug: await withTimeout(
@@ -9464,11 +9610,7 @@ var Orchestrator = class {
9464
9610
  if (Object.keys(patch).length === 0) continue;
9465
9611
  updateThread(t.id, patch);
9466
9612
  }
9467
- const titled = this.requireThread(thread.id);
9468
- if (!titled.userSetTitle && meta.title && titled.title !== meta.title) {
9469
- updateThread(thread.id, { title: meta.title });
9470
- }
9471
- const { autoArchiveOnMergeEnabled } = await import("./app-settings-CLARFJUX.js");
9613
+ const { autoArchiveOnMergeEnabled } = await import("./app-settings-OM7H64YM.js");
9472
9614
  const latest = this.requireThread(thread.id);
9473
9615
  if (!shouldAutoArchiveOnPrMerge({
9474
9616
  previousPrState: prevState || null,
@@ -9575,13 +9717,7 @@ var Orchestrator = class {
9575
9717
  const patch = {};
9576
9718
  if (details.url && details.url !== thread.prUrl) patch.prUrl = details.url;
9577
9719
  if (details.title && details.title !== thread.prTitle) patch.prTitle = details.title;
9578
- if (Object.keys(patch).length > 0) {
9579
- updateThread(thread.id, patch);
9580
- const latest = this.requireThread(thread.id);
9581
- if (!latest.userSetTitle && details.title && latest.title !== details.title) {
9582
- updateThread(thread.id, { title: details.title });
9583
- }
9584
- }
9720
+ if (Object.keys(patch).length > 0) updateThread(thread.id, patch);
9585
9721
  }
9586
9722
  return details;
9587
9723
  }
@@ -9589,8 +9725,9 @@ var Orchestrator = class {
9589
9725
  return this.setThreadOptions(threadRef, { autonomy });
9590
9726
  }
9591
9727
  /**
9592
- * Open a Review chat tab on a worktree thread (same as the desktop Review button)
9593
- * and send the merge-readiness prefill.
9728
+ * Run a merge-readiness review on a worktree thread (same as the desktop
9729
+ * Review button). Reuses a single unused idle agent when that is the only
9730
+ * chat; otherwise opens a Review tab so existing work is not interrupted.
9594
9731
  */
9595
9732
  async requestReview(threadRef) {
9596
9733
  const { tab } = await requestReview(threadRef, (ref, prompt) => this.send(ref, prompt));
@@ -9764,7 +9901,7 @@ var Orchestrator = class {
9764
9901
  this.enforceHistoryRetention();
9765
9902
  if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
9766
9903
  try {
9767
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-IXZD7EC4.js");
9904
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-2XTDS7N2.js");
9768
9905
  await ensureWorkspace2(thread.repoPath);
9769
9906
  } catch {
9770
9907
  }
@@ -9791,7 +9928,7 @@ var Orchestrator = class {
9791
9928
  await runArchiveScript(thread.repoPath, thread.worktreePath);
9792
9929
  } catch {
9793
9930
  }
9794
- const { deleteBranchOnPurgeEnabled } = await import("./app-settings-CLARFJUX.js");
9931
+ const { deleteBranchOnPurgeEnabled } = await import("./app-settings-OM7H64YM.js");
9795
9932
  const deleteBranch = opts?.deleteBranch ?? deleteBranchOnPurgeEnabled();
9796
9933
  await removeWorktree(thread.repoPath, thread.worktreePath, {
9797
9934
  deleteBranch: deleteBranch ? thread.branchName : void 0
@@ -9818,7 +9955,7 @@ var Orchestrator = class {
9818
9955
  `Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
9819
9956
  );
9820
9957
  }
9821
- const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-DAAF64UU.js");
9958
+ const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-DDDF3WHV.js");
9822
9959
  const slug = thread.worktreePath.split("/").pop();
9823
9960
  const dest = thread.worktreePath;
9824
9961
  await withRepoGitLock(thread.repoPath, async () => {
@@ -9910,8 +10047,8 @@ async function startOrchestration(opts) {
9910
10047
  }
9911
10048
  return thread2;
9912
10049
  }
9913
- const { titleFromPrompt } = await import("./title-4WAKWZRF.js");
9914
- const title = titleFromPrompt(goal) || "Orchestration";
10050
+ const { titleFromPrompt: titleFromPrompt2 } = await import("./title-ERD6D3C3.js");
10051
+ const title = titleFromPrompt2(goal) || "Orchestration";
9915
10052
  const createOpts = {
9916
10053
  agent: opts.agent,
9917
10054
  repoPath,
@@ -9928,7 +10065,7 @@ async function startOrchestration(opts) {
9928
10065
  sourceRef: "default",
9929
10066
  ...createOpts
9930
10067
  }).catch(async () => {
9931
- const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-DAAF64UU.js");
10068
+ const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-DDDF3WHV.js");
9932
10069
  const repo = await resolveRepoRoot2(repoPath);
9933
10070
  const def = await resolveDefaultBranch2(repo);
9934
10071
  return orch.createThread({
@@ -9938,7 +10075,7 @@ async function startOrchestration(opts) {
9938
10075
  repoPath: repo
9939
10076
  });
9940
10077
  });
9941
- const { updateThread: upd } = await import("./thread-store-HDQ4CH54.js");
10078
+ const { updateThread: upd } = await import("./thread-store-FJ5CDX2M.js");
9942
10079
  const updated = upd(thread.id, {
9943
10080
  sourceType: "orchestration",
9944
10081
  sourceRef: goal
@@ -1,6 +1,3 @@
1
- import {
2
- appDataDir
3
- } from "./chunk-EHT2DRT4.js";
4
1
  import {
5
2
  npmGlobalNodeModules,
6
3
  run
@@ -9,6 +6,9 @@ import {
9
6
  isElectronLikeCommand,
10
7
  wrapElectronAsNodeLaunch
11
8
  } from "./chunk-4TR3HZFT.js";
9
+ import {
10
+ appDataDir
11
+ } from "./chunk-EHT2DRT4.js";
12
12
 
13
13
  // src/agents/error-detail.ts
14
14
  function formatUnknownDetail(err) {
@@ -1246,8 +1246,10 @@ export {
1246
1246
  formatUnknownDetail,
1247
1247
  extractJsonErrorMessage,
1248
1248
  pushTurnStderr,
1249
+ looksLikeHugeToolResultDump,
1249
1250
  clipToolResultForStore,
1250
1251
  looksLikeV8Oom,
1252
+ TOOL_RESULT_STORE_MAX_CHARS,
1251
1253
  summarizeTurnStderr,
1252
1254
  looksLikeInvalidAgentSession,
1253
1255
  looksLikeCursorHttp2StreamClose,