@sideboard-ai/core 0.1.238 → 0.1.240

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.
package/dist/index.cjs CHANGED
@@ -3980,12 +3980,14 @@ function skillCommandFromInput(input) {
3980
3980
  }
3981
3981
  return void 0;
3982
3982
  }
3983
+ function looksLikeComposerSkillExpansion(text7) {
3984
+ const t = text7.trim();
3985
+ return /^## Skill: \//m.test(t) && /Follow this skill for the request above:/i.test(t);
3986
+ }
3983
3987
  function looksLikeSkillBody(text7) {
3984
3988
  const t = text7.trim();
3985
3989
  if (!t) return false;
3986
- if (/^## Skill: \//m.test(t) && /Follow this skill for the request above:/i.test(t)) {
3987
- return true;
3988
- }
3990
+ if (looksLikeComposerSkillExpansion(t)) return true;
3989
3991
  return skillNameFromFrontmatter(t) != null;
3990
3992
  }
3991
3993
  function skillNameFromFrontmatter(text7) {
@@ -4006,11 +4008,13 @@ function isCompactToolName(name) {
4006
4008
  short
4007
4009
  );
4008
4010
  }
4009
- function isContextCompactInProgress(text7) {
4010
- return /^Compressing context/i.test(text7.trim());
4011
- }
4012
4011
  function isContextCompactDone(text7) {
4013
- return /^Context compressed\b/i.test(text7.trim());
4012
+ return /\bContext compressed\b/i.test(text7.trim());
4013
+ }
4014
+ function isContextCompactInProgress(text7) {
4015
+ const t = text7.trim();
4016
+ if (isContextCompactDone(t)) return false;
4017
+ return /^Compressing context/i.test(t);
4014
4018
  }
4015
4019
  function looksLikeConversationSummary(text7) {
4016
4020
  const t = text7.trim();
@@ -4517,7 +4521,7 @@ function applyAgentEvent(parts, event) {
4517
4521
  );
4518
4522
  }
4519
4523
  const acc = next[next.length - 1];
