@sideboard-ai/core 0.1.111 → 0.1.116

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 (43) hide show
  1. package/dist/agents/cursor-runner.cjs +51 -21
  2. package/dist/agents/cursor-runner.js +3 -3
  3. package/dist/{agents-NN22A4G5.js → agents-7NIX44RB.js} +7 -7
  4. package/dist/{agents-GH3FWDW2.js → agents-DU7DHY7A.js} +10 -10
  5. package/dist/{chunk-JTQQPJAU.js → chunk-4HOFVKPC.js} +52 -38
  6. package/dist/{chunk-4EWPKYOU.js → chunk-4OJMZ6P2.js} +2 -2
  7. package/dist/{chunk-NC3U42ZP.js → chunk-5KSLD4MU.js} +317 -33
  8. package/dist/{chunk-KQBI5HNT.js → chunk-7WC5UWEB.js} +2 -2
  9. package/dist/{chunk-WIHKHR5R.js → chunk-AXQ4ZWHK.js} +5 -0
  10. package/dist/{chunk-LGXBYZZA.js → chunk-DVM4ID64.js} +69 -13
  11. package/dist/{chunk-DMJKOFTO.js → chunk-DWP25N32.js} +44 -35
  12. package/dist/{chunk-2GO3YKBA.js → chunk-EKIDHL2T.js} +4 -4
  13. package/dist/{chunk-C4KHDW3U.js → chunk-FZCIQYNQ.js} +1 -1
  14. package/dist/{chunk-363Z34PY.js → chunk-GBY7OOMB.js} +273 -218
  15. package/dist/{chunk-7KWYXGIU.js → chunk-K3TIQXOH.js} +2 -2
  16. package/dist/{chunk-3KETJKYA.js → chunk-KPIYENTF.js} +69 -13
  17. package/dist/{chunk-KVFNTWFG.js → chunk-OFF5AFCR.js} +300 -43
  18. package/dist/{chunk-VOD3HFLP.js → chunk-XOYQ7LNQ.js} +2 -2
  19. package/dist/{chunk-7YKXHBIW.js → chunk-YMRT2DU6.js} +3 -3
  20. package/dist/{chunk-YXDR43ZC.js → chunk-ZMROW673.js} +5 -5
  21. package/dist/{chunk-YFAXVUY2.js → chunk-ZRCX43LS.js} +2 -2
  22. package/dist/{chunk-AROMOP3C.js → chunk-ZYEFCSZJ.js} +2 -2
  23. package/dist/{connected-teams-M5XNXRI5.js → connected-teams-O6D4PM7A.js} +2 -2
  24. package/dist/{connected-teams-J4I5AKMR.js → connected-teams-ZCOU6KCD.js} +2 -2
  25. package/dist/{coordinator-prompt-AR66L3N4.js → coordinator-prompt-4KCALEKD.js} +3 -3
  26. package/dist/{coordinator-prompt-BHMLWL64.js → coordinator-prompt-FML4I5AR.js} +3 -3
  27. package/dist/{global-workspace-XSUFEIAQ.js → global-workspace-CSWABOG5.js} +4 -4
  28. package/dist/{global-workspace-SKFODUQQ.js → global-workspace-H4YNASM6.js} +4 -4
  29. package/dist/index.cjs +855 -440
  30. package/dist/index.d.cts +59 -1
  31. package/dist/index.d.ts +59 -1
  32. package/dist/index.js +37 -17
  33. package/dist/mcp/run-stdio.cjs +966 -635
  34. package/dist/mcp/run-stdio.js +20 -16
  35. package/dist/{orchestrator-4T2SXDZ7.js → orchestrator-NXPANCZA.js} +8 -8
  36. package/dist/{orchestrator-EP57AB5W.js → orchestrator-ZY4RUJKT.js} +10 -10
  37. package/dist/{run-XKTAJRWF.js → run-USF6FRKV.js} +3 -1
  38. package/dist/{run-CFKZPY7F.js → run-XQKGHQZ2.js} +3 -1
  39. package/dist/{workspaces-XAQVKTLO.js → workspaces-HJ3EVATC.js} +5 -5
  40. package/dist/{workspaces-HV3J4TTW.js → workspaces-QG6PGFQR.js} +5 -5
  41. package/dist/{worktree-XFJED3VU.js → worktree-IW3BX26B.js} +2 -2
  42. package/dist/{worktree-N2EV24EE.js → worktree-OTFQO2W7.js} +2 -2
  43. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -3583,12 +3583,47 @@ var init_path = __esm({
3583
3583
  }
3584
3584
  });
3585
3585
 
3586
+ // src/git/stale-lock.ts
3587
+ function isIndexLockError(text4) {
3588
+ return /Unable to create ['"][^'"]*index\.lock['"]: File exists/i.test(text4);
3589
+ }
3590
+ function clearStaleIndexLock(gitDir, maxAgeMs = STALE_INDEX_LOCK_MS, now = Date.now()) {
3591
+ const lockPath = (0, import_node_path14.join)(gitDir, "index.lock");
3592
+ try {
3593
+ if (!(0, import_node_fs14.existsSync)(lockPath)) return null;
3594
+ if (now - (0, import_node_fs14.statSync)(lockPath).mtimeMs < maxAgeMs) return null;
3595
+ (0, import_node_fs14.unlinkSync)(lockPath);
3596
+ return lockPath;
3597
+ } catch {
3598
+ return null;
3599
+ }
3600
+ }
3601
+ function clearStaleIndexLocks(gitDirs, maxAgeMs = STALE_INDEX_LOCK_MS) {
3602
+ const now = Date.now();
3603
+ const removed = [];
3604
+ for (const dir of new Set(gitDirs)) {
3605
+ const cleared = clearStaleIndexLock(dir, maxAgeMs, now);
3606
+ if (cleared) removed.push(cleared);
3607
+ }
3608
+ return removed;
3609
+ }
3610
+ var import_node_fs14, import_node_path14, STALE_INDEX_LOCK_MS;
3611
+ var init_stale_lock = __esm({
3612
+ "src/git/stale-lock.ts"() {
3613
+ "use strict";
3614
+ import_node_fs14 = require("fs");
3615
+ import_node_path14 = require("path");
3616
+ STALE_INDEX_LOCK_MS = 2e4;
3617
+ }
3618
+ });
3619
+
3586
3620
  // src/git/run.ts
3587
3621
  var run_exports = {};
3588
3622
  __export(run_exports, {
3589
3623
  gh: () => gh,
3590
3624
  git: () => git,
3591
3625
  resolveGhAuthToken: () => resolveGhAuthToken,
3626
+ resolveGitDirsForLockRecovery: () => resolveGitDirsForLockRecovery,
3592
3627
  run: () => run
3593
3628
  });
3594
3629
  async function run(file, args, opts) {
@@ -3617,6 +3652,21 @@ async function run(file, args, opts) {
3617
3652
  throw err;
3618
3653
  }
3619
3654
  }