4520
- if (acc?.type === "text" && looksLikeSkillBody(acc.text)) {
4524
+ if (acc?.type === "text" && looksLikeComposerSkillExpansion(acc.text)) {
4521
4525
  next[next.length - 1] = skillToolFromTextPart(acc, `skill-${next.length}`);
4522
4526
  } else if (acc?.type === "text" && looksLikeConversationSummary(acc.text)) {
4523
4527
  next[next.length - 1] = compactToolPart(acc.text, `compact-${next.length}`, {
@@ -13264,10 +13268,10 @@ function eventsFromClaudeSystem(obj) {
13264
13268
  if (subtype === "api_retry") {
13265
13269
  const attempt = obj.attempt;
13266
13270
  const max = obj.max_retries;
13267
- const delay = obj.retry_delay_ms;
13271
+ const delay2 = obj.retry_delay_ms;
13268
13272
  return {
13269
13273
  type: "thinking",
13270
- data: `API retry ${attempt ?? "?"}/${max ?? "?"}${typeof delay === "number" ? ` (wait ${delay}ms)` : ""}`
13274
+ data: `API retry ${attempt ?? "?"}/${max ?? "?"}${typeof delay2 === "number" ? ` (wait ${delay2}ms)` : ""}`
13271
13275
  };
13272
13276
  }
13273
13277
  if (subtype === "status") {
@@ -13282,7 +13286,8 @@ function eventsFromClaudeSystem(obj) {
13282
13286
  const trigger = meta.trigger ? ` (${meta.trigger})` : "";
13283
13287
  const thinking = {
13284
13288
  type: "thinking",
13285
- data: `Context compressed${trigger}`
13289
+ data: `Context compressed${trigger}`,
13290
+ replace: true
13286
13291
  };
13287
13292
  if (meta.postTokens != null && meta.postTokens > 0) {
13288
13293
  return [
@@ -17481,15 +17486,76 @@ var init_request_review = __esm({
17481
17486
  }
17482
17487
  });
17483
17488
 
17489
+ // src/hook/worktree-run-ports.ts
17490
+ function worktreeRunPortsPath(worktreePath) {
17491
+ return (0, import_node_path44.join)(worktreePath, RUN_PORTS_REL);
17492
+ }
17493
+ function isPort(value) {
17494
+ return typeof value === "number" && Number.isInteger(value) && value > 0 && value <= 65535;
17495
+ }
17496
+ function parseFile(raw) {
17497
+ try {
17498
+ const parsed = JSON.parse(raw);
17499
+ if (!parsed || typeof parsed !== "object") return {};
17500
+ const scripts = parsed.scripts;
17501
+ if (!scripts || typeof scripts !== "object") return {};
17502
+ const next = {};
17503
+ for (const [name, ports] of Object.entries(scripts)) {
17504
+ if (!name || !Array.isArray(ports)) continue;
17505
+ const cleaned = ports.filter(isPort);
17506
+ if (cleaned.length) next[name] = cleaned;
17507
+ }
17508
+ return { scripts: next };
17509
+ } catch {
17510
+ return {};
17511
+ }
17512
+ }
17513
+ function loadWorktreeRunPorts(worktreePath, scriptName) {
17514
+ if (!worktreePath.trim() || !scriptName.trim()) return null;
17515
+ try {
17516
+ const raw = (0, import_node_fs44.readFileSync)(worktreeRunPortsPath(worktreePath), "utf8");
17517
+ const ports = parseFile(raw).scripts?.[scriptName];
17518
+ return ports?.length ? ports : null;
17519
+ } catch {
17520
+ return null;
17521
+ }
17522
+ }
17523
+ function saveWorktreeRunPorts(worktreePath, scriptName, ports) {
17524
+ if (!worktreePath.trim() || !scriptName.trim()) return;
17525
+ const cleaned = ports.filter(isPort);
17526
+ if (!cleaned.length) return;
17527
+ const path2 = worktreeRunPortsPath(worktreePath);
17528
+ let current = {};
17529
+ try {
17530
+ current = parseFile((0, import_node_fs44.readFileSync)(path2, "utf8"));
17531
+ } catch {
17532
+ current = {};
17533
+ }
17534
+ const scripts = { ...current.scripts ?? {} };
17535
+ scripts[scriptName] = cleaned;
17536
+ (0, import_node_fs44.mkdirSync)((0, import_node_path44.dirname)(path2), { recursive: true });
17537
+ (0, import_node_fs44.writeFileSync)(path2, `${JSON.stringify({ scripts }, null, 2)}
17538
+ `, "utf8");
17539
+ }
17540
+ var import_node_fs44, import_node_path44, RUN_PORTS_REL;
17541
+ var init_worktree_run_ports = __esm({
17542
+ "src/hook/worktree-run-ports.ts"() {
17543
+ "use strict";
17544
+ import_node_fs44 = require("fs");
17545
+ import_node_path44 = require("path");
17546
+ RUN_PORTS_REL = ".context/.sideboard/run-ports.json";
17547
+ }
17548
+ });
17549
+
17484
17550
  // src/hook/conductor.ts
17485
17551
  function matchSimpleGlob(pattern, name) {
17486
17552
  const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
17487
17553
  return new RegExp(`^${escaped}$`).test(name);
17488
17554
  }
17489
17555
  function readWorktreeInclude(repoPath) {
17490
- const path2 = (0, import_node_path44.join)(repoPath, ".worktreeinclude");
17491
- if (!(0, import_node_fs44.existsSync)(path2)) return [];
17492
- return (0, import_node_fs44.readFileSync)(path2, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
17556
+ const path2 = (0, import_node_path45.join)(repoPath, ".worktreeinclude");
17557
+ if (!(0, import_node_fs45.existsSync)(path2)) return [];
17558
+ return (0, import_node_fs45.readFileSync)(path2, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
17493
17559
  }
17494
17560
  function resolveFilesToCopy(repoPath) {
17495
17561
  const fromInclude = readWorktreeInclude(repoPath);
@@ -17499,10 +17565,10 @@ function resolveFilesToCopy(repoPath) {
17499
17565
  if (settings?.fileIncludeGlobs?.length) {
17500
17566
  const matched = [];
17501
17567
  try {
17502
- for (const entry of (0, import_node_fs44.readdirSync)(repoPath, { withFileTypes: true })) {
17568
+ for (const entry of (0, import_node_fs45.readdirSync)(repoPath, { withFileTypes: true })) {
17503
17569
  if (!entry.isFile()) continue;
17504
17570
  for (const glob of settings.fileIncludeGlobs) {
17505
- if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path44.basename)(glob), entry.name)) {
17571
+ if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path45.basename)(glob), entry.name)) {
17506
17572
  matched.push(entry.name);
17507
17573
  break;
17508
17574
  }
@@ -17514,7 +17580,7 @@ function resolveFilesToCopy(repoPath) {
17514
17580
  }
17515
17581
  const defaults = [];
17516
17582
  try {
17517
- for (const entry of (0, import_node_fs44.readdirSync)(repoPath, { withFileTypes: true })) {
17583
+ for (const entry of (0, import_node_fs45.readdirSync)(repoPath, { withFileTypes: true })) {
17518
17584
  if (entry.isFile() && entry.name.startsWith(".env")) {
17519
17585
  defaults.push(entry.name);
17520
17586
  }
@@ -17528,11 +17594,11 @@ function copyConfiguredFiles(repoPath, worktreePath) {
17528
17594
  const patterns = resolveFilesToCopy(repoPath);
17529
17595
  const copied = [];
17530
17596
  for (const rel of patterns) {
17531
- const src = (0, import_node_path44.join)(repoPath, rel);
17532
- if (!(0, import_node_fs44.existsSync)(src)) continue;
17533
- const dest = (0, import_node_path44.join)(worktreePath, rel);
17534
- (0, import_node_fs44.mkdirSync)((0, import_node_path44.dirname)(dest), { recursive: true });
17535
- (0, import_node_fs44.copyFileSync)(src, dest);
17597
+ const src = (0, import_node_path45.join)(repoPath, rel);
17598
+ if (!(0, import_node_fs45.existsSync)(src)) continue;
17599
+ const dest = (0, import_node_path45.join)(worktreePath, rel);
17600
+ (0, import_node_fs45.mkdirSync)((0, import_node_path45.dirname)(dest), { recursive: true });
17601
+ (0, import_node_fs45.copyFileSync)(src, dest);
17536
17602
  copied.push(rel);
17537
17603
  }
17538
17604
  return copied;
@@ -17567,7 +17633,7 @@ function buildWorkspaceScriptEnv(opts, baseEnv) {
17567
17633
  const env = stripNestedElectronEnv({
17568
17634
  ...baseEnv ?? process.env
17569
17635
  });
17570
- const name = opts.workspaceName ?? (0, import_node_path44.basename)(opts.worktreePath);
17636
+ const name = opts.workspaceName ?? (0, import_node_path45.basename)(opts.worktreePath);
17571
17637
  const ports = opts.ports ?? [];
17572
17638
  const primary = ports[0];
17573
17639
  env.SIDEBOARD_WORKSPACE_NAME = name;
@@ -17607,6 +17673,57 @@ function killableListenerPids(raw, selfPid = process.pid) {
17607
17673
  }
17608
17674
  return pids;
17609
17675
  }
17676
+ function listUnixListenerPids(port, selfPid) {
17677
+ try {
17678
+ const raw = (0, import_node_child_process5.execFileSync)("lsof", [`-tiTCP:${port}`, "-sTCP:LISTEN"], {
17679
+ encoding: "utf8",
17680
+ stdio: ["ignore", "pipe", "ignore"],
17681
+ timeout: 2e3
17682
+ });
17683
+ return killableListenerPids(raw, selfPid);
17684
+ } catch {
17685
+ return [];
17686
+ }
17687
+ }
17688
+ function listenerCwd(pid) {
17689
+ if (!Number.isFinite(pid) || pid <= 0) return null;
17690
+ try {
17691
+ const raw = (0, import_node_child_process5.execFileSync)("lsof", ["-a", "-p", String(pid), "-d", "cwd", "-Fn"], {
17692
+ encoding: "utf8",
17693
+ stdio: ["ignore", "pipe", "ignore"],
17694
+ timeout: 2e3
17695
+ });
17696
+ for (const line of raw.split("\n")) {
17697
+ if (line.startsWith("n") && line.length > 1) return line.slice(1);
17698
+ }
17699
+ } catch {
17700
+ }
17701
+ return null;
17702
+ }
17703
+ function realpathOrResolve(path2) {
17704
+ try {
17705
+ return (0, import_node_fs45.realpathSync)(path2);
17706
+ } catch {
17707
+ return (0, import_node_path45.resolve)(path2);
17708
+ }
17709
+ }
17710
+ function isOtherWorktreeListenerCwd(cwd, worktreePath) {
17711
+ const wt = realpathOrResolve(worktreePath);
17712
+ const c = realpathOrResolve(cwd);
17713
+ if (c === wt || c.startsWith(wt + import_node_path45.sep)) return false;
17714
+ const parent = (0, import_node_path45.dirname)(wt);
17715
+ const thisName = (0, import_node_path45.basename)(wt);
17716
+ if (!thisName || c === parent) return false;
17717
+ if (!c.startsWith(parent + import_node_path45.sep)) return false;
17718
+ const first = c.slice(parent.length + 1).split(import_node_path45.sep)[0];
17719
+ return Boolean(first) && first !== thisName;
17720
+ }
17721
+ function signalPid(pid, signal) {
17722
+ try {
17723
+ process.kill(pid, signal);
17724
+ } catch {
17725
+ }
17726
+ }
17610
17727
  function killListenersOnPorts(ports) {
17611
17728
  const selfPid = process.pid;
17612
17729
  for (const port of ports) {
@@ -17624,26 +17741,32 @@ function killListenersOnPorts(ports) {
17624
17741
  );
17625
17742
  continue;
17626
17743
  }
17627
- let raw = "";
17628
- try {
17629
- raw = (0, import_node_child_process5.execFileSync)("lsof", [`-tiTCP:${port}`, "-sTCP:LISTEN"], {
17630
- encoding: "utf8",
17631
- stdio: ["ignore", "pipe", "ignore"],
17632
- timeout: 2e3
17633
- });
17634
- } catch {
17635
- continue;
17636
- }
17637
- for (const pid of killableListenerPids(raw, selfPid)) {
17638
- try {
17639
- process.kill(pid, "SIGTERM");
17640
- } catch {
17641
- }
17744
+ for (const pid of listUnixListenerPids(port, selfPid)) {
17745
+ signalPid(pid, "SIGTERM");
17642
17746
  }
17643
17747
  } catch {
17644
17748
  }
17645
17749
  }
17646
17750
  }
17751
+ function killStaleWorktreeListeners(ports, worktreePath, signal = "SIGTERM") {
17752
+ if (!worktreePath.trim()) {
17753
+ killListenersOnPorts(ports);
17754
+ return;
17755
+ }
17756
+ if (process.platform === "win32") {
17757
+ killListenersOnPorts(ports);
17758
+ return;
17759
+ }
17760
+ const selfPid = process.pid;
17761
+ for (const port of ports) {
17762
+ if (!Number.isFinite(port) || port <= 0) continue;
17763
+ for (const pid of listUnixListenerPids(port, selfPid)) {
17764
+ const cwd = listenerCwd(pid);
17765
+ if (cwd && isOtherWorktreeListenerCwd(cwd, worktreePath)) continue;
17766
+ signalPid(pid, signal);
17767
+ }
17768
+ }
17769
+ }
17647
17770
  function killScriptTree(child, ports = []) {
17648
17771
  const pid = child.pid;
17649
17772
  if (pid) {
@@ -17805,7 +17928,7 @@ function getRunMode(worktreePath, repoPath) {
17805
17928
  return loadWorkspaceSettings(worktreePath, repoPath)?.runMode ?? "concurrent";
17806
17929
  }
17807
17930
  async function reservePort() {
17808
- return new Promise((resolve, reject) => {
17931
+ return new Promise((resolve2, reject) => {
17809
17932
  const server = (0, import_node_net.createServer)();
17810
17933
  let released = false;
17811
17934
  const release = () => new Promise((res) => {
@@ -17822,7 +17945,7 @@ async function reservePort() {
17822
17945
  void release().then(() => reject(new Error("Failed to allocate port")));
17823
17946
  return;
17824
17947
  }
17825
- resolve({ port: addr.port, release });
17948
+ resolve2({ port: addr.port, release });
17826
17949
  });
17827
17950
  server.on("error", reject);
17828
17951
  });
@@ -17833,7 +17956,8 @@ async function allocatePort() {
17833
17956
  return held.port;
17834
17957
  }
17835
17958
  async function tryReservePort(port) {
17836
- return new Promise((resolve) => {
17959
+ if (!Number.isInteger(port) || port <= 0 || port > 65535) return null;
17960
+ return new Promise((resolve2) => {
17837
17961
  const server = (0, import_node_net.createServer)();
17838
17962
  let released = false;
17839
17963
  const release = () => new Promise((res) => {
@@ -17844,23 +17968,63 @@ async function tryReservePort(port) {
17844
17968
  released = true;
17845
17969
  server.close(() => res());
17846
17970
  });
17847
- server.once("error", () => resolve(null));
17971
+ server.once("error", () => {
17972
+ try {
17973
+ server.close();
17974
+ } catch {
17975
+ }
17976
+ resolve2(null);
17977
+ });
17848
17978
  server.listen(port, "127.0.0.1", () => {
17849
- resolve({ port, release });
17979
+ resolve2({ port, release });
17850
17980
  });
17851
17981
  });
17852
17982
  }
17853
- async function reservePortRange(size = PORT_RANGE_SIZE) {
17854
- const held = [await reservePort()];
17855
- const base = held[0].port;
17983
+ async function tryReservePorts(ports) {
17984
+ const held = [];
17985
+ for (const port of ports) {
17986
+ const next = await tryReservePort(port);
17987
+ if (!next) {
17988
+ await Promise.all(held.map((h) => h.release()));
17989
+ return null;
17990
+ }
17991
+ held.push(next);
17992
+ }
17993
+ return held;
17994
+ }
17995
+ function normalizePreferredPorts(ports, size) {
17996
+ if (!ports?.length) return [];
17997
+ const seen = /* @__PURE__ */ new Set();
17998
+ const out = [];
17999
+ for (const p of ports) {
18000
+ if (!Number.isInteger(p) || p <= 0 || p > 65535 || seen.has(p)) continue;
18001
+ seen.add(p);
18002
+ out.push(p);
18003
+ if (out.length >= size) break;
18004
+ }
18005
+ return out;
18006
+ }
18007
+ function delay(ms) {
18008
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
18009
+ }
18010
+ async function fillPortRange(held, size) {
18011
+ if (held.length >= size) return held;
18012
+ const base = held[0]?.port;
18013
+ const taken = new Set(held.map((h) => h.port));
17856
18014
  try {
17857
- for (let i = 1; i < size; i++) {
17858
- const candidate = base + i;
17859
- const next = await tryReservePort(candidate);
18015
+ let offset = 0;
18016
+ while (held.length < size) {
18017
+ const candidate = base != null ? base + offset : null;
18018
+ offset += 1;
18019
+ if (candidate != null && taken.has(candidate)) continue;
18020
+ const next = candidate != null ? await tryReservePort(candidate) : null;
17860
18021
  if (next) {
17861
18022
  held.push(next);
18023
+ taken.add(next.port);
17862
18024
  } else {
17863
- held.push(await reservePort());
18025
+ const ephemeral = await reservePort();
18026
+ held.push(ephemeral);
18027
+ taken.add(ephemeral.port);
17864
18028
  }
17865
18029
  }
17866
18030
  return held;
@@ -17869,6 +18033,49 @@ async function reservePortRange(size = PORT_RANGE_SIZE) {
17869
18033
  throw err;
17870
18034
  }
17871
18035
  }
18036
+ async function tryReserveAvailablePorts(ports) {
18037
+ const held = [];
18038
+ for (const port of ports) {
18039
+ const next = await tryReservePort(port);
18040
+ if (next) held.push(next);
18041
+ }
18042
+ return held;
18043
+ }
18044
+ async function reclaimPreferredPorts(ports, worktreePath) {
18045
+ const primary = ports[0];
18046
+ if (primary == null) return null;
18047
+ const takePrimary = async () => {
18048
+ const held2 = await tryReserveAvailablePorts(ports);
18049
+ if (held2.some((h) => h.port === primary)) return held2;
18050
+ await Promise.all(held2.map((h) => h.release()));
18051
+ return null;
18052
+ };
18053
+ let held = await takePrimary();
18054
+ if (held) return held;
18055
+ if (worktreePath) {
18056
+ killStaleWorktreeListeners(ports, worktreePath, "SIGTERM");
18057
+ } else {
18058
+ killListenersOnPorts(ports);
18059
+ }
18060
+ for (let i = 0; i < RECLAIM_TRIES; i++) {
18061
+ await delay(RECLAIM_RETRY_DELAY_MS);
18062
+ held = await takePrimary();
18063
+ if (held) return held;
18064
+ if (i === 2 && worktreePath) {
18065
+ killStaleWorktreeListeners(ports, worktreePath, "SIGKILL");
18066
+ }
18067
+ }
18068
+ return null;
18069
+ }
18070
+ async function reservePortRange(size = PORT_RANGE_SIZE, opts) {
18071
+ const preferred = normalizePreferredPorts(opts?.preferred, size);
18072
+ if (preferred.length) {
18073
+ const reused = await reclaimPreferredPorts(preferred, opts?.worktreePath);
18074
+ if (reused) return fillPortRange(reused, size);
18075
+ }
18076
+ const held = [await reservePort()];
18077
+ return fillPortRange(held, size);
18078
+ }
17872
18079
  async function allocatePortRange(size = PORT_RANGE_SIZE) {
17873
18080
  const held = await reservePortRange(size);
17874
18081
  const ports = held.map((h) => h.port);
@@ -17878,8 +18085,13 @@ async function allocatePortRange(size = PORT_RANGE_SIZE) {
17878
18085
  async function startDevServer(repoPath, worktreePath, onLine, opts) {
17879
18086
  const script = getRunScript(worktreePath, repoPath, opts?.scriptName);
17880
18087
  if (!script) return null;
17881
- const held = await reservePortRange(PORT_RANGE_SIZE);
18088
+ const preferred = loadWorktreeRunPorts(worktreePath, script.name) ?? opts?.preferredPorts;
18089
+ const held = await reservePortRange(PORT_RANGE_SIZE, {
18090
+ preferred: preferred ?? void 0,
18091
+ worktreePath
18092
+ });
17882
18093
  const ports = held.map((h) => h.port);
18094
+ saveWorktreeRunPorts(worktreePath, script.name, ports);
17883
18095
  try {
17884
18096
  const handle = await spawnWorkspaceScript(script.command, {
17885
18097
  worktreePath,
@@ -17902,14 +18114,14 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
17902
18114
  throw err;
17903
18115
  }
17904
18116
  }
17905
- var import_node_fs44, import_node_child_process5, import_node_net, import_node_path44, import_execa4, import_node_readline3, PORT_RANGE_SIZE, cachedLoginEnv;
18117
+ var import_node_fs45, import_node_child_process5, import_node_net, import_node_path45, import_execa4, import_node_readline3, PORT_RANGE_SIZE, RECLAIM_RETRY_DELAY_MS, RECLAIM_TRIES, cachedLoginEnv;
17906
18118
  var init_conductor = __esm({
17907
18119
  "src/hook/conductor.ts"() {
17908
18120
  "use strict";
17909
- import_node_fs44 = require("fs");
18121
+ import_node_fs45 = require("fs");
17910
18122
  import_node_child_process5 = require("child_process");
17911
18123
  import_node_net = require("net");
17912
- import_node_path44 = require("path");
18124
+ import_node_path45 = require("path");
17913
18125
  import_execa4 = require("execa");
17914
18126
  import_node_readline3 = require("readline");
17915
18127
  init_settings();
@@ -17920,8 +18132,12 @@ var init_conductor = __esm({
17920
18132
  init_git_auth_mode();
17921
18133
  init_request_review();
17922
18134
  init_worktree_exclude();
18135
+ init_worktree_run_ports();
18136
+ init_worktree_run_ports();
17923
18137
  init_nested_electron_env();
17924
18138
  PORT_RANGE_SIZE = 10;
18139
+ RECLAIM_RETRY_DELAY_MS = 40;
18140
+ RECLAIM_TRIES = 8;
17925
18141
  cachedLoginEnv = null;
17926
18142
  }
17927
18143
  });
@@ -17937,9 +18153,9 @@ async function findOrphanWorktrees(repoPaths) {
17937
18153
  repoPaths?.length ? repoPaths : threads.map((t) => t.repoPath).filter(Boolean)
17938
18154
  );
17939
18155
  const homeRoot = sideboardWorkspacesDir();
17940
- if ((0, import_node_fs45.existsSync)(homeRoot)) {
18156
+ if ((0, import_node_fs46.existsSync)(homeRoot)) {
17941
18157
  try {
17942
- for (const entry of (0, import_node_fs45.readdirSync)(homeRoot, { withFileTypes: true })) {
18158
+ for (const entry of (0, import_node_fs46.readdirSync)(homeRoot, { withFileTypes: true })) {
17943
18159
  if (!entry.isDirectory()) continue;
17944
18160
  void entry;
17945
18161
  }
@@ -17949,7 +18165,7 @@ async function findOrphanWorktrees(repoPaths) {
17949
18165
  const orphans = [];
17950
18166
  const seen = /* @__PURE__ */ new Set();
17951
18167
  for (const repoPath of repos) {
17952
- if (!repoPath || !(0, import_node_fs45.existsSync)(repoPath)) continue;
18168
+ if (!repoPath || !(0, import_node_fs46.existsSync)(repoPath)) continue;
17953
18169
  try {
17954
18170
  const wts = await listWorktrees(repoPath);
17955
18171
  for (const wt of wts) {
@@ -17960,7 +18176,7 @@ async function findOrphanWorktrees(repoPaths) {
17960
18176
  seen.add(path2);
17961
18177
  let mtimeMs = 0;
17962
18178
  try {
17963
- mtimeMs = (0, import_node_fs45.statSync)(path2).mtimeMs;
18179
+ mtimeMs = (0, import_node_fs46.statSync)(path2).mtimeMs;
17964
18180
  } catch {
17965
18181
  mtimeMs = 0;
17966
18182
  }
@@ -17970,16 +18186,16 @@ async function findOrphanWorktrees(repoPaths) {
17970
18186
  }
17971
18187
  try {
17972
18188
  const root = worktreesRoot(repoPath);
17973
- if ((0, import_node_fs45.existsSync)(root)) {
17974
- for (const entry of (0, import_node_fs45.readdirSync)(root, { withFileTypes: true })) {
18189
+ if ((0, import_node_fs46.existsSync)(root)) {
18190
+ for (const entry of (0, import_node_fs46.readdirSync)(root, { withFileTypes: true })) {
17975
18191
  if (!entry.isDirectory()) continue;
17976
- const path2 = (0, import_node_path45.join)(root, entry.name).replace(/\/$/, "");
18192
+ const path2 = (0, import_node_path46.join)(root, entry.name).replace(/\/$/, "");
17977
18193
  if (known.has(path2) || seen.has(path2)) continue;
17978
- if (!(0, import_node_fs45.existsSync)((0, import_node_path45.join)(path2, ".git"))) continue;
18194
+ if (!(0, import_node_fs46.existsSync)((0, import_node_path46.join)(path2, ".git"))) continue;
17979
18195
  seen.add(path2);
17980
18196
  let mtimeMs = 0;
17981
18197
  try {
17982
- mtimeMs = (0, import_node_fs45.statSync)(path2).mtimeMs;
18198
+ mtimeMs = (0, import_node_fs46.statSync)(path2).mtimeMs;
17983
18199
  } catch {
17984
18200
  mtimeMs = Date.now();
17985
18201
  }
@@ -18040,12 +18256,12 @@ function worktreeCleanupSettings() {
18040
18256
  autoCleanupOrphans: a.autoCleanupOrphans
18041
18257
  };
18042
18258
  }
18043
- var import_node_fs45, import_node_path45;
18259
+ var import_node_fs46, import_node_path46;
18044
18260
  var init_orphan_cleanup = __esm({
18045
18261
  "src/git/orphan-cleanup.ts"() {
18046
18262
  "use strict";
18047
- import_node_fs45 = require("fs");
18048
- import_node_path45 = require("path");
18263
+ import_node_fs46 = require("fs");
18264
+ import_node_path46 = require("path");
18049
18265
  init_worktree();
18050
18266
  init_thread_store();
18051
18267
  init_paths();
@@ -18220,12 +18436,12 @@ async function cloneRepoIntoSideboard(opts) {
18220
18436
  if (!url) throw new Error("Clone URL is required");
18221
18437
  let name = opts.name?.trim();
18222
18438
  if (!name) {
18223
- const leaf = (0, import_node_path46.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
18439
+ const leaf = (0, import_node_path47.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
18224
18440
  name = leaf || "repo";
18225
18441
  }
18226
18442
  name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
18227
- const dest = (0, import_node_path46.join)(sideboardReposDir(), name);
18228
- if ((0, import_node_fs46.existsSync)(dest)) {
18443
+ const dest = (0, import_node_path47.join)(sideboardReposDir(), name);
18444
+ if ((0, import_node_fs47.existsSync)(dest)) {
18229
18445
  const repoPath2 = await resolveRepoRoot(dest);
18230
18446
  const workspace2 = await ensureWorkspace(repoPath2);
18231
18447
  return { repoPath: repoPath2, workspace: workspace2 };
@@ -18240,12 +18456,12 @@ async function cloneRepoIntoSideboard(opts) {
18240
18456
  const workspace = await ensureWorkspace(repoPath);
18241
18457
  return { repoPath, workspace };
18242
18458
  }
18243
- var import_node_fs46, import_node_path46, import_execa6;
18459
+ var import_node_fs47, import_node_path47, import_execa6;
18244
18460
  var init_clone_repo = __esm({
18245
18461
  "src/git/clone-repo.ts"() {
18246
18462
  "use strict";
18247
- import_node_fs46 = require("fs");
18248
- import_node_path46 = require("path");
18463
+ import_node_fs47 = require("fs");
18464
+ import_node_path47 = require("path");
18249
18465
  import_execa6 = require("execa");
18250
18466
  init_paths();
18251
18467
  init_workspaces();
@@ -18374,24 +18590,24 @@ function jobTreeAlive(pid) {
18374
18590
  return jobAlive(pid) || processGroupAlive(pid);
18375
18591
  }
18376
18592
  function readIntFile(file) {
18377
- if (!(0, import_node_fs47.existsSync)(file)) return null;
18378
- const n = Number.parseInt((0, import_node_fs47.readFileSync)(file, "utf8").trim(), 10);
18593
+ if (!(0, import_node_fs48.existsSync)(file)) return null;
18594
+ const n = Number.parseInt((0, import_node_fs48.readFileSync)(file, "utf8").trim(), 10);
18379
18595
  return Number.isInteger(n) ? n : null;
18380
18596
  }
18381
18597
  function jobDir(root, id, legacy = false) {
18382
- return (0, import_node_path47.join)(root, legacy ? LEGACY_DETACHED_JOBS_DIR : DETACHED_JOBS_DIR, id);
18598
+ return (0, import_node_path48.join)(root, legacy ? LEGACY_DETACHED_JOBS_DIR : DETACHED_JOBS_DIR, id);
18383
18599
  }
18384
18600
  function resolveJobDir(root, id) {
18385
18601
  const modern = jobDir(root, id, false);
18386
- if ((0, import_node_fs47.existsSync)(modern)) return modern;
18602
+ if ((0, import_node_fs48.existsSync)(modern)) return modern;
18387
18603
  const legacy = jobDir(root, id, true);
18388
- if ((0, import_node_fs47.existsSync)(legacy)) return legacy;
18604
+ if ((0, import_node_fs48.existsSync)(legacy)) return legacy;
18389
18605
  return modern;
18390
18606
  }
18391
18607
  function listJobIdsIn(root, rel) {
18392
- const dir = (0, import_node_path47.join)(root, rel);
18393
- if (!(0, import_node_fs47.existsSync)(dir)) return [];
18394
- return (0, import_node_fs47.readdirSync)(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && JOB_ID_RE.test(e.name)).map((e) => e.name);
18608
+ const dir = (0, import_node_path48.join)(root, rel);
18609
+ if (!(0, import_node_fs48.existsSync)(dir)) return [];
18610
+ return (0, import_node_fs48.readdirSync)(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && JOB_ID_RE.test(e.name)).map((e) => e.name);
18395
18611
  }
18396
18612
  function listRunningDetachedJobs(worktreePath) {
18397
18613
  const root = worktreePath.trim();
@@ -18403,7 +18619,7 @@ function listRunningDetachedJobs(worktreePath) {
18403
18619
  const running = [];
18404
18620
  for (const id of ids) {
18405
18621
  const dir = resolveJobDir(root, id);
18406
- const pid = readIntFile((0, import_node_path47.join)(dir, "pid"));
18622
+ const pid = readIntFile((0, import_node_path48.join)(dir, "pid"));
18407
18623
  if (jobTreeAlive(pid)) running.push(id);
18408
18624
  }
18409
18625
  return running.sort();
@@ -18486,8 +18702,8 @@ function planJobContinue(opts) {
18486
18702
  return { action: "none" };
18487
18703
  }
18488
18704
  function tailProgress(logFile, maxLines = 12) {
18489
- if (!(0, import_node_fs47.existsSync)(logFile)) return "(no log yet)";
18490
- const lines = (0, import_node_fs47.readFileSync)(logFile, "utf8").split("\n");
18705
+ if (!(0, import_node_fs48.existsSync)(logFile)) return "(no log yet)";
18706
+ const lines = (0, import_node_fs48.readFileSync)(logFile, "utf8").split("\n");
18491
18707
  return lines.slice(-maxLines).join("\n");
18492
18708
  }
18493
18709
  function lastProgressLine(progress) {
@@ -18495,8 +18711,8 @@ function lastProgressLine(progress) {
18495
18711
  return last ? last.slice(0, 72) : void 0;
18496
18712
  }
18497
18713
  function readLogLines(file) {
18498
- if (!(0, import_node_fs47.existsSync)(file)) return [];
18499
- const lines = (0, import_node_fs47.readFileSync)(file, "utf8").split("\n");
18714
+ if (!(0, import_node_fs48.existsSync)(file)) return [];
18715
+ const lines = (0, import_node_fs48.readFileSync)(file, "utf8").split("\n");
18500
18716
  if (lines.length && lines[lines.length - 1] === "") lines.pop();
18501
18717
  return lines;
18502
18718
  }
@@ -18507,15 +18723,15 @@ function takeDelta(logFile, cursorFile) {
18507
18723
  return { delta: capJobLogDelta(lines.slice(start).join("\n")), nextCursor: lines.length };
18508
18724
  }
18509
18725
  function snapshotJob(dir) {
18510
- const pid = readIntFile((0, import_node_path47.join)(dir, "pid"));
18726
+ const pid = readIntFile((0, import_node_path48.join)(dir, "pid"));
18511
18727
  const running = jobTreeAlive(pid);
18512
18728
  return {
18513
18729
  pid,
18514
18730
  running,
18515
- exitCode: readIntFile((0, import_node_path47.join)(dir, "exit")),
18516
- log: (0, import_node_path47.join)(dir, "log"),
18517
- cursor: (0, import_node_path47.join)(dir, "present.cursor"),
18518
- progress: tailProgress((0, import_node_path47.join)(dir, "log"))
18731
+ exitCode: readIntFile((0, import_node_path48.join)(dir, "exit")),
18732
+ log: (0, import_node_path48.join)(dir, "log"),
18733
+ cursor: (0, import_node_path48.join)(dir, "present.cursor"),
18734
+ progress: tailProgress((0, import_node_path48.join)(dir, "log"))
18519
18735
  };
18520
18736
  }
18521
18737
  function toResult(id, snap, extra) {
@@ -18524,8 +18740,8 @@ function toResult(id, snap, extra) {
18524
18740
  const stillRunning = snap.running && !ok;
18525
18741
  const { delta, nextCursor } = takeDelta(snap.log, snap.cursor);
18526
18742
  try {
18527
- (0, import_node_fs47.mkdirSync)((0, import_node_path47.dirname)(snap.cursor), { recursive: true });
18528
- (0, import_node_fs47.writeFileSync)(snap.cursor, `${nextCursor}
18743
+ (0, import_node_fs48.mkdirSync)((0, import_node_path48.dirname)(snap.cursor), { recursive: true });
18744
+ (0, import_node_fs48.writeFileSync)(snap.cursor, `${nextCursor}
18529
18745
  `);
18530
18746
  } catch {
18531
18747
  }
@@ -18546,7 +18762,7 @@ function toResult(id, snap, extra) {
18546
18762
  };
18547
18763
  }
18548
18764
  async function sleepMs(ms) {
18549
- await new Promise((resolve) => setTimeout(resolve, ms));
18765
+ await new Promise((resolve2) => setTimeout(resolve2, ms));
18550
18766
  }
18551
18767
  async function waitForDetachedJob(cwd, id, opts) {
18552
18768
  const jobId = sanitizeDetachedJobId(id);
@@ -18554,7 +18770,7 @@ async function waitForDetachedJob(cwd, id, opts) {
18554
18770
  const dir = resolveJobDir(root, jobId);
18555
18771
  const timeoutMs = mcpWaitForJobTimeoutMs(opts?.timeoutMs);
18556
18772
  const sleep2 = opts?.sleep ?? sleepMs;
18557
- if (!(0, import_node_fs47.existsSync)(dir)) {
18773
+ if (!(0, import_node_fs48.existsSync)(dir)) {
18558
18774
  return {
18559
18775
  stillRunning: false,
18560
18776
  ok: false,
@@ -18600,10 +18816,10 @@ function killProcessTree(pid, signal) {
18600
18816
  }
18601
18817
  function appendJobLog(logFile, line) {
18602
18818
  try {
18603
- (0, import_node_fs47.mkdirSync)((0, import_node_path47.dirname)(logFile), { recursive: true });
18819
+ (0, import_node_fs48.mkdirSync)((0, import_node_path48.dirname)(logFile), { recursive: true });
18604
18820
  const body = line.endsWith("\n") ? line : `${line}
18605
18821
  `;
18606
- (0, import_node_fs47.appendFileSync)(logFile, body);
18822
+ (0, import_node_fs48.appendFileSync)(logFile, body);
18607
18823
  } catch {
18608
18824
  }
18609
18825
  }
@@ -18613,7 +18829,7 @@ async function stopDetachedJob(cwd, id, opts) {
18613
18829
  const dir = resolveJobDir(root, jobId);
18614
18830
  const sleep2 = opts?.sleep ?? sleepMs;
18615
18831
  const why = opts?.reason?.trim() ?? "";
18616
- if (!(0, import_node_fs47.existsSync)(dir)) {
18832
+ if (!(0, import_node_fs48.existsSync)(dir)) {
18617
18833
  return {
18618
18834
  stillRunning: false,
18619
18835
  ok: false,
@@ -18649,10 +18865,10 @@ async function stopDetachedJob(cwd, id, opts) {
18649
18865
  killProcessTree(targetPid, "SIGKILL");
18650
18866
  await sleep2(100);
18651
18867
  }
18652
- const exitFile = (0, import_node_path47.join)(dir, "exit");
18653
- if (!(0, import_node_fs47.existsSync)(exitFile)) {
18868
+ const exitFile = (0, import_node_path48.join)(dir, "exit");
18869
+ if (!(0, import_node_fs48.existsSync)(exitFile)) {
18654
18870
  try {
18655
- (0, import_node_fs47.writeFileSync)(exitFile, "1\n");
18871
+ (0, import_node_fs48.writeFileSync)(exitFile, "1\n");
18656
18872
  } catch {
18657
18873
  }
18658
18874
  }
@@ -18672,12 +18888,12 @@ async function stopDetachedJob(cwd, id, opts) {
18672
18888
  hint: stopped ? MCP_STOP_JOB_HINT : MCP_WAIT_JOB_STILL_RUNNING_HINT
18673
18889
  };
18674
18890
  }
18675
- var import_node_fs47, import_node_path47, MAX_JOB_CONTINUES, MAX_JOB_DELTA_LINES, MAX_JOB_DELTA_CHARS, DEFERRED_DONE_MAX_CHARS, GH_WATCH_REFRESH, MCP_WAIT_JOB_STILL_RUNNING_HINT, MCP_STOP_JOB_HINT, JOB_ID_RE;
18891
+ var import_node_fs48, import_node_path48, MAX_JOB_CONTINUES, MAX_JOB_DELTA_LINES, MAX_JOB_DELTA_CHARS, DEFERRED_DONE_MAX_CHARS, GH_WATCH_REFRESH, MCP_WAIT_JOB_STILL_RUNNING_HINT, MCP_STOP_JOB_HINT, JOB_ID_RE;
18676
18892
  var init_wait_for_job = __esm({
18677
18893
  "src/mcp/wait-for-job.ts"() {
18678
18894
  "use strict";
18679
- import_node_fs47 = require("fs");
18680
- import_node_path47 = require("path");
18895
+ import_node_fs48 = require("fs");
18896
+ import_node_path48 = require("path");
18681
18897
  init_workspace_scratch();
18682
18898
  init_wait_for_turn();
18683
18899
  MAX_JOB_CONTINUES = 8;
@@ -18922,14 +19138,14 @@ async function startAbleTimeOAuth(opts) {
18922
19138
  const pkce = createAbleTimePkce();
18923
19139
  const authorizeUrl = ableTimeOAuthAuthorizeUrl(clientId, state, pkce.challenge, host);
18924
19140
  const timeoutMs = opts?.timeoutMs ?? 5 * 6e4;
18925
- const code = await new Promise((resolve, reject) => {
19141
+ const code = await new Promise((resolve2, reject) => {
18926
19142
  let settled = false;
18927
19143
  const finish = (err, value) => {
18928
19144
  if (settled) return;
18929
19145
  settled = true;
18930
19146
  cleanup();
18931
19147
  if (err) reject(err);
18932
- else resolve(value);
19148
+ else resolve2(value);
18933
19149
  };
18934
19150
  const server = (0, import_node_http.createServer)((req, res) => {
18935
19151
  try {
@@ -20222,7 +20438,7 @@ function reuseLiveThread(input, repoPath, match) {
20222
20438
  }
20223
20439
  async function createThread(input, _onSetupLine) {
20224
20440
  const repoPath = await resolveRepoRoot(input.repoPath);
20225
- if (!(0, import_node_fs48.existsSync)(repoPath)) {
20441
+ if (!(0, import_node_fs49.existsSync)(repoPath)) {
20226
20442
  throw new Error(`Repo not found: ${repoPath}`);
20227
20443
  }
20228
20444
  const reused = reuseLiveThread(input, repoPath, {
@@ -20407,11 +20623,11 @@ async function listLinearIssues(agent, repoPath) {
20407
20623
  }
20408
20624
  return adapter.listLinearIssues(repoPath);
20409
20625
  }
20410
- var import_node_fs48;
20626
+ var import_node_fs49;
20411
20627
  var init_create = __esm({
20412
20628
  "src/threads/create.ts"() {
20413
20629
  "use strict";
20414
- import_node_fs48 = require("fs");
20630
+ import_node_fs49 = require("fs");
20415
20631
  init_detect();
20416
20632
  init_worktree();
20417
20633
  init_home_board();
@@ -20563,20 +20779,20 @@ function writeTurnLive(threadId, progress) {
20563
20779
  const path2 = threadLivePath(threadId);
20564
20780
  const tmp = `${path2}.${process.pid}.tmp`;
20565
20781
  try {
20566
- (0, import_node_fs49.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
20567
- (0, import_node_fs49.renameSync)(tmp, path2);
20782
+ (0, import_node_fs50.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
20783
+ (0, import_node_fs50.renameSync)(tmp, path2);
20568
20784
  } catch {
20569
20785
  try {
20570
- (0, import_node_fs49.unlinkSync)(tmp);
20786
+ (0, import_node_fs50.unlinkSync)(tmp);
20571
20787
  } catch {
20572
20788
  }
20573
20789
  }
20574
20790
  }
20575
20791
  function readTurnLive(threadId) {
20576
20792
  const path2 = threadLivePath(threadId);
20577
- if (!(0, import_node_fs49.existsSync)(path2)) return null;
20793
+ if (!(0, import_node_fs50.existsSync)(path2)) return null;
20578
20794
  try {
20579
- const raw = JSON.parse((0, import_node_fs49.readFileSync)(path2, "utf8"));
20795
+ const raw = JSON.parse((0, import_node_fs50.readFileSync)(path2, "utf8"));
20580
20796
  if (!raw || typeof raw.summary !== "string") return null;
20581
20797
  return raw;
20582
20798
  } catch {
@@ -20588,17 +20804,17 @@ function clearTurnLive(threadId) {
20588
20804
  if (buf?.timer) clearTimeout(buf.timer);
20589
20805
  buffers.delete(threadId);
20590
20806
  const path2 = threadLivePath(threadId);
20591
- if (!(0, import_node_fs49.existsSync)(path2)) return;
20807
+ if (!(0, import_node_fs50.existsSync)(path2)) return;
20592
20808
  try {
20593
- (0, import_node_fs49.unlinkSync)(path2);
20809
+ (0, import_node_fs50.unlinkSync)(path2);
20594
20810
  } catch {
20595
20811
  }
20596
20812
  }
20597
- var import_node_fs49, buffers, FLUSH_MS, MAX_PARTS;
20813
+ var import_node_fs50, buffers, FLUSH_MS, MAX_PARTS;
20598
20814
  var init_turn_live = __esm({
20599
20815
  "src/store/turn-live.ts"() {
20600
20816
  "use strict";
20601
- import_node_fs49 = require("fs");
20817
+ import_node_fs50 = require("fs");
20602
20818
  init_message_parts();
20603
20819
  init_paths();
20604
20820
  buffers = /* @__PURE__ */ new Map();
@@ -20842,7 +21058,7 @@ var init_quota_failover = __esm({
20842
21058
  // src/threads/adopt.ts
20843
21059
  function thisModuleFile2() {
20844
21060
  const cjsFile = typeof __filename !== "undefined" ? __filename : "";
20845
- return cjsFile || process.argv[1] || (0, import_node_path48.join)(process.cwd(), "package.json");
21061
+ return cjsFile || process.argv[1] || (0, import_node_path49.join)(process.cwd(), "package.json");
20846
21062
  }
20847
21063
  function openReadonlySqlite(file) {
20848
21064
  const req = (0, import_node_module5.createRequire)(thisModuleFile2());
@@ -20860,21 +21076,21 @@ function mapAgentType(raw) {
20860
21076
  return null;
20861
21077
  }
20862
21078
  function resolveConductorCursorAgentId(workspacePath) {
20863
- if (!workspacePath || !(0, import_node_fs50.existsSync)(CURSOR_SDK_STORE)) return null;
21079
+ if (!workspacePath || !(0, import_node_fs51.existsSync)(CURSOR_SDK_STORE)) return null;
20864
21080
  const normalized = workspacePath.replace(/\/$/, "");
20865
21081
  let best = null;
20866
21082
  let hashes;
20867
21083
  try {
20868
- hashes = (0, import_node_fs50.readdirSync)(CURSOR_SDK_STORE);
21084
+ hashes = (0, import_node_fs51.readdirSync)(CURSOR_SDK_STORE);
20869
21085
  } catch {
20870
21086
  return null;
20871
21087
  }
20872
21088
  for (const hash of hashes) {
20873
- const agentsFile = (0, import_node_path48.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
20874
- if (!(0, import_node_fs50.existsSync)(agentsFile)) continue;
21089
+ const agentsFile = (0, import_node_path49.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
21090
+ if (!(0, import_node_fs51.existsSync)(agentsFile)) continue;
20875
21091
  let text7;
20876
21092
  try {
20877
- text7 = (0, import_node_fs50.readFileSync)(agentsFile, "utf8");
21093
+ text7 = (0, import_node_fs51.readFileSync)(agentsFile, "utf8");
20878
21094
  } catch {
20879
21095
  continue;
20880
21096
  }
@@ -20898,7 +21114,7 @@ function resolveConductorCursorAgentId(workspacePath) {
20898
21114
  return best?.agentId ?? null;
20899
21115
  }
20900
21116
  async function adoptThread(input) {
20901
- if (!(0, import_node_fs50.existsSync)(input.worktreePath)) {
21117
+ if (!(0, import_node_fs51.existsSync)(input.worktreePath)) {
20902
21118
  throw new Error(`Worktree not found: ${input.worktreePath}`);
20903
21119
  }
20904
21120
  const repoPath = await resolveRepoRoot(input.worktreePath);
@@ -20927,18 +21143,18 @@ function conductorDbPath() {
20927
21143
  return CONDUCTOR_DB;
20928
21144
  }
20929
21145
  function listConductorWorkspaces() {
20930
- if (!(0, import_node_fs50.existsSync)(CONDUCTOR_DB)) {
21146
+ if (!(0, import_node_fs51.existsSync)(CONDUCTOR_DB)) {
20931
21147
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
20932
21148
  }
20933
- const tmp = (0, import_node_fs50.mkdtempSync)((0, import_node_path48.join)((0, import_node_os14.tmpdir)(), "sideboard-conductor-"));
20934
- const snapshot = (0, import_node_path48.join)(tmp, "conductor.db");
21149
+ const tmp = (0, import_node_fs51.mkdtempSync)((0, import_node_path49.join)((0, import_node_os14.tmpdir)(), "sideboard-conductor-"));
21150
+ const snapshot = (0, import_node_path49.join)(tmp, "conductor.db");
20935
21151
  try {
20936
- (0, import_node_fs50.copyFileSync)(CONDUCTOR_DB, snapshot);
21152
+ (0, import_node_fs51.copyFileSync)(CONDUCTOR_DB, snapshot);
20937
21153
  for (const suffix of ["-wal", "-shm"]) {
20938
21154
  const src = `${CONDUCTOR_DB}${suffix}`;
20939
- if ((0, import_node_fs50.existsSync)(src)) {
21155
+ if ((0, import_node_fs51.existsSync)(src)) {
20940
21156
  try {
20941
- (0, import_node_fs50.copyFileSync)(src, `${snapshot}${suffix}`);
21157
+ (0, import_node_fs51.copyFileSync)(src, `${snapshot}${suffix}`);
20942
21158
  } catch {
20943
21159
  }
20944
21160
  }
@@ -21014,22 +21230,22 @@ function listConductorWorkspaces() {
21014
21230
  db.close();
21015
21231
  }
21016
21232
  } finally {
21017
- (0, import_node_fs50.rmSync)(tmp, { recursive: true, force: true });
21233
+ (0, import_node_fs51.rmSync)(tmp, { recursive: true, force: true });
21018
21234
  }
21019
21235
  }
21020
21236
  function importConductorWorkspace(workspaceId) {
21021
- if (!(0, import_node_fs50.existsSync)(CONDUCTOR_DB)) {
21237
+ if (!(0, import_node_fs51.existsSync)(CONDUCTOR_DB)) {
21022
21238
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
21023
21239
  }
21024
- const tmp = (0, import_node_fs50.mkdtempSync)((0, import_node_path48.join)((0, import_node_os14.tmpdir)(), "sideboard-conductor-"));
21025
- const snapshot = (0, import_node_path48.join)(tmp, "conductor.db");
21240
+ const tmp = (0, import_node_fs51.mkdtempSync)((0, import_node_path49.join)((0, import_node_os14.tmpdir)(), "sideboard-conductor-"));
21241
+ const snapshot = (0, import_node_path49.join)(tmp, "conductor.db");
21026
21242
  try {
21027
- (0, import_node_fs50.copyFileSync)(CONDUCTOR_DB, snapshot);
21243
+ (0, import_node_fs51.copyFileSync)(CONDUCTOR_DB, snapshot);
21028
21244
  for (const suffix of ["-wal", "-shm"]) {
21029
21245
  const src = `${CONDUCTOR_DB}${suffix}`;
21030
- if ((0, import_node_fs50.existsSync)(src)) {
21246
+ if ((0, import_node_fs51.existsSync)(src)) {
21031
21247
  try {
21032
- (0, import_node_fs50.copyFileSync)(src, `${snapshot}${suffix}`);
21248
+ (0, import_node_fs51.copyFileSync)(src, `${snapshot}${suffix}`);
21033
21249
  } catch {
21034
21250
  }
21035
21251
  }
@@ -21047,7 +21263,7 @@ function importConductorWorkspace(workspaceId) {
21047
21263
  ).get(workspaceId);
21048
21264
  if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
21049
21265
  const worktreePath = String(row.workspacePath);
21050
- if (!(0, import_node_fs50.existsSync)(worktreePath)) {
21266
+ if (!(0, import_node_fs51.existsSync)(worktreePath)) {
21051
21267
  throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
21052
21268
  }
21053
21269
  let sessionId = null;
@@ -21110,31 +21326,31 @@ function importConductorWorkspace(workspaceId) {
21110
21326
  db.close();
21111
21327
  }
21112
21328
  } finally {
21113
- (0, import_node_fs50.rmSync)(tmp, { recursive: true, force: true });
21329
+ (0, import_node_fs51.rmSync)(tmp, { recursive: true, force: true });
21114
21330
  }
21115
21331
  }
21116
21332
  async function importConductorWorkspaceAsync(workspaceId) {
21117
21333
  return importConductorWorkspace(workspaceId);
21118
21334
  }
21119
- var import_node_child_process6, import_node_fs50, import_node_os14, import_node_path48, import_node_module5, CONDUCTOR_APP_SUPPORT, CONDUCTOR_DB, CURSOR_SDK_STORE;
21335
+ var import_node_child_process6, import_node_fs51, import_node_os14, import_node_path49, import_node_module5, CONDUCTOR_APP_SUPPORT, CONDUCTOR_DB, CURSOR_SDK_STORE;
21120
21336
  var init_adopt = __esm({
21121
21337
  "src/threads/adopt.ts"() {
21122
21338
  "use strict";
21123
21339
  import_node_child_process6 = require("child_process");
21124
- import_node_fs50 = require("fs");
21340
+ import_node_fs51 = require("fs");
21125
21341
  import_node_os14 = require("os");
21126
- import_node_path48 = require("path");
21342
+ import_node_path49 = require("path");
21127
21343
  import_node_module5 = require("module");
21128
21344
  init_worktree();
21129
21345
  init_thread_store();
21130
- CONDUCTOR_APP_SUPPORT = (0, import_node_path48.join)(
21346
+ CONDUCTOR_APP_SUPPORT = (0, import_node_path49.join)(
21131
21347
  process.env.HOME ?? "",
21132
21348
  "Library",
21133
21349
  "Application Support",
21134
21350
  "com.conductor.app"
21135
21351
  );
21136
- CONDUCTOR_DB = (0, import_node_path48.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
21137
- CURSOR_SDK_STORE = (0, import_node_path48.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
21352
+ CONDUCTOR_DB = (0, import_node_path49.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
21353
+ CURSOR_SDK_STORE = (0, import_node_path49.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
21138
21354
  }
21139
21355
  });
21140
21356
 
@@ -21201,7 +21417,7 @@ async function openStackLayer(input, _onSetupLine) {
21201
21417
  let createdWorktree = false;
21202
21418
  const trees = await listWorktrees(repoPath);
21203
21419
  const checkedOut = trees.find((w) => w.branch === branchName);
21204
- if (checkedOut?.path && (0, import_node_fs51.existsSync)(checkedOut.path)) {
21420
+ if (checkedOut?.path && (0, import_node_fs52.existsSync)(checkedOut.path)) {
21205
21421
  if (input.reuseExistingWorktree !== false) {
21206
21422
  worktreePath = checkedOut.path;
21207
21423
  } else {
@@ -21343,7 +21559,7 @@ async function initStackFromThread(input, onSetupLine) {
21343
21559
  async function createPrStack(input, onSetupLine) {
21344
21560
  await requireAgent(input.agent);
21345
21561
  const repoPath = await resolveRepoRoot(input.repoPath);
21346
- if (!(0, import_node_fs51.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
21562
+ if (!(0, import_node_fs52.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
21347
21563
  if (!input.branches.length) throw new Error("At least one branch name required");
21348
21564
  const status = await detectGhStack(repoPath);
21349
21565
  if (!status.available) throw new Error(status.reason);
@@ -21410,7 +21626,7 @@ async function createPrStack(input, onSetupLine) {
21410
21626
  }
21411
21627
  }
21412
21628
  const claimed = new Set(threads.map((t) => t.worktreePath));
21413
- if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs51.existsSync)(bootstrap.worktreePath)) {
21629
+ if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs52.existsSync)(bootstrap.worktreePath)) {
21414
21630
  try {
21415
21631
  await removeWorktree(repoPath, bootstrap.worktreePath, {
21416
21632
  deleteBranch: bootstrap.branchName
@@ -21430,11 +21646,11 @@ function stackAgentDefaultsFrom(input) {
21430
21646
  planMode: input.planMode
21431
21647
  };
21432
21648
  }
21433
- var import_node_fs51;
21649
+ var import_node_fs52;
21434
21650
  var init_stack_layers = __esm({
21435
21651
  "src/threads/stack-layers.ts"() {
21436
21652
  "use strict";
21437
- import_node_fs51 = require("fs");
21653
+ import_node_fs52 = require("fs");
21438
21654
  init_detect();
21439
21655
  init_run();
21440
21656
  init_stack();
@@ -21447,7 +21663,7 @@ var init_stack_layers = __esm({
21447
21663
 
21448
21664
  // src/diff/diff.ts
21449
21665
  async function inspectGitWorktree(worktreePath) {
21450
- if (!worktreePath || !(0, import_node_fs52.existsSync)(worktreePath)) return "missing_worktree";
21666
+ if (!worktreePath || !(0, import_node_fs53.existsSync)(worktreePath)) return "missing_worktree";
21451
21667
  const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
21452
21668
  reject: false
21453
21669
  });
@@ -21455,7 +21671,7 @@ async function inspectGitWorktree(worktreePath) {
21455
21671
  return "ok";
21456
21672
  }
21457
21673
  async function initializeGitRepository(worktreePath) {
21458
- if (!worktreePath || !(0, import_node_fs52.existsSync)(worktreePath)) {
21674
+ if (!worktreePath || !(0, import_node_fs53.existsSync)(worktreePath)) {
21459
21675
  throw new Error("Worktree not found");
21460
21676
  }
21461
21677
  const status = await inspectGitWorktree(worktreePath);
@@ -21589,11 +21805,11 @@ new file mode 100644
21589
21805
  };
21590
21806
  }
21591
21807
  async function untrackedPatch(worktreePath, path2, maxHunk) {
21592
- const abs = (0, import_node_path49.join)(worktreePath, path2);
21808
+ const abs = (0, import_node_path50.join)(worktreePath, path2);
21593
21809
  try {
21594
- const st = (0, import_node_fs52.statSync)(abs);
21810
+ const st = (0, import_node_fs53.statSync)(abs);
21595
21811
  if (st.isFile() && st.size > maxHunk) {
21596
- const buf = (0, import_node_fs52.readFileSync)(abs).subarray(0, maxHunk);
21812
+ const buf = (0, import_node_fs53.readFileSync)(abs).subarray(0, maxHunk);
21597
21813
  return syntheticAddPatch(path2, buf.toString("utf8"), maxHunk);
21598
21814
  }
21599
21815
  } catch {
@@ -22060,9 +22276,9 @@ async function getDiff(worktreePath, repoPath, opts) {
22060
22276
  }
22061
22277
  function statWorktreePath(worktreePath, relativePath) {
22062
22278
  assertSafeRelativePath(relativePath);
22063
- const abs = (0, import_node_path49.join)(worktreePath, relativePath);
22064
- if (!(0, import_node_fs52.existsSync)(abs)) return "missing";
22065
- const st = (0, import_node_fs52.statSync)(abs);
22279
+ const abs = (0, import_node_path50.join)(worktreePath, relativePath);
22280
+ if (!(0, import_node_fs53.existsSync)(abs)) return "missing";
22281
+ const st = (0, import_node_fs53.statSync)(abs);
22066
22282
  if (st.isDirectory()) return "dir";
22067
22283
  if (st.isFile()) return "file";
22068
22284
  return "missing";
@@ -22091,8 +22307,8 @@ function isImageRelativePath(relativePath) {
22091
22307
  function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
22092
22308
  assertSafeRelativePath(relativePath);
22093
22309
  const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
22094
- const abs = (0, import_node_path49.join)(worktreePath, relativePath);
22095
- const st = (0, import_node_fs52.statSync)(abs);
22310
+ const abs = (0, import_node_path50.join)(worktreePath, relativePath);
22311
+ const st = (0, import_node_fs53.statSync)(abs);
22096
22312
  if (!st.isFile()) {
22097
22313
  throw new Error(`Not a file: ${relativePath}`);
22098
22314
  }
@@ -22101,7 +22317,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
22101
22317
  `File too large to upload (${st.size} bytes; max ${maxBytes})`
22102
22318
  );
22103
22319
  }
22104
- const buf = (0, import_node_fs52.readFileSync)(abs);
22320
+ const buf = (0, import_node_fs53.readFileSync)(abs);
22105
22321
  return {
22106
22322
  path: relativePath,
22107
22323
  contentBase64: buf.toString("base64"),
@@ -22111,12 +22327,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
22111
22327
  function readWorktreeFile(worktreePath, relativePath, opts) {
22112
22328
  assertSafeRelativePath(relativePath);
22113
22329
  const maxBytes = opts?.maxBytes ?? 2e5;
22114
- const abs = (0, import_node_path49.join)(worktreePath, relativePath);
22115
- const st = (0, import_node_fs52.statSync)(abs);
22330
+ const abs = (0, import_node_path50.join)(worktreePath, relativePath);
22331
+ const st = (0, import_node_fs53.statSync)(abs);
22116
22332
  if (!st.isFile()) {
22117
22333
  throw new Error(`Not a file: ${relativePath}`);
22118
22334
  }
22119
- const buf = (0, import_node_fs52.readFileSync)(abs);
22335
+ const buf = (0, import_node_fs53.readFileSync)(abs);
22120
22336
  if (isImageRelativePath(relativePath)) {
22121
22337
  const maxImageBytes = Math.max(maxBytes, 15e6);
22122
22338
  const truncated2 = buf.length > maxImageBytes;
@@ -22159,9 +22375,9 @@ function assertSafeRelativePath(relativePath) {
22159
22375
  }
22160
22376
  function writeWorktreeFile(worktreePath, relativePath, content) {
22161
22377
  assertSafeRelativePath(relativePath);
22162
- const abs = (0, import_node_path49.join)(worktreePath, relativePath);
22163
- (0, import_node_fs52.mkdirSync)((0, import_node_path49.dirname)(abs), { recursive: true });
22164
- (0, import_node_fs52.writeFileSync)(abs, content, "utf8");
22378
+ const abs = (0, import_node_path50.join)(worktreePath, relativePath);
22379
+ (0, import_node_fs53.mkdirSync)((0, import_node_path50.dirname)(abs), { recursive: true });
22380
+ (0, import_node_fs53.writeFileSync)(abs, content, "utf8");
22165
22381
  return { path: relativePath };
22166
22382
  }
22167
22383
  async function getWorktreeDirtyStat(worktreePath) {
@@ -22201,12 +22417,12 @@ async function getDiffSummary(worktreePath, repoPath, opts) {
22201
22417
  truncated: full.files.length > maxFiles
22202
22418
  };
22203
22419
  }
22204
- var import_node_fs52, import_node_path49, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS2, DEFAULT_UPLOAD_MAX_BYTES;
22420
+ var import_node_fs53, import_node_path50, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS2, DEFAULT_UPLOAD_MAX_BYTES;
22205
22421
  var init_diff = __esm({
22206
22422
  "src/diff/diff.ts"() {
22207
22423
  "use strict";
22208
- import_node_fs52 = require("fs");
22209
- import_node_path49 = require("path");
22424
+ import_node_fs53 = require("fs");
22425
+ import_node_path50 = require("path");
22210
22426
  init_run();
22211
22427
  init_worktree();
22212
22428
  mergeBaseCache = /* @__PURE__ */ new Map();
@@ -22563,7 +22779,7 @@ function parseFrontmatter(content) {
22563
22779
  }
22564
22780
  function readSkill(skillMd, source) {
22565
22781
  try {
22566
- const content = (0, import_node_fs53.readFileSync)(skillMd, "utf8");
22782
+ const content = (0, import_node_fs54.readFileSync)(skillMd, "utf8");
22567
22783
  const { name: fmName, description } = parseFrontmatter(content);
22568
22784
  const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
22569
22785
  const name = fmName || dirName;
@@ -22582,19 +22798,19 @@ function readSkill(skillMd, source) {
22582
22798
  }
22583
22799
  }
22584
22800
  function scanSkillsDir(dir, source, out) {
22585
- if (!(0, import_node_fs53.existsSync)(dir)) return;
22801
+ if (!(0, import_node_fs54.existsSync)(dir)) return;
22586
22802
  let entries;
22587
22803
  try {
22588
- entries = (0, import_node_fs53.readdirSync)(dir);
22804
+ entries = (0, import_node_fs54.readdirSync)(dir);
22589
22805
  } catch {
22590
22806
  return;
22591
22807
  }
22592
22808
  for (const entry of entries) {
22593
22809
  if (entry.startsWith(".")) continue;
22594
- const skillMd = (0, import_node_path50.join)(dir, entry, "SKILL.md");
22595
- if (!(0, import_node_fs53.existsSync)(skillMd)) continue;
22810
+ const skillMd = (0, import_node_path51.join)(dir, entry, "SKILL.md");
22811
+ if (!(0, import_node_fs54.existsSync)(skillMd)) continue;
22596
22812
  try {
22597
- if (!(0, import_node_fs53.statSync)(skillMd).isFile()) continue;
22813
+ if (!(0, import_node_fs54.statSync)(skillMd).isFile()) continue;
22598
22814
  } catch {
22599
22815
  continue;
22600
22816
  }
@@ -22603,24 +22819,24 @@ function scanSkillsDir(dir, source, out) {
22603
22819
  }
22604
22820
  }
22605
22821
  function scanClaudePluginSkills(pluginsRoot, out) {
22606
- if (!(0, import_node_fs53.existsSync)(pluginsRoot)) return;
22822
+ if (!(0, import_node_fs54.existsSync)(pluginsRoot)) return;
22607
22823
  const walk = (dir, depth, lookingForSkillsDir) => {
22608
22824
  if (depth > 7) return;
22609
22825
  let entries;
22610
22826
  try {
22611
- entries = (0, import_node_fs53.readdirSync)(dir);
22827
+ entries = (0, import_node_fs54.readdirSync)(dir);
22612
22828
  } catch {
22613
22829
  return;
22614
22830
  }
22615
22831
  if (lookingForSkillsDir && entries.includes("SKILL.md")) {
22616
- const skill = readSkill((0, import_node_path50.join)(dir, "SKILL.md"), "cli");
22832
+ const skill = readSkill((0, import_node_path51.join)(dir, "SKILL.md"), "cli");
22617
22833
  if (skill) out.push(skill);
22618
22834
  }
22619
22835
  for (const entry of entries) {
22620
22836
  if (entry === "node_modules" || entry === ".git") continue;
22621
- const full = (0, import_node_path50.join)(dir, entry);
22837
+ const full = (0, import_node_path51.join)(dir, entry);
22622
22838
  try {
22623
- if (!(0, import_node_fs53.statSync)(full).isDirectory()) continue;
22839
+ if (!(0, import_node_fs54.statSync)(full).isDirectory()) continue;
22624
22840
  } catch {
22625
22841
  continue;
22626
22842
  }
@@ -22638,17 +22854,17 @@ function discoverSkills(worktreePath) {
22638
22854
  const home = (0, import_node_os15.homedir)();
22639
22855
  const collected = [];
22640
22856
  for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
22641
- scanSkillsDir((0, import_node_path50.join)(worktreePath, rel), "workspace", collected);
22857
+ scanSkillsDir((0, import_node_path51.join)(worktreePath, rel), "workspace", collected);
22642
22858
  }
22643
22859
  for (const abs of [
22644
- (0, import_node_path50.join)(home, ".claude/skills"),
22645
- (0, import_node_path50.join)(home, ".cursor/skills"),
22646
- (0, import_node_path50.join)(home, ".sideboard/skills"),
22647
- (0, import_node_path50.join)(home, ".brightsy/skills")
22860
+ (0, import_node_path51.join)(home, ".claude/skills"),
22861
+ (0, import_node_path51.join)(home, ".cursor/skills"),
22862
+ (0, import_node_path51.join)(home, ".sideboard/skills"),
22863
+ (0, import_node_path51.join)(home, ".brightsy/skills")
22648
22864
  ]) {
22649
22865
  scanSkillsDir(abs, "user", collected);
22650
22866
  }
22651
- scanClaudePluginSkills((0, import_node_path50.join)(home, ".claude/plugins"), collected);
22867
+ scanClaudePluginSkills((0, import_node_path51.join)(home, ".claude/plugins"), collected);
22652
22868
  collected.push(...bundledSkills());
22653
22869
  const rank = {
22654
22870
  workspace: 0,
@@ -22674,7 +22890,7 @@ function readSkillBody(skillPath, maxChars = 12e3) {
22674
22890
  \u2026(truncated)` : body;
22675
22891
  }
22676
22892
  }
22677
- const raw = (0, import_node_fs53.readFileSync)(skillPath, "utf8");
22893
+ const raw = (0, import_node_fs54.readFileSync)(skillPath, "utf8");
22678
22894
  if (raw.startsWith("---")) {
22679
22895
  const end = raw.indexOf("\n---", 3);
22680
22896
  if (end >= 0) {
@@ -22688,13 +22904,13 @@ function readSkillBody(skillPath, maxChars = 12e3) {
22688
22904
 
22689
22905
  \u2026(truncated)` : raw;
22690
22906
  }
22691
- var import_node_fs53, import_node_os15, import_node_path50, BUNDLED_SKILL_PREFIX;
22907
+ var import_node_fs54, import_node_os15, import_node_path51, BUNDLED_SKILL_PREFIX;
22692
22908
  var init_discover = __esm({
22693
22909
  "src/skills/discover.ts"() {
22694
22910
  "use strict";
22695
- import_node_fs53 = require("fs");
22911
+ import_node_fs54 = require("fs");
22696
22912
  import_node_os15 = require("os");
22697
- import_node_path50 = require("path");
22913
+ import_node_path51 = require("path");
22698
22914
  init_long_running();
22699
22915
  BUNDLED_SKILL_PREFIX = "bundled:";
22700
22916
  }
@@ -22849,7 +23065,7 @@ function compiledModuleDir() {
22849
23065
  try {
22850
23066
  const url = import_meta4.url;
22851
23067
  if (typeof url === "string" && url.length > 0) {
22852
- return (0, import_node_path51.dirname)((0, import_node_url4.fileURLToPath)(url));
23068
+ return (0, import_node_path52.dirname)((0, import_node_url4.fileURLToPath)(url));
22853
23069
  }
22854
23070
  } catch {
22855
23071
  }
@@ -22857,8 +23073,8 @@ function compiledModuleDir() {
22857
23073
  }
22858
23074
  function detachedJobScriptIn(dir) {
22859
23075
  for (const name of DETACHED_JOB_FILENAMES) {
22860
- const script = (0, import_node_path51.join)(dir, "scripts", name);
22861
- if ((0, import_node_fs54.existsSync)(script)) return script;
23076
+ const script = (0, import_node_path52.join)(dir, "scripts", name);
23077
+ if ((0, import_node_fs55.existsSync)(script)) return script;
22862
23078
  }
22863
23079
  return null;
22864
23080
  }
@@ -22875,7 +23091,7 @@ function resolveDetachedJobScript() {
22875
23091
  for (let i = 0; i < 8; i++) {
22876
23092
  const candidate = detachedJobScriptIn(dir);
22877
23093
  if (candidate) return candidate;
22878
- const parent = (0, import_node_path51.dirname)(dir);
23094
+ const parent = (0, import_node_path52.dirname)(dir);
22879
23095
  if (parent === dir) break;
22880
23096
  dir = parent;
22881
23097
  }
@@ -22886,12 +23102,12 @@ function formatDetachedJobInvoke(scriptPath) {
22886
23102
  if (resolved) return `node ${JSON.stringify(resolved)}`;
22887
23103
  return "node scripts/detached-job.cjs";
22888
23104
  }
22889
- var import_node_fs54, import_node_path51, import_node_url4, import_meta4, DETACHED_JOB_FILENAMES;
23105
+ var import_node_fs55, import_node_path52, import_node_url4, import_meta4, DETACHED_JOB_FILENAMES;
22890
23106
  var init_detached_job_path = __esm({
22891
23107
  "src/skills/detached-job-path.ts"() {
22892
23108
  "use strict";
22893
- import_node_fs54 = require("fs");
22894
- import_node_path51 = require("path");
23109
+ import_node_fs55 = require("fs");
23110
+ import_node_path52 = require("path");
22895
23111
  import_node_url4 = require("url");
22896
23112
  init_packaged_runtime();
22897
23113
  import_meta4 = {};
@@ -22992,9 +23208,9 @@ function formatWorktreeDirective(thread, opts) {
22992
23208
  );
22993
23209
  } else {
22994
23210
  const slug = opts?.githubSlug ?? "<origin-owner/name>";
22995
- const resolve = opts?.githubSlug ? "" : " Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree.";
23211
+ const resolve2 = opts?.githubSlug ? "" : " Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree.";
22996
23212
  lines.push(
22997
- `- Prefer a draft PR first: \`gh pr create --draft -R ${slug}\` (update via \`gh pr edit -R ${slug}\`). Always pass \`-R\` \u2014 bare \`gh pr create\` may target upstream on dual-remote checkouts.${resolve} Mark ready for review only when asked. If GitHub rejects the body as too long, retry with a short \`--body-file\` \u2014 do not paste a changelog or diff into \`--body\`.`
23213
+ `- Prefer a draft PR first: \`gh pr create --draft -R ${slug}\` (update via \`gh pr edit -R ${slug}\`). Always pass \`-R\` \u2014 bare \`gh pr create\` may target upstream on dual-remote checkouts.${resolve2} Mark ready for review only when asked. If GitHub rejects the body as too long, retry with a short \`--body-file\` \u2014 do not paste a changelog or diff into \`--body\`.`
22998
23214
  );
22999
23215
  }
23000
23216
  lines.push(
@@ -23103,9 +23319,9 @@ function formatPrGateDirective() {
23103
23319
  }
23104
23320
  function formatProcessGuideDirective(opts) {
23105
23321
  const worktree = opts?.worktreePath?.trim();
23106
- const hasGraphSkill = !!worktree && (0, import_node_fs55.existsSync)((0, import_node_path52.join)(worktree, ".claude/skills/graph-engineering/SKILL.md"));
23107
- const hasReviewSkill = !!worktree && (0, import_node_fs55.existsSync)((0, import_node_path52.join)(worktree, ".claude/skills/review/SKILL.md"));
23108
- const hasInstallSkill = !!worktree && (0, import_node_fs55.existsSync)((0, import_node_path52.join)(worktree, ".claude/skills/worktree-install/SKILL.md"));
23322
+ const hasGraphSkill = !!worktree && (0, import_node_fs56.existsSync)((0, import_node_path53.join)(worktree, ".claude/skills/graph-engineering/SKILL.md"));
23323
+ const hasReviewSkill = !!worktree && (0, import_node_fs56.existsSync)((0, import_node_path53.join)(worktree, ".claude/skills/review/SKILL.md"));
23324
+ const hasInstallSkill = !!worktree && (0, import_node_fs56.existsSync)((0, import_node_path53.join)(worktree, ".claude/skills/worktree-install/SKILL.md"));
23109
23325
  return [
23110
23326
  "Process guides (recurring work only):",
23111
23327
  hasGraphSkill ? "- Migrations, ports, batch fixes, and other fan-out: follow `.claude/skills/graph-engineering/SKILL.md` (`/graph-engineering`). Judge first; state on disk; grow the rulebook; do not patch around it." : null,
@@ -23144,12 +23360,12 @@ function formatArtifactDirective() {
23144
23360
  function formatUiReminder() {
23145
23361
  return "Sideboard UI: markdown table is enough to read data; present_schema if they ask to edit/filter (even after markdown); present_files for the file manager. html fence or present_artifact, not both for the same document. type=log appends (same artifact_id, new lines only). ask_user only for a real multiple-choice (not hellos, \u201Cwhat next?\u201D, or after a review) \u2014 reply in chat. ask_user wakes the parent orchestrator; notify_orchestrator if blocked without a picker. Do not say artifacts/CMS UI are unavailable. Dev / preview: run_dev_script (same as the Dev button) returns {url, port, preview} (SIDEBOARD_PORT \u2014 never guess :3000). preview=url \u2192 open url; preview=window \u2192 Electron window is the app, url is renderer/HMR only. list_run_scripts active[].url if already running; get_run_log for the Run-tab terminal; stop_dev_script to stop.";
23146
23362
  }
23147
- var import_node_fs55, import_node_path52, PR_GOAL_RE, GITHUB_TICKET_REF, KEYED_TICKET_REF;
23363
+ var import_node_fs56, import_node_path53, PR_GOAL_RE, GITHUB_TICKET_REF, KEYED_TICKET_REF;
23148
23364
  var init_instructions = __esm({
23149
23365
  "src/agents/instructions.ts"() {
23150
23366
  "use strict";
23151
- import_node_fs55 = require("fs");
23152
- import_node_path52 = require("path");
23367
+ import_node_fs56 = require("fs");
23368
+ import_node_path53 = require("path");
23153
23369
  init_git_auth_mode();
23154
23370
  init_branch_prefix();
23155
23371
  init_worktree_labels();
@@ -23535,40 +23751,40 @@ __export(plan_file_exports, {
23535
23751
  writePlanFile: () => writePlanFile
23536
23752
  });
23537
23753
  function ensureAttachmentsGitignore(worktreePath) {
23538
- const gitignoreAbs = (0, import_node_path53.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
23539
- if ((0, import_node_fs56.existsSync)(gitignoreAbs)) return;
23540
- (0, import_node_fs56.mkdirSync)((0, import_node_path53.dirname)(gitignoreAbs), { recursive: true });
23541
- (0, import_node_fs56.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
23754
+ const gitignoreAbs = (0, import_node_path54.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
23755
+ if ((0, import_node_fs57.existsSync)(gitignoreAbs)) return;
23756
+ (0, import_node_fs57.mkdirSync)((0, import_node_path54.dirname)(gitignoreAbs), { recursive: true });
23757
+ (0, import_node_fs57.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
23542
23758
  }
23543
23759
  function planFileAbs(worktreePath) {
23544
- return (0, import_node_path53.join)(worktreePath, PLAN_FILE_REL);
23760
+ return (0, import_node_path54.join)(worktreePath, PLAN_FILE_REL);
23545
23761
  }
23546
23762
  function readTextIfPresent2(abs) {
23547
- if (!(0, import_node_fs56.existsSync)(abs)) return null;
23763
+ if (!(0, import_node_fs57.existsSync)(abs)) return null;
23548
23764
  try {
23549
- const content = (0, import_node_fs56.readFileSync)(abs, "utf8");
23765
+ const content = (0, import_node_fs57.readFileSync)(abs, "utf8");
23550
23766
  return content.trim() ? content : null;
23551
23767
  } catch {
23552
23768
  return null;
23553
23769
  }
23554
23770
  }
23555
23771
  function readPlanFile(worktreePath) {
23556
- return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path53.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path53.join)(worktreePath, LEGACY_PLAN_FILE_REL));
23772
+ return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path54.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path54.join)(worktreePath, LEGACY_PLAN_FILE_REL));
23557
23773
  }
23558
23774
  function writePlanFile(worktreePath, content) {
23559
23775
  ensureAttachmentsGitignore(worktreePath);
23560
23776
  const abs = planFileAbs(worktreePath);
23561
- (0, import_node_fs56.mkdirSync)((0, import_node_path53.dirname)(abs), { recursive: true });
23777
+ (0, import_node_fs57.mkdirSync)((0, import_node_path54.dirname)(abs), { recursive: true });
23562
23778
  const body = content.trimEnd() + (content.endsWith("\n") ? "" : "\n");
23563
- (0, import_node_fs56.writeFileSync)(abs, body, "utf8");
23779
+ (0, import_node_fs57.writeFileSync)(abs, body, "utf8");
23564
23780
  return PLAN_FILE_REL;
23565
23781
  }
23566
- var import_node_fs56, import_node_path53;
23782
+ var import_node_fs57, import_node_path54;
23567
23783
  var init_plan_file = __esm({
23568
23784
  "src/plan/plan-file.ts"() {
23569
23785
  "use strict";
23570
- import_node_fs56 = require("fs");
23571
- import_node_path53 = require("path");
23786
+ import_node_fs57 = require("fs");
23787
+ import_node_path54 = require("path");
23572
23788
  init_workspace_scratch();
23573
23789
  init_plan_present();
23574
23790
  init_plan_present();
@@ -23630,9 +23846,9 @@ function recoverFinishedCursorRun(opts) {
23630
23846
  return best;
23631
23847
  }
23632
23848
  function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
23633
- if (!(0, import_node_fs57.existsSync)(runsPath)) return null;
23849
+ if (!(0, import_node_fs58.existsSync)(runsPath)) return null;
23634
23850
  try {
23635
- const lines = (0, import_node_fs57.readFileSync)(runsPath, "utf8").split("\n");
23851
+ const lines = (0, import_node_fs58.readFileSync)(runsPath, "utf8").split("\n");
23636
23852
  let best = null;
23637
23853
  for (const line of lines) {
23638
23854
  const trimmed = line.trim();
@@ -23658,11 +23874,11 @@ function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
23658
23874
  return null;
23659
23875
  }
23660
23876
  }
23661
- var import_node_fs57;
23877
+ var import_node_fs58;
23662
23878
  var init_cursor_recover = __esm({
23663
23879
  "src/agents/cursor-recover.ts"() {
23664
23880
  "use strict";
23665
- import_node_fs57 = require("fs");
23881
+ import_node_fs58 = require("fs");
23666
23882
  init_cursor_store();
23667
23883
  }
23668
23884
  });
@@ -23816,7 +24032,7 @@ async function startOrchestration(opts) {
23816
24032
  }
23817
24033
  return updated;
23818
24034
  }
23819
- var import_node_events, import_node_crypto13, import_node_fs58, LIVE_TURN_SPAWN_GRACE_MS, RUN_SCRIPT_DESKTOP_ADOPT_MS, STALE_AGENT_PID_WAIT_MS, LIGHT_RECONCILE_THROTTLE_MS, Orchestrator, singleton;
24035
+ var import_node_events, import_node_crypto13, import_node_fs59, LIVE_TURN_SPAWN_GRACE_MS, RUN_SCRIPT_DESKTOP_ADOPT_MS, STALE_AGENT_PID_WAIT_MS, LIGHT_RECONCILE_THROTTLE_MS, Orchestrator, singleton;
23820
24036
  var init_orchestrator = __esm({
23821
24037
  "src/orchestrator/orchestrator.ts"() {
23822
24038
  "use strict";
@@ -23824,7 +24040,7 @@ var init_orchestrator = __esm({
23824
24040
  init_injected_notices();
23825
24041
  init_task_state();
23826
24042
  import_node_crypto13 = require("crypto");
23827
- import_node_fs58 = require("fs");
24043
+ import_node_fs59 = require("fs");
23828
24044
  init_error_detail();
23829
24045
  init_run();
23830
24046
  init_stale_lock();
@@ -24003,7 +24219,7 @@ var init_orchestrator = __esm({
24003
24219
  this.lightReconcileAt.set(repoPath, Date.now());
24004
24220
  for (const thread of listThreads()) {
24005
24221
  if (isGlobalThread(thread) || thread.repoPath !== repoPath) continue;
24006
- if (!(0, import_node_fs58.existsSync)(thread.worktreePath)) {
24222
+ if (!(0, import_node_fs59.existsSync)(thread.worktreePath)) {
24007
24223
  setStatus(thread.id, "broken", "Worktree missing on disk");
24008
24224
  this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
24009
24225
  }
@@ -24032,7 +24248,7 @@ var init_orchestrator = __esm({
24032
24248
  }
24033
24249
  continue;
24034
24250
  }
24035
- if (!(0, import_node_fs58.existsSync)(thread.worktreePath)) {
24251
+ if (!(0, import_node_fs59.existsSync)(thread.worktreePath)) {
24036
24252
  setStatus(thread.id, "broken", "Worktree missing on disk");
24037
24253
  this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
24038
24254
  continue;
@@ -24200,8 +24416,8 @@ var init_orchestrator = __esm({
24200
24416
  scheduleQuotaResume(threadId, resumeAt) {
24201
24417
  this.clearQuotaResumeTimer(threadId);
24202
24418
  updateThread(threadId, { quotaResumeAt: resumeAt.toISOString() });
24203
- const delay = Math.max(5e3, resumeAt.getTime() - Date.now());
24204
- const capped = Math.min(delay, 2147483647);
24419
+ const delay2 = Math.max(5e3, resumeAt.getTime() - Date.now());
24420
+ const capped = Math.min(delay2, 2147483647);
24205
24421
  const timer = setTimeout(() => {
24206
24422
  this.quotaResumeTimers.delete(threadId);
24207
24423
  void this.resumeAfterQuotaWait(threadId);
@@ -25256,6 +25472,7 @@ var init_orchestrator = __esm({
25256
25472
  return { port: shared.devPort, scriptName: resolvedName, ports: [shared.devPort] };
25257
25473
  }
25258
25474
  }
25475
+ const preferredPorts = active?.ports?.length ? active.ports : active?.port != null ? [active.port] : void 0;
25259
25476
  if (active && !existing) {
25260
25477
  killListenersOnPorts(collectActiveRunPorts([active]));
25261
25478
  this.syncWorktreeRuns(
@@ -25294,7 +25511,7 @@ var init_orchestrator = __esm({
25294
25511
  thread.repoPath,
25295
25512
  thread.worktreePath,
25296
25513
  runOutput.push,
25297
- { scriptName: resolvedName }
25514
+ { scriptName: resolvedName, preferredPorts }
25298
25515
  );
25299
25516
  } catch (err) {
25300
25517
  runOutput.flush();
@@ -25743,7 +25960,7 @@ var init_orchestrator = __esm({
25743
25960
  return thread;
25744
25961
  }
25745
25962
  const start = Date.now();
25746
- return new Promise((resolve, reject) => {
25963
+ return new Promise((resolve2, reject) => {
25747
25964
  let settled = false;
25748
25965
  let timer;
25749
25966
  const finish = (fn) => {
@@ -25761,7 +25978,7 @@ var init_orchestrator = __esm({
25761
25978
  finish(() => reject(new Error(`Thread not found: ${thread.id}`)));
25762
25979
  return;
25763
25980
  }
25764
- finish(() => resolve(latest));
25981
+ finish(() => resolve2(latest));
25765
25982
  return;
25766
25983
  }
25767
25984
  if (event.type === "status_changed") {
@@ -25771,7 +25988,7 @@ var init_orchestrator = __esm({
25771
25988
  return;
25772
25989
  }
25773
25990
  if (!["running", "queued"].includes(latest.status)) {
25774
- finish(() => resolve(latest));
25991
+ finish(() => resolve2(latest));
25775
25992
  }
25776
25993
  }
25777
25994
  });
@@ -25783,12 +26000,12 @@ var init_orchestrator = __esm({
25783
26000
  }
25784
26001
  const current = this.healStaleReportedActivity(raw);
25785
26002
  if (!this.threadLooksLive(current)) {
25786
- finish(() => resolve(current));
26003
+ finish(() => resolve2(current));
25787
26004
  return;
25788
26005
  }
25789
26006
  if (Date.now() - start > timeoutMs) {
25790
26007
  if (opts?.resolveIfStillRunning) {
25791
- finish(() => resolve(current));
26008
+ finish(() => resolve2(current));
25792
26009
  } else {
25793
26010
  finish(() => reject(new Error("wait_for_turn timed out")));
25794
26011
  }
@@ -26380,7 +26597,7 @@ var init_orchestrator = __esm({
26380
26597
  this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
26381
26598
  return restored2;
26382
26599
  }
26383
- if (!(0, import_node_fs58.existsSync)(thread.worktreePath)) {
26600
+ if (!(0, import_node_fs59.existsSync)(thread.worktreePath)) {
26384
26601
  if (isCowboyThread(thread) || isPrimaryCheckoutThread(thread)) {
26385
26602
  throw new Error(
26386
26603
  `Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
@@ -26526,14 +26743,14 @@ function armOne(schedule) {
26526
26743
  if (!schedule.enabled) return;
26527
26744
  const at = new Date(schedule.nextRunAt);
26528
26745
  if (Number.isNaN(at.getTime())) return;
26529
- const delay = Math.max(0, at.getTime() - Date.now());
26530
- if (delay <= 250) {
26746
+ const delay2 = Math.max(0, at.getTime() - Date.now());
26747
+ if (delay2 <= 250) {
26531
26748
  void fireSchedule(schedule.id).then(() => {
26532
26749
  if (isThisProcessDesktopHost()) armSchedules();
26533
26750
  });
26534
26751
  return;
26535
26752
  }
26536
- const capped = Math.min(delay, SET_TIMEOUT_MAX);
26753
+ const capped = Math.min(delay2, SET_TIMEOUT_MAX);
26537
26754
  const timer = setTimeout(() => {
26538
26755
  timers.delete(schedule.id);
26539
26756
  const live = getSchedule(schedule.id);
@@ -26671,6 +26888,7 @@ __export(index_exports, {
26671
26888
  PLAN_FILE_REL: () => PLAN_FILE_REL,
26672
26889
  PLAN_MODE_INSTRUCTION: () => PLAN_MODE_INSTRUCTION,
26673
26890
  PLAN_QUESTION_ANSWERS_PREFIX: () => PLAN_QUESTION_ANSWERS_PREFIX,
26891
+ PORT_RANGE_SIZE: () => PORT_RANGE_SIZE,
26674
26892
  PROFILE_NOTES_MAX: () => PROFILE_NOTES_MAX,
26675
26893
  PR_DETAILS_JSON_FIELDS: () => PR_DETAILS_JSON_FIELDS,
26676
26894
  REPO_REVIEW_NAME: () => REPO_REVIEW_NAME,
@@ -26681,6 +26899,7 @@ __export(index_exports, {
26681
26899
  REVIEW_REQUEST_TEMPLATE: () => REVIEW_REQUEST_TEMPLATE,
26682
26900
  REVIEW_SKILL_NAME: () => REVIEW_SKILL_NAME,
26683
26901
  REVIEW_SKILL_PATH: () => REVIEW_SKILL_PATH,
26902
+ RUN_PORTS_REL: () => RUN_PORTS_REL,
26684
26903
  RUN_SCRIPT_DESKTOP_ADOPT_MS: () => RUN_SCRIPT_DESKTOP_ADOPT_MS,
26685
26904
  SEED_FULL_TOOL_MESSAGES: () => SEED_FULL_TOOL_MESSAGES,
26686
26905
  SEED_MAX_CHARS: () => SEED_MAX_CHARS,
@@ -27111,6 +27330,7 @@ __export(index_exports, {
27111
27330
  isOptionalServiceId: () => isOptionalServiceId,
27112
27331
  isOrchestratorCapableAgent: () => isOrchestratorCapableAgent,
27113
27332
  isOrchestratorThread: () => isOrchestratorThread,
27333
+ isOtherWorktreeListenerCwd: () => isOtherWorktreeListenerCwd,
27114
27334
  isPidAlive: () => isPidAlive,
27115
27335
  isPlaceholderBranch: () => isPlaceholderBranch,
27116
27336
  isPlanQuestionAnswersMessage: () => isPlanQuestionAnswersMessage,
@@ -27142,6 +27362,7 @@ __export(index_exports, {
27142
27362
  issueSourceLabel: () => issueSourceLabel,
27143
27363
  issueTicketFromThread: () => issueTicketFromThread,
27144
27364
  killListenersOnPorts: () => killListenersOnPorts,
27365
+ killStaleWorktreeListeners: () => killStaleWorktreeListeners,
27145
27366
  killableListenerPids: () => killableListenerPids,
27146
27367
  lastAgentReply: () => lastAgentReply,
27147
27368
  lastAssistantMessageText: () => lastAssistantMessageText,
@@ -27189,6 +27410,7 @@ __export(index_exports, {
27189
27410
  listWorkspaces: () => listWorkspaces,
27190
27411
  listWorktreeFiles: () => listWorktreeFiles,
27191
27412
  listWorktrees: () => listWorktrees,
27413
+ listenerCwd: () => listenerCwd,
27192
27414
  liveActivitySummary: () => liveActivitySummary,
27193
27415
  loadAppSettings: () => loadAppSettings,
27194
27416
  loadBrightsyConfig: () => loadBrightsyConfig,
@@ -27196,9 +27418,11 @@ __export(index_exports, {
27196
27418
  loadHomeBoardInputs: () => loadHomeBoardInputs,
27197
27419
  loadRepoSettings: () => loadRepoSettings,
27198
27420
  loadWorkspaceSettings: () => loadWorkspaceSettings,
27421
+ loadWorktreeRunPorts: () => loadWorktreeRunPorts,
27199
27422
  localhostPreviewUrl: () => localhostPreviewUrl,
27200
27423
  locksDir: () => locksDir,
27201
27424
  loginAgent: () => loginAgent,
27425
+ looksLikeComposerSkillExpansion: () => looksLikeComposerSkillExpansion,
27202
27426
  looksLikeConversationSummary: () => looksLikeConversationSummary,
27203
27427
  looksLikeSkillBody: () => looksLikeSkillBody,
27204
27428
  lookupSoccerTeam: () => lookupSoccerTeam,
@@ -27389,6 +27613,7 @@ __export(index_exports, {
27389
27613
  saveAbleTimeConnection: () => saveAbleTimeConnection,
27390
27614
  saveAppSettings: () => saveAppSettings,
27391
27615
  saveLinearOAuth: () => saveLinearOAuth,
27616
+ saveWorktreeRunPorts: () => saveWorktreeRunPorts,
27392
27617
  schedulesPath: () => schedulesPath,
27393
27618
  scrubGithubTokensFromChildEnv: () => scrubGithubTokensFromChildEnv,
27394
27619
  searchAbleTimeTasks: () => searchAbleTimeTasks,
@@ -27478,6 +27703,8 @@ __export(index_exports, {
27478
27703
  toolFilePath: () => toolFilePath,
27479
27704
  totalTokens: () => totalTokens,
27480
27705
  trustSystemCertificates: () => trustSystemCertificates,
27706
+ tryReservePort: () => tryReservePort,
27707
+ tryReservePorts: () => tryReservePorts,
27481
27708
  turnCostUsdFromCursorUsage: () => turnCostUsdFromCursorUsage,
27482
27709
  updateAbleTimeTask: () => updateAbleTimeTask,
27483
27710
  updateAdvancedSettings: () => updateAdvancedSettings,
@@ -27516,6 +27743,7 @@ __export(index_exports, {
27516
27743
  worktreeDisplayLabel: () => worktreeDisplayLabel,
27517
27744
  worktreeDisplayLabelForGroup: () => worktreeDisplayLabelForGroup,
27518
27745
  worktreeNameFromPath: () => worktreeNameFromPath,
27746
+ worktreeRunPortsPath: () => worktreeRunPortsPath,
27519
27747
  worktreeSlugForTicket: () => worktreeSlugForTicket,
27520
27748
  worktreesRoot: () => worktreesRoot,
27521
27749
  wrapReviewSkillMarkdown: () => wrapReviewSkillMarkdown,
@@ -28002,14 +28230,14 @@ async function startLinearOAuth(opts) {
28002
28230
  const pkce = createLinearPkce();
28003
28231
  const authorizeUrl = linearOAuthAuthorizeUrl(clientId, state, pkce.challenge);
28004
28232
  const timeoutMs = opts?.timeoutMs ?? 5 * 6e4;
28005
- const code = await new Promise((resolve, reject) => {
28233
+ const code = await new Promise((resolve2, reject) => {
28006
28234
  let settled = false;
28007
28235
  const finish = (err, value) => {
28008
28236
  if (settled) return;
28009
28237
  settled = true;
28010
28238
  cleanup();
28011
28239
  if (err) reject(err);
28012
- else resolve(value);
28240
+ else resolve2(value);
28013
28241
  };
28014
28242
  const server = (0, import_node_http2.createServer)((req, res) => {
28015
28243
  try {
@@ -30171,7 +30399,7 @@ var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
30171
30399
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
30172
30400
  var import_zod9 = require("zod");
30173
30401
  var import_node_crypto17 = require("crypto");
30174
- var import_node_path59 = require("path");
30402
+ var import_node_path60 = require("path");
30175
30403
  init_orchestrator();
30176
30404
  init_task_state();
30177
30405
  init_worktree();
@@ -30507,8 +30735,8 @@ ${link}` : link;
30507
30735
  }
30508
30736
 
30509
30737
  // src/slack/outbound-watch.ts
30510
- var import_node_fs60 = require("fs");
30511
- var import_node_path56 = require("path");
30738
+ var import_node_fs61 = require("fs");
30739
+ var import_node_path57 = require("path");
30512
30740
  init_paths();
30513
30741
  init_private_file();
30514
30742
  init_secure_file();
@@ -30516,19 +30744,19 @@ init_thread_store();
30516
30744
  init_injected_notices();
30517
30745
 
30518
30746
  // src/slack/reply-target.ts
30519
- var import_node_fs59 = require("fs");
30520
- var import_node_path54 = require("path");
30747
+ var import_node_fs60 = require("fs");
30748
+ var import_node_path55 = require("path");
30521
30749
  init_paths();
30522
30750
  init_private_file();
30523
30751
  init_secure_file();
30524
30752
  function storePath2() {
30525
- return (0, import_node_path54.join)(appDataDir(), "slack-reply-to.json");
30753
+ return (0, import_node_path55.join)(appDataDir(), "slack-reply-to.json");
30526
30754
  }
30527
30755
  function readStore2() {
30528
30756
  const path2 = storePath2();
30529
- if (!(0, import_node_fs59.existsSync)(path2)) return {};
30757
+ if (!(0, import_node_fs60.existsSync)(path2)) return {};
30530
30758
  try {
30531
- const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs59.readFileSync)(path2, "utf8"));
30759
+ const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs60.readFileSync)(path2, "utf8"));
30532
30760
  return parsed?.targets && typeof parsed.targets === "object" ? parsed.targets : {};
30533
30761
  } catch {
30534
30762
  return {};
@@ -30545,11 +30773,11 @@ function getSlackReplyTarget(threadId) {
30545
30773
  }
30546
30774
 
30547
30775
  // src/slack/workspaces.ts
30548
- var import_node_path55 = require("path");
30776
+ var import_node_path56 = require("path");
30549
30777
  init_paths();
30550
30778
  init_secure_file();
30551
30779
  function storePath3() {
30552
- return (0, import_node_path55.join)(appDataDir(), "slack-workspaces.json");
30780
+ return (0, import_node_path56.join)(appDataDir(), "slack-workspaces.json");
30553
30781
  }
30554
30782
  function readStore3() {
30555
30783
  try {
@@ -30665,7 +30893,7 @@ var POLL_INTERVAL_MS = 12e3;
30665
30893
  var lastPollMs = 0;
30666
30894
  var nameCache = /* @__PURE__ */ new Map();
30667
30895
  function storePath4() {
30668
- return (0, import_node_path56.join)(appDataDir(), "slack-outbound-watch.json");
30896
+ return (0, import_node_path57.join)(appDataDir(), "slack-outbound-watch.json");
30669
30897
  }
30670
30898
  function watchId(teamId, channelId, ts) {
30671
30899
  return `${teamId}:${channelId}:${ts}`;
@@ -30678,9 +30906,9 @@ function tsNewer(a, b) {
30678
30906
  }
30679
30907
  function readStore4() {
30680
30908
  const path2 = storePath4();
30681
- if (!(0, import_node_fs60.existsSync)(path2)) return [];
30909
+ if (!(0, import_node_fs61.existsSync)(path2)) return [];
30682
30910
  try {
30683
- const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs60.readFileSync)(path2, "utf8"));
30911
+ const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs61.readFileSync)(path2, "utf8"));
30684
30912
  return Array.isArray(parsed?.watches) ? parsed.watches : [];
30685
30913
  } catch {
30686
30914
  return [];
@@ -32431,27 +32659,27 @@ init_gh_errors();
32431
32659
  init_git_auth_mode();
32432
32660
 
32433
32661
  // src/board/load-home-board.ts
32434
- var import_node_fs62 = require("fs");
32435
- var import_node_path58 = require("path");
32662
+ var import_node_fs63 = require("fs");
32663
+ var import_node_path59 = require("path");
32436
32664
  init_worktree();
32437
32665
  init_paths();
32438
32666
 
32439
32667
  // src/board/board-pins.ts
32440
32668
  var import_node_crypto16 = require("crypto");
32441
- var import_node_fs61 = require("fs");
32442
- var import_node_path57 = require("path");
32669
+ var import_node_fs62 = require("fs");
32670
+ var import_node_path58 = require("path");
32443
32671
  init_paths();
32444
32672
  init_home_board();
32445
32673
  var FILE = "home-board-pins.json";
32446
32674
  var VERSION = 1;
32447
32675
  function pinsFile() {
32448
- return (0, import_node_path57.join)(appDataDir(), FILE);
32676
+ return (0, import_node_path58.join)(appDataDir(), FILE);
32449
32677
  }
32450
32678
  function readDisk() {
32451
32679
  const path2 = pinsFile();
32452
- if (!(0, import_node_fs61.existsSync)(path2)) return [];
32680
+ if (!(0, import_node_fs62.existsSync)(path2)) return [];
32453
32681
  try {
32454
- const raw = JSON.parse((0, import_node_fs61.readFileSync)(path2, "utf8"));
32682
+ const raw = JSON.parse((0, import_node_fs62.readFileSync)(path2, "utf8"));
32455
32683
  if (raw?.version !== VERSION || !Array.isArray(raw.items)) return [];
32456
32684
  return raw.items.filter((item) => item?.id && item.kind && item.ref);
32457
32685
  } catch {
@@ -32459,8 +32687,8 @@ function readDisk() {
32459
32687
  }
32460
32688
  }
32461
32689
  function writeDisk(items) {
32462
- (0, import_node_fs61.mkdirSync)(appDataDir(), { recursive: true });
32463
- (0, import_node_fs61.writeFileSync)(pinsFile(), JSON.stringify({ version: VERSION, items }, null, 2), "utf8");
32690
+ (0, import_node_fs62.mkdirSync)(appDataDir(), { recursive: true });
32691
+ (0, import_node_fs62.writeFileSync)(pinsFile(), JSON.stringify({ version: VERSION, items }, null, 2), "utf8");
32464
32692
  }
32465
32693
  function listBoardPins() {
32466
32694
  return readDisk();
@@ -32512,7 +32740,7 @@ function replaceBoardPins(items) {
32512
32740
  }
32513
32741
  function clearBoardPins() {
32514
32742
  try {
32515
- (0, import_node_fs61.unlinkSync)(pinsFile());
32743
+ (0, import_node_fs62.unlinkSync)(pinsFile());
32516
32744
  } catch {
32517
32745
  }
32518
32746
  }
@@ -32529,7 +32757,7 @@ function homeBoardWorkspaceKey(workspaces) {
32529
32757
  return workspaces.map((w) => w.path).filter(Boolean).sort().join("\n");
32530
32758
  }
32531
32759
  function cacheFile() {
32532
- return (0, import_node_path58.join)(appDataDir(), "home-board-cache.json");
32760
+ return (0, import_node_path59.join)(appDataDir(), "home-board-cache.json");
32533
32761
  }
32534
32762
  function emptyInputs() {
32535
32763
  return {
@@ -32555,9 +32783,9 @@ function shouldCacheHomeBoardInputs(inputs) {
32555
32783
  }
32556
32784
  function readDiskCache() {
32557
32785
  const path2 = cacheFile();
32558
- if (!(0, import_node_fs62.existsSync)(path2)) return null;
32786
+ if (!(0, import_node_fs63.existsSync)(path2)) return null;
32559
32787
  try {
32560
- const raw = JSON.parse((0, import_node_fs62.readFileSync)(path2, "utf8"));
32788
+ const raw = JSON.parse((0, import_node_fs63.readFileSync)(path2, "utf8"));
32561
32789
  if (raw?.version !== CACHE_VERSION || typeof raw.fetchedAt !== "number") {
32562
32790
  return null;
32563
32791
  }
@@ -32571,14 +32799,14 @@ function readDiskCache() {
32571
32799
  }
32572
32800
  function writeDiskCache(entry) {
32573
32801
  try {
32574
- (0, import_node_fs62.mkdirSync)(appDataDir(), { recursive: true });
32575
- (0, import_node_fs62.writeFileSync)(cacheFile(), JSON.stringify(entry), "utf8");
32802
+ (0, import_node_fs63.mkdirSync)(appDataDir(), { recursive: true });
32803
+ (0, import_node_fs63.writeFileSync)(cacheFile(), JSON.stringify(entry), "utf8");
32576
32804
  } catch {
32577
32805
  }
32578
32806
  }
32579
32807
  function deleteDiskCache() {
32580
32808
  try {
32581
- (0, import_node_fs62.unlinkSync)(cacheFile());
32809
+ (0, import_node_fs63.unlinkSync)(cacheFile());
32582
32810
  } catch {
32583
32811
  }
32584
32812
  }
@@ -32765,14 +32993,14 @@ function orchCreateThreadAgentNote(input) {
32765
32993
  var MAX_ORCH_THREADS = 5;
32766
32994
  var CREATE_THREAD_TIMEOUT_MS = 9e4;
32767
32995
  function withTimeout2(promise, ms, label) {
32768
- return new Promise((resolve, reject) => {
32996
+ return new Promise((resolve2, reject) => {
32769
32997
  const timer = setTimeout(() => {
32770
32998
  reject(new Error(`${label} timed out after ${Math.round(ms / 1e3)}s`));
32771
32999
  }, ms);
32772
33000
  promise.then(
32773
33001
  (value) => {
32774
33002
  clearTimeout(timer);
32775
- resolve(value);
33003
+ resolve2(value);
32776
33004
  },
32777
33005
  (err) => {
32778
33006
  clearTimeout(timer);
@@ -32944,7 +33172,7 @@ async function startMcpServer() {
32944
33172
  async () => {
32945
33173
  const threads = orch.getThreads(true);
32946
33174
  const lines = threads.map((t) => {
32947
- const repo = t.repoPath === GLOBAL_WORKSPACE_ID2 ? "Orchestration" : (0, import_node_path59.basename)(t.repoPath) || t.repoPath;
33175
+ const repo = t.repoPath === GLOBAL_WORKSPACE_ID2 ? "Orchestration" : (0, import_node_path60.basename)(t.repoPath) || t.repoPath;
32948
33176
  const live = orch.threadLooksLive(t) ? readTurnLive(t.id) : null;
32949
33177
  const parent = t.parentThreadId ? ` parent:${t.parentThreadId.slice(0, 8)}` : "";
32950
33178
  const preview = lastMessagePreview(t.messages, 80);
@@ -34398,13 +34626,13 @@ async function runCloudConnect(opts) {
34398
34626
  log(`poll error: ${msg}`);
34399
34627
  }
34400
34628
  }
34401
- await new Promise((resolve) => {
34402
- const t = setTimeout(resolve, pollMs);
34629
+ await new Promise((resolve2) => {
34630
+ const t = setTimeout(resolve2, pollMs);
34403
34631
  opts.signal?.addEventListener(
34404
34632
  "abort",
34405
34633
  () => {
34406
34634
  clearTimeout(t);
34407
- resolve();
34635
+ resolve2();
34408
34636
  },
34409
34637
  { once: true }
34410
34638
  );
@@ -34612,14 +34840,14 @@ function slackOAuthAuthorizeUrl(clientId, state) {
34612
34840
  return `https://slack.com/oauth/v2/authorize?${params.toString()}`;
34613
34841
  }
34614
34842
  function sleep(ms, signal) {
34615
- return new Promise((resolve, reject) => {
34843
+ return new Promise((resolve2, reject) => {
34616
34844
  if (signal?.aborted) {
34617
34845
  reject(new SlackOAuthCancelledError());
34618
34846
  return;
34619
34847
  }
34620
34848
  const timer = setTimeout(() => {
34621
34849
  signal?.removeEventListener("abort", onAbort);
34622
- resolve();
34850
+ resolve2();
34623
34851
  }, ms);
34624
34852
  const onAbort = () => {
34625
34853
  clearTimeout(timer);
@@ -34811,12 +35039,12 @@ function resolveWebSocket(ctor) {
34811
35039
  return nodeWebSocketCtor();
34812
35040
  }
34813
35041
  function wait(ms, signal) {
34814
- return new Promise((resolve, reject) => {
35042
+ return new Promise((resolve2, reject) => {
34815
35043
  if (signal?.aborted) {
34816
35044
  reject(new Error("aborted"));
34817
35045
  return;
34818
35046
  }
34819
- const t = setTimeout(resolve, ms);
35047
+ const t = setTimeout(resolve2, ms);
34820
35048
  signal?.addEventListener(
34821
35049
  "abort",
34822
35050
  () => {
@@ -34861,14 +35089,14 @@ async function runSlackSocketMode(opts) {
34861
35089
  }
34862
35090
  }
34863
35091
  function connectSession(ws, opts, log) {
34864
- return new Promise((resolve, reject) => {
35092
+ return new Promise((resolve2, reject) => {
34865
35093
  let settled = false;
34866
35094
  const finish = (err) => {
34867
35095
  if (settled) return;
34868
35096
  settled = true;
34869
35097
  opts.signal?.removeEventListener("abort", onAbort);
34870
35098
  if (err) reject(err);
34871
- else resolve();
35099
+ else resolve2();
34872
35100
  };
34873
35101
  const onAbort = () => {
34874
35102
  try {
@@ -35039,12 +35267,12 @@ var CLAIM_FALLBACK_MS = 400;
35039
35267
  var BACKOFF_START_MS2 = 1e3;
35040
35268
  var BACKOFF_MAX_MS2 = 3e4;
35041
35269
  function wait2(ms, signal) {
35042
- return new Promise((resolve, reject) => {
35270
+ return new Promise((resolve2, reject) => {
35043
35271
  if (signal?.aborted) {
35044
35272
  reject(new Error("aborted"));
35045
35273
  return;
35046
35274
  }
35047
- const t = setTimeout(resolve, ms);
35275
+ const t = setTimeout(resolve2, ms);
35048
35276
  signal?.addEventListener(
35049
35277
  "abort",
35050
35278
  () => {
@@ -35103,7 +35331,7 @@ async function runSlackRelayClient(opts) {
35103
35331
  }
35104
35332
  }
35105
35333
  function connectSession2(ws, opts, log) {
35106
- return new Promise((resolve, reject) => {
35334
+ return new Promise((resolve2, reject) => {
35107
35335
  let settled = false;
35108
35336
  const pending = /* @__PURE__ */ new Map();
35109
35337
  let relayAnswersClaims = false;
@@ -35137,7 +35365,7 @@ function connectSession2(ws, opts, log) {
35137
35365
  stopKeepalive();
35138
35366
  opts.signal?.removeEventListener("abort", onAbort);
35139
35367
  if (err) reject(err);
35140
- else resolve();
35368
+ else resolve2();
35141
35369
  };
35142
35370
  const onAbort = () => {
35143
35371
  try {
@@ -36063,9 +36291,9 @@ var import_node_http4 = require("http");
36063
36291
  var import_ws3 = require("ws");
36064
36292
 
36065
36293
  // src/slack/relay-static.ts
36066
- var import_node_fs63 = require("fs");
36294
+ var import_node_fs64 = require("fs");
36067
36295
  var import_promises = require("fs/promises");
36068
- var import_node_path60 = __toESM(require("path"), 1);
36296
+ var import_node_path61 = __toESM(require("path"), 1);
36069
36297
  var TYPES = {
36070
36298
  ".css": "text/css; charset=utf-8",
36071
36299
  ".html": "text/html; charset=utf-8",
@@ -36096,9 +36324,9 @@ function resolveStaticPath(root, requestUrl) {
36096
36324
  return null;
36097
36325
  }
36098
36326
  if (!pathname.startsWith("/") || pathname.includes("\0")) return null;
36099
- const rootResolved = import_node_path60.default.resolve(root);
36100
- const candidate = import_node_path60.default.resolve(rootResolved, `.${pathname}`);
36101
- if (candidate !== rootResolved && !candidate.startsWith(rootResolved + import_node_path60.default.sep)) {
36327
+ const rootResolved = import_node_path61.default.resolve(root);
36328
+ const candidate = import_node_path61.default.resolve(rootResolved, `.${pathname}`);
36329
+ if (candidate !== rootResolved && !candidate.startsWith(rootResolved + import_node_path61.default.sep)) {
36102
36330
  return null;
36103
36331
  }
36104
36332
  return candidate;
@@ -36112,7 +36340,7 @@ async function fileSize(file) {
36112
36340
  }
36113
36341
  }
36114
36342
  function sendFile(req, res, file, size) {
36115
- const ext = import_node_path60.default.extname(file).toLowerCase();
36343
+ const ext = import_node_path61.default.extname(file).toLowerCase();
36116
36344
  res.writeHead(200, {
36117
36345
  "Content-Type": TYPES[ext] ?? "application/octet-stream",
36118
36346
  "Content-Length": size,
@@ -36122,7 +36350,7 @@ function sendFile(req, res, file, size) {
36122
36350
  res.end();
36123
36351
  return true;
36124
36352
  }
36125
- (0, import_node_fs63.createReadStream)(file).pipe(res);
36353
+ (0, import_node_fs64.createReadStream)(file).pipe(res);
36126
36354
  return true;
36127
36355
  }
36128
36356
  async function tryServeStatic(req, res, root) {
@@ -36131,7 +36359,7 @@ async function tryServeStatic(req, res, root) {
36131
36359
  if (!candidate) return false;
36132
36360
  const direct = await fileSize(candidate);
36133
36361
  if (direct != null) return sendFile(req, res, candidate, direct);
36134
- const asIndex = import_node_path60.default.join(candidate, "index.html");
36362
+ const asIndex = import_node_path61.default.join(candidate, "index.html");
36135
36363
  const indexSize = await fileSize(asIndex);
36136
36364
  if (indexSize != null) return sendFile(req, res, asIndex, indexSize);
36137
36365
  return false;
@@ -36331,9 +36559,9 @@ async function startSlackRelayServer(opts) {
36331
36559
  });
36332
36560
  const port = opts.port ?? 0;
36333
36561
  const host = opts.host ?? "0.0.0.0";
36334
- await new Promise((resolve, reject) => {
36562
+ await new Promise((resolve2, reject) => {
36335
36563
  httpServer.once("error", reject);
36336
- httpServer.listen(port, host, () => resolve());
36564
+ httpServer.listen(port, host, () => resolve2());
36337
36565
  });
36338
36566
  const address = httpServer.address();
36339
36567
  const boundPort = typeof address === "object" && address ? address.port : typeof port === "number" ? port : 0;
@@ -36362,11 +36590,11 @@ async function startSlackRelayServer(opts) {
36362
36590
  close: async () => {
36363
36591
  opts.signal?.removeEventListener("abort", onAbort);
36364
36592
  ac.abort();
36365
- await new Promise((resolve) => {
36366
- wss.close(() => resolve());
36593
+ await new Promise((resolve2) => {
36594
+ wss.close(() => resolve2());
36367
36595
  });
36368
- await new Promise((resolve, reject) => {
36369
- httpServer.close((err) => err ? reject(err) : resolve());
36596
+ await new Promise((resolve2, reject) => {
36597
+ httpServer.close((err) => err ? reject(err) : resolve2());
36370
36598
  });
36371
36599
  await socketModeDone.catch(() => void 0);
36372
36600
  }
@@ -36462,6 +36690,7 @@ async function startSlackRelayServer(opts) {
36462
36690
  PLAN_FILE_REL,
36463
36691
  PLAN_MODE_INSTRUCTION,
36464
36692
  PLAN_QUESTION_ANSWERS_PREFIX,
36693
+ PORT_RANGE_SIZE,
36465
36694
  PROFILE_NOTES_MAX,
36466
36695
  PR_DETAILS_JSON_FIELDS,
36467
36696
  REPO_REVIEW_NAME,
@@ -36472,6 +36701,7 @@ async function startSlackRelayServer(opts) {
36472
36701
  REVIEW_REQUEST_TEMPLATE,
36473
36702
  REVIEW_SKILL_NAME,
36474
36703
  REVIEW_SKILL_PATH,
36704
+ RUN_PORTS_REL,
36475
36705
  RUN_SCRIPT_DESKTOP_ADOPT_MS,
36476
36706
  SEED_FULL_TOOL_MESSAGES,
36477
36707
  SEED_MAX_CHARS,
@@ -36902,6 +37132,7 @@ async function startSlackRelayServer(opts) {
36902
37132
  isOptionalServiceId,
36903
37133
  isOrchestratorCapableAgent,
36904
37134
  isOrchestratorThread,
37135
+ isOtherWorktreeListenerCwd,
36905
37136
  isPidAlive,
36906
37137
  isPlaceholderBranch,
36907
37138
  isPlanQuestionAnswersMessage,
@@ -36933,6 +37164,7 @@ async function startSlackRelayServer(opts) {
36933
37164
  issueSourceLabel,
36934
37165
  issueTicketFromThread,
36935
37166
  killListenersOnPorts,
37167
+ killStaleWorktreeListeners,
36936
37168
  killableListenerPids,
36937
37169
  lastAgentReply,
36938
37170
  lastAssistantMessageText,
@@ -36980,6 +37212,7 @@ async function startSlackRelayServer(opts) {
36980
37212
  listWorkspaces,
36981
37213
  listWorktreeFiles,
36982
37214
  listWorktrees,
37215
+ listenerCwd,
36983
37216
  liveActivitySummary,
36984
37217
  loadAppSettings,
36985
37218
  loadBrightsyConfig,
@@ -36987,9 +37220,11 @@ async function startSlackRelayServer(opts) {
36987
37220
  loadHomeBoardInputs,
36988
37221
  loadRepoSettings,
36989
37222
  loadWorkspaceSettings,
37223
+ loadWorktreeRunPorts,
36990
37224
  localhostPreviewUrl,
36991
37225
  locksDir,
36992
37226
  loginAgent,
37227
+ looksLikeComposerSkillExpansion,
36993
37228
  looksLikeConversationSummary,
36994
37229
  looksLikeSkillBody,
36995
37230
  lookupSoccerTeam,
@@ -37180,6 +37415,7 @@ async function startSlackRelayServer(opts) {
37180
37415
  saveAbleTimeConnection,
37181
37416
  saveAppSettings,
37182
37417
  saveLinearOAuth,
37418
+ saveWorktreeRunPorts,
37183
37419
  schedulesPath,
37184
37420
  scrubGithubTokensFromChildEnv,
37185
37421
  searchAbleTimeTasks,
@@ -37269,6 +37505,8 @@ async function startSlackRelayServer(opts) {
37269
37505
  toolFilePath,
37270
37506
  totalTokens,
37271
37507
  trustSystemCertificates,
37508
+ tryReservePort,
37509
+ tryReservePorts,
37272
37510
  turnCostUsdFromCursorUsage,
37273
37511
  updateAbleTimeTask,
37274
37512
  updateAdvancedSettings,
@@ -37307,6 +37545,7 @@ async function startSlackRelayServer(opts) {
37307
37545
  worktreeDisplayLabel,
37308
37546
  worktreeDisplayLabelForGroup,
37309
37547
  worktreeNameFromPath,
37548
+ worktreeRunPortsPath,
37310
37549
  worktreeSlugForTicket,
37311
37550
  worktreesRoot,
37312
37551
  wrapReviewSkillMarkdown,