3655
+ async function resolveGitDirsForLockRecovery(cwd, env = {}) {
3656
+ const dirs = /* @__PURE__ */ new Set();
3657
+ const [gitDir, commonDir] = await Promise.all([
3658
+ run("git", ["rev-parse", "--absolute-git-dir"], { cwd, reject: false, env, timeoutMs: 5e3 }),
3659
+ run("git", ["rev-parse", "--path-format=absolute", "--git-common-dir"], {
3660
+ cwd,
3661
+ reject: false,
3662
+ env,
3663
+ timeoutMs: 5e3
3664
+ })
3665
+ ]);
3666
+ if (gitDir.exitCode === 0 && gitDir.stdout.trim()) dirs.add(gitDir.stdout.trim());
3667
+ if (commonDir.exitCode === 0 && commonDir.stdout.trim()) dirs.add(commonDir.stdout.trim());
3668
+ return [...dirs];
3669
+ }
3620
3670
  async function git(args, cwd, opts) {
3621
3671
  const prefix = [];
3622
3672
  if (opts?.config) {
@@ -3625,21 +3675,32 @@ async function git(args, cwd, opts) {
3625
3675
  prefix.push("-c", `${key}=${value}`);
3626
3676
  }
3627
3677
  }
3628
- return run("git", ["--no-pager", ...prefix, ...args], {
3629
- cwd,
3630
- reject: opts?.reject,
3631
- timeoutMs: opts?.timeoutMs,
3678
+ const gitArgs = ["--no-pager", ...prefix, ...args];
3679
+ const env = {
3632
3680
  // Never block forever on a credential/SSH prompt inside MCP / Electron.
3633
- env: {
3634
- GIT_TERMINAL_PROMPT: "0",
3635
- GIT_ASKPASS: process.env.GIT_ASKPASS || "echo",
3636
- SSH_ASKPASS: process.env.SSH_ASKPASS || "echo",
3637
- GIT_SSH_COMMAND: process.env.GIT_SSH_COMMAND || "ssh -o BatchMode=yes -o ConnectTimeout=15",
3638
- GCM_INTERACTIVE: "never",
3639
- GH_PROMPT_DISABLED: "1",
3640
- ...opts?.env
3681
+ GIT_TERMINAL_PROMPT: "0",
3682
+ GIT_ASKPASS: process.env.GIT_ASKPASS || "echo",
3683
+ SSH_ASKPASS: process.env.SSH_ASKPASS || "echo",
3684
+ GIT_SSH_COMMAND: process.env.GIT_SSH_COMMAND || "ssh -o BatchMode=yes -o ConnectTimeout=15",
3685
+ GCM_INTERACTIVE: "never",
3686
+ GH_PROMPT_DISABLED: "1",
3687
+ ...opts?.env
3688
+ };
3689
+ let result = await run("git", gitArgs, { cwd, reject: false, timeoutMs: opts?.timeoutMs, env });
3690
+ if (result.exitCode !== 0 && isIndexLockError(result.stderr)) {
3691
+ const gitDirs = await resolveGitDirsForLockRecovery(cwd, env);
3692
+ const cleared = clearStaleIndexLocks(gitDirs);
3693
+ if (cleared.length > 0) {
3694
+ result = await run("git", gitArgs, { cwd, reject: false, timeoutMs: opts?.timeoutMs, env });
3641
3695
  }
3642
- });
3696
+ }
3697
+ if ((opts?.reject ?? true) && result.exitCode !== 0) {
3698
+ throw new Error(
3699
+ `Command failed with exit code ${result.exitCode}: git ${gitArgs.join(" ")}
3700
+ ${result.stderr}`
3701
+ );
3702
+ }
3703
+ return result;
3643
3704
  }
3644
3705
  async function gh(args, cwd, opts) {
3645
3706
  return run("gh", args, {
@@ -3664,6 +3725,7 @@ var init_run = __esm({
3664
3725
  "use strict";
3665
3726
  import_execa2 = require("execa");
3666
3727
  init_path();
3728
+ init_stale_lock();
3667
3729
  }
3668
3730
  });
3669
3731
 
@@ -3758,7 +3820,7 @@ async function warmGithubAgentAuth(opts) {
3758
3820
  }
3759
3821
  function normalizeWritableRoot(raw) {
3760
3822
  const trimmed = raw.trim().replace(/\/+$/, "");
3761
- return trimmed && (0, import_node_path14.isAbsolute)(trimmed) ? trimmed : null;
3823
+ return trimmed && (0, import_node_path15.isAbsolute)(trimmed) ? trimmed : null;
3762
3824
  }
3763
3825
  async function resolveCodexGitWritableRoots(cwd) {
3764
3826
  const roots = /* @__PURE__ */ new Set();
@@ -3835,11 +3897,11 @@ function formatGitAuthModeDirective(mode) {
3835
3897
  ].join("\n");
3836
3898
  }
3837
3899
  }
3838
- var import_node_path14, HTTPS_REWRITE, TOKEN_TTL_MS, tokenMemo, GITHUB_CHILD_TOKEN_KEYS;
3900
+ var import_node_path15, HTTPS_REWRITE, TOKEN_TTL_MS, tokenMemo, GITHUB_CHILD_TOKEN_KEYS;
3839
3901
  var init_git_auth_mode = __esm({
3840
3902
  "src/git/git-auth-mode.ts"() {
3841
3903
  "use strict";
3842
- import_node_path14 = require("path");
3904
+ import_node_path15 = require("path");
3843
3905
  init_app_settings();
3844
3906
  init_github_agent_auth();
3845
3907
  init_run();
@@ -5037,8 +5099,8 @@ function isLocalPrFetchBranch(ref) {
5037
5099
  }
5038
5100
  async function createThreadWorktree(opts) {
5039
5101
  let branchName = `thread/${opts.slug}`;
5040
- const worktreePath = (0, import_node_path15.join)(worktreesRoot(opts.repoPath), opts.slug);
5041
- if ((0, import_node_fs14.existsSync)(worktreePath)) {
5102
+ const worktreePath = (0, import_node_path16.join)(worktreesRoot(opts.repoPath), opts.slug);
5103
+ if ((0, import_node_fs15.existsSync)(worktreePath)) {
5042
5104
  throw new Error(`Worktree already exists at ${worktreePath}`);
5043
5105
  }
5044
5106
  await ensureGhPreferOrigin(opts.repoPath);
@@ -5105,8 +5167,8 @@ ${add.stdout}`;
5105
5167
  async function createExistingBranchWorktree(opts) {
5106
5168
  const branchName = opts.branchName.trim();
5107
5169
  if (!branchName) throw new Error("branch name required");
5108
- const worktreePath = (0, import_node_path15.join)(worktreesRoot(opts.repoPath), opts.slug);
5109
- if ((0, import_node_fs14.existsSync)(worktreePath)) {
5170
+ const worktreePath = (0, import_node_path16.join)(worktreesRoot(opts.repoPath), opts.slug);
5171
+ if ((0, import_node_fs15.existsSync)(worktreePath)) {
5110
5172
  throw new Error(`Worktree already exists at ${worktreePath}`);
5111
5173
  }
5112
5174
  await ensureGhPreferOrigin(opts.repoPath);
@@ -5397,10 +5459,10 @@ function sameRepoPath(a, b) {
5397
5459
  return normalizeWorktreePath(a) === normalizeWorktreePath(b);
5398
5460
  }
5399
5461
  function listLocalThreadBranchSlugs(repoPath) {
5400
- const refsDir = (0, import_node_path15.join)(repoPath, ".git", "refs", "heads", "thread");
5401
- if (!(0, import_node_fs14.existsSync)(refsDir)) return [];
5462
+ const refsDir = (0, import_node_path16.join)(repoPath, ".git", "refs", "heads", "thread");
5463
+ if (!(0, import_node_fs15.existsSync)(refsDir)) return [];
5402
5464
  try {
5403
- return (0, import_node_fs14.readdirSync)(refsDir).filter((name) => !name.startsWith(".")).map((name) => normalizeTakenSlug(name));
5465
+ return (0, import_node_fs15.readdirSync)(refsDir).filter((name) => !name.startsWith(".")).map((name) => normalizeTakenSlug(name));
5404
5466
  } catch {
5405
5467
  return [];
5406
5468
  }
@@ -5408,8 +5470,8 @@ function listLocalThreadBranchSlugs(repoPath) {
5408
5470
  function collectTakenTeamSlugs(repoPath) {
5409
5471
  const taken = /* @__PURE__ */ new Set();
5410
5472
  const root = worktreesRoot(repoPath);
5411
- if ((0, import_node_fs14.existsSync)(root)) {
5412
- for (const entry of (0, import_node_fs14.readdirSync)(root, { withFileTypes: true })) {
5473
+ if ((0, import_node_fs15.existsSync)(root)) {
5474
+ for (const entry of (0, import_node_fs15.readdirSync)(root, { withFileTypes: true })) {
5413
5475
  if (entry.isDirectory() && entry.name !== ".DS_Store") {
5414
5476
  taken.add(normalizeTakenSlug(entry.name));
5415
5477
  }
@@ -5430,18 +5492,18 @@ function allocateTeamSlug(repoPath) {
5430
5492
  const taken = collectTakenTeamSlugs(repoPath);
5431
5493
  for (let attempt = 0; attempt < 32; attempt++) {
5432
5494
  const team = allocateTeamName(taken);
5433
- const path2 = (0, import_node_path15.join)(worktreesRoot(repoPath), team.slug);
5434
- if (!(0, import_node_fs14.existsSync)(path2)) return team;
5495
+ const path2 = (0, import_node_path16.join)(worktreesRoot(repoPath), team.slug);
5496
+ if (!(0, import_node_fs15.existsSync)(path2)) return team;
5435
5497
  taken.add(team.slug);
5436
5498
  }
5437
5499
  throw new Error("No available soccer team worktree directories left");
5438
5500
  }
5439
- var import_node_fs14, import_node_path15;
5501
+ var import_node_fs15, import_node_path16;
5440
5502
  var init_worktree = __esm({
5441
5503
  "src/git/worktree.ts"() {
5442
5504
  "use strict";
5443
- import_node_fs14 = require("fs");
5444
- import_node_path15 = require("path");
5505
+ import_node_fs15 = require("fs");
5506
+ import_node_path16 = require("path");
5445
5507
  init_paths();
5446
5508
  init_thread_store();
5447
5509
  init_teams();
@@ -5518,7 +5580,7 @@ function coordinatorTurnReminder(opts) {
5518
5580
  function ensureGlobalCoordinatorCwd(opts) {
5519
5581
  const dir = globalAgentCwd();
5520
5582
  try {
5521
- (0, import_node_fs15.mkdirSync)(dir, { recursive: true });
5583
+ (0, import_node_fs16.mkdirSync)(dir, { recursive: true });
5522
5584
  } catch {
5523
5585
  return dir;
5524
5586
  }
@@ -5526,7 +5588,7 @@ function ensureGlobalCoordinatorCwd(opts) {
5526
5588
  let orchId = opts?.orchestratorThreadId?.trim() || "";
5527
5589
  if (!orchId) {
5528
5590
  try {
5529
- const existing = (0, import_node_fs15.readFileSync)((0, import_node_path16.join)(dir, "AGENTS.md"), "utf8");
5591
+ const existing = (0, import_node_fs16.readFileSync)((0, import_node_path17.join)(dir, "AGENTS.md"), "utf8");
5530
5592
  const m = existing.match(
5531
5593
  /YOUR orchestration thread id is `([0-9a-f-]{36})`/i
5532
5594
  );
@@ -5568,9 +5630,9 @@ function ensureGlobalCoordinatorCwd(opts) {
5568
5630
  "Always ask worktree agents to commit, push, and open draft PRs (`ask_git` / `send_to_thread`). Tell them to merge only when the user explicitly asked. The worktree agent runs git/gh; never merge from this orchestration cwd."
5569
5631
  ].join("\n");
5570
5632
  try {
5571
- (0, import_node_fs15.writeFileSync)((0, import_node_path16.join)(dir, "CLAUDE.md"), `${body}
5633
+ (0, import_node_fs16.writeFileSync)((0, import_node_path17.join)(dir, "CLAUDE.md"), `${body}
5572
5634
  `, "utf8");
5573
- (0, import_node_fs15.writeFileSync)((0, import_node_path16.join)(dir, "AGENTS.md"), `${body}
5635
+ (0, import_node_fs16.writeFileSync)((0, import_node_path17.join)(dir, "AGENTS.md"), `${body}
5574
5636
  `, "utf8");
5575
5637
  } catch {
5576
5638
  }
@@ -5602,12 +5664,12 @@ function coordinatorSystemPrompt(opts) {
5602
5664
  formatWorkspaceInventory(opts.workspaces)
5603
5665
  ].join("\n");
5604
5666
  }
5605
- var import_node_fs15, import_node_path16, COORDINATOR_TOOL_PLAYBOOK, SLACK_REPLY_FORMATTING;
5667
+ var import_node_fs16, import_node_path17, COORDINATOR_TOOL_PLAYBOOK, SLACK_REPLY_FORMATTING;
5606
5668
  var init_coordinator_prompt = __esm({
5607
5669
  "src/orchestrator/coordinator-prompt.ts"() {
5608
5670
  "use strict";
5609
- import_node_fs15 = require("fs");
5610
- import_node_path16 = require("path");
5671
+ import_node_fs16 = require("fs");
5672
+ import_node_path17 = require("path");
5611
5673
  init_worktree();
5612
5674
  init_app_settings();
5613
5675
  init_paths();
@@ -5633,7 +5695,7 @@ var init_coordinator_prompt = __esm({
5633
5695
  "- fork_worktree \u2014 fork a worktree chat into a NEW git worktree + chat (transcript attached); optional agent; leave model unset (Auto) unless you have a reason. Not for orchestration chats.",
5634
5696
  "- fork_chat \u2014 fork a worktree chat (same worktree tab) OR a Global orchestration chat (new orchestration tab); optional agent; leave model unset (Auto) unless you have a reason. Remote coordinators: use this to continue another orchestration chat on a different agent after session limits.",
5635
5697
  "- send_to_thread \u2014 queue a prompt (start/continue a chat turn); pass force_stop: true to interrupt mid-turn / clear stale queued prompts before replacing with a new request",
5636
- "- wait_for_turn / get_turn_result \u2014 wait for and read the agent reply. wait_for_turn returns within ~45s even if the child is still working (MCP clients kill longer tool calls). If stillRunning is true, progress is a live snapshot of tools/thinking \u2014 call wait_for_turn again. Do not send \u201Care you stuck?\u201D or assume a hang while lastActivityAt is recent. On status error, lastError (and text) is the failure \u2014 switch agent, tell the user, or retry; do not treat empty text as success.",
5698
+ "- wait_for_turn / get_turn_result \u2014 wait for and read the agent reply. wait_for_turn returns within ~45s even if the child is still working (MCP clients kill longer tool calls). If stillRunning is true, progress is a live snapshot of tools/thinking \u2014 call wait_for_turn again. status=queued with no lastActivityAt means the child has not started yet (concurrency cap) \u2014 keep waiting; do not force_stop or send a check-in. Do not send \u201Care you stuck?\u201D or assume a hang while lastActivityAt is recent. On status error, lastError (and text) is the failure \u2014 switch agent, tell the user, or retry; do not treat empty text as success.",
5637
5699
  "- stop_thread \u2014 force-stop: kill in-flight turn AND clear queued prompts (do not leave stale queue after an interrupt)",
5638
5700
  "- archive_thread / restore_thread \u2014 archive (tears down worktree when last tab) or restore",
5639
5701
  "Setup / run:",
@@ -5950,13 +6012,13 @@ var init_api = __esm({
5950
6012
 
5951
6013
  // src/slack/reply-target.ts
5952
6014
  function storePath() {
5953
- return (0, import_node_path17.join)(appDataDir(), "slack-reply-to.json");
6015
+ return (0, import_node_path18.join)(appDataDir(), "slack-reply-to.json");
5954
6016
  }
5955
6017
  function readStore() {
5956
6018
  const path2 = storePath();
5957
- if (!(0, import_node_fs16.existsSync)(path2)) return {};
6019
+ if (!(0, import_node_fs17.existsSync)(path2)) return {};
5958
6020
  try {
5959
- const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs16.readFileSync)(path2, "utf8"));
6021
+ const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs17.readFileSync)(path2, "utf8"));
5960
6022
  return parsed?.targets && typeof parsed.targets === "object" ? parsed.targets : {};
5961
6023
  } catch {
5962
6024
  return {};
@@ -5971,12 +6033,12 @@ function setSlackReplyTarget(target) {
5971
6033
  function getSlackReplyTarget(threadId) {
5972
6034
  return readStore()[threadId] ?? null;
5973
6035
  }
5974
- var import_node_fs16, import_node_path17;
6036
+ var import_node_fs17, import_node_path18;
5975
6037
  var init_reply_target = __esm({
5976
6038
  "src/slack/reply-target.ts"() {
5977
6039
  "use strict";
5978
- import_node_fs16 = require("fs");
5979
- import_node_path17 = require("path");
6040
+ import_node_fs17 = require("fs");
6041
+ import_node_path18 = require("path");
5980
6042
  init_paths();
5981
6043
  init_private_file();
5982
6044
  init_secure_file();
@@ -5985,7 +6047,7 @@ var init_reply_target = __esm({
5985
6047
 
5986
6048
  // src/slack/workspaces.ts
5987
6049
  function storePath2() {
5988
- return (0, import_node_path18.join)(appDataDir(), "slack-workspaces.json");
6050
+ return (0, import_node_path19.join)(appDataDir(), "slack-workspaces.json");
5989
6051
  }
5990
6052
  function readStore2() {
5991
6053
  try {
@@ -6092,11 +6154,11 @@ function requireSlackWorkspace(teamId) {
6092
6154
  }
6093
6155
  return ws;
6094
6156
  }
6095
- var import_node_path18;
6157
+ var import_node_path19;
6096
6158
  var init_workspaces = __esm({
6097
6159
  "src/slack/workspaces.ts"() {
6098
6160
  "use strict";
6099
- import_node_path18 = require("path");
6161
+ import_node_path19 = require("path");
6100
6162
  init_paths();
6101
6163
  init_secure_file();
6102
6164
  init_api();
@@ -6105,7 +6167,7 @@ var init_workspaces = __esm({
6105
6167
 
6106
6168
  // src/slack/outbound-watch.ts
6107
6169
  function storePath3() {
6108
- return (0, import_node_path19.join)(appDataDir(), "slack-outbound-watch.json");
6170
+ return (0, import_node_path20.join)(appDataDir(), "slack-outbound-watch.json");
6109
6171
  }
6110
6172
  function watchId(teamId, channelId, ts) {
6111
6173
  return `${teamId}:${channelId}:${ts}`;
@@ -6135,9 +6197,9 @@ function tsNewer(a, b) {
6135
6197
  }
6136
6198
  function readStore3() {
6137
6199
  const path2 = storePath3();
6138
- if (!(0, import_node_fs17.existsSync)(path2)) return [];
6200
+ if (!(0, import_node_fs18.existsSync)(path2)) return [];
6139
6201
  try {
6140
- const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs17.readFileSync)(path2, "utf8"));
6202
+ const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs18.readFileSync)(path2, "utf8"));
6141
6203
  return Array.isArray(parsed?.watches) ? parsed.watches : [];
6142
6204
  } catch {
6143
6205
  return [];
@@ -6480,12 +6542,12 @@ async function refreshSlackReplyBadges(opts) {
6480
6542
  if (changed) writeStore2(watches);
6481
6543
  return listSlackReplyBadges();
6482
6544
  }
6483
- var import_node_fs17, import_node_path19, MAX_WATCHES, MAX_REPLIES_PER_WATCH, WATCH_TTL_MS, POLL_INTERVAL_MS, lastPollMs, nameCache;
6545
+ var import_node_fs18, import_node_path20, MAX_WATCHES, MAX_REPLIES_PER_WATCH, WATCH_TTL_MS, POLL_INTERVAL_MS, lastPollMs, nameCache;
6484
6546
  var init_outbound_watch = __esm({
6485
6547
  "src/slack/outbound-watch.ts"() {
6486
6548
  "use strict";
6487
- import_node_fs17 = require("fs");
6488
- import_node_path19 = require("path");
6549
+ import_node_fs18 = require("fs");
6550
+ import_node_path20 = require("path");
6489
6551
  init_paths();
6490
6552
  init_private_file();
6491
6553
  init_secure_file();
@@ -6635,6 +6697,7 @@ function looksLikeRetryableRunnerCrash(text4) {
6635
6697
  }
6636
6698
  function shouldRetryFailedAgentTurn(detail, opts) {
6637
6699
  if (looksLikeInvalidAgentSession(detail) && opts.hasSession) return true;
6700
+ if (looksLikeV8Oom(detail) && opts.hasSession) return true;
6638
6701
  return looksLikeRetryableRunnerCrash(detail);
6639
6702
  }
6640
6703
  function looksLikeAgentFailureMessage(text4) {
@@ -6727,39 +6790,39 @@ var init_error_detail = __esm({
6727
6790
  NESTED_ELECTRON_SUMMARY = "Cursor local agent crashed at Electron startup (nested Chromium / HasCustomHostObject)";
6728
6791
  HOMEBREW_LIBUV_SUMMARY = "Cursor runner crashed in Node (Homebrew Node + shared libuv). Install Node 22 LTS (`brew install node@22`) and retry.";
6729
6792
  BUNDLED_NODE_CRASH_SUMMARY = "Cursor runner crashed in Node. Retry the turn.";
6730
- V8_OOM_SUMMARY = "Cursor runner ran out of memory (JavaScript heap). Retry; if it keeps happening, exclude large files from the project folder or start a new chat.";
6793
+ V8_OOM_SUMMARY = "Agent ran out of memory (JavaScript heap). If it keeps happening, exclude large files from the project folder.";
6731
6794
  MINIFIED_DUMP_SUMMARY = "Cursor local agent crashed during startup (truncated crash dump)";
6732
6795
  }
6733
6796
  });
6734
6797
 
6735
6798
  // src/brightsy/config.ts
6736
6799
  function brightsyConfigPath() {
6737
- return (0, import_node_path20.join)((0, import_node_os6.homedir)(), ".brightsy", "config.json");
6800
+ return (0, import_node_path21.join)((0, import_node_os6.homedir)(), ".brightsy", "config.json");
6738
6801
  }
6739
6802
  function loadBrightsyConfig() {
6740
6803
  const path2 = brightsyConfigPath();
6741
- if (!(0, import_node_fs18.existsSync)(path2)) {
6804
+ if (!(0, import_node_fs19.existsSync)(path2)) {
6742
6805
  throw new Error("Brightsy not logged in \u2014 run `brightsy login` first");
6743
6806
  }
6744
- const raw = JSON.parse((0, import_node_fs18.readFileSync)(path2, "utf8"));
6807
+ const raw = JSON.parse((0, import_node_fs19.readFileSync)(path2, "utf8"));
6745
6808
  if (!raw.access_token || !raw.account_id) {
6746
6809
  throw new Error("Brightsy config incomplete \u2014 run `brightsy login`");
6747
6810
  }
6748
6811
  return raw;
6749
6812
  }
6750
6813
  function saveBrightsyConfig(cfg) {
6751
- (0, import_node_fs18.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
6814
+ (0, import_node_fs19.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
6752
6815
  `, {
6753
6816
  mode: 384
6754
6817
  });
6755
6818
  }
6756
- var import_node_fs18, import_node_os6, import_node_path20;
6819
+ var import_node_fs19, import_node_os6, import_node_path21;
6757
6820
  var init_config = __esm({
6758
6821
  "src/brightsy/config.ts"() {
6759
6822
  "use strict";
6760
- import_node_fs18 = require("fs");
6823
+ import_node_fs19 = require("fs");
6761
6824
  import_node_os6 = require("os");
6762
- import_node_path20 = require("path");
6825
+ import_node_path21 = require("path");
6763
6826
  }
6764
6827
  });
6765
6828
 
@@ -6862,22 +6925,22 @@ __export(connected_teams_exports, {
6862
6925
  listConnectedBrightsyTeams: () => listConnectedBrightsyTeams
6863
6926
  });
6864
6927
  function storePath4() {
6865
- return (0, import_node_path21.join)(appDataDir(), "brightsy-teams.json");
6928
+ return (0, import_node_path22.join)(appDataDir(), "brightsy-teams.json");
6866
6929
  }
6867
6930
  function readStore4() {
6868
6931
  const path2 = storePath4();
6869
- if (!(0, import_node_fs19.existsSync)(path2)) return [];
6932
+ if (!(0, import_node_fs20.existsSync)(path2)) return [];
6870
6933
  try {
6871
- const parsed = JSON.parse((0, import_node_fs19.readFileSync)(path2, "utf8"));
6934
+ const parsed = JSON.parse((0, import_node_fs20.readFileSync)(path2, "utf8"));
6872
6935
  return Array.isArray(parsed.teams) ? parsed.teams : [];
6873
6936
  } catch {
6874
6937
  return [];
6875
6938
  }
6876
6939
  }
6877
6940
  function writeStore3(teams) {
6878
- (0, import_node_fs19.mkdirSync)(appDataDir(), { recursive: true });
6941
+ (0, import_node_fs20.mkdirSync)(appDataDir(), { recursive: true });
6879
6942
  const path2 = storePath4();
6880
- (0, import_node_fs19.writeFileSync)(path2, `${JSON.stringify({ teams }, null, 2)}
6943
+ (0, import_node_fs20.writeFileSync)(path2, `${JSON.stringify({ teams }, null, 2)}
6881
6944
  `, {
6882
6945
  mode: 384
6883
6946
  });
@@ -7039,12 +7102,12 @@ function brightsyMcpServerName(slug) {
7039
7102
  const cleaned = slug.replace(/[^A-Za-z0-9_-]/g, "_").replace(/^_+|_+$/g, "");
7040
7103
  return `brightsy_${cleaned || "team"}`;
7041
7104
  }
7042
- var import_node_fs19, import_node_path21;
7105
+ var import_node_fs20, import_node_path22;
7043
7106
  var init_connected_teams = __esm({
7044
7107
  "src/brightsy/connected-teams.ts"() {
7045
7108
  "use strict";
7046
- import_node_fs19 = require("fs");
7047
- import_node_path21 = require("path");
7109
+ import_node_fs20 = require("fs");
7110
+ import_node_path22 = require("path");
7048
7111
  init_paths();
7049
7112
  init_accounts();
7050
7113
  init_config();
@@ -7422,11 +7485,11 @@ async function syncCliForTarget(accountId) {
7422
7485
  }
7423
7486
  applyConnectedTeamToCli(team);
7424
7487
  }
7425
- var import_node_fs20, brightsyAdapter;
7488
+ var import_node_fs21, brightsyAdapter;
7426
7489
  var init_brightsy = __esm({
7427
7490
  "src/agents/brightsy.ts"() {
7428
7491
  "use strict";
7429
- import_node_fs20 = require("fs");
7492
+ import_node_fs21 = require("fs");
7430
7493
  init_run();
7431
7494
  init_connected_teams();
7432
7495
  init_config();
@@ -7441,7 +7504,7 @@ var init_brightsy = __esm({
7441
7504
  async detect() {
7442
7505
  const brightsy = resolveAgentExecutable("brightsy");
7443
7506
  if (brightsy !== "brightsy") {
7444
- if (!(0, import_node_fs20.existsSync)(brightsy)) {
7507
+ if (!(0, import_node_fs21.existsSync)(brightsy)) {
7445
7508
  return {
7446
7509
  agent: "brightsy",
7447
7510
  installed: false,
@@ -7617,9 +7680,9 @@ function toolDescription(name, input) {
7617
7680
  if (/connectedAgentRequest/i.test(name)) {
7618
7681
  return str2(input?.agent_id) ? `Ask connected agent` : "Ask connected agent";
7619
7682
  }
7620
- if (desc && kind) return `${kind}: ${desc}`;
7621
- if (desc) return desc;
7622
- return "Subagent";
7683
+ if (desc && kind) return `${kind}: ${desc}${subagentLiveSuffix(input)}`;
7684
+ if (desc) return `${desc}${subagentLiveSuffix(input)}`;
7685
+ return `Subagent${subagentLiveSuffix(input)}`;
7623
7686
  }
7624
7687
  if (/^(create|update)_artifact$/i.test(name.replace(/^mcp__[^_]+__/, ""))) {
7625
7688
  return str2(input?.title) ? `Artifact ${str2(input?.title)}` : "Artifact";
@@ -7644,13 +7707,151 @@ function toolDescription(name, input) {
7644
7707
  }
7645
7708
  if (/grep/i.test(name)) return "Search files";
7646
7709
  if (/glob/i.test(name)) return "Find files";
7710
+ const compact = n.replace(/[_-]/g, "");
7711
+ if (/^taskoutput$/i.test(compact)) {
7712
+ return str2(input.task_id) ? `Wait for ${str2(input.task_id)}` : "Wait for background task";
7713
+ }
7714
+ if (/^taskstop$/i.test(compact)) {
7715
+ return str2(input.task_id) ? `Stop ${str2(input.task_id)}` : "Stop background task";
7716
+ }
7717
+ if (/^monitor$/i.test(compact)) {
7718
+ const command = str2(input.command);
7719
+ return command ? `Watch ${command.length > 48 ? `${command.slice(0, 45)}\u2026` : command}` : "Watch command";
7720
+ }
7647
7721
  return n;
7648
7722
  }
7723
+ function subagentLiveSuffix(input) {
7724
+ if (!input) return "";
7725
+ const bits = [];
7726
+ const status = str2(input.live_status);
7727
+ if (status && !/^runn(ing)?$|^working$/i.test(status)) bits.push(status);
7728
+ if (typeof input.live_tool_uses === "number") bits.push(`${input.live_tool_uses} tools`);
7729
+ if (typeof input.live_duration_ms === "number") {
7730
+ bits.push(`${Math.max(0, Math.round(Number(input.live_duration_ms) / 1e3))}s`);
7731
+ }
7732
+ const last = str2(input.live_last_tool);
7733
+ if (last) bits.push(last);
7734
+ return bits.length ? ` \xB7 ${bits.join(" \xB7 ")}` : "";
7735
+ }
7649
7736
  function isSubagentToolName(name) {
7650
7737
  const n = (name ?? "").trim();
7651
7738
  if (/^(task|agent|spawn_agent)$/i.test(n)) return true;
7652
7739
  return /connectedAgentRequest/i.test(n);
7653
7740
  }
7741
+ function isPollWrapperToolName(name) {
7742
+ const n = (name ?? "").replace(/[_-]/g, "");
7743
+ return /^(taskoutput|taskstop|sleep)$/i.test(n);
7744
+ }
7745
+ function lastTextPart(parts, type) {
7746
+ for (let i = parts.length - 1; i >= 0; i--) {
7747
+ const p = parts[i];
7748
+ if (p.type === type && p.text.trim()) return p.text.trim();
7749
+ }
7750
+ return "";
7751
+ }
7752
+ function toolLabel(tool) {
7753
+ return tool.description || toolDescription(tool.name, tool.input) || tool.name;
7754
+ }
7755
+ function fileBasename(path2) {
7756
+ const parts = path2.replace(/\/$/, "").split(/[/\\]/);
7757
+ return parts[parts.length - 1] || path2;
7758
+ }
7759
+ function classifyTool(name) {
7760
+ const compact = name.replace(/^mcp__[^_]+__/, "").replace(/[_-]/g, "");
7761
+ if (/bash|shell|terminal|^zsh$|^sh$/i.test(compact)) return "shell";
7762
+ if (/grep|glob|search|ripgrep|findfiles|semsearch/i.test(compact)) return "search";
7763
+ if (/^(read|cat)$/i.test(compact) || /^read/i.test(compact)) return "read";
7764
+ if (/edit|write|apply|strreplace|multiedit|updatefile|createfile/i.test(compact)) {
7765
+ return "edit";
7766
+ }
7767
+ return "other";
7768
+ }
7769
+ function isShellToolName(name) {
7770
+ return classifyTool(name ?? "") === "shell";
7771
+ }
7772
+ function toolActivityLine(parts) {
7773
+ const tools = parts.filter((p) => {
7774
+ if (p.type !== "tool" || p.parentId) return false;
7775
+ if (isPollWrapperToolName(p.name)) return false;
7776
+ if (/present_plan$/i.test(p.name ?? "")) return false;
7777
+ if (/ask_user|AskUserQuestion/i.test(p.name ?? "")) return false;
7778
+ return true;
7779
+ });
7780
+ if (tools.length === 0) return null;
7781
+ const edited = [];
7782
+ let reads = 0;
7783
+ let searches = 0;
7784
+ let shells = 0;
7785
+ let others = 0;
7786
+ let additions = 0;
7787
+ let deletions = 0;
7788
+ for (const tool of tools) {
7789
+ const kind = classifyTool(tool.name);
7790
+ if (kind === "edit") {
7791
+ const path2 = tool.filePath ?? toolFilePath(tool.input);
7792
+ edited.push({
7793
+ name: path2 ? fileBasename(path2) : tool.name,
7794
+ running: tool.status === "running"
7795
+ });
7796
+ } else if (kind === "read") reads += 1;
7797
+ else if (kind === "search") searches += 1;
7798
+ else if (kind === "shell") shells += 1;
7799
+ else others += 1;
7800
+ if (typeof tool.additions === "number") additions += tool.additions;
7801
+ if (typeof tool.deletions === "number") deletions += tool.deletions;
7802
+ }
7803
+ const bits = [];
7804
+ const editing = edited.filter((e) => e.running);
7805
+ const editedDone = edited.filter((e) => !e.running);
7806
+ if (editing.length === 1) bits.push(`Editing ${editing[0].name}`);
7807
+ else if (editing.length > 1) bits.push(`Editing ${editing.length} files`);
7808
+ if (editedDone.length === 1) bits.push(`${editing.length ? "edited" : "Edited"} ${editedDone[0].name}`);
7809
+ else if (editedDone.length > 1) {
7810
+ bits.push(`${editing.length ? "edited" : "Edited"} ${editedDone.length} files`);
7811
+ }
7812
+ if (reads === 1) bits.push("explored 1 file");
7813
+ else if (reads > 1) bits.push(`explored ${reads} files`);
7814
+ if (searches === 1) bits.push("1 search");
7815
+ else if (searches > 1) bits.push(`${searches} searches`);
7816
+ if (shells === 1) bits.push("ran 1 command");
7817
+ else if (shells > 1) bits.push(`ran ${shells} commands`);
7818
+ if (others === 1) bits.push("1 tool");
7819
+ else if (others > 1) bits.push(`${others} tools`);
7820
+ if (bits.length === 0) return null;
7821
+ return { text: bits.join(", "), additions, deletions };
7822
+ }
7823
+ function liveActivitySummary(parts, opts) {
7824
+ if (opts?.queued && parts.length === 0) {
7825
+ return "Queued \u2014 waiting for a slot";
7826
+ }
7827
+ const tools = parts.filter((p) => p.type === "tool");
7828
+ const runningSubs = tools.filter(
7829
+ (t) => t.status === "running" && !t.parentId && isSubagentToolName(t.name)
7830
+ );
7831
+ const runningNested = [...tools].reverse().find((t) => t.status === "running" && t.parentId && !isPollWrapperToolName(t.name));
7832
+ const runningTop = [...tools].reverse().find(
7833
+ (t) => t.status === "running" && !t.parentId && !isPollWrapperToolName(t.name) && !isSubagentToolName(t.name)
7834
+ );
7835
+ const runningPoll = [...tools].reverse().find((t) => t.status === "running" && isPollWrapperToolName(t.name));
7836
+ const thinking = lastTextPart(parts, "thinking");
7837
+ const text4 = lastTextPart(parts, "text");
7838
+ if (runningSubs.length > 0) {
7839
+ const heads = runningSubs.map(toolLabel);
7840
+ const head = runningSubs.length === 1 ? heads[0] : `${runningSubs.length} subagents \xB7 ${heads.slice(0, 2).join(" \xB7 ")}`;
7841
+ if (runningNested) return `${head} \xB7 ${toolLabel(runningNested)}`;
7842
+ return head;
7843
+ }
7844
+ if (runningTop) return toolLabel(runningTop);
7845
+ if (runningPoll) return toolLabel(runningPoll);
7846
+ if (thinking) return thinking.length > 96 ? `\u2026${thinking.slice(-96)}` : thinking;
7847
+ if (text4) return "Writing reply\u2026";
7848
+ const last = [...tools].reverse().find((t) => !isPollWrapperToolName(t.name)) ?? tools.at(-1);
7849
+ if (last) {
7850
+ const label = toolLabel(last);
7851
+ return last.status === "running" ? label : `Finished ${label}`;
7852
+ }
7853
+ return "Working\u2026";
7854
+ }
7654
7855
  function messagePartParentId(part) {
7655
7856
  if ("parentId" in part && typeof part.parentId === "string" && part.parentId.trim()) {
7656
7857
  return part.parentId;
@@ -7736,6 +7937,25 @@ function applyAgentEvent(parts, event) {
7736
7937
  const data = event.data;
7737
7938
  if (!data) return parts;
7738
7939
  const next = [...parts];
7940
+ if (event.replace) {
7941
+ for (let i = next.length - 1; i >= 0; i--) {
7942
+ const prev = next[i];
7943
+ if (prev?.type === "thinking" && sameParentId(prev.parentId, event.parentId)) {
7944
+ next[i] = {
7945
+ type: "thinking",
7946
+ text: data,
7947
+ ...event.parentId ? { parentId: event.parentId } : {}
7948
+ };
7949
+ return next;
7950
+ }
7951
+ }
7952
+ next.push({
7953
+ type: "thinking",
7954
+ text: data,
7955
+ ...event.parentId ? { parentId: event.parentId } : {}
7956
+ });
7957
+ return next;
7958
+ }
7739
7959
  const last = next[next.length - 1];
7740
7960
  if (last?.type === "thinking" && sameParentId(last.parentId, event.parentId)) {
7741
7961
  next[next.length - 1] = {
@@ -7759,14 +7979,18 @@ function applyAgentEvent(parts, event) {
7759
7979
  if (existing >= 0) {
7760
7980
  const prev = parts[existing];
7761
7981
  const next = [...parts];
7762
- const mergedInput = input && Object.keys(input).length > 0 ? input : prev.input ?? input;
7982
+ const mergedInput = {
7983
+ ...prev.input ?? {},
7984
+ ...input ?? {}
7985
+ };
7986
+ const mergedRecord = Object.keys(mergedInput).length > 0 ? mergedInput : void 0;
7763
7987
  next[existing] = {
7764
7988
  ...prev,
7765
7989
  name: event.name || prev.name,
7766
- input: mergedInput,
7767
- description: toolDescription(event.name || prev.name, mergedInput),
7768
- detail: toolDetail(event.name || prev.name, mergedInput) ?? prev.detail,
7769
- filePath: toolFilePath(mergedInput) ?? prev.filePath,
7990
+ input: mergedRecord,
7991
+ description: toolDescription(event.name || prev.name, mergedRecord),
7992
+ detail: toolDetail(event.name || prev.name, mergedRecord) ?? prev.detail,
7993
+ filePath: toolFilePath(mergedRecord) ?? prev.filePath,
7770
7994
  additions: diff.additions ?? prev.additions,
7771
7995
  deletions: diff.deletions ?? prev.deletions,
7772
7996
  parentId: event.parentId ?? prev.parentId
@@ -7792,6 +8016,30 @@ function applyAgentEvent(parts, event) {
7792
8016
  if (event.type === "tool_result") {
7793
8017
  const existing = parts.findIndex((p) => p.type === "tool" && p.id === event.id);
7794
8018
  const fromResult = parseDiffStat(event.content);
8019
+ if (event.partial) {
8020
+ if (existing < 0) {
8021
+ return [
8022
+ ...parts,
8023
+ {
8024
+ type: "tool",
8025
+ id: event.id,
8026
+ name: "tool",
8027
+ description: "tool",
8028
+ status: event.isError ? "error" : "running",
8029
+ result: event.content,
8030
+ ...event.parentId ? { parentId: event.parentId } : {}
8031
+ }
8032
+ ];
8033
+ }
8034
+ return parts.map((p, i) => {
8035
+ if (i !== existing || p.type !== "tool") return p;
8036
+ if (p.status === "done" || p.status === "error") return p;
8037
+ return {
8038
+ ...p,
8039
+ result: event.content ?? p.result
8040
+ };
8041
+ });
8042
+ }
7795
8043
  if (existing < 0) {
7796
8044
  return [
7797
8045
  ...parts,
@@ -7884,47 +8132,68 @@ function electronResourcesPath() {
7884
8132
  function packagedCursorRuntimeDir() {
7885
8133
  const resources = electronResourcesPath();
7886
8134
  if (!resources) return null;
7887
- const dir = (0, import_node_path22.join)(resources, "cursor-runtime");
7888
- if (!(0, import_node_fs21.existsSync)((0, import_node_path22.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
8135
+ const dir = (0, import_node_path23.join)(resources, "cursor-runtime");
8136
+ if (!(0, import_node_fs22.existsSync)((0, import_node_path23.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
7889
8137
  return dir;
7890
8138
  }
7891
8139
  function packagedCursorRunnerPath() {
7892
8140
  const dir = packagedCursorRuntimeDir();
7893
- return dir ? (0, import_node_path22.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
8141
+ return dir ? (0, import_node_path23.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
7894
8142
  }
7895
8143
  function packagedMcpDir() {
7896
8144
  const resources = electronResourcesPath();
7897
8145
  if (!resources) return null;
7898
- const dir = (0, import_node_path22.join)(resources, "sideboard-mcp");
7899
- if (!(0, import_node_fs21.existsSync)((0, import_node_path22.join)(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
8146
+ const dir = (0, import_node_path23.join)(resources, "sideboard-mcp");
8147
+ if (!(0, import_node_fs22.existsSync)((0, import_node_path23.join)(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
7900
8148
  return dir;
7901
8149
  }
7902
8150
  function packagedMcpStdioPath() {
7903
8151
  const dir = packagedMcpDir();
7904
- return dir ? (0, import_node_path22.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
8152
+ return dir ? (0, import_node_path23.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
7905
8153
  }
7906
8154
  function packagedBundledNodePath() {
7907
8155
  const resources = electronResourcesPath();
7908
8156
  if (!resources) return null;
7909
- const bin = (0, import_node_path22.join)(resources, "node", "bin", "node");
7910
- if (!(0, import_node_fs21.existsSync)(bin)) return null;
8157
+ const bin = (0, import_node_path23.join)(resources, "node", "bin", "node");
8158
+ if (!(0, import_node_fs22.existsSync)(bin)) return null;
7911
8159
  return bin;
7912
8160
  }
7913
8161
  function packagedCursorRipgrepCandidate(platformPkg, binName) {
7914
8162
  const dir = packagedCursorRuntimeDir();
7915
8163
  if (!dir) return null;
7916
- return (0, import_node_path22.join)(dir, "node_modules", platformPkg, "bin", binName);
8164
+ return (0, import_node_path23.join)(dir, "node_modules", platformPkg, "bin", binName);
7917
8165
  }
7918
- var import_node_fs21, import_node_path22;
8166
+ var import_node_fs22, import_node_path23;
7919
8167
  var init_packaged_runtime = __esm({
7920
8168
  "src/agents/packaged-runtime.ts"() {
7921
8169
  "use strict";
7922
- import_node_fs21 = require("fs");
7923
- import_node_path22 = require("path");
8170
+ import_node_fs22 = require("fs");
8171
+ import_node_path23 = require("path");
7924
8172
  }
7925
8173
  });
7926
8174
 
7927
8175
  // src/agents/node-launch.ts
8176
+ function withMaxOldSpaceSize(nodeOptions, heapMb) {
8177
+ const existing = (nodeOptions ?? "").trim();
8178
+ const match = MAX_OLD_SPACE_FLAG.exec(existing);
8179
+ if (match) {
8180
+ const current = match[2] ? Number(match[2]) : 0;
8181
+ if (Number.isFinite(current) && current >= heapMb) return existing;
8182
+ return existing.replace(MAX_OLD_SPACE_FLAG, ` --max-old-space-size=${heapMb}`).trim();
8183
+ }
8184
+ return existing ? `${existing} --max-old-space-size=${heapMb}` : `--max-old-space-size=${heapMb}`;
8185
+ }
8186
+ function applyAgentRunnerHeapEnv(env) {
8187
+ env.NODE_OPTIONS = withMaxOldSpaceSize(
8188
+ env.NODE_OPTIONS,
8189
+ AGENT_RUNNER_MAX_OLD_SPACE_MB
8190
+ );
8191
+ }
8192
+ function envWithAgentHeap(env) {
8193
+ const next = { ...env };
8194
+ applyAgentRunnerHeapEnv(next);
8195
+ return next;
8196
+ }
7928
8197
  function isAsarPath(filePath) {
7929
8198
  if (/\.asar\.unpacked([/\\]|$)/.test(filePath)) return false;
7930
8199
  return /\.asar([/\\]|$)/.test(filePath);
@@ -7933,7 +8202,7 @@ function unpackedAsarPath(filePath) {
7933
8202
  if (!isAsarPath(filePath)) return null;
7934
8203
  const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
7935
8204
  if (unpacked === filePath) return null;
7936
- return (0, import_node_fs22.existsSync)(unpacked) ? unpacked : null;
8205
+ return (0, import_node_fs23.existsSync)(unpacked) ? unpacked : null;
7937
8206
  }
7938
8207
  function nodeReadableScriptPath(scriptPath) {
7939
8208
  return unpackedAsarPath(scriptPath) ?? scriptPath;
@@ -7973,37 +8242,37 @@ function pickPreferredNode(candidates) {
7973
8242
  return best;
7974
8243
  }
7975
8244
  function versionDirNodeBins(root, toBin) {
7976
- if (!(0, import_node_fs22.existsSync)(root)) return [];
8245
+ if (!(0, import_node_fs23.existsSync)(root)) return [];
7977
8246
  try {
7978
- return (0, import_node_fs22.readdirSync)(root).map(toBin);
8247
+ return (0, import_node_fs23.readdirSync)(root).map(toBin);
7979
8248
  } catch {
7980
8249
  return [];
7981
8250
  }
7982
8251
  }
7983
8252
  function defaultNodeBinCandidates(home = (0, import_node_os7.homedir)()) {
7984
8253
  const kegs = ["/opt/homebrew", "/usr/local"].flatMap(
7985
- (prefix) => PREFERRED_LTS_MAJORS.map((major) => (0, import_node_path23.join)(prefix, "opt", `node@${major}`, "bin", "node"))
8254
+ (prefix) => PREFERRED_LTS_MAJORS.map((major) => (0, import_node_path24.join)(prefix, "opt", `node@${major}`, "bin", "node"))
7986
8255
  );
7987
8256
  return [
7988
8257
  ...kegs,
7989
8258
  "/opt/homebrew/bin/node",
7990
8259
  "/usr/local/bin/node",
7991
- (0, import_node_path23.join)(home, ".local/share/fnm/aliases/default/bin/node"),
7992
- (0, import_node_path23.join)(home, ".nvm/current/bin/node"),
7993
- (0, import_node_path23.join)(home, ".volta/bin/node"),
7994
- (0, import_node_path23.join)(home, ".asdf/shims/node"),
7995
- (0, import_node_path23.join)(home, ".local/share/mise/shims/node"),
8260
+ (0, import_node_path24.join)(home, ".local/share/fnm/aliases/default/bin/node"),
8261
+ (0, import_node_path24.join)(home, ".nvm/current/bin/node"),
8262
+ (0, import_node_path24.join)(home, ".volta/bin/node"),
8263
+ (0, import_node_path24.join)(home, ".asdf/shims/node"),
8264
+ (0, import_node_path24.join)(home, ".local/share/mise/shims/node"),
7996
8265
  ...versionDirNodeBins(
7997
- (0, import_node_path23.join)(home, ".nvm", "versions", "node"),
7998
- (name) => (0, import_node_path23.join)(home, ".nvm", "versions", "node", name, "bin", "node")
8266
+ (0, import_node_path24.join)(home, ".nvm", "versions", "node"),
8267
+ (name) => (0, import_node_path24.join)(home, ".nvm", "versions", "node", name, "bin", "node")
7999
8268
  ),
8000
8269
  ...versionDirNodeBins(
8001
- (0, import_node_path23.join)(home, ".local/share/fnm", "node-versions"),
8002
- (name) => (0, import_node_path23.join)(home, ".local/share/fnm", "node-versions", name, "installation", "bin", "node")
8270
+ (0, import_node_path24.join)(home, ".local/share/fnm", "node-versions"),
8271
+ (name) => (0, import_node_path24.join)(home, ".local/share/fnm", "node-versions", name, "installation", "bin", "node")
8003
8272
  ),
8004
8273
  ...versionDirNodeBins(
8005
- (0, import_node_path23.join)(home, ".volta", "tools", "image", "node"),
8006
- (name) => (0, import_node_path23.join)(home, ".volta", "tools", "image", "node", name, "bin", "node")
8274
+ (0, import_node_path24.join)(home, ".volta", "tools", "image", "node"),
8275
+ (name) => (0, import_node_path24.join)(home, ".volta", "tools", "image", "node", name, "bin", "node")
8007
8276
  )
8008
8277
  ];
8009
8278
  }
@@ -8012,10 +8281,10 @@ function uniqueExistingNodeBins(paths) {
8012
8281
  const out = [];
8013
8282
  for (const raw of paths) {
8014
8283
  const p = raw.trim();
8015
- if (!p || !(0, import_node_fs22.existsSync)(p) || isElectronLikeCommand(p)) continue;
8284
+ if (!p || !(0, import_node_fs23.existsSync)(p) || isElectronLikeCommand(p)) continue;
8016
8285
  let key = p;
8017
8286
  try {
8018
- key = (0, import_node_fs22.realpathSync)(p);
8287
+ key = (0, import_node_fs23.realpathSync)(p);
8019
8288
  } catch {
8020
8289
  continue;
8021
8290
  }
@@ -8060,13 +8329,21 @@ async function findSystemNode() {
8060
8329
  function applyNodeLaunch(launch, args) {
8061
8330
  const readableArgs = args.map(nodeReadableScriptPath);
8062
8331
  if (!launch.env.ELECTRON_RUN_AS_NODE) {
8063
- return { file: launch.file, args: readableArgs, env: launch.env };
8332
+ return {
8333
+ file: launch.file,
8334
+ args: readableArgs,
8335
+ env: envWithAgentHeap(launch.env)
8336
+ };
8064
8337
  }
8065
8338
  const wrapped = wrapElectronAsNodeLaunch(launch.file, readableArgs);
8066
8339
  if (process.platform === "win32") {
8067
- return { file: wrapped.file, args: wrapped.args, env: launch.env };
8340
+ return {
8341
+ file: wrapped.file,
8342
+ args: wrapped.args,
8343
+ env: envWithAgentHeap(launch.env)
8344
+ };
8068
8345
  }
8069
- const env = { ...launch.env };
8346
+ const env = envWithAgentHeap(launch.env);
8070
8347
  delete env.ELECTRON_RUN_AS_NODE;
8071
8348
  return { file: wrapped.file, args: wrapped.args, env };
8072
8349
  }
@@ -8087,16 +8364,18 @@ async function resolveNodeLaunch(scriptPath) {
8087
8364
  env: { ELECTRON_RUN_AS_NODE: "1" }
8088
8365
  };
8089
8366
  }
8090
- var import_node_fs22, import_node_os7, import_node_path23, PREFERRED_LTS_MAJORS;
8367
+ var import_node_fs23, import_node_os7, import_node_path24, AGENT_RUNNER_MAX_OLD_SPACE_MB, MAX_OLD_SPACE_FLAG, PREFERRED_LTS_MAJORS;
8091
8368
  var init_node_launch = __esm({
8092
8369
  "src/agents/node-launch.ts"() {
8093
8370
  "use strict";
8094
- import_node_fs22 = require("fs");
8371
+ import_node_fs23 = require("fs");
8095
8372
  import_node_os7 = require("os");
8096
- import_node_path23 = require("path");
8373
+ import_node_path24 = require("path");
8097
8374
  init_nested_electron_env();
8098
8375
  init_run();
8099
8376
  init_packaged_runtime();
8377
+ AGENT_RUNNER_MAX_OLD_SPACE_MB = 8192;
8378
+ MAX_OLD_SPACE_FLAG = /(?:^|\s)(--max[-_]old[-_]space[-_]size)(?:[= ](\d+))?(?=\s|$)/;
8100
8379
  PREFERRED_LTS_MAJORS = [24, 22, 20];
8101
8380
  }
8102
8381
  });
@@ -8184,37 +8463,37 @@ function corePackageDir() {
8184
8463
  try {
8185
8464
  const url = import_meta.url;
8186
8465
  if (typeof url === "string" && url.length > 0) {
8187
- return (0, import_node_path24.dirname)((0, import_node_url.fileURLToPath)(url));
8466
+ return (0, import_node_path25.dirname)((0, import_node_url.fileURLToPath)(url));
8188
8467
  }
8189
8468
  } catch {
8190
8469
  }
8191
8470
  try {
8192
- const req = (0, import_node_module.createRequire)((0, import_node_path24.join)(process.cwd(), "package.json"));
8193
- return (0, import_node_path24.dirname)(req.resolve("@sideboard-ai/core"));
8471
+ const req = (0, import_node_module.createRequire)((0, import_node_path25.join)(process.cwd(), "package.json"));
8472
+ return (0, import_node_path25.dirname)(req.resolve("@sideboard-ai/core"));
8194
8473
  } catch {
8195
8474
  return process.cwd();
8196
8475
  }
8197
8476
  }
8198
8477
  function findSideboardMcpJsEntry() {
8199
8478
  const override = process.env.SIDEBOARD_MCP_ENTRY?.trim() || process.env.SIDEBOARD_CLI?.trim();
8200
- if (override && (0, import_node_fs23.existsSync)(override)) return override;
8479
+ if (override && (0, import_node_fs24.existsSync)(override)) return override;
8201
8480
  const packaged = packagedMcpStdioPath();
8202
8481
  if (packaged) return packaged;
8203
8482
  let dir = corePackageDir();
8204
8483
  for (let i = 0; i < 10; i++) {
8205
8484
  const candidates = [
8206
- (0, import_node_path24.join)(dir, "mcp/run-stdio.js"),
8207
- (0, import_node_path24.join)(dir, "mcp/run-stdio.cjs"),
8208
- (0, import_node_path24.join)(dir, "dist/mcp/run-stdio.js"),
8209
- (0, import_node_path24.join)(dir, "dist/mcp/run-stdio.cjs"),
8210
- (0, import_node_path24.join)(dir, "packages/core/dist/mcp/run-stdio.js"),
8211
- (0, import_node_path24.join)(dir, "packages/cli/dist/index.js"),
8212
- (0, import_node_path24.join)(dir, "cli/dist/index.js")
8485
+ (0, import_node_path25.join)(dir, "mcp/run-stdio.js"),
8486
+ (0, import_node_path25.join)(dir, "mcp/run-stdio.cjs"),
8487
+ (0, import_node_path25.join)(dir, "dist/mcp/run-stdio.js"),
8488
+ (0, import_node_path25.join)(dir, "dist/mcp/run-stdio.cjs"),
8489
+ (0, import_node_path25.join)(dir, "packages/core/dist/mcp/run-stdio.js"),
8490
+ (0, import_node_path25.join)(dir, "packages/cli/dist/index.js"),
8491
+ (0, import_node_path25.join)(dir, "cli/dist/index.js")
8213
8492
  ];
8214
8493
  for (const p of candidates) {
8215
- if ((0, import_node_fs23.existsSync)(p) && !isAsarPath(p)) return p;
8494
+ if ((0, import_node_fs24.existsSync)(p) && !isAsarPath(p)) return p;
8216
8495
  }
8217
- const parent = (0, import_node_path24.dirname)(dir);
8496
+ const parent = (0, import_node_path25.dirname)(dir);
8218
8497
  if (parent === dir) break;
8219
8498
  dir = parent;
8220
8499
  }
@@ -8262,6 +8541,7 @@ async function buildInjectedMcpServers(opts) {
8262
8541
  );
8263
8542
  } catch {
8264
8543
  }
8544
+ applyAgentRunnerHeapEnv(sideboard.env);
8265
8545
  servers.push(sideboard);
8266
8546
  }
8267
8547
  if (opts.includeBrightsy && isBrightsyConnected()) {
@@ -8355,22 +8635,22 @@ function writeMcpServersConfig(servers) {
8355
8635
  ...env ? { env } : {}
8356
8636
  };
8357
8637
  }
8358
- const dir = (0, import_node_fs23.mkdtempSync)((0, import_node_path24.join)((0, import_node_os8.tmpdir)(), "sideboard-mcp-"));
8359
- const cfgPath = (0, import_node_path24.join)(dir, "mcp.json");
8360
- (0, import_node_fs23.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
8638
+ const dir = (0, import_node_fs24.mkdtempSync)((0, import_node_path25.join)((0, import_node_os8.tmpdir)(), "sideboard-mcp-"));
8639
+ const cfgPath = (0, import_node_path25.join)(dir, "mcp.json");
8640
+ (0, import_node_fs24.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
8361
8641
  return cfgPath;
8362
8642
  }
8363
8643
  async function writeInjectedMcpConfig(opts) {
8364
8644
  return writeMcpServersConfig(await buildInjectedMcpServers(opts));
8365
8645
  }
8366
- var import_node_fs23, import_node_module, import_node_os8, import_node_path24, import_node_url, import_meta, SIDEBOARD_MCP_ALLOWED_TOOLS, SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS, BRIGHTSY_MCP_ALLOWED_TOOLS, brightsyMcpCommandCache, BRIGHTSY_WORD;
8646
+ var import_node_fs24, import_node_module, import_node_os8, import_node_path25, import_node_url, import_meta, SIDEBOARD_MCP_ALLOWED_TOOLS, SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS, BRIGHTSY_MCP_ALLOWED_TOOLS, brightsyMcpCommandCache, BRIGHTSY_WORD;
8367
8647
  var init_injected_mcp = __esm({
8368
8648
  "src/agents/injected-mcp.ts"() {
8369
8649
  "use strict";
8370
- import_node_fs23 = require("fs");
8650
+ import_node_fs24 = require("fs");
8371
8651
  import_node_module = require("module");
8372
8652
  import_node_os8 = require("os");
8373
- import_node_path24 = require("path");
8653
+ import_node_path25 = require("path");
8374
8654
  import_node_url = require("url");
8375
8655
  init_run();
8376
8656
  init_config();
@@ -8548,6 +8828,80 @@ function claudeParentToolUseId(obj) {
8548
8828
  }
8549
8829
  return void 0;
8550
8830
  }
8831
+ function claudeString(obj, key) {
8832
+ const v = obj[key];
8833
+ return typeof v === "string" && v.trim() ? v.trim() : void 0;
8834
+ }
8835
+ function eventsFromClaudeSystem(obj) {
8836
+ const subtype = claudeString(obj, "subtype") ?? "";
8837
+ const parentId = claudeParentToolUseId(obj);
8838
+ if (subtype === "init") {
8839
+ if (parentId) return null;
8840
+ const sid = claudeString(obj, "session_id");
8841
+ return sid ? { type: "session_id", data: sid } : null;
8842
+ }
8843
+ if (subtype === "task_started") {
8844
+ const id = claudeString(obj, "tool_use_id") ?? claudeString(obj, "task_id");
8845
+ if (!id) return null;
8846
+ const description = claudeString(obj, "description");
8847
+ const taskType = claudeString(obj, "task_type");
8848
+ const prompt = claudeString(obj, "prompt");
8849
+ return withEventParentId(
8850
+ {
8851
+ type: "tool_use",
8852
+ id,
8853
+ name: taskType || "Agent",
8854
+ input: {
8855
+ ...description ? { description } : {},
8856
+ ...prompt ? { prompt } : {},
8857
+ ...claudeString(obj, "task_id") ? { task_id: claudeString(obj, "task_id") } : {}
8858
+ }
8859
+ },
8860
+ parentId
8861
+ );
8862
+ }
8863
+ if (subtype === "task_notification") {
8864
+ const id = claudeString(obj, "tool_use_id") ?? claudeString(obj, "task_id") ?? parentId;
8865
+ if (!id) return null;
8866
+ const status = claudeString(obj, "status") ?? "working";
8867
+ const tools = typeof obj.tool_uses === "number" ? obj.tool_uses : void 0;
8868
+ const durationMs = typeof obj.duration_ms === "number" ? obj.duration_ms : void 0;
8869
+ const lastTool = claudeString(obj, "last_tool") ?? claudeString(obj, "current_tool") ?? claudeString(obj, "tool");
8870
+ const snapshot = [
8871
+ status,
8872
+ tools != null ? `${tools} tools` : null,
8873
+ durationMs != null ? `${Math.round(durationMs / 1e3)}s` : null,
8874
+ lastTool
8875
+ ].filter((bit) => Boolean(bit)).join(" \xB7 ");
8876
+ return [
8877
+ {
8878
+ type: "tool_use",
8879
+ id,
8880
+ name: claudeString(obj, "task_type") || "Agent",
8881
+ input: {
8882
+ live_status: status,
8883
+ ...tools != null ? { live_tool_uses: tools } : {},
8884
+ ...durationMs != null ? { live_duration_ms: durationMs } : {},
8885
+ ...lastTool ? { live_last_tool: lastTool } : {}
8886
+ }
8887
+ },
8888
+ withEventParentId(
8889
+ { type: "thinking", data: snapshot, replace: true },
8890
+ id
8891
+ )
8892
+ ];
8893
+ }
8894
+ if (subtype === "api_retry") {
8895
+ const attempt = obj.attempt;
8896
+ const max = obj.max_retries;
8897
+ const delay = obj.retry_delay_ms;
8898
+ return {
8899
+ type: "thinking",
8900
+ data: `API retry ${attempt ?? "?"}/${max ?? "?"}${typeof delay === "number" ? ` (wait ${delay}ms)` : ""}`
8901
+ };
8902
+ }
8903
+ return null;
8904
+ }
8551
8905
  function parseIssuesJson(raw) {
8552
8906
  const text4 = raw.trim();
8553
8907
  const candidates = [text4];
@@ -8573,11 +8927,11 @@ function parseIssuesJson(raw) {
8573
8927
  }
8574
8928
  return [];
8575
8929
  }
8576
- var import_node_fs24, BASE_ALLOWED_TOOLS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, claudeAdapter;
8930
+ var import_node_fs25, BASE_ALLOWED_TOOLS, CLAUDE_PRINT_BG_WAIT_CEILING_MS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, claudeAdapter;
8577
8931
  var init_claude = __esm({
8578
8932
  "src/agents/claude.ts"() {
8579
8933
  "use strict";
8580
- import_node_fs24 = require("fs");
8934
+ import_node_fs25 = require("fs");
8581
8935
  init_run();
8582
8936
  init_app_settings();
8583
8937
  init_claude_mcp();
@@ -8597,8 +8951,14 @@ var init_claude = __esm({
8597
8951
  "WebSearch",
8598
8952
  // Subagents (Claude Code v2.1.63 renamed Task → Agent; allow both).
8599
8953
  "Task",
8600
- "Agent"
8954
+ "Agent",
8955
+ "TaskOutput",
8956
+ "TaskStop",
8957
+ "EnterWorktree",
8958
+ "ExitWorktree",
8959
+ "Skill"
8601
8960
  ];
8961
+ CLAUDE_PRINT_BG_WAIT_CEILING_MS = 72e5;
8602
8962
  CLAUDE_CHROME_ALLOWED_TOOLS = [
8603
8963
  "mcp__claude-in-chrome",
8604
8964
  "mcp__claude-in-chrome__*",
@@ -8610,7 +8970,7 @@ var init_claude = __esm({
8610
8970
  async detect() {
8611
8971
  const claude = resolveClaudeExecutable();
8612
8972
  if (claude !== "claude") {
8613
- if (!(0, import_node_fs24.existsSync)(claude)) {
8973
+ if (!(0, import_node_fs25.existsSync)(claude)) {
8614
8974
  return {
8615
8975
  agent: "claude",
8616
8976
  installed: false,
@@ -8727,7 +9087,12 @@ var init_claude = __esm({
8727
9087
  stdin: useStdin ? `${promptText}
8728
9088
  ` : void 0,
8729
9089
  // Nested Task/Agent thinking+text in stream-json (Claude Code 2.1.211+).
8730
- env: { CLAUDE_CODE_FORWARD_SUBAGENT_TEXT: "1" }
9090
+ // Raise the -p background-agent wait so long TaskOutput polls are not
9091
+ // abandoned at Claude Code’s 10-minute default.
9092
+ env: {
9093
+ CLAUDE_CODE_FORWARD_SUBAGENT_TEXT: "1",
9094
+ CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS: process.env.CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS ?? String(CLAUDE_PRINT_BG_WAIT_CEILING_MS)
9095
+ }
8731
9096
  };
8732
9097
  },
8733
9098
  parseEvent(line) {
@@ -8735,13 +9100,8 @@ var init_claude = __esm({
8735
9100
  if (!trimmed) return null;
8736
9101
  try {
8737
9102
  const obj = JSON.parse(trimmed);
8738
- if (obj.type === "system" && obj.subtype === "init") {
8739
- const sid = obj.session_id;
8740
- if (typeof sid === "string") return { type: "session_id", data: sid };
8741
- return null;
8742
- }
8743
- if (obj.type === "system" && typeof obj.session_id === "string") {
8744
- return { type: "session_id", data: obj.session_id };
9103
+ if (obj.type === "system") {
9104
+ return eventsFromClaudeSystem(obj);
8745
9105
  }
8746
9106
  if (obj.type === "assistant" || obj.type === "user") {
8747
9107
  const parentId = claudeParentToolUseId(obj);
@@ -8861,7 +9221,7 @@ async function listCodexModels() {
8861
9221
  if (codex === "codex") {
8862
9222
  const which = await run("which", ["codex"], { reject: false });
8863
9223
  if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
8864
- } else if (!(0, import_node_fs25.existsSync)(codex)) {
9224
+ } else if (!(0, import_node_fs26.existsSync)(codex)) {
8865
9225
  return FALLBACK_CODEX_MODELS;
8866
9226
  }
8867
9227
  const listed = await run(codex, ["debug", "models"], { reject: false });
@@ -8896,12 +9256,12 @@ function usageFromCodex(usage) {
8896
9256
  }
8897
9257
  function codexConfigHasNetworkAccess() {
8898
9258
  const candidates = [
8899
- (0, import_node_path25.join)((0, import_node_os9.homedir)(), ".codex", "config.toml"),
8900
- (0, import_node_path25.join)((0, import_node_os9.homedir)(), ".config", "codex", "config.toml")
9259
+ (0, import_node_path26.join)((0, import_node_os9.homedir)(), ".codex", "config.toml"),
9260
+ (0, import_node_path26.join)((0, import_node_os9.homedir)(), ".config", "codex", "config.toml")
8901
9261
  ];
8902
9262
  for (const path2 of candidates) {
8903
- if (!(0, import_node_fs25.existsSync)(path2)) continue;
8904
- const text4 = (0, import_node_fs25.readFileSync)(path2, "utf8");
9263
+ if (!(0, import_node_fs26.existsSync)(path2)) continue;
9264
+ const text4 = (0, import_node_fs26.readFileSync)(path2, "utf8");
8905
9265
  if (/network_access\s*=\s*true/.test(text4)) return true;
8906
9266
  }
8907
9267
  return false;
@@ -8933,21 +9293,21 @@ function asRecord2(value) {
8933
9293
  return void 0;
8934
9294
  }
8935
9295
  function codexLooksAuthenticated() {
8936
- const authPath = (0, import_node_path25.join)((0, import_node_os9.homedir)(), ".codex", "auth.json");
8937
- if (!(0, import_node_fs25.existsSync)(authPath)) return false;
9296
+ const authPath = (0, import_node_path26.join)((0, import_node_os9.homedir)(), ".codex", "auth.json");
9297
+ if (!(0, import_node_fs26.existsSync)(authPath)) return false;
8938
9298
  try {
8939
- return (0, import_node_fs25.statSync)(authPath).size > 2;
9299
+ return (0, import_node_fs26.statSync)(authPath).size > 2;
8940
9300
  } catch {
8941
9301
  return false;
8942
9302
  }
8943
9303
  }
8944
- var import_node_fs25, import_node_os9, import_node_path25, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
9304
+ var import_node_fs26, import_node_os9, import_node_path26, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
8945
9305
  var init_codex = __esm({
8946
9306
  "src/agents/codex.ts"() {
8947
9307
  "use strict";
8948
- import_node_fs25 = require("fs");
9308
+ import_node_fs26 = require("fs");
8949
9309
  import_node_os9 = require("os");
8950
- import_node_path25 = require("path");
9310
+ import_node_path26 = require("path");
8951
9311
  init_run();
8952
9312
  init_app_settings();
8953
9313
  init_global_workspace();
@@ -8972,7 +9332,7 @@ var init_codex = __esm({
8972
9332
  async detect() {
8973
9333
  const codex = resolveAgentExecutable("codex");
8974
9334
  if (codex !== "codex") {
8975
- if (!(0, import_node_fs25.existsSync)(codex)) {
9335
+ if (!(0, import_node_fs26.existsSync)(codex)) {
8976
9336
  return {
8977
9337
  agent: "codex",
8978
9338
  installed: false,
@@ -9112,13 +9472,22 @@ var init_codex = __esm({
9112
9472
  const events = [
9113
9473
  { type: "tool_use", id: item.id, name: "Bash", input }
9114
9474
  ];
9115
- if (type === "item.completed" || item.status === "completed" || item.status === "failed") {
9475
+ const finished = type === "item.completed" || item.status === "completed" || item.status === "failed";
9476
+ const output = typeof item.aggregated_output === "string" && item.aggregated_output ? item.aggregated_output : void 0;
9477
+ if (finished) {
9116
9478
  events.push({
9117
9479
  type: "tool_result",
9118
9480
  id: item.id,
9119
- content: item.aggregated_output,
9481
+ content: output,
9120
9482
  isError: item.status === "failed"
9121
9483
  });
9484
+ } else if (output) {
9485
+ events.push({
9486
+ type: "tool_result",
9487
+ id: item.id,
9488
+ content: output,
9489
+ partial: true
9490
+ });
9122
9491
  }
9123
9492
  return events.length === 1 ? events[0] : events;
9124
9493
  }
@@ -9161,9 +9530,6 @@ var init_codex = __esm({
9161
9530
  if (sid && (type === "thread.started" || type === "session" || !type)) {
9162
9531
  return { type: "session_id", data: sid };
9163
9532
  }
9164
- if (sid && type.endsWith(".started")) {
9165
- return { type: "session_id", data: sid };
9166
- }
9167
9533
  if (type === "turn.completed" || type === "turn_completed") {
9168
9534
  const usage = usageFromCodex(obj.usage);
9169
9535
  return usage ? { type: "usage", data: usage, scope: "turn" } : null;
@@ -9337,7 +9703,7 @@ function cursorSdkMessageToEvents(msg) {
9337
9703
  if (msg.type === "tool_call" && msg.call_id && msg.name) {
9338
9704
  const normalized = normalizeCursorToolCall(msg.name, msg.args);
9339
9705
  if (msg.status === "running") {
9340
- return [
9706
+ const events = [
9341
9707
  {
9342
9708
  type: "tool_use",
9343
9709
  id: msg.call_id,
@@ -9345,6 +9711,16 @@ function cursorSdkMessageToEvents(msg) {
9345
9711
  input: normalized.input
9346
9712
  }
9347
9713
  ];
9714
+ const live = unwrapCursorToolResult(msg.result);
9715
+ if (live) {
9716
+ events.push({
9717
+ type: "tool_result",
9718
+ id: msg.call_id,
9719
+ content: live,
9720
+ partial: true
9721
+ });
9722
+ }
9723
+ return events;
9348
9724
  }
9349
9725
  if (msg.status === "completed" || msg.status === "error") {
9350
9726
  return [
@@ -9411,21 +9787,21 @@ function platformRipgrepPackage() {
9411
9787
  }
9412
9788
  function usableRipgrepPath(candidate) {
9413
9789
  const raw = candidate?.trim();
9414
- if (!raw || !(0, import_node_path26.isAbsolute)(raw)) return null;
9790
+ if (!raw || !(0, import_node_path27.isAbsolute)(raw)) return null;
9415
9791
  const readable = nodeReadableScriptPath(raw);
9416
- if (!(0, import_node_fs26.existsSync)(readable) || isAsarPath(readable)) return null;
9792
+ if (!(0, import_node_fs27.existsSync)(readable) || isAsarPath(readable)) return null;
9417
9793
  return readable;
9418
9794
  }
9419
9795
  function walkForBundledRipgrep(startFile) {
9420
9796
  if (!startFile) return null;
9421
9797
  const pkg = platformRipgrepPackage();
9422
9798
  const name = rgBinaryName();
9423
- let dir = (0, import_node_path26.dirname)((0, import_node_path26.resolve)(startFile));
9424
- const root = (0, import_node_path26.parse)(dir).root;
9799
+ let dir = (0, import_node_path27.dirname)((0, import_node_path27.resolve)(startFile));
9800
+ const root = (0, import_node_path27.parse)(dir).root;
9425
9801
  while (dir !== root) {
9426
- const hit = usableRipgrepPath((0, import_node_path26.join)(dir, "node_modules", pkg, "bin", name));
9802
+ const hit = usableRipgrepPath((0, import_node_path27.join)(dir, "node_modules", pkg, "bin", name));
9427
9803
  if (hit) return hit;
9428
- const next = (0, import_node_path26.dirname)(dir);
9804
+ const next = (0, import_node_path27.dirname)(dir);
9429
9805
  if (next === dir) break;
9430
9806
  dir = next;
9431
9807
  }
@@ -9435,7 +9811,7 @@ function requireResolveBundledRipgrep(fromFile) {
9435
9811
  try {
9436
9812
  const req = (0, import_node_module2.createRequire)(fromFile);
9437
9813
  const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
9438
- return usableRipgrepPath((0, import_node_path26.join)((0, import_node_path26.dirname)(pkgJson), "bin", rgBinaryName()));
9814
+ return usableRipgrepPath((0, import_node_path27.join)((0, import_node_path27.dirname)(pkgJson), "bin", rgBinaryName()));
9439
9815
  } catch {
9440
9816
  return null;
9441
9817
  }
@@ -9457,13 +9833,13 @@ function cursorRipgrepEnv(opts) {
9457
9833
  const path2 = resolveCursorRipgrepPath(opts);
9458
9834
  return path2 ? { [RIPGREP_ENV]: path2 } : {};
9459
9835
  }
9460
- var import_node_fs26, import_node_module2, import_node_path26, RIPGREP_ENV;
9836
+ var import_node_fs27, import_node_module2, import_node_path27, RIPGREP_ENV;
9461
9837
  var init_cursor_ripgrep = __esm({
9462
9838
  "src/agents/cursor-ripgrep.ts"() {
9463
9839
  "use strict";
9464
- import_node_fs26 = require("fs");
9840
+ import_node_fs27 = require("fs");
9465
9841
  import_node_module2 = require("module");
9466
- import_node_path26 = require("path");
9842
+ import_node_path27 = require("path");
9467
9843
  init_node_launch();
9468
9844
  init_packaged_runtime();
9469
9845
  RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
@@ -9509,11 +9885,11 @@ function entryDir() {
9509
9885
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
9510
9886
  if (cjsDir) return cjsDir;
9511
9887
  try {
9512
- return (0, import_node_path27.dirname)((0, import_node_url2.fileURLToPath)(import_meta2.url));
9888
+ return (0, import_node_path28.dirname)((0, import_node_url2.fileURLToPath)(import_meta2.url));
9513
9889
  } catch {
9514
9890
  try {
9515
9891
  const req = (0, import_node_module3.createRequire)(process.cwd() + "/");
9516
- return (0, import_node_path27.dirname)(req.resolve("@sideboard-ai/core"));
9892
+ return (0, import_node_path28.dirname)(req.resolve("@sideboard-ai/core"));
9517
9893
  } catch {
9518
9894
  return process.cwd();
9519
9895
  }
@@ -9524,27 +9900,27 @@ function cursorRunnerPath() {
9524
9900
  if (packaged) return packaged;
9525
9901
  const root = entryDir();
9526
9902
  const candidates = [
9527
- (0, import_node_path27.join)(root, "agents", "cursor-runner.js"),
9528
- (0, import_node_path27.join)(root, "agents", "cursor-runner.cjs"),
9903
+ (0, import_node_path28.join)(root, "agents", "cursor-runner.js"),
9904
+ (0, import_node_path28.join)(root, "agents", "cursor-runner.cjs"),
9529
9905
  // If somehow resolved from package root instead of dist/
9530
- (0, import_node_path27.join)(root, "dist", "agents", "cursor-runner.js"),
9531
- (0, import_node_path27.join)(root, "dist", "agents", "cursor-runner.cjs"),
9906
+ (0, import_node_path28.join)(root, "dist", "agents", "cursor-runner.js"),
9907
+ (0, import_node_path28.join)(root, "dist", "agents", "cursor-runner.cjs"),
9532
9908
  // Source tree (dev): packages/core/src/agents/cursor-runner.ts
9533
- (0, import_node_path27.join)(root, "cursor-runner.ts"),
9534
- (0, import_node_path27.join)(root, "src", "agents", "cursor-runner.ts")
9909
+ (0, import_node_path28.join)(root, "cursor-runner.ts"),
9910
+ (0, import_node_path28.join)(root, "src", "agents", "cursor-runner.ts")
9535
9911
  ];
9536
9912
  for (const candidate of candidates) {
9537
- if ((0, import_node_fs27.existsSync)(candidate)) return candidate;
9913
+ if ((0, import_node_fs28.existsSync)(candidate)) return candidate;
9538
9914
  }
9539
9915
  return candidates[0];
9540
9916
  }
9541
- var import_node_fs27, import_node_module3, import_node_path27, import_node_url2, import_sdk, import_meta2, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
9917
+ var import_node_fs28, import_node_module3, import_node_path28, import_node_url2, import_sdk, import_meta2, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
9542
9918
  var init_cursor = __esm({
9543
9919
  "src/agents/cursor.ts"() {
9544
9920
  "use strict";
9545
- import_node_fs27 = require("fs");
9921
+ import_node_fs28 = require("fs");
9546
9922
  import_node_module3 = require("module");
9547
- import_node_path27 = require("path");
9923
+ import_node_path28 = require("path");
9548
9924
  import_node_url2 = require("url");
9549
9925
  import_sdk = require("@cursor/sdk");
9550
9926
  init_run();
@@ -9694,7 +10070,7 @@ async function listOpencodeModels() {
9694
10070
  if (opencode === "opencode") {
9695
10071
  const which = await run("which", ["opencode"], { reject: false });
9696
10072
  if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
9697
- } else if (!(0, import_node_fs28.existsSync)(opencode)) {
10073
+ } else if (!(0, import_node_fs29.existsSync)(opencode)) {
9698
10074
  return FALLBACK_OPENCODE_MODELS;
9699
10075
  }
9700
10076
  const listed = await run(opencode, ["models"], { reject: false });
@@ -9724,11 +10100,11 @@ function usageFromOpencode(tokens) {
9724
10100
  cacheWriteTokens: tokens.cache?.write ? Number(tokens.cache.write) : void 0
9725
10101
  };
9726
10102
  }
9727
- var import_node_fs28, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
10103
+ var import_node_fs29, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
9728
10104
  var init_opencode = __esm({
9729
10105
  "src/agents/opencode.ts"() {
9730
10106
  "use strict";
9731
- import_node_fs28 = require("fs");
10107
+ import_node_fs29 = require("fs");
9732
10108
  init_run();
9733
10109
  init_app_settings();
9734
10110
  init_global_workspace();
@@ -9755,7 +10131,7 @@ var init_opencode = __esm({
9755
10131
  async detect() {
9756
10132
  const opencode = resolveAgentExecutable("opencode");
9757
10133
  if (opencode !== "opencode") {
9758
- if (!(0, import_node_fs28.existsSync)(opencode)) {
10134
+ if (!(0, import_node_fs29.existsSync)(opencode)) {
9759
10135
  return {
9760
10136
  agent: "opencode",
9761
10137
  installed: false,
@@ -9841,7 +10217,8 @@ var init_opencode = __esm({
9841
10217
  return { type: "stderr", data: detail };
9842
10218
  }
9843
10219
  const sid = typeof obj.sessionID === "string" && obj.sessionID || typeof obj.sessionId === "string" && obj.sessionId || typeof obj.session_id === "string" && obj.session_id;
9844
- if (sid && (!obj.type || obj.type === "step_start" || obj.type === "session")) {
10220
+ const childSid = str3(obj.childSessionID) ?? str3(obj.childSessionId) ?? str3(obj.parentID) ?? str3(obj.parentId);
10221
+ if (sid && !childSid && (!obj.type || obj.type === "step_start" || obj.type === "session")) {
9845
10222
  return { type: "session_id", data: sid };
9846
10223
  }
9847
10224
  if (obj.type === "text") {
@@ -9861,13 +10238,16 @@ var init_opencode = __esm({
9861
10238
  );
9862
10239
  const events = [{ type: "tool_use", id, name, input }];
9863
10240
  const output = state?.output;
9864
- if (output != null || state?.status === "completed" || state?.status === "error") {
10241
+ const finished = state?.status === "completed" || state?.status === "error" || state?.status === "failed";
10242
+ const running = state?.status === "running" || state?.status === "in_progress" || state?.status === "pending";
10243
+ if (output != null || finished) {
9865
10244
  const content = typeof output === "string" ? output : output != null ? JSON.stringify(output) : formatUnknownDetail(state?.error) || void 0;
9866
10245
  events.push({
9867
10246
  type: "tool_result",
9868
10247
  id,
9869
10248
  content,
9870
- isError: state?.status === "error" || state?.status === "failed"
10249
+ isError: state?.status === "error" || state?.status === "failed",
10250
+ ...running && !finished ? { partial: true } : {}
9871
10251
  });
9872
10252
  }
9873
10253
  return events.length === 1 ? events[0] : events;
@@ -9902,14 +10282,17 @@ var init_opencode = __esm({
9902
10282
  withEventParentId({ type: "tool_use", id, name, input }, parentId)
9903
10283
  ];
9904
10284
  const output = state?.output ?? part.output;
9905
- if (output != null || state?.status === "completed" || state?.status === "error") {
10285
+ const finished = state?.status === "completed" || state?.status === "error" || state?.status === "failed";
10286
+ const running = state?.status === "running" || state?.status === "in_progress" || state?.status === "pending";
10287
+ if (output != null || finished) {
9906
10288
  nested.push(
9907
10289
  withEventParentId(
9908
10290
  {
9909
10291
  type: "tool_result",
9910
10292
  id,
9911
10293
  content: typeof output === "string" ? output : output != null ? JSON.stringify(output) : void 0,
9912
- isError: state?.status === "error" || state?.status === "failed"
10294
+ isError: state?.status === "error" || state?.status === "failed",
10295
+ ...running && !finished ? { partial: true } : {}
9913
10296
  },
9914
10297
  parentId
9915
10298
  )
@@ -10572,6 +10955,11 @@ function createAgentStreamCoalescer(emit, opts) {
10572
10955
  return;
10573
10956
  }
10574
10957
  if (!event.data) return;
10958
+ if (event.type === "thinking" && event.replace) {
10959
+ flush2();
10960
+ emit(event);
10961
+ return;
10962
+ }
10575
10963
  if (pending && pending.type === event.type && parentKey(pending) === parentKey(event)) {
10576
10964
  pending.data += event.data;
10577
10965
  } else {
@@ -10628,6 +11016,7 @@ async function spawnAgentTurn(thread, input, onEvent) {
10628
11016
  }
10629
11017
  const env = childEnvWithAppSettings(cmd.env);
10630
11018
  applyPromptCacheTtlEnv(thread.agent, env);
11019
+ applyAgentRunnerHeapEnv(env);
10631
11020
  try {
10632
11021
  if (isOrchestratorThread(thread)) {
10633
11022
  mergeAgentGitAuthEnv(env, await resolveAgentGitAuthEnv(env));
@@ -10735,9 +11124,11 @@ var init_spawn = __esm({
10735
11124
  init_agents();
10736
11125
  init_orchestrator_capable();
10737
11126
  init_message_parts();
11127
+ init_node_launch();
10738
11128
  init_path();
10739
11129
  init_usage();
10740
11130
  init_cursor_stream_coalesce();
11131
+ init_node_launch();
10741
11132
  }
10742
11133
  });
10743
11134
 
@@ -11463,21 +11854,21 @@ function shouldRefreshReviewRequestTemplate(content) {
11463
11854
  return LEGACY_REVIEW_TEMPLATE_MARKERS.every((m) => trimmed.includes(m));
11464
11855
  }
11465
11856
  function readTextIfPresent(abs) {
11466
- if (!(0, import_node_fs29.existsSync)(abs)) return null;
11857
+ if (!(0, import_node_fs30.existsSync)(abs)) return null;
11467
11858
  try {
11468
- const content = (0, import_node_fs29.readFileSync)(abs, "utf8");
11859
+ const content = (0, import_node_fs30.readFileSync)(abs, "utf8");
11469
11860
  return content.trim() ? content : null;
11470
11861
  } catch {
11471
11862
  return null;
11472
11863
  }
11473
11864
  }
11474
11865
  function readLocalGuidelines(worktreePath) {
11475
- const localAbs = (0, import_node_path28.join)(worktreePath, REVIEW_REQUEST_PATH);
11866
+ const localAbs = (0, import_node_path29.join)(worktreePath, REVIEW_REQUEST_PATH);
11476
11867
  const localContent = readTextIfPresent(localAbs);
11477
11868
  if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
11478
11869
  return { path: REVIEW_REQUEST_PATH, content: localContent };
11479
11870
  }
11480
- const legacyAbs = (0, import_node_path28.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
11871
+ const legacyAbs = (0, import_node_path29.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
11481
11872
  const legacyContent = readTextIfPresent(legacyAbs);
11482
11873
  if (legacyContent && !shouldRefreshReviewRequestTemplate(legacyContent)) {
11483
11874
  return { path: LEGACY_REVIEW_REQUEST_PATH, content: legacyContent };
@@ -11493,20 +11884,20 @@ function skillGuidelines(content, source) {
11493
11884
  };
11494
11885
  }
11495
11886
  function ensureReviewSkillFile(worktreePath) {
11496
- const abs = (0, import_node_path28.join)(worktreePath, REVIEW_SKILL_PATH);
11887
+ const abs = (0, import_node_path29.join)(worktreePath, REVIEW_SKILL_PATH);
11497
11888
  const existing = readTextIfPresent(abs);
11498
11889
  if (existing) {
11499
11890
  return { path: REVIEW_SKILL_PATH, content: existing, wrote: false };
11500
11891
  }
11501
- const fromRepo = readTextIfPresent((0, import_node_path28.join)(worktreePath, REPO_REVIEW_PATH));
11892
+ const fromRepo = readTextIfPresent((0, import_node_path29.join)(worktreePath, REPO_REVIEW_PATH));
11502
11893
  const fromLocal = readLocalGuidelines(worktreePath)?.content ?? null;
11503
11894
  const content = wrapReviewSkillMarkdown(fromRepo ?? fromLocal ?? REVIEW_REQUEST_TEMPLATE);
11504
- (0, import_node_fs29.mkdirSync)((0, import_node_path28.dirname)(abs), { recursive: true });
11505
- (0, import_node_fs29.writeFileSync)(abs, content, "utf8");
11895
+ (0, import_node_fs30.mkdirSync)((0, import_node_path29.dirname)(abs), { recursive: true });
11896
+ (0, import_node_fs30.writeFileSync)(abs, content, "utf8");
11506
11897
  return { path: REVIEW_SKILL_PATH, content, wrote: true };
11507
11898
  }
11508
11899
  function resolveReviewGuidelines(worktreePath) {
11509
- const skillContent = readTextIfPresent((0, import_node_path28.join)(worktreePath, REVIEW_SKILL_PATH));
11900
+ const skillContent = readTextIfPresent((0, import_node_path29.join)(worktreePath, REVIEW_SKILL_PATH));
11510
11901
  if (skillContent) return skillGuidelines(skillContent, "skill");
11511
11902
  const local = readLocalGuidelines(worktreePath);
11512
11903
  if (local) {
@@ -11536,7 +11927,7 @@ function buildReviewRequestAttachment(content, opts) {
11536
11927
  };
11537
11928
  }
11538
11929
  function readExistingReviewRequestFile(worktreePath) {
11539
- return readTextIfPresent((0, import_node_path28.join)(worktreePath, REVIEW_SKILL_PATH)) ?? readTextIfPresent((0, import_node_path28.join)(worktreePath, REPO_REVIEW_PATH)) ?? readTextIfPresent((0, import_node_path28.join)(worktreePath, REVIEW_REQUEST_PATH)) ?? readTextIfPresent((0, import_node_path28.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH));
11930
+ return readTextIfPresent((0, import_node_path29.join)(worktreePath, REVIEW_SKILL_PATH)) ?? readTextIfPresent((0, import_node_path29.join)(worktreePath, REPO_REVIEW_PATH)) ?? readTextIfPresent((0, import_node_path29.join)(worktreePath, REVIEW_REQUEST_PATH)) ?? readTextIfPresent((0, import_node_path29.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH));
11540
11931
  }
11541
11932
  async function requestReview(threadRef, send2) {
11542
11933
  const from = findThreadByRef(threadRef);
@@ -11563,13 +11954,13 @@ async function requestReview(threadRef, send2) {
11563
11954
  const started = await send2(tab.id, REVIEW_REQUEST_PREFILL);
11564
11955
  return { tab: started, from };
11565
11956
  }
11566
- var import_node_crypto6, import_node_fs29, import_node_path28, REPO_REVIEW_PATH, REPO_REVIEW_NAME, REVIEW_REQUEST_PATH, LEGACY_REVIEW_REQUEST_PATH, REVIEW_REQUEST_NAME, REVIEW_REQUEST_PREFILL, LEGACY_REVIEW_TEMPLATE_MARKERS;
11957
+ var import_node_crypto6, import_node_fs30, import_node_path29, REPO_REVIEW_PATH, REPO_REVIEW_NAME, REVIEW_REQUEST_PATH, LEGACY_REVIEW_REQUEST_PATH, REVIEW_REQUEST_NAME, REVIEW_REQUEST_PREFILL, LEGACY_REVIEW_TEMPLATE_MARKERS;
11567
11958
  var init_request_review = __esm({
11568
11959
  "src/review/request-review.ts"() {
11569
11960
  "use strict";
11570
11961
  import_node_crypto6 = require("crypto");
11571
- import_node_fs29 = require("fs");
11572
- import_node_path28 = require("path");
11962
+ import_node_fs30 = require("fs");
11963
+ import_node_path29 = require("path");
11573
11964
  init_global_workspace();
11574
11965
  init_chat_tabs();
11575
11966
  init_thread_store();
@@ -11594,9 +11985,9 @@ function matchSimpleGlob(pattern, name) {
11594
11985
  return new RegExp(`^${escaped}$`).test(name);
11595
11986
  }
11596
11987
  function readWorktreeInclude(repoPath) {
11597
- const path2 = (0, import_node_path29.join)(repoPath, ".worktreeinclude");
11598
- if (!(0, import_node_fs30.existsSync)(path2)) return [];
11599
- return (0, import_node_fs30.readFileSync)(path2, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
11988
+ const path2 = (0, import_node_path30.join)(repoPath, ".worktreeinclude");
11989
+ if (!(0, import_node_fs31.existsSync)(path2)) return [];
11990
+ return (0, import_node_fs31.readFileSync)(path2, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
11600
11991
  }
11601
11992
  function resolveFilesToCopy(repoPath) {
11602
11993
  const fromInclude = readWorktreeInclude(repoPath);
@@ -11606,10 +11997,10 @@ function resolveFilesToCopy(repoPath) {
11606
11997
  if (settings?.fileIncludeGlobs?.length) {
11607
11998
  const matched = [];
11608
11999
  try {
11609
- for (const entry of (0, import_node_fs30.readdirSync)(repoPath, { withFileTypes: true })) {
12000
+ for (const entry of (0, import_node_fs31.readdirSync)(repoPath, { withFileTypes: true })) {
11610
12001
  if (!entry.isFile()) continue;
11611
12002
  for (const glob of settings.fileIncludeGlobs) {
11612
- if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path29.basename)(glob), entry.name)) {
12003
+ if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path30.basename)(glob), entry.name)) {
11613
12004
  matched.push(entry.name);
11614
12005
  break;
11615
12006
  }
@@ -11621,7 +12012,7 @@ function resolveFilesToCopy(repoPath) {
11621
12012
  }
11622
12013
  const defaults = [];
11623
12014
  try {
11624
- for (const entry of (0, import_node_fs30.readdirSync)(repoPath, { withFileTypes: true })) {
12015
+ for (const entry of (0, import_node_fs31.readdirSync)(repoPath, { withFileTypes: true })) {
11625
12016
  if (entry.isFile() && entry.name.startsWith(".env")) {
11626
12017
  defaults.push(entry.name);
11627
12018
  }
@@ -11635,11 +12026,11 @@ function copyConfiguredFiles(repoPath, worktreePath) {
11635
12026
  const patterns = resolveFilesToCopy(repoPath);
11636
12027
  const copied = [];
11637
12028
  for (const rel of patterns) {
11638
- const src = (0, import_node_path29.join)(repoPath, rel);
11639
- if (!(0, import_node_fs30.existsSync)(src)) continue;
11640
- const dest = (0, import_node_path29.join)(worktreePath, rel);
11641
- (0, import_node_fs30.mkdirSync)((0, import_node_path29.dirname)(dest), { recursive: true });
11642
- (0, import_node_fs30.copyFileSync)(src, dest);
12029
+ const src = (0, import_node_path30.join)(repoPath, rel);
12030
+ if (!(0, import_node_fs31.existsSync)(src)) continue;
12031
+ const dest = (0, import_node_path30.join)(worktreePath, rel);
12032
+ (0, import_node_fs31.mkdirSync)((0, import_node_path30.dirname)(dest), { recursive: true });
12033
+ (0, import_node_fs31.copyFileSync)(src, dest);
11643
12034
  copied.push(rel);
11644
12035
  }
11645
12036
  return copied;
@@ -11674,7 +12065,7 @@ function buildWorkspaceScriptEnv(opts, baseEnv) {
11674
12065
  const env = stripNestedElectronEnv({
11675
12066
  ...baseEnv ?? process.env
11676
12067
  });
11677
- const name = opts.workspaceName ?? (0, import_node_path29.basename)(opts.worktreePath);
12068
+ const name = opts.workspaceName ?? (0, import_node_path30.basename)(opts.worktreePath);
11678
12069
  const ports = opts.ports ?? [];
11679
12070
  const primary = ports[0];
11680
12071
  env.SIDEBOARD_WORKSPACE_NAME = name;
@@ -11935,13 +12326,13 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
11935
12326
  done: handle.done
11936
12327
  };
11937
12328
  }
11938
- var import_node_fs30, import_node_net, import_node_path29, import_execa4, import_node_readline3, PORT_RANGE_SIZE, cachedLoginEnv;
12329
+ var import_node_fs31, import_node_net, import_node_path30, import_execa4, import_node_readline3, PORT_RANGE_SIZE, cachedLoginEnv;
11939
12330
  var init_conductor = __esm({
11940
12331
  "src/hook/conductor.ts"() {
11941
12332
  "use strict";
11942
- import_node_fs30 = require("fs");
12333
+ import_node_fs31 = require("fs");
11943
12334
  import_node_net = require("net");
11944
- import_node_path29 = require("path");
12335
+ import_node_path30 = require("path");
11945
12336
  import_execa4 = require("execa");
11946
12337
  import_node_readline3 = require("readline");
11947
12338
  init_settings();
@@ -11967,9 +12358,9 @@ async function findOrphanWorktrees(repoPaths) {
11967
12358
  repoPaths?.length ? repoPaths : threads.map((t) => t.repoPath).filter(Boolean)
11968
12359
  );
11969
12360
  const homeRoot = sideboardWorkspacesDir();
11970
- if ((0, import_node_fs31.existsSync)(homeRoot)) {
12361
+ if ((0, import_node_fs32.existsSync)(homeRoot)) {
11971
12362
  try {
11972
- for (const entry of (0, import_node_fs31.readdirSync)(homeRoot, { withFileTypes: true })) {
12363
+ for (const entry of (0, import_node_fs32.readdirSync)(homeRoot, { withFileTypes: true })) {
11973
12364
  if (!entry.isDirectory()) continue;
11974
12365
  void entry;
11975
12366
  }
@@ -11979,7 +12370,7 @@ async function findOrphanWorktrees(repoPaths) {
11979
12370
  const orphans = [];
11980
12371
  const seen = /* @__PURE__ */ new Set();
11981
12372
  for (const repoPath of repos) {
11982
- if (!repoPath || !(0, import_node_fs31.existsSync)(repoPath)) continue;
12373
+ if (!repoPath || !(0, import_node_fs32.existsSync)(repoPath)) continue;
11983
12374
  try {
11984
12375
  const wts = await listWorktrees(repoPath);
11985
12376
  for (const wt of wts) {
@@ -11990,7 +12381,7 @@ async function findOrphanWorktrees(repoPaths) {
11990
12381
  seen.add(path2);
11991
12382
  let mtimeMs = 0;
11992
12383
  try {
11993
- mtimeMs = (0, import_node_fs31.statSync)(path2).mtimeMs;
12384
+ mtimeMs = (0, import_node_fs32.statSync)(path2).mtimeMs;
11994
12385
  } catch {
11995
12386
  mtimeMs = 0;
11996
12387
  }
@@ -12000,16 +12391,16 @@ async function findOrphanWorktrees(repoPaths) {
12000
12391
  }
12001
12392
  try {
12002
12393
  const root = worktreesRoot(repoPath);
12003
- if ((0, import_node_fs31.existsSync)(root)) {
12004
- for (const entry of (0, import_node_fs31.readdirSync)(root, { withFileTypes: true })) {
12394
+ if ((0, import_node_fs32.existsSync)(root)) {
12395
+ for (const entry of (0, import_node_fs32.readdirSync)(root, { withFileTypes: true })) {
12005
12396
  if (!entry.isDirectory()) continue;
12006
- const path2 = (0, import_node_path30.join)(root, entry.name).replace(/\/$/, "");
12397
+ const path2 = (0, import_node_path31.join)(root, entry.name).replace(/\/$/, "");
12007
12398
  if (known.has(path2) || seen.has(path2)) continue;
12008
- if (!(0, import_node_fs31.existsSync)((0, import_node_path30.join)(path2, ".git"))) continue;
12399
+ if (!(0, import_node_fs32.existsSync)((0, import_node_path31.join)(path2, ".git"))) continue;
12009
12400
  seen.add(path2);
12010
12401
  let mtimeMs = 0;
12011
12402
  try {
12012
- mtimeMs = (0, import_node_fs31.statSync)(path2).mtimeMs;
12403
+ mtimeMs = (0, import_node_fs32.statSync)(path2).mtimeMs;
12013
12404
  } catch {
12014
12405
  mtimeMs = Date.now();
12015
12406
  }
@@ -12070,12 +12461,12 @@ function worktreeCleanupSettings() {
12070
12461
  autoCleanupOrphans: a.autoCleanupOrphans
12071
12462
  };
12072
12463
  }
12073
- var import_node_fs31, import_node_path30;
12464
+ var import_node_fs32, import_node_path31;
12074
12465
  var init_orphan_cleanup = __esm({
12075
12466
  "src/git/orphan-cleanup.ts"() {
12076
12467
  "use strict";
12077
- import_node_fs31 = require("fs");
12078
- import_node_path30 = require("path");
12468
+ import_node_fs32 = require("fs");
12469
+ import_node_path31 = require("path");
12079
12470
  init_worktree();
12080
12471
  init_thread_store();
12081
12472
  init_paths();
@@ -12182,38 +12573,38 @@ __export(workspaces_exports, {
12182
12573
  syncWorkspacesFromThreads: () => syncWorkspacesFromThreads
12183
12574
  });
12184
12575
  function workspacesFile() {
12185
- return (0, import_node_path31.join)(appDataDir(), "workspaces.json");
12576
+ return (0, import_node_path32.join)(appDataDir(), "workspaces.json");
12186
12577
  }
12187
12578
  function removedWorkspacesFile() {
12188
- return (0, import_node_path31.join)(appDataDir(), "removed-workspaces.json");
12579
+ return (0, import_node_path32.join)(appDataDir(), "removed-workspaces.json");
12189
12580
  }
12190
12581
  function readAll2() {
12191
12582
  const path2 = workspacesFile();
12192
- if (!(0, import_node_fs32.existsSync)(path2)) return [];
12583
+ if (!(0, import_node_fs33.existsSync)(path2)) return [];
12193
12584
  try {
12194
- const raw = JSON.parse((0, import_node_fs32.readFileSync)(path2, "utf8"));
12585
+ const raw = JSON.parse((0, import_node_fs33.readFileSync)(path2, "utf8"));
12195
12586
  return Array.isArray(raw) ? raw : [];
12196
12587
  } catch {
12197
12588
  return [];
12198
12589
  }
12199
12590
  }
12200
12591
  function writeAll2(list) {
12201
- (0, import_node_fs32.mkdirSync)(appDataDir(), { recursive: true });
12202
- (0, import_node_fs32.writeFileSync)(workspacesFile(), JSON.stringify(list, null, 2), "utf8");
12592
+ (0, import_node_fs33.mkdirSync)(appDataDir(), { recursive: true });
12593
+ (0, import_node_fs33.writeFileSync)(workspacesFile(), JSON.stringify(list, null, 2), "utf8");
12203
12594
  }
12204
12595
  function readRemoved() {
12205
12596
  const path2 = removedWorkspacesFile();
12206
- if (!(0, import_node_fs32.existsSync)(path2)) return /* @__PURE__ */ new Set();
12597
+ if (!(0, import_node_fs33.existsSync)(path2)) return /* @__PURE__ */ new Set();
12207
12598
  try {
12208
- const raw = JSON.parse((0, import_node_fs32.readFileSync)(path2, "utf8"));
12599
+ const raw = JSON.parse((0, import_node_fs33.readFileSync)(path2, "utf8"));
12209
12600
  return new Set(Array.isArray(raw) ? raw.filter((p) => typeof p === "string") : []);
12210
12601
  } catch {
12211
12602
  return /* @__PURE__ */ new Set();
12212
12603
  }
12213
12604
  }
12214
12605
  function writeRemoved(paths) {
12215
- (0, import_node_fs32.mkdirSync)(appDataDir(), { recursive: true });
12216
- (0, import_node_fs32.writeFileSync)(removedWorkspacesFile(), JSON.stringify([...paths].sort(), null, 2), "utf8");
12606
+ (0, import_node_fs33.mkdirSync)(appDataDir(), { recursive: true });
12607
+ (0, import_node_fs33.writeFileSync)(removedWorkspacesFile(), JSON.stringify([...paths].sort(), null, 2), "utf8");
12217
12608
  }
12218
12609
  function rememberRemoved(repoPath) {
12219
12610
  const next = readRemoved();
@@ -12236,7 +12627,7 @@ function listWorkspaces() {
12236
12627
  async function addWorkspace(repoPath) {
12237
12628
  const root = await resolveRepoRoot(repoPath);
12238
12629
  if (!root || root === "/") throw new Error(`Invalid repo path: ${repoPath}`);
12239
- if (!(0, import_node_fs32.existsSync)(root)) throw new Error(`Repo not found: ${root}`);
12630
+ if (!(0, import_node_fs33.existsSync)(root)) throw new Error(`Repo not found: ${root}`);
12240
12631
  forgetRemoved(root);
12241
12632
  await ensureGhPreferOrigin(root);
12242
12633
  const current = readAll2();
@@ -12244,7 +12635,7 @@ async function addWorkspace(repoPath) {
12244
12635
  if (existing) return existing;
12245
12636
  const next = {
12246
12637
  path: root,
12247
- name: (0, import_node_path31.basename)(root),
12638
+ name: (0, import_node_path32.basename)(root),
12248
12639
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
12249
12640
  };
12250
12641
  writeAll2([...current, next]);
@@ -12266,10 +12657,10 @@ function syncWorkspacesFromThreads(repoPaths) {
12266
12657
  if (!path2 || path2 === "/" || isGlobalRepoPath(path2) || byPath.has(path2) || removed.has(path2)) {
12267
12658
  continue;
12268
12659
  }
12269
- if (!(0, import_node_fs32.existsSync)(path2)) continue;
12660
+ if (!(0, import_node_fs33.existsSync)(path2)) continue;
12270
12661
  const ws = {
12271
12662
  path: path2,
12272
- name: (0, import_node_path31.basename)(path2),
12663
+ name: (0, import_node_path32.basename)(path2),
12273
12664
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
12274
12665
  };
12275
12666
  byPath.set(path2, ws);
@@ -12279,12 +12670,12 @@ function syncWorkspacesFromThreads(repoPaths) {
12279
12670
  if (dirty) writeAll2(next);
12280
12671
  return next.sort((a, b) => a.name.localeCompare(b.name));
12281
12672
  }
12282
- var import_node_fs32, import_node_path31;
12673
+ var import_node_fs33, import_node_path32;
12283
12674
  var init_workspaces2 = __esm({
12284
12675
  "src/store/workspaces.ts"() {
12285
12676
  "use strict";
12286
- import_node_fs32 = require("fs");
12287
- import_node_path31 = require("path");
12677
+ import_node_fs33 = require("fs");
12678
+ import_node_path32 = require("path");
12288
12679
  init_paths();
12289
12680
  init_global_workspace();
12290
12681
  init_worktree();
@@ -12297,12 +12688,12 @@ async function cloneRepoIntoSideboard(opts) {
12297
12688
  if (!url) throw new Error("Clone URL is required");
12298
12689
  let name = opts.name?.trim();
12299
12690
  if (!name) {
12300
- const leaf = (0, import_node_path32.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
12691
+ const leaf = (0, import_node_path33.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
12301
12692
  name = leaf || "repo";
12302
12693
  }
12303
12694
  name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
12304
- const dest = (0, import_node_path32.join)(sideboardReposDir(), name);
12305
- if ((0, import_node_fs33.existsSync)(dest)) {
12695
+ const dest = (0, import_node_path33.join)(sideboardReposDir(), name);
12696
+ if ((0, import_node_fs34.existsSync)(dest)) {
12306
12697
  const repoPath2 = await resolveRepoRoot(dest);
12307
12698
  const workspace2 = await ensureWorkspace(repoPath2);
12308
12699
  return { repoPath: repoPath2, workspace: workspace2 };
@@ -12317,12 +12708,12 @@ async function cloneRepoIntoSideboard(opts) {
12317
12708
  const workspace = await ensureWorkspace(repoPath);
12318
12709
  return { repoPath, workspace };
12319
12710
  }
12320
- var import_node_fs33, import_node_path32, import_execa6;
12711
+ var import_node_fs34, import_node_path33, import_execa6;
12321
12712
  var init_clone_repo = __esm({
12322
12713
  "src/git/clone-repo.ts"() {
12323
12714
  "use strict";
12324
- import_node_fs33 = require("fs");
12325
- import_node_path32 = require("path");
12715
+ import_node_fs34 = require("fs");
12716
+ import_node_path33 = require("path");
12326
12717
  import_execa6 = require("execa");
12327
12718
  init_paths();
12328
12719
  init_workspaces2();
@@ -12380,7 +12771,7 @@ async function createThread(input, _onSetupLine) {
12380
12771
  });
12381
12772
  await requireAgent(resolved.agent);
12382
12773
  const repoPath = await resolveRepoRoot(input.repoPath);
12383
- if (!(0, import_node_fs34.existsSync)(repoPath)) {
12774
+ if (!(0, import_node_fs35.existsSync)(repoPath)) {
12384
12775
  throw new Error(`Repo not found: ${repoPath}`);
12385
12776
  }
12386
12777
  if (input.cowboy) {
@@ -12503,11 +12894,11 @@ async function listLinearIssues(agent, repoPath) {
12503
12894
  }
12504
12895
  return adapter.listLinearIssues(repoPath);
12505
12896
  }
12506
- var import_node_fs34;
12897
+ var import_node_fs35;
12507
12898
  var init_create = __esm({
12508
12899
  "src/threads/create.ts"() {
12509
12900
  "use strict";
12510
- import_node_fs34 = require("fs");
12901
+ import_node_fs35 = require("fs");
12511
12902
  init_detect();
12512
12903
  init_worktree();
12513
12904
  init_conductor();
@@ -12552,21 +12943,13 @@ function summarizeTurnLive(parts) {
12552
12943
  (p) => p.type === "tool"
12553
12944
  );
12554
12945
  const lastTool = tools[tools.length - 1];
12555
- const lastToolLabel = lastTool ? lastTool.description || toolDescription(lastTool.name, lastTool.input) || lastTool.name : void 0;
12556
- const running = lastTool?.status === "running";
12946
+ const interesting = [...tools].reverse().find((t) => !isPollWrapperToolName(t.name)) ?? lastTool;
12947
+ const lastToolLabel = interesting ? interesting.description || toolDescription(interesting.name, interesting.input) || interesting.name : void 0;
12557
12948
  const thinking = lastText(parts, "thinking");
12558
12949
  const text4 = lastText(parts, "text");
12559
12950
  const excerptRaw = thinking || text4;
12560
12951
  const excerpt = excerptRaw.length > 280 ? `${excerptRaw.slice(-280)}` : excerptRaw || void 0;
12561
- let summary = "Working\u2026";
12562
- if (lastToolLabel) {
12563
- const verb = running ? lastToolLabel : `Finished ${lastToolLabel}`;
12564
- summary = tools.length > 1 ? `${verb} (${tools.length} tools)` : verb;
12565
- } else if (thinking) {
12566
- summary = "Thinking\u2026";
12567
- } else if (text4) {
12568
- summary = "Writing reply\u2026";
12569
- }
12952
+ const summary = liveActivitySummary(parts);
12570
12953
  return {
12571
12954
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
12572
12955
  summary,
@@ -12616,20 +12999,20 @@ function writeTurnLive(threadId, progress) {
12616
12999
  const path2 = threadLivePath(threadId);
12617
13000
  const tmp = `${path2}.${process.pid}.tmp`;
12618
13001
  try {
12619
- (0, import_node_fs35.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
12620
- (0, import_node_fs35.renameSync)(tmp, path2);
13002
+ (0, import_node_fs36.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
13003
+ (0, import_node_fs36.renameSync)(tmp, path2);
12621
13004
  } catch {
12622
13005
  try {
12623
- (0, import_node_fs35.unlinkSync)(tmp);
13006
+ (0, import_node_fs36.unlinkSync)(tmp);
12624
13007
  } catch {
12625
13008
  }
12626
13009
  }
12627
13010
  }
12628
13011
  function readTurnLive(threadId) {
12629
13012
  const path2 = threadLivePath(threadId);
12630
- if (!(0, import_node_fs35.existsSync)(path2)) return null;
13013
+ if (!(0, import_node_fs36.existsSync)(path2)) return null;
12631
13014
  try {
12632
- const raw = JSON.parse((0, import_node_fs35.readFileSync)(path2, "utf8"));
13015
+ const raw = JSON.parse((0, import_node_fs36.readFileSync)(path2, "utf8"));
12633
13016
  if (!raw || typeof raw.summary !== "string") return null;
12634
13017
  return raw;
12635
13018
  } catch {
@@ -12641,17 +13024,17 @@ function clearTurnLive(threadId) {
12641
13024
  if (buf?.timer) clearTimeout(buf.timer);
12642
13025
  buffers.delete(threadId);
12643
13026
  const path2 = threadLivePath(threadId);
12644
- if (!(0, import_node_fs35.existsSync)(path2)) return;
13027
+ if (!(0, import_node_fs36.existsSync)(path2)) return;
12645
13028
  try {
12646
- (0, import_node_fs35.unlinkSync)(path2);
13029
+ (0, import_node_fs36.unlinkSync)(path2);
12647
13030
  } catch {
12648
13031
  }
12649
13032
  }
12650
- var import_node_fs35, buffers, FLUSH_MS, MAX_PARTS;
13033
+ var import_node_fs36, buffers, FLUSH_MS, MAX_PARTS;
12651
13034
  var init_turn_live = __esm({
12652
13035
  "src/store/turn-live.ts"() {
12653
13036
  "use strict";
12654
- import_node_fs35 = require("fs");
13037
+ import_node_fs36 = require("fs");
12655
13038
  init_message_parts();
12656
13039
  init_paths();
12657
13040
  buffers = /* @__PURE__ */ new Map();
@@ -12830,7 +13213,7 @@ var init_quota_failover = __esm({
12830
13213
  // src/threads/adopt.ts
12831
13214
  function thisModuleFile() {
12832
13215
  const cjsFile = typeof __filename !== "undefined" ? __filename : "";
12833
- return cjsFile || process.argv[1] || (0, import_node_path33.join)(process.cwd(), "package.json");
13216
+ return cjsFile || process.argv[1] || (0, import_node_path34.join)(process.cwd(), "package.json");
12834
13217
  }
12835
13218
  function openReadonlySqlite(file) {
12836
13219
  const req = (0, import_node_module4.createRequire)(thisModuleFile());
@@ -12848,21 +13231,21 @@ function mapAgentType(raw) {
12848
13231
  return null;
12849
13232
  }
12850
13233
  function resolveConductorCursorAgentId(workspacePath) {
12851
- if (!workspacePath || !(0, import_node_fs36.existsSync)(CURSOR_SDK_STORE)) return null;
13234
+ if (!workspacePath || !(0, import_node_fs37.existsSync)(CURSOR_SDK_STORE)) return null;
12852
13235
  const normalized = workspacePath.replace(/\/$/, "");
12853
13236
  let best = null;
12854
13237
  let hashes;
12855
13238
  try {
12856
- hashes = (0, import_node_fs36.readdirSync)(CURSOR_SDK_STORE);
13239
+ hashes = (0, import_node_fs37.readdirSync)(CURSOR_SDK_STORE);
12857
13240
  } catch {
12858
13241
  return null;
12859
13242
  }
12860
13243
  for (const hash of hashes) {
12861
- const agentsFile = (0, import_node_path33.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
12862
- if (!(0, import_node_fs36.existsSync)(agentsFile)) continue;
13244
+ const agentsFile = (0, import_node_path34.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
13245
+ if (!(0, import_node_fs37.existsSync)(agentsFile)) continue;
12863
13246
  let text4;
12864
13247
  try {
12865
- text4 = (0, import_node_fs36.readFileSync)(agentsFile, "utf8");
13248
+ text4 = (0, import_node_fs37.readFileSync)(agentsFile, "utf8");
12866
13249
  } catch {
12867
13250
  continue;
12868
13251
  }
@@ -12886,7 +13269,7 @@ function resolveConductorCursorAgentId(workspacePath) {
12886
13269
  return best?.agentId ?? null;
12887
13270
  }
12888
13271
  async function adoptThread(input) {
12889
- if (!(0, import_node_fs36.existsSync)(input.worktreePath)) {
13272
+ if (!(0, import_node_fs37.existsSync)(input.worktreePath)) {
12890
13273
  throw new Error(`Worktree not found: ${input.worktreePath}`);
12891
13274
  }
12892
13275
  const repoPath = await resolveRepoRoot(input.worktreePath);
@@ -12913,18 +13296,18 @@ function conductorDbPath() {
12913
13296
  return CONDUCTOR_DB;
12914
13297
  }
12915
13298
  function listConductorWorkspaces() {
12916
- if (!(0, import_node_fs36.existsSync)(CONDUCTOR_DB)) {
13299
+ if (!(0, import_node_fs37.existsSync)(CONDUCTOR_DB)) {
12917
13300
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
12918
13301
  }
12919
- const tmp = (0, import_node_fs36.mkdtempSync)((0, import_node_path33.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
12920
- const snapshot = (0, import_node_path33.join)(tmp, "conductor.db");
13302
+ const tmp = (0, import_node_fs37.mkdtempSync)((0, import_node_path34.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
13303
+ const snapshot = (0, import_node_path34.join)(tmp, "conductor.db");
12921
13304
  try {
12922
- (0, import_node_fs36.copyFileSync)(CONDUCTOR_DB, snapshot);
13305
+ (0, import_node_fs37.copyFileSync)(CONDUCTOR_DB, snapshot);
12923
13306
  for (const suffix of ["-wal", "-shm"]) {
12924
13307
  const src = `${CONDUCTOR_DB}${suffix}`;
12925
- if ((0, import_node_fs36.existsSync)(src)) {
13308
+ if ((0, import_node_fs37.existsSync)(src)) {
12926
13309
  try {
12927
- (0, import_node_fs36.copyFileSync)(src, `${snapshot}${suffix}`);
13310
+ (0, import_node_fs37.copyFileSync)(src, `${snapshot}${suffix}`);
12928
13311
  } catch {
12929
13312
  }
12930
13313
  }
@@ -13000,22 +13383,22 @@ function listConductorWorkspaces() {
13000
13383
  db.close();
13001
13384
  }
13002
13385
  } finally {
13003
- (0, import_node_fs36.rmSync)(tmp, { recursive: true, force: true });
13386
+ (0, import_node_fs37.rmSync)(tmp, { recursive: true, force: true });
13004
13387
  }
13005
13388
  }
13006
13389
  function importConductorWorkspace(workspaceId) {
13007
- if (!(0, import_node_fs36.existsSync)(CONDUCTOR_DB)) {
13390
+ if (!(0, import_node_fs37.existsSync)(CONDUCTOR_DB)) {
13008
13391
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
13009
13392
  }
13010
- const tmp = (0, import_node_fs36.mkdtempSync)((0, import_node_path33.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
13011
- const snapshot = (0, import_node_path33.join)(tmp, "conductor.db");
13393
+ const tmp = (0, import_node_fs37.mkdtempSync)((0, import_node_path34.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
13394
+ const snapshot = (0, import_node_path34.join)(tmp, "conductor.db");
13012
13395
  try {
13013
- (0, import_node_fs36.copyFileSync)(CONDUCTOR_DB, snapshot);
13396
+ (0, import_node_fs37.copyFileSync)(CONDUCTOR_DB, snapshot);
13014
13397
  for (const suffix of ["-wal", "-shm"]) {
13015
13398
  const src = `${CONDUCTOR_DB}${suffix}`;
13016
- if ((0, import_node_fs36.existsSync)(src)) {
13399
+ if ((0, import_node_fs37.existsSync)(src)) {
13017
13400
  try {
13018
- (0, import_node_fs36.copyFileSync)(src, `${snapshot}${suffix}`);
13401
+ (0, import_node_fs37.copyFileSync)(src, `${snapshot}${suffix}`);
13019
13402
  } catch {
13020
13403
  }
13021
13404
  }
@@ -13033,7 +13416,7 @@ function importConductorWorkspace(workspaceId) {
13033
13416
  ).get(workspaceId);
13034
13417
  if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
13035
13418
  const worktreePath = String(row.workspacePath);
13036
- if (!(0, import_node_fs36.existsSync)(worktreePath)) {
13419
+ if (!(0, import_node_fs37.existsSync)(worktreePath)) {
13037
13420
  throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
13038
13421
  }
13039
13422
  let sessionId = null;
@@ -13096,31 +13479,31 @@ function importConductorWorkspace(workspaceId) {
13096
13479
  db.close();
13097
13480
  }
13098
13481
  } finally {
13099
- (0, import_node_fs36.rmSync)(tmp, { recursive: true, force: true });
13482
+ (0, import_node_fs37.rmSync)(tmp, { recursive: true, force: true });
13100
13483
  }
13101
13484
  }
13102
13485
  async function importConductorWorkspaceAsync(workspaceId) {
13103
13486
  return importConductorWorkspace(workspaceId);
13104
13487
  }
13105
- var import_node_child_process4, import_node_fs36, import_node_os10, import_node_path33, import_node_module4, CONDUCTOR_APP_SUPPORT, CONDUCTOR_DB, CURSOR_SDK_STORE;
13488
+ var import_node_child_process4, import_node_fs37, import_node_os10, import_node_path34, import_node_module4, CONDUCTOR_APP_SUPPORT, CONDUCTOR_DB, CURSOR_SDK_STORE;
13106
13489
  var init_adopt = __esm({
13107
13490
  "src/threads/adopt.ts"() {
13108
13491
  "use strict";
13109
13492
  import_node_child_process4 = require("child_process");
13110
- import_node_fs36 = require("fs");
13493
+ import_node_fs37 = require("fs");
13111
13494
  import_node_os10 = require("os");
13112
- import_node_path33 = require("path");
13495
+ import_node_path34 = require("path");
13113
13496
  import_node_module4 = require("module");
13114
13497
  init_worktree();
13115
13498
  init_thread_store();
13116
- CONDUCTOR_APP_SUPPORT = (0, import_node_path33.join)(
13499
+ CONDUCTOR_APP_SUPPORT = (0, import_node_path34.join)(
13117
13500
  process.env.HOME ?? "",
13118
13501
  "Library",
13119
13502
  "Application Support",
13120
13503
  "com.conductor.app"
13121
13504
  );
13122
- CONDUCTOR_DB = (0, import_node_path33.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
13123
- CURSOR_SDK_STORE = (0, import_node_path33.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
13505
+ CONDUCTOR_DB = (0, import_node_path34.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
13506
+ CURSOR_SDK_STORE = (0, import_node_path34.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
13124
13507
  }
13125
13508
  });
13126
13509
 
@@ -13187,7 +13570,7 @@ async function openStackLayer(input, _onSetupLine) {
13187
13570
  let createdWorktree = false;
13188
13571
  const trees = await listWorktrees(repoPath);
13189
13572
  const checkedOut = trees.find((w) => w.branch === branchName);
13190
- if (checkedOut?.path && (0, import_node_fs37.existsSync)(checkedOut.path)) {
13573
+ if (checkedOut?.path && (0, import_node_fs38.existsSync)(checkedOut.path)) {
13191
13574
  if (input.reuseExistingWorktree !== false) {
13192
13575
  worktreePath = checkedOut.path;
13193
13576
  } else {
@@ -13329,7 +13712,7 @@ async function initStackFromThread(input, onSetupLine) {
13329
13712
  async function createPrStack(input, onSetupLine) {
13330
13713
  await requireAgent(input.agent);
13331
13714
  const repoPath = await resolveRepoRoot(input.repoPath);
13332
- if (!(0, import_node_fs37.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
13715
+ if (!(0, import_node_fs38.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
13333
13716
  if (!input.branches.length) throw new Error("At least one branch name required");
13334
13717
  const status = await detectGhStack(repoPath);
13335
13718
  if (!status.available) throw new Error(status.reason);
@@ -13396,7 +13779,7 @@ async function createPrStack(input, onSetupLine) {
13396
13779
  }
13397
13780
  }
13398
13781
  const claimed = new Set(threads.map((t) => t.worktreePath));
13399
- if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs37.existsSync)(bootstrap.worktreePath)) {
13782
+ if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs38.existsSync)(bootstrap.worktreePath)) {
13400
13783
  try {
13401
13784
  await removeWorktree(repoPath, bootstrap.worktreePath, {
13402
13785
  deleteBranch: bootstrap.branchName
@@ -13416,11 +13799,11 @@ function stackAgentDefaultsFrom(input) {
13416
13799
  planMode: input.planMode
13417
13800
  };
13418
13801
  }
13419
- var import_node_fs37;
13802
+ var import_node_fs38;
13420
13803
  var init_stack_layers = __esm({
13421
13804
  "src/threads/stack-layers.ts"() {
13422
13805
  "use strict";
13423
- import_node_fs37 = require("fs");
13806
+ import_node_fs38 = require("fs");
13424
13807
  init_detect();
13425
13808
  init_run();
13426
13809
  init_stack();
@@ -13433,7 +13816,7 @@ var init_stack_layers = __esm({
13433
13816
 
13434
13817
  // src/diff/diff.ts
13435
13818
  async function inspectGitWorktree(worktreePath) {
13436
- if (!worktreePath || !(0, import_node_fs38.existsSync)(worktreePath)) return "missing_worktree";
13819
+ if (!worktreePath || !(0, import_node_fs39.existsSync)(worktreePath)) return "missing_worktree";
13437
13820
  const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
13438
13821
  reject: false
13439
13822
  });
@@ -13441,7 +13824,7 @@ async function inspectGitWorktree(worktreePath) {
13441
13824
  return "ok";
13442
13825
  }
13443
13826
  async function initializeGitRepository(worktreePath) {
13444
- if (!worktreePath || !(0, import_node_fs38.existsSync)(worktreePath)) {
13827
+ if (!worktreePath || !(0, import_node_fs39.existsSync)(worktreePath)) {
13445
13828
  throw new Error("Worktree not found");
13446
13829
  }
13447
13830
  const status = await inspectGitWorktree(worktreePath);
@@ -13575,11 +13958,11 @@ new file mode 100644
13575
13958
  };
13576
13959
  }
13577
13960
  async function untrackedPatch(worktreePath, path2, maxHunk) {
13578
- const abs = (0, import_node_path34.join)(worktreePath, path2);
13961
+ const abs = (0, import_node_path35.join)(worktreePath, path2);
13579
13962
  try {
13580
- const st = (0, import_node_fs38.statSync)(abs);
13963
+ const st = (0, import_node_fs39.statSync)(abs);
13581
13964
  if (st.isFile() && st.size > maxHunk) {
13582
- const buf = (0, import_node_fs38.readFileSync)(abs).subarray(0, maxHunk);
13965
+ const buf = (0, import_node_fs39.readFileSync)(abs).subarray(0, maxHunk);
13583
13966
  return syntheticAddPatch(path2, buf.toString("utf8"), maxHunk);
13584
13967
  }
13585
13968
  } catch {
@@ -14068,8 +14451,8 @@ function isImageRelativePath(relativePath) {
14068
14451
  function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
14069
14452
  assertSafeRelativePath(relativePath);
14070
14453
  const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
14071
- const abs = (0, import_node_path34.join)(worktreePath, relativePath);
14072
- const st = (0, import_node_fs38.statSync)(abs);
14454
+ const abs = (0, import_node_path35.join)(worktreePath, relativePath);
14455
+ const st = (0, import_node_fs39.statSync)(abs);
14073
14456
  if (!st.isFile()) {
14074
14457
  throw new Error(`Not a file: ${relativePath}`);
14075
14458
  }
@@ -14078,7 +14461,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
14078
14461
  `File too large to upload (${st.size} bytes; max ${maxBytes})`
14079
14462
  );
14080
14463
  }
14081
- const buf = (0, import_node_fs38.readFileSync)(abs);
14464
+ const buf = (0, import_node_fs39.readFileSync)(abs);
14082
14465
  return {
14083
14466
  path: relativePath,
14084
14467
  contentBase64: buf.toString("base64"),
@@ -14088,12 +14471,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
14088
14471
  function readWorktreeFile(worktreePath, relativePath, opts) {
14089
14472
  assertSafeRelativePath(relativePath);
14090
14473
  const maxBytes = opts?.maxBytes ?? 2e5;
14091
- const abs = (0, import_node_path34.join)(worktreePath, relativePath);
14092
- const st = (0, import_node_fs38.statSync)(abs);
14474
+ const abs = (0, import_node_path35.join)(worktreePath, relativePath);
14475
+ const st = (0, import_node_fs39.statSync)(abs);
14093
14476
  if (!st.isFile()) {
14094
14477
  throw new Error(`Not a file: ${relativePath}`);
14095
14478
  }
14096
- const buf = (0, import_node_fs38.readFileSync)(abs);
14479
+ const buf = (0, import_node_fs39.readFileSync)(abs);
14097
14480
  if (isImageRelativePath(relativePath)) {
14098
14481
  const maxImageBytes = Math.max(maxBytes, 15e6);
14099
14482
  const truncated2 = buf.length > maxImageBytes;
@@ -14136,9 +14519,9 @@ function assertSafeRelativePath(relativePath) {
14136
14519
  }
14137
14520
  function writeWorktreeFile(worktreePath, relativePath, content) {
14138
14521
  assertSafeRelativePath(relativePath);
14139
- const abs = (0, import_node_path34.join)(worktreePath, relativePath);
14140
- (0, import_node_fs38.mkdirSync)((0, import_node_path34.dirname)(abs), { recursive: true });
14141
- (0, import_node_fs38.writeFileSync)(abs, content, "utf8");
14522
+ const abs = (0, import_node_path35.join)(worktreePath, relativePath);
14523
+ (0, import_node_fs39.mkdirSync)((0, import_node_path35.dirname)(abs), { recursive: true });
14524
+ (0, import_node_fs39.writeFileSync)(abs, content, "utf8");
14142
14525
  return { path: relativePath };
14143
14526
  }
14144
14527
  async function getDiffSummary(worktreePath, repoPath, opts) {
@@ -14155,12 +14538,12 @@ async function getDiffSummary(worktreePath, repoPath, opts) {
14155
14538
  truncated: full.files.length > maxFiles
14156
14539
  };
14157
14540
  }
14158
- var import_node_fs38, import_node_path34, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS, DEFAULT_UPLOAD_MAX_BYTES;
14541
+ var import_node_fs39, import_node_path35, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS, DEFAULT_UPLOAD_MAX_BYTES;
14159
14542
  var init_diff = __esm({
14160
14543
  "src/diff/diff.ts"() {
14161
14544
  "use strict";
14162
- import_node_fs38 = require("fs");
14163
- import_node_path34 = require("path");
14545
+ import_node_fs39 = require("fs");
14546
+ import_node_path35 = require("path");
14164
14547
  init_run();
14165
14548
  init_worktree();
14166
14549
  mergeBaseCache = /* @__PURE__ */ new Map();
@@ -14328,7 +14711,7 @@ function parseFrontmatter(content) {
14328
14711
  }
14329
14712
  function readSkill(skillMd, source) {
14330
14713
  try {
14331
- const content = (0, import_node_fs39.readFileSync)(skillMd, "utf8");
14714
+ const content = (0, import_node_fs40.readFileSync)(skillMd, "utf8");
14332
14715
  const { name: fmName, description } = parseFrontmatter(content);
14333
14716
  const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
14334
14717
  const name = fmName || dirName;
@@ -14347,19 +14730,19 @@ function readSkill(skillMd, source) {
14347
14730
  }
14348
14731
  }
14349
14732
  function scanSkillsDir(dir, source, out) {
14350
- if (!(0, import_node_fs39.existsSync)(dir)) return;
14733
+ if (!(0, import_node_fs40.existsSync)(dir)) return;
14351
14734
  let entries;
14352
14735
  try {
14353
- entries = (0, import_node_fs39.readdirSync)(dir);
14736
+ entries = (0, import_node_fs40.readdirSync)(dir);
14354
14737
  } catch {
14355
14738
  return;
14356
14739
  }
14357
14740
  for (const entry of entries) {
14358
14741
  if (entry.startsWith(".")) continue;
14359
- const skillMd = (0, import_node_path35.join)(dir, entry, "SKILL.md");
14360
- if (!(0, import_node_fs39.existsSync)(skillMd)) continue;
14742
+ const skillMd = (0, import_node_path36.join)(dir, entry, "SKILL.md");
14743
+ if (!(0, import_node_fs40.existsSync)(skillMd)) continue;
14361
14744
  try {
14362
- if (!(0, import_node_fs39.statSync)(skillMd).isFile()) continue;
14745
+ if (!(0, import_node_fs40.statSync)(skillMd).isFile()) continue;
14363
14746
  } catch {
14364
14747
  continue;
14365
14748
  }
@@ -14368,24 +14751,24 @@ function scanSkillsDir(dir, source, out) {
14368
14751
  }
14369
14752
  }
14370
14753
  function scanClaudePluginSkills(pluginsRoot, out) {
14371
- if (!(0, import_node_fs39.existsSync)(pluginsRoot)) return;
14754
+ if (!(0, import_node_fs40.existsSync)(pluginsRoot)) return;
14372
14755
  const walk = (dir, depth, lookingForSkillsDir) => {
14373
14756
  if (depth > 7) return;
14374
14757
  let entries;
14375
14758
  try {
14376
- entries = (0, import_node_fs39.readdirSync)(dir);
14759
+ entries = (0, import_node_fs40.readdirSync)(dir);
14377
14760
  } catch {
14378
14761
  return;
14379
14762
  }
14380
14763
  if (lookingForSkillsDir && entries.includes("SKILL.md")) {
14381
- const skill = readSkill((0, import_node_path35.join)(dir, "SKILL.md"), "cli");
14764
+ const skill = readSkill((0, import_node_path36.join)(dir, "SKILL.md"), "cli");
14382
14765
  if (skill) out.push(skill);
14383
14766
  }
14384
14767
  for (const entry of entries) {
14385
14768
  if (entry === "node_modules" || entry === ".git") continue;
14386
- const full = (0, import_node_path35.join)(dir, entry);
14769
+ const full = (0, import_node_path36.join)(dir, entry);
14387
14770
  try {
14388
- if (!(0, import_node_fs39.statSync)(full).isDirectory()) continue;
14771
+ if (!(0, import_node_fs40.statSync)(full).isDirectory()) continue;
14389
14772
  } catch {
14390
14773
  continue;
14391
14774
  }
@@ -14403,17 +14786,17 @@ function discoverSkills(worktreePath) {
14403
14786
  const home = (0, import_node_os11.homedir)();
14404
14787
  const collected = [];
14405
14788
  for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
14406
- scanSkillsDir((0, import_node_path35.join)(worktreePath, rel), "workspace", collected);
14789
+ scanSkillsDir((0, import_node_path36.join)(worktreePath, rel), "workspace", collected);
14407
14790
  }
14408
14791
  for (const abs of [
14409
- (0, import_node_path35.join)(home, ".claude/skills"),
14410
- (0, import_node_path35.join)(home, ".cursor/skills"),
14411
- (0, import_node_path35.join)(home, ".sideboard/skills"),
14412
- (0, import_node_path35.join)(home, ".brightsy/skills")
14792
+ (0, import_node_path36.join)(home, ".claude/skills"),
14793
+ (0, import_node_path36.join)(home, ".cursor/skills"),
14794
+ (0, import_node_path36.join)(home, ".sideboard/skills"),
14795
+ (0, import_node_path36.join)(home, ".brightsy/skills")
14413
14796
  ]) {
14414
14797
  scanSkillsDir(abs, "user", collected);
14415
14798
  }
14416
- scanClaudePluginSkills((0, import_node_path35.join)(home, ".claude/plugins"), collected);
14799
+ scanClaudePluginSkills((0, import_node_path36.join)(home, ".claude/plugins"), collected);
14417
14800
  const rank = { workspace: 0, user: 1, cli: 2 };
14418
14801
  const byCommand = /* @__PURE__ */ new Map();
14419
14802
  for (const skill of collected) {
@@ -14425,7 +14808,7 @@ function discoverSkills(worktreePath) {
14425
14808
  return [...byCommand.values()].sort((a, b) => a.command.localeCompare(b.command));
14426
14809
  }
14427
14810
  function readSkillBody(skillPath, maxChars = 12e3) {
14428
- const raw = (0, import_node_fs39.readFileSync)(skillPath, "utf8");
14811
+ const raw = (0, import_node_fs40.readFileSync)(skillPath, "utf8");
14429
14812
  if (raw.startsWith("---")) {
14430
14813
  const end = raw.indexOf("\n---", 3);
14431
14814
  if (end >= 0) {
@@ -14439,13 +14822,13 @@ function readSkillBody(skillPath, maxChars = 12e3) {
14439
14822
 
14440
14823
  \u2026(truncated)` : raw;
14441
14824
  }
14442
- var import_node_fs39, import_node_os11, import_node_path35;
14825
+ var import_node_fs40, import_node_os11, import_node_path36;
14443
14826
  var init_discover = __esm({
14444
14827
  "src/skills/discover.ts"() {
14445
14828
  "use strict";
14446
- import_node_fs39 = require("fs");
14829
+ import_node_fs40 = require("fs");
14447
14830
  import_node_os11 = require("os");
14448
- import_node_path35 = require("path");
14831
+ import_node_path36 = require("path");
14449
14832
  }
14450
14833
  });
14451
14834
 
@@ -14536,7 +14919,7 @@ var init_expand = __esm({
14536
14919
 
14537
14920
  // src/composer/stage-files.ts
14538
14921
  function fileExtension(filePath) {
14539
- const base = (0, import_node_path36.basename)(filePath).toLowerCase();
14922
+ const base = (0, import_node_path37.basename)(filePath).toLowerCase();
14540
14923
  return base.includes(".") ? base.split(".").pop() || "" : "";
14541
14924
  }
14542
14925
  function isImageFilePath(filePath) {
@@ -14546,22 +14929,22 @@ function imageMimeType(filePath) {
14546
14929
  return IMAGE_MIME_BY_EXT[fileExtension(filePath)] || "image/png";
14547
14930
  }
14548
14931
  function ensureAttachmentsDir(worktreePath) {
14549
- const dir = (0, import_node_path36.join)(worktreePath, ATTACHMENTS_DIR);
14550
- (0, import_node_fs40.mkdirSync)(dir, { recursive: true });
14551
- const gi = (0, import_node_path36.join)(dir, ".gitignore");
14552
- if (!(0, import_node_fs40.existsSync)(gi)) {
14553
- (0, import_node_fs40.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
14932
+ const dir = (0, import_node_path37.join)(worktreePath, ATTACHMENTS_DIR);
14933
+ (0, import_node_fs41.mkdirSync)(dir, { recursive: true });
14934
+ const gi = (0, import_node_path37.join)(dir, ".gitignore");
14935
+ if (!(0, import_node_fs41.existsSync)(gi)) {
14936
+ (0, import_node_fs41.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
14554
14937
  }
14555
14938
  return dir;
14556
14939
  }
14557
14940
  function uniqueAttachmentName(dir, originalName) {
14558
14941
  const safe = originalName.replace(/[/\\]/g, "_") || "file";
14559
- if (!(0, import_node_fs40.existsSync)((0, import_node_path36.join)(dir, safe))) return safe;
14560
- const ext = (0, import_node_path36.extname)(safe);
14942
+ if (!(0, import_node_fs41.existsSync)((0, import_node_path37.join)(dir, safe))) return safe;
14943
+ const ext = (0, import_node_path37.extname)(safe);
14561
14944
  const stem = ext ? safe.slice(0, -ext.length) : safe;
14562
14945
  for (let i = 1; i < 1e4; i++) {
14563
14946
  const candidate = `${stem}-${i}${ext}`;
14564
- if (!(0, import_node_fs40.existsSync)((0, import_node_path36.join)(dir, candidate))) return candidate;
14947
+ if (!(0, import_node_fs41.existsSync)((0, import_node_path37.join)(dir, candidate))) return candidate;
14565
14948
  }
14566
14949
  return `${stem}-${(0, import_node_crypto8.randomUUID)()}${ext}`;
14567
14950
  }
@@ -14613,9 +14996,9 @@ function attachmentFromBuffer(name, buf, opts) {
14613
14996
  };
14614
14997
  }
14615
14998
  function attachmentFromAbsolutePath(absolutePath) {
14616
- const name = (0, import_node_path36.basename)(absolutePath);
14999
+ const name = (0, import_node_path37.basename)(absolutePath);
14617
15000
  try {
14618
- const st = (0, import_node_fs40.statSync)(absolutePath);
15001
+ const st = (0, import_node_fs41.statSync)(absolutePath);
14619
15002
  if (!st.isFile()) {
14620
15003
  return {
14621
15004
  id: (0, import_node_crypto8.randomUUID)(),
@@ -14624,7 +15007,7 @@ function attachmentFromAbsolutePath(absolutePath) {
14624
15007
  content: `(not a file: ${absolutePath})`
14625
15008
  };
14626
15009
  }
14627
- const buf = (0, import_node_fs40.readFileSync)(absolutePath);
15010
+ const buf = (0, import_node_fs41.readFileSync)(absolutePath);
14628
15011
  return attachmentFromBuffer(name, buf, { sourceLabel: absolutePath });
14629
15012
  } catch (err) {
14630
15013
  return {
@@ -14640,15 +15023,15 @@ function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
14640
15023
  const dir = ensureAttachmentsDir(worktreePath);
14641
15024
  const out = [];
14642
15025
  for (const abs of absolutePaths) {
14643
- const originalName = (0, import_node_path36.basename)(abs);
15026
+ const originalName = (0, import_node_path37.basename)(abs);
14644
15027
  try {
14645
- const st = (0, import_node_fs40.statSync)(abs);
15028
+ const st = (0, import_node_fs41.statSync)(abs);
14646
15029
  if (!st.isFile()) continue;
14647
15030
  const name = uniqueAttachmentName(dir, originalName);
14648
- const destAbs = (0, import_node_path36.join)(dir, name);
14649
- (0, import_node_fs40.copyFileSync)(abs, destAbs);
15031
+ const destAbs = (0, import_node_path37.join)(dir, name);
15032
+ (0, import_node_fs41.copyFileSync)(abs, destAbs);
14650
15033
  const rel = `${ATTACHMENTS_DIR}/${name}`;
14651
- const buf = (0, import_node_fs40.readFileSync)(destAbs);
15034
+ const buf = (0, import_node_fs41.readFileSync)(destAbs);
14652
15035
  out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
14653
15036
  } catch (err) {
14654
15037
  out.push({
@@ -14670,8 +15053,8 @@ function stageBuffersAsAttachments(worktreePath, buffers2) {
14670
15053
  try {
14671
15054
  const buf = Buffer.from(item.dataBase64, "base64");
14672
15055
  const name = uniqueAttachmentName(dir, originalName);
14673
- const destAbs = (0, import_node_path36.join)(dir, name);
14674
- (0, import_node_fs40.writeFileSync)(destAbs, buf);
15056
+ const destAbs = (0, import_node_path37.join)(dir, name);
15057
+ (0, import_node_fs41.writeFileSync)(destAbs, buf);
14675
15058
  const rel = `${ATTACHMENTS_DIR}/${name}`;
14676
15059
  out.push(attachmentFromBuffer(name, buf, { path: rel }));
14677
15060
  } catch (err) {
@@ -14707,18 +15090,18 @@ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
14707
15090
  if (!rel || rel.includes("..") || rel.startsWith("/")) {
14708
15091
  out.push({
14709
15092
  id: (0, import_node_crypto8.randomUUID)(),
14710
- name: (0, import_node_path36.basename)(rel) || "file",
15093
+ name: (0, import_node_path37.basename)(rel) || "file",
14711
15094
  kind: "file",
14712
15095
  content: `(invalid path: ${rel})`
14713
15096
  });
14714
15097
  continue;
14715
15098
  }
14716
- const name = (0, import_node_path36.basename)(rel);
15099
+ const name = (0, import_node_path37.basename)(rel);
14717
15100
  try {
14718
- const abs = (0, import_node_path36.join)(worktreePath, rel);
14719
- const st = (0, import_node_fs40.statSync)(abs);
15101
+ const abs = (0, import_node_path37.join)(worktreePath, rel);
15102
+ const st = (0, import_node_fs41.statSync)(abs);
14720
15103
  if (!st.isFile()) continue;
14721
- const buf = (0, import_node_fs40.readFileSync)(abs);
15104
+ const buf = (0, import_node_fs41.readFileSync)(abs);
14722
15105
  out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
14723
15106
  } catch (err) {
14724
15107
  out.push({
@@ -14731,12 +15114,12 @@ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
14731
15114
  }
14732
15115
  return out;
14733
15116
  }
14734
- var import_node_fs40, import_node_path36, import_node_crypto8, IMAGE_EXTENSIONS2, IMAGE_MIME_BY_EXT, MAX_INLINE_BYTES, MAX_PREVIEW_BYTES;
15117
+ var import_node_fs41, import_node_path37, import_node_crypto8, IMAGE_EXTENSIONS2, IMAGE_MIME_BY_EXT, MAX_INLINE_BYTES, MAX_PREVIEW_BYTES;
14735
15118
  var init_stage_files = __esm({
14736
15119
  "src/composer/stage-files.ts"() {
14737
15120
  "use strict";
14738
- import_node_fs40 = require("fs");
14739
- import_node_path36 = require("path");
15121
+ import_node_fs41 = require("fs");
15122
+ import_node_path37 = require("path");
14740
15123
  import_node_crypto8 = require("crypto");
14741
15124
  init_workspace_scratch();
14742
15125
  IMAGE_EXTENSIONS2 = /* @__PURE__ */ new Set([
@@ -14883,14 +15266,15 @@ function formatArtifactDirective() {
14883
15266
  return [
14884
15267
  "Sideboard side column (desktop UI):",
14885
15268
  "claude.ai\u2019s \u201CArtifact\u201D tool does NOT exist in Claude Code. That is expected.",
15269
+ "Do not unprompted-duplicate a payload. Chat markdown (including tables) already renders in the transcript \u2014 do not also call present_schema with those same rows just to display them. If the user asks for an editable / interactive table, call present_schema even if markdown already showed the data. Do not also call present_artifact for a document you already fenced in chat.",
14886
15270
  "Documents (HTML/SVG/markdown):",
14887
15271
  "1) Emit a fenced code block tagged `html` (preferred), `svg`, or `markdown` with the FULL document \u2014 Sideboard opens a side column. Example:",
14888
15272
  "```html",
14889
15273
  "<!DOCTYPE html><html><head><title>Demo</title></head><body><h1>Hi</h1></body></html>",
14890
15274
  "```",
14891
- "2) Or call Sideboard MCP `present_artifact` with title, type (html|svg|markdown), and content.",
15275
+ "2) Or call Sideboard MCP `present_artifact` with title, type (html|svg|markdown), and content \u2014 not both a fence and this tool for the same body.",
14892
15276
  "CMS / JSON Schema forms & tables (Brightsy or any schema+schemaUi source):",
14893
- "3) Call Sideboard MCP `present_schema` with title, mode (table|form), and either:",
15277
+ "3) Call Sideboard MCP `present_schema` when the user needs to filter, edit, publish, or persist rows \u2014 including after you already showed a markdown table, if they then ask for an editable table. If they only need to read the data, a markdown table is enough. When you do call it, pass title, mode (table|form), and either:",
14894
15278
  " - datasource=brightsy + resource_id (record type UUID) after fetching types via Brightsy MCP, or",
14895
15279
  " - datasource=inline + resource: { id, title, schema, schemaUi } and optional records/record.",
14896
15280
  "Files / media browser (CMS file manager column):",
@@ -14899,11 +15283,11 @@ function formatArtifactDirective() {
14899
15283
  "Multiple-choice questions:",
14900
15284
  "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.",
14901
15285
  "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.",
14902
- "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."
15286
+ "Never say artifacts, CMS UI, or the Files column are unavailable. present_schema is for interactive list/edit/publish (use it when they ask to edit, even if chat already had a markdown table); present_files for storage UI; html fences for standalone pages; ask_user only for those blocked predefined-option questions."
14903
15287
  ].join("\n");
14904
15288
  }
14905
15289
  function formatUiReminder() {
14906
- return "Sideboard UI: html fence or present_artifact / present_schema / present_files; ask_user only for a real multiple-choice (not hellos or \u201Cwhat next?\u201D) \u2014 reply in chat. Do not say artifacts/CMS UI are unavailable.";
15290
+ 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. ask_user only for a real multiple-choice (not hellos or \u201Cwhat next?\u201D) \u2014 reply in chat. Do not say artifacts/CMS UI are unavailable.";
14907
15291
  }
14908
15292
  function loadAgentInstructions(worktreePath, agent) {
14909
15293
  const candidates = FILES_BY_AGENT[agent] ?? FILES_BY_AGENT.claude;
@@ -14912,11 +15296,11 @@ function loadAgentInstructions(worktreePath, agent) {
14912
15296
  const out = [];
14913
15297
  for (const rel of candidates) {
14914
15298
  if (seenPaths.has(rel)) continue;
14915
- const abs = (0, import_node_path37.join)(worktreePath, rel);
14916
- if (!(0, import_node_fs41.existsSync)(abs)) continue;
15299
+ const abs = (0, import_node_path38.join)(worktreePath, rel);
15300
+ if (!(0, import_node_fs42.existsSync)(abs)) continue;
14917
15301
  try {
14918
- if (!(0, import_node_fs41.statSync)(abs).isFile()) continue;
14919
- let content = (0, import_node_fs41.readFileSync)(abs, "utf8");
15302
+ if (!(0, import_node_fs42.statSync)(abs).isFile()) continue;
15303
+ let content = (0, import_node_fs42.readFileSync)(abs, "utf8");
14920
15304
  if (!content.trim()) continue;
14921
15305
  if (content.length > MAX_CHARS_PER_FILE) {
14922
15306
  content = `${content.slice(0, MAX_CHARS_PER_FILE)}
@@ -14956,12 +15340,12 @@ function withAgentInstructions(prompt, files) {
14956
15340
 
14957
15341
  ${prompt}`;
14958
15342
  }
14959
- var import_node_fs41, import_node_path37, FILES_BY_AGENT, MAX_CHARS_PER_FILE;
15343
+ var import_node_fs42, import_node_path38, FILES_BY_AGENT, MAX_CHARS_PER_FILE;
14960
15344
  var init_instructions = __esm({
14961
15345
  "src/agents/instructions.ts"() {
14962
15346
  "use strict";
14963
- import_node_fs41 = require("fs");
14964
- import_node_path37 = require("path");
15347
+ import_node_fs42 = require("fs");
15348
+ import_node_path38 = require("path");
14965
15349
  init_git_auth_mode();
14966
15350
  init_worktree_labels();
14967
15351
  FILES_BY_AGENT = {
@@ -15051,40 +15435,40 @@ __export(plan_file_exports, {
15051
15435
  writePlanFile: () => writePlanFile
15052
15436
  });
15053
15437
  function ensureAttachmentsGitignore(worktreePath) {
15054
- const gitignoreAbs = (0, import_node_path38.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
15055
- if ((0, import_node_fs42.existsSync)(gitignoreAbs)) return;
15056
- (0, import_node_fs42.mkdirSync)((0, import_node_path38.dirname)(gitignoreAbs), { recursive: true });
15057
- (0, import_node_fs42.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
15438
+ const gitignoreAbs = (0, import_node_path39.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
15439
+ if ((0, import_node_fs43.existsSync)(gitignoreAbs)) return;
15440
+ (0, import_node_fs43.mkdirSync)((0, import_node_path39.dirname)(gitignoreAbs), { recursive: true });
15441
+ (0, import_node_fs43.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
15058
15442
  }
15059
15443
  function planFileAbs(worktreePath) {
15060
- return (0, import_node_path38.join)(worktreePath, PLAN_FILE_REL);
15444
+ return (0, import_node_path39.join)(worktreePath, PLAN_FILE_REL);
15061
15445
  }
15062
15446
  function readTextIfPresent2(abs) {
15063
- if (!(0, import_node_fs42.existsSync)(abs)) return null;
15447
+ if (!(0, import_node_fs43.existsSync)(abs)) return null;
15064
15448
  try {
15065
- const content = (0, import_node_fs42.readFileSync)(abs, "utf8");
15449
+ const content = (0, import_node_fs43.readFileSync)(abs, "utf8");
15066
15450
  return content.trim() ? content : null;
15067
15451
  } catch {
15068
15452
  return null;
15069
15453
  }
15070
15454
  }
15071
15455
  function readPlanFile(worktreePath) {
15072
- return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path38.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path38.join)(worktreePath, LEGACY_PLAN_FILE_REL));
15456
+ return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path39.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path39.join)(worktreePath, LEGACY_PLAN_FILE_REL));
15073
15457
  }
15074
15458
  function writePlanFile(worktreePath, content) {
15075
15459
  ensureAttachmentsGitignore(worktreePath);
15076
15460
  const abs = planFileAbs(worktreePath);
15077
- (0, import_node_fs42.mkdirSync)((0, import_node_path38.dirname)(abs), { recursive: true });
15461
+ (0, import_node_fs43.mkdirSync)((0, import_node_path39.dirname)(abs), { recursive: true });
15078
15462
  const body = content.trimEnd() + (content.endsWith("\n") ? "" : "\n");
15079
- (0, import_node_fs42.writeFileSync)(abs, body, "utf8");
15463
+ (0, import_node_fs43.writeFileSync)(abs, body, "utf8");
15080
15464
  return PLAN_FILE_REL;
15081
15465
  }
15082
- var import_node_fs42, import_node_path38;
15466
+ var import_node_fs43, import_node_path39;
15083
15467
  var init_plan_file = __esm({
15084
15468
  "src/plan/plan-file.ts"() {
15085
15469
  "use strict";
15086
- import_node_fs42 = require("fs");
15087
- import_node_path38 = require("path");
15470
+ import_node_fs43 = require("fs");
15471
+ import_node_path39 = require("path");
15088
15472
  init_workspace_scratch();
15089
15473
  init_plan_present();
15090
15474
  init_plan_present();
@@ -15138,10 +15522,10 @@ __export(cursor_recover_exports, {
15138
15522
  function recoverFinishedCursorRun(opts) {
15139
15523
  const agentId = opts.agentId.trim();
15140
15524
  if (!agentId) return null;
15141
- const runsPath = (0, import_node_path39.join)(appDataDir(), "cursor-sdk-store", "runs.ndjson");
15142
- if (!(0, import_node_fs43.existsSync)(runsPath)) return null;
15525
+ const runsPath = (0, import_node_path40.join)(appDataDir(), "cursor-sdk-store", "runs.ndjson");
15526
+ if (!(0, import_node_fs44.existsSync)(runsPath)) return null;
15143
15527
  try {
15144
- const lines = (0, import_node_fs43.readFileSync)(runsPath, "utf8").split("\n");
15528
+ const lines = (0, import_node_fs44.readFileSync)(runsPath, "utf8").split("\n");
15145
15529
  let best = null;
15146
15530
  for (const line of lines) {
15147
15531
  const trimmed = line.trim();
@@ -15167,12 +15551,12 @@ function recoverFinishedCursorRun(opts) {
15167
15551
  return null;
15168
15552
  }
15169
15553
  }
15170
- var import_node_fs43, import_node_path39;
15554
+ var import_node_fs44, import_node_path40;
15171
15555
  var init_cursor_recover = __esm({
15172
15556
  "src/agents/cursor-recover.ts"() {
15173
15557
  "use strict";
15174
- import_node_fs43 = require("fs");
15175
- import_node_path39 = require("path");
15558
+ import_node_fs44 = require("fs");
15559
+ import_node_path40 = require("path");
15176
15560
  init_paths();
15177
15561
  }
15178
15562
  });
@@ -15303,14 +15687,16 @@ async function startOrchestration(opts) {
15303
15687
  }
15304
15688
  return updated;
15305
15689
  }
15306
- var import_node_events, import_node_fs44, STALE_AGENT_PID_WAIT_MS, Orchestrator, singleton;
15690
+ var import_node_events, import_node_fs45, STALE_AGENT_PID_WAIT_MS, Orchestrator, singleton;
15307
15691
  var init_orchestrator = __esm({
15308
15692
  "src/orchestrator/orchestrator.ts"() {
15309
15693
  "use strict";
15310
15694
  import_node_events = require("events");
15311
15695
  init_outbound_watch();
15312
- import_node_fs44 = require("fs");
15696
+ import_node_fs45 = require("fs");
15313
15697
  init_error_detail();
15698
+ init_run();
15699
+ init_stale_lock();
15314
15700
  init_spawn();
15315
15701
  init_agents();
15316
15702
  init_worktree();
@@ -15426,7 +15812,7 @@ var init_orchestrator = __esm({
15426
15812
  }
15427
15813
  continue;
15428
15814
  }
15429
- if (!(0, import_node_fs44.existsSync)(thread.worktreePath)) {
15815
+ if (!(0, import_node_fs45.existsSync)(thread.worktreePath)) {
15430
15816
  setStatus(thread.id, "broken", "Worktree missing on disk");
15431
15817
  this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
15432
15818
  continue;
@@ -16019,7 +16405,15 @@ var init_orchestrator = __esm({
16019
16405
  hasSession: Boolean(this.requireThread(threadId).sessionId)
16020
16406
  })) {
16021
16407
  updateThread(threadId, { sessionId: null });
16022
- const retryNote = looksLikeInvalidAgentSession(detail) ? "Agent session missing \u2014 starting a fresh session" : "Agent runner crashed \u2014 restarting Node once";
16408
+ try {
16409
+ const gitDirs = await resolveGitDirsForLockRecovery(thread.worktreePath);
16410
+ const clearedLocks = clearStaleIndexLocks(gitDirs, 2e3);
16411
+ if (clearedLocks.length > 0) {
16412
+ pushTurnStderr(stderrTail, "Cleared a stale git lock left by the crashed agent process");
16413
+ }
16414
+ } catch {
16415
+ }
16416
+ const retryNote = looksLikeInvalidAgentSession(detail) ? "Agent session missing \u2014 starting a fresh session" : looksLikeV8Oom(detail) ? "Agent ran out of memory \u2014 starting a fresh session" : "Agent runner crashed \u2014 restarting Node once";
16023
16417
  pushTurnStderr(stderrTail, retryNote);
16024
16418
  this.emit({
16025
16419
  type: "turn_output",
@@ -16491,13 +16885,14 @@ var init_orchestrator = __esm({
16491
16885
  const text4 = (lastAgent?.text ?? "").trim() || (thread.status === "error" ? lastError ?? "" : "");
16492
16886
  const stillRunning = thread.status === "running" || thread.status === "queued";
16493
16887
  const live = stillRunning ? readTurnLive(thread.id) : null;
16888
+ const queuedHint = thread.status === "queued" && !live?.summary ? "Queued \u2014 waiting for a concurrency slot" : null;
16494
16889
  return {
16495
16890
  text: text4,
16496
16891
  status: thread.status,
16497
16892
  sessionId: thread.sessionId,
16498
16893
  lastError,
16499
16894
  stillRunning,
16500
- progress: live?.summary ?? null,
16895
+ progress: live?.summary ?? queuedHint,
16501
16896
  lastActivityAt: live?.updatedAt ?? null
16502
16897
  };
16503
16898
  }
@@ -17014,7 +17409,7 @@ var init_orchestrator = __esm({
17014
17409
  this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
17015
17410
  return restored2;
17016
17411
  }
17017
- if (!(0, import_node_fs44.existsSync)(thread.worktreePath)) {
17412
+ if (!(0, import_node_fs45.existsSync)(thread.worktreePath)) {
17018
17413
  if (isCowboyThread(thread) || isPrimaryCheckoutThread(thread)) {
17019
17414
  throw new Error(
17020
17415
  `Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
@@ -17216,6 +17611,7 @@ var init_schedule_runner = __esm({
17216
17611
  var index_exports = {};
17217
17612
  __export(index_exports, {
17218
17613
  AGENT_GIT_ACTIONS: () => AGENT_GIT_ACTIONS,
17614
+ AGENT_RUNNER_MAX_OLD_SPACE_MB: () => AGENT_RUNNER_MAX_OLD_SPACE_MB,
17219
17615
  ATTACHMENTS_DIR: () => ATTACHMENTS_DIR,
17220
17616
  BAKED_SLACK_RELAY_URL: () => BAKED_SLACK_RELAY_URL,
17221
17617
  BRIGHTSY_MCP_ALLOWED_TOOLS: () => BRIGHTSY_MCP_ALLOWED_TOOLS,
@@ -17291,6 +17687,7 @@ __export(index_exports, {
17291
17687
  appendIndexedGitConfig: () => appendIndexedGitConfig,
17292
17688
  appendMessage: () => appendMessage,
17293
17689
  applyAgentEvent: () => applyAgentEvent,
17690
+ applyAgentRunnerHeapEnv: () => applyAgentRunnerHeapEnv,
17294
17691
  applyAppEnvironment: () => applyAppEnvironment,
17295
17692
  applyCompaction: () => applyCompaction,
17296
17693
  applyGithubGitAuthEnv: () => applyGithubGitAuthEnv,
@@ -17524,10 +17921,12 @@ __export(index_exports, {
17524
17921
  isOrchestratorThread: () => isOrchestratorThread,
17525
17922
  isPidAlive: () => isPidAlive,
17526
17923
  isPlaceholderBranch: () => isPlaceholderBranch,
17924
+ isPollWrapperToolName: () => isPollWrapperToolName,
17527
17925
  isPrNotMergeableError: () => isPrNotMergeableError,
17528
17926
  isPresentPlanToolName: () => isPresentPlanToolName,
17529
17927
  isPrimaryCheckoutThread: () => isPrimaryCheckoutThread,
17530
17928
  isSessionQuotaLimit: () => isSessionQuotaLimit,
17929
+ isShellToolName: () => isShellToolName,
17531
17930
  isSideboardScratchPath: () => isSideboardScratchPath,
17532
17931
  isSlackCoordinatorThread: () => isSlackCoordinatorThread,
17533
17932
  isSlackExternalReplyPrompt: () => isSlackExternalReplyPrompt,
@@ -17569,6 +17968,7 @@ __export(index_exports, {
17569
17968
  listWorkspaces: () => listWorkspaces,
17570
17969
  listWorktreeFiles: () => listWorktreeFiles,
17571
17970
  listWorktrees: () => listWorktrees,
17971
+ liveActivitySummary: () => liveActivitySummary,
17572
17972
  loadAgentInstructions: () => loadAgentInstructions,
17573
17973
  loadAppSettings: () => loadAppSettings,
17574
17974
  loadBrightsyConfig: () => loadBrightsyConfig,
@@ -17662,6 +18062,7 @@ __export(index_exports, {
17662
18062
  resolveEffectiveIssueSource: () => resolveEffectiveIssueSource,
17663
18063
  resolveFilesToCopy: () => resolveFilesToCopy,
17664
18064
  resolveGhAuthToken: () => resolveGhAuthToken,
18065
+ resolveGitDirsForLockRecovery: () => resolveGitDirsForLockRecovery,
17665
18066
  resolveGithubAgentToken: () => resolveGithubAgentToken,
17666
18067
  resolveGithubRepoSlug: () => resolveGithubRepoSlug,
17667
18068
  resolveLinearState: () => resolveLinearState,
@@ -17755,6 +18156,7 @@ __export(index_exports, {
17755
18156
  threadsDir: () => threadsDir,
17756
18157
  threadsSharingWorktree: () => threadsSharingWorktree,
17757
18158
  toPublicAppSettings: () => toPublicAppSettings,
18159
+ toolActivityLine: () => toolActivityLine,
17758
18160
  toolDescription: () => toolDescription,
17759
18161
  toolDetail: () => toolDetail,
17760
18162
  toolFilePath: () => toolFilePath,
@@ -17780,6 +18182,7 @@ __export(index_exports, {
17780
18182
  withEventParentId: () => withEventParentId,
17781
18183
  withEventsParentId: () => withEventsParentId,
17782
18184
  withExportedPath: () => withExportedPath,
18185
+ withMaxOldSpaceSize: () => withMaxOldSpaceSize,
17783
18186
  withThreadLock: () => withThreadLock,
17784
18187
  workspaceSettingsSourceLabel: () => workspaceSettingsSourceLabel,
17785
18188
  worktreeCleanupSettings: () => worktreeCleanupSettings,
@@ -18751,7 +19154,7 @@ init_orphan_cleanup();
18751
19154
  var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
18752
19155
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
18753
19156
  var import_zod4 = require("zod");
18754
- var import_node_path40 = require("path");
19157
+ var import_node_path41 = require("path");
18755
19158
  init_orchestrator();
18756
19159
  init_worktree();
18757
19160
  init_create();
@@ -18778,6 +19181,10 @@ function mcpWaitForTurnTimeoutMs(requested) {
18778
19181
  return Math.min(Math.max(1e3, Math.floor(n)), MCP_WAIT_FOR_TURN_MAX_MS);
18779
19182
  }
18780
19183
  var MCP_WAIT_STILL_RUNNING_HINT = "Child is still working. Call wait_for_turn again. Do not send a check-in prompt or assume a hang while progress is updating.";
19184
+ var MCP_WAIT_QUEUED_HINT = "Child is queued waiting for a concurrency slot \u2014 it has not started yet. Call wait_for_turn again. Do not send a check-in prompt, force_stop, or assume it failed to start.";
19185
+ function mcpWaitStillRunningHint(status) {
19186
+ return status === "queued" ? MCP_WAIT_QUEUED_HINT : MCP_WAIT_STILL_RUNNING_HINT;
19187
+ }
18781
19188
 
18782
19189
  // src/mcp/server.ts
18783
19190
  init_turn_live();
@@ -19624,7 +20031,7 @@ async function startMcpServer() {
19624
20031
  async () => {
19625
20032
  const threads = orch.getThreads(true);
19626
20033
  const lines = threads.map((t) => {
19627
- const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path40.basename)(t.repoPath) || t.repoPath;
20034
+ const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path41.basename)(t.repoPath) || t.repoPath;
19628
20035
  const live = t.status === "running" || t.status === "queued" ? readTurnLive(t.id) : null;
19629
20036
  const progress = live?.summary ? ` ${live.summary}` : "";
19630
20037
  return `${t.id.slice(0, 8)} ${t.status.padEnd(9)} ${t.agent.padEnd(8)} ${repo} ${t.sourceType}:${t.sourceRef} ${t.title} sideboard://thread/${t.id}${t.devPort ? ` http://localhost:${t.devPort}` : ""}${progress}`;
@@ -19660,7 +20067,7 @@ async function startMcpServer() {
19660
20067
  prUrl: t.prUrl,
19661
20068
  lastError: t.lastError ?? null,
19662
20069
  stillRunning: t.status === "running" || t.status === "queued",
19663
- progress: live?.summary ?? null,
20070
+ progress: live?.summary ?? (t.status === "queued" ? "Queued \u2014 waiting for a concurrency slot" : null),
19664
20071
  lastActivityAt: live?.updatedAt ?? null
19665
20072
  };
19666
20073
  return { content: [{ type: "text", text: JSON.stringify(summary, null, 2) }] };
@@ -19669,7 +20076,7 @@ async function startMcpServer() {
19669
20076
  }
19670
20077
  server.tool(
19671
20078
  "present_artifact",
19672
- "Show an HTML, SVG, markdown, or React document in Sideboard\u2019s Claude-style side column (desktop). Use instead of claude.ai\u2019s artifact tool \u2014 pass the full document content. Prefer type=html for interactive pages. For type=react, pass a single component module that `export default`s a component (JSX/TSX ok) \u2014 Sideboard bootstraps React/ReactDOM/Babel and renders it; only `react`/`react-dom` imports are available, no other npm packages.",
20079
+ "Show an HTML, SVG, markdown, or React document in Sideboard\u2019s Claude-style side column (desktop). Use instead of claude.ai\u2019s artifact tool \u2014 pass the full document content. Do not also emit the same document as a chat html/markdown fence. Prefer type=html for interactive pages. For type=react, pass a single component module that `export default`s a component (JSX/TSX ok) \u2014 Sideboard bootstraps React/ReactDOM/Babel and renders it; only `react`/`react-dom` imports are available, no other npm packages.",
19673
20080
  {
19674
20081
  title: import_zod4.z.string().describe("Short title shown in the artifact pane header"),
19675
20082
  type: import_zod4.z.enum(["html", "svg", "markdown", "react"]).describe(
@@ -19746,7 +20153,7 @@ async function startMcpServer() {
19746
20153
  );
19747
20154
  server.tool(
19748
20155
  "present_schema",
19749
- "Open Sideboard\u2019s schema-driven side column (filterable table and/or form). Pass JSON Schema + optional schemaUi. Prefer datasource=inline with embedded resource/records. Use datasource=brightsy with resource_id only when the user is logged into Brightsy.",
20156
+ "Open Sideboard\u2019s schema-driven side column (filterable table and/or form) when the user needs to filter, edit, publish, or persist records. Do not call this just to re-display rows you already wrote as a markdown table. If the user asks for an editable / interactive table, call this even if chat already showed those rows. Pass JSON Schema + optional schemaUi. Prefer datasource=inline with embedded resource/records. Use datasource=brightsy with resource_id only when the user is logged into Brightsy.",
19750
20157
  {
19751
20158
  title: import_zod4.z.string().describe("Pane title"),
19752
20159
  mode: import_zod4.z.enum(["table", "form"]).optional().describe("table = list/filter records; form = edit one record"),
@@ -19994,7 +20401,7 @@ async function startMcpServer() {
19994
20401
  );
19995
20402
  server.tool(
19996
20403
  "wait_for_turn",
19997
- "Wait until the thread finishes its current/queued turn, or return early with a live progress snapshot. MCP clients often kill tools around 60s, so this returns within 45s even while the child is still working. If stillRunning is true, progress is tools/thinking \u2014 call wait_for_turn again. Do not send a check-in prompt or assume a hang. On status error, lastError/text is the failure.",
20404
+ "Wait until the thread finishes its current/queued turn, or return early with a live progress snapshot. MCP clients often kill tools around 60s, so this returns within 45s even while the child is still working. If stillRunning is true, progress is tools/thinking (or \u201Cqueued, waiting for a concurrency slot\u201D if it has not started). Call wait_for_turn again. Do not send a check-in prompt, force_stop, or assume a hang. On status error, lastError/text is the failure.",
19998
20405
  {
19999
20406
  ref: import_zod4.z.string(),
20000
20407
  timeoutMs: import_zod4.z.number().optional()
@@ -20016,7 +20423,7 @@ async function startMcpServer() {
20016
20423
  stillRunning: result.stillRunning,
20017
20424
  progress: result.progress,
20018
20425
  lastActivityAt: result.lastActivityAt,
20019
- hint: result.stillRunning ? MCP_WAIT_STILL_RUNNING_HINT : void 0
20426
+ hint: result.stillRunning ? mcpWaitStillRunningHint(result.status) : void 0
20020
20427
  })
20021
20428
  }
20022
20429
  ]
@@ -20035,7 +20442,7 @@ async function startMcpServer() {
20035
20442
  type: "text",
20036
20443
  text: JSON.stringify({
20037
20444
  ...result,
20038
- hint: result.stillRunning ? MCP_WAIT_STILL_RUNNING_HINT : void 0
20445
+ hint: result.stillRunning ? mcpWaitStillRunningHint(result.status) : void 0
20039
20446
  })
20040
20447
  }
20041
20448
  ]
@@ -20964,16 +21371,16 @@ init_connected_teams();
20964
21371
  init_injected_mcp();
20965
21372
 
20966
21373
  // src/agents/user-mcp-config.ts
20967
- var import_node_fs45 = require("fs");
21374
+ var import_node_fs46 = require("fs");
20968
21375
  var import_node_os12 = require("os");
20969
- var import_node_path41 = require("path");
21376
+ var import_node_path42 = require("path");
20970
21377
  init_paths();
20971
21378
  init_injected_mcp();
20972
21379
  function userCursorMcpConfigPath() {
20973
- return (0, import_node_path41.join)((0, import_node_os12.homedir)(), ".cursor", "mcp.json");
21380
+ return (0, import_node_path42.join)((0, import_node_os12.homedir)(), ".cursor", "mcp.json");
20974
21381
  }
20975
21382
  function userClaudeMcpConfigPath() {
20976
- return (0, import_node_path41.join)((0, import_node_os12.homedir)(), ".claude.json");
21383
+ return (0, import_node_path42.join)((0, import_node_os12.homedir)(), ".claude.json");
20977
21384
  }
20978
21385
  function asObject(value) {
20979
21386
  if (!value || typeof value !== "object" || Array.isArray(value)) return {};
@@ -21000,16 +21407,16 @@ function mergeSideboardIntoMcpServersJson(existing, sideboard) {
21000
21407
  }
21001
21408
  function writeMergedMcpServersJson(configPath, sideboard) {
21002
21409
  let existing = {};
21003
- if ((0, import_node_fs45.existsSync)(configPath)) {
21410
+ if ((0, import_node_fs46.existsSync)(configPath)) {
21004
21411
  try {
21005
- existing = JSON.parse((0, import_node_fs45.readFileSync)(configPath, "utf8"));
21412
+ existing = JSON.parse((0, import_node_fs46.readFileSync)(configPath, "utf8"));
21006
21413
  } catch {
21007
21414
  existing = {};
21008
21415
  }
21009
21416
  }
21010
21417
  const next = mergeSideboardIntoMcpServersJson(existing, sideboard);
21011
- (0, import_node_fs45.mkdirSync)((0, import_node_path41.dirname)(configPath), { recursive: true });
21012
- (0, import_node_fs45.writeFileSync)(configPath, `${JSON.stringify(next, null, 2)}
21418
+ (0, import_node_fs46.mkdirSync)((0, import_node_path42.dirname)(configPath), { recursive: true });
21419
+ (0, import_node_fs46.writeFileSync)(configPath, `${JSON.stringify(next, null, 2)}
21013
21420
  `);
21014
21421
  }
21015
21422
  function launchFromResolved(server) {
@@ -21027,7 +21434,7 @@ async function registerPackagedUserMcpClients() {
21027
21434
  const cursor = userCursorMcpConfigPath();
21028
21435
  writeMergedMcpServersJson(cursor, launch);
21029
21436
  const claude = userClaudeMcpConfigPath();
21030
- if ((0, import_node_fs45.existsSync)(claude)) {
21437
+ if ((0, import_node_fs46.existsSync)(claude)) {
21031
21438
  writeMergedMcpServersJson(claude, launch);
21032
21439
  return { cursor, claude };
21033
21440
  }
@@ -22657,9 +23064,9 @@ var import_node_http3 = require("http");
22657
23064
  var import_ws3 = require("ws");
22658
23065
 
22659
23066
  // src/slack/relay-static.ts
22660
- var import_node_fs46 = require("fs");
23067
+ var import_node_fs47 = require("fs");
22661
23068
  var import_promises = require("fs/promises");
22662
- var import_node_path42 = __toESM(require("path"), 1);
23069
+ var import_node_path43 = __toESM(require("path"), 1);
22663
23070
  var TYPES = {
22664
23071
  ".css": "text/css; charset=utf-8",
22665
23072
  ".html": "text/html; charset=utf-8",
@@ -22690,9 +23097,9 @@ function resolveStaticPath(root, requestUrl) {
22690
23097
  return null;
22691
23098
  }
22692
23099
  if (!pathname.startsWith("/") || pathname.includes("\0")) return null;
22693
- const rootResolved = import_node_path42.default.resolve(root);
22694
- const candidate = import_node_path42.default.resolve(rootResolved, `.${pathname}`);
22695
- if (candidate !== rootResolved && !candidate.startsWith(rootResolved + import_node_path42.default.sep)) {
23100
+ const rootResolved = import_node_path43.default.resolve(root);
23101
+ const candidate = import_node_path43.default.resolve(rootResolved, `.${pathname}`);
23102
+ if (candidate !== rootResolved && !candidate.startsWith(rootResolved + import_node_path43.default.sep)) {
22696
23103
  return null;
22697
23104
  }
22698
23105
  return candidate;
@@ -22706,7 +23113,7 @@ async function fileSize(file) {
22706
23113
  }
22707
23114
  }
22708
23115
  function sendFile(req, res, file, size) {
22709
- const ext = import_node_path42.default.extname(file).toLowerCase();
23116
+ const ext = import_node_path43.default.extname(file).toLowerCase();
22710
23117
  res.writeHead(200, {
22711
23118
  "Content-Type": TYPES[ext] ?? "application/octet-stream",
22712
23119
  "Content-Length": size,
@@ -22716,7 +23123,7 @@ function sendFile(req, res, file, size) {
22716
23123
  res.end();
22717
23124
  return true;
22718
23125
  }
22719
- (0, import_node_fs46.createReadStream)(file).pipe(res);
23126
+ (0, import_node_fs47.createReadStream)(file).pipe(res);
22720
23127
  return true;
22721
23128
  }
22722
23129
  async function tryServeStatic(req, res, root) {
@@ -22725,7 +23132,7 @@ async function tryServeStatic(req, res, root) {
22725
23132
  if (!candidate) return false;
22726
23133
  const direct = await fileSize(candidate);
22727
23134
  if (direct != null) return sendFile(req, res, candidate, direct);
22728
- const asIndex = import_node_path42.default.join(candidate, "index.html");
23135
+ const asIndex = import_node_path43.default.join(candidate, "index.html");
22729
23136
  const indexSize = await fileSize(asIndex);
22730
23137
  if (indexSize != null) return sendFile(req, res, asIndex, indexSize);
22731
23138
  return false;
@@ -22961,6 +23368,7 @@ init_outbound_watch();
22961
23368
  // Annotate the CommonJS export names for ESM import in node:
22962
23369
  0 && (module.exports = {
22963
23370
  AGENT_GIT_ACTIONS,
23371
+ AGENT_RUNNER_MAX_OLD_SPACE_MB,
22964
23372
  ATTACHMENTS_DIR,
22965
23373
  BAKED_SLACK_RELAY_URL,
22966
23374
  BRIGHTSY_MCP_ALLOWED_TOOLS,
@@ -23036,6 +23444,7 @@ init_outbound_watch();
23036
23444
  appendIndexedGitConfig,
23037
23445
  appendMessage,
23038
23446
  applyAgentEvent,
23447
+ applyAgentRunnerHeapEnv,
23039
23448
  applyAppEnvironment,
23040
23449
  applyCompaction,
23041
23450
  applyGithubGitAuthEnv,
@@ -23269,10 +23678,12 @@ init_outbound_watch();
23269
23678
  isOrchestratorThread,
23270
23679
  isPidAlive,
23271
23680
  isPlaceholderBranch,
23681
+ isPollWrapperToolName,
23272
23682
  isPrNotMergeableError,
23273
23683
  isPresentPlanToolName,
23274
23684
  isPrimaryCheckoutThread,
23275
23685
  isSessionQuotaLimit,
23686
+ isShellToolName,
23276
23687
  isSideboardScratchPath,
23277
23688
  isSlackCoordinatorThread,
23278
23689
  isSlackExternalReplyPrompt,
@@ -23314,6 +23725,7 @@ init_outbound_watch();
23314
23725
  listWorkspaces,
23315
23726
  listWorktreeFiles,
23316
23727
  listWorktrees,
23728
+ liveActivitySummary,
23317
23729
  loadAgentInstructions,
23318
23730
  loadAppSettings,
23319
23731
  loadBrightsyConfig,
@@ -23407,6 +23819,7 @@ init_outbound_watch();
23407
23819
  resolveEffectiveIssueSource,
23408
23820
  resolveFilesToCopy,
23409
23821
  resolveGhAuthToken,
23822
+ resolveGitDirsForLockRecovery,
23410
23823
  resolveGithubAgentToken,
23411
23824
  resolveGithubRepoSlug,
23412
23825
  resolveLinearState,
@@ -23500,6 +23913,7 @@ init_outbound_watch();
23500
23913
  threadsDir,
23501
23914
  threadsSharingWorktree,
23502
23915
  toPublicAppSettings,
23916
+ toolActivityLine,
23503
23917
  toolDescription,
23504
23918
  toolDetail,
23505
23919
  toolFilePath,
@@ -23525,6 +23939,7 @@ init_outbound_watch();
23525
23939
  withEventParentId,
23526
23940
  withEventsParentId,
23527
23941
  withExportedPath,
23942
+ withMaxOldSpaceSize,
23528
23943
  withThreadLock,
23529
23944
  workspaceSettingsSourceLabel,
23530
23945
  worktreeCleanupSettings,