@sideboard-ai/core 0.1.237 → 0.1.239

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.
@@ -11236,10 +11236,10 @@ function eventsFromClaudeSystem(obj) {
11236
11236
  if (subtype === "api_retry") {
11237
11237
  const attempt = obj.attempt;
11238
11238
  const max = obj.max_retries;
11239
- const delay = obj.retry_delay_ms;
11239
+ const delay2 = obj.retry_delay_ms;
11240
11240
  return {
11241
11241
  type: "thinking",
11242
- data: `API retry ${attempt ?? "?"}/${max ?? "?"}${typeof delay === "number" ? ` (wait ${delay}ms)` : ""}`
11242
+ data: `API retry ${attempt ?? "?"}/${max ?? "?"}${typeof delay2 === "number" ? ` (wait ${delay2}ms)` : ""}`
11243
11243
  };
11244
11244
  }
11245
11245
  if (subtype === "status") {
@@ -14525,15 +14525,76 @@ var init_request_review = __esm({
14525
14525
  }
14526
14526
  });
14527
14527
 
14528
+ // src/hook/worktree-run-ports.ts
14529
+ function worktreeRunPortsPath(worktreePath) {
14530
+ return (0, import_node_path38.join)(worktreePath, RUN_PORTS_REL);
14531
+ }
14532
+ function isPort(value) {
14533
+ return typeof value === "number" && Number.isInteger(value) && value > 0 && value <= 65535;
14534
+ }
14535
+ function parseFile(raw) {
14536
+ try {
14537
+ const parsed = JSON.parse(raw);
14538
+ if (!parsed || typeof parsed !== "object") return {};
14539
+ const scripts = parsed.scripts;
14540
+ if (!scripts || typeof scripts !== "object") return {};
14541
+ const next = {};
14542
+ for (const [name, ports] of Object.entries(scripts)) {
14543
+ if (!name || !Array.isArray(ports)) continue;
14544
+ const cleaned = ports.filter(isPort);
14545
+ if (cleaned.length) next[name] = cleaned;
14546
+ }
14547
+ return { scripts: next };
14548
+ } catch {
14549
+ return {};
14550
+ }
14551
+ }
14552
+ function loadWorktreeRunPorts(worktreePath, scriptName) {
14553
+ if (!worktreePath.trim() || !scriptName.trim()) return null;
14554
+ try {
14555
+ const raw = (0, import_node_fs38.readFileSync)(worktreeRunPortsPath(worktreePath), "utf8");
14556
+ const ports = parseFile(raw).scripts?.[scriptName];
14557
+ return ports?.length ? ports : null;
14558
+ } catch {
14559
+ return null;
14560
+ }
14561
+ }
14562
+ function saveWorktreeRunPorts(worktreePath, scriptName, ports) {
14563
+ if (!worktreePath.trim() || !scriptName.trim()) return;
14564
+ const cleaned = ports.filter(isPort);
14565
+ if (!cleaned.length) return;
14566
+ const path = worktreeRunPortsPath(worktreePath);
14567
+ let current = {};
14568
+ try {
14569
+ current = parseFile((0, import_node_fs38.readFileSync)(path, "utf8"));
14570
+ } catch {
14571
+ current = {};
14572
+ }
14573
+ const scripts = { ...current.scripts ?? {} };
14574
+ scripts[scriptName] = cleaned;
14575
+ (0, import_node_fs38.mkdirSync)((0, import_node_path38.dirname)(path), { recursive: true });
14576
+ (0, import_node_fs38.writeFileSync)(path, `${JSON.stringify({ scripts }, null, 2)}
14577
+ `, "utf8");
14578
+ }
14579
+ var import_node_fs38, import_node_path38, RUN_PORTS_REL;
14580
+ var init_worktree_run_ports = __esm({
14581
+ "src/hook/worktree-run-ports.ts"() {
14582
+ "use strict";
14583
+ import_node_fs38 = require("fs");
14584
+ import_node_path38 = require("path");
14585
+ RUN_PORTS_REL = ".context/.sideboard/run-ports.json";
14586
+ }
14587
+ });
14588
+
14528
14589
  // src/hook/conductor.ts
14529
14590
  function matchSimpleGlob(pattern, name) {
14530
14591
  const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
14531
14592
  return new RegExp(`^${escaped}$`).test(name);
14532
14593
  }
14533
14594
  function readWorktreeInclude(repoPath) {
14534
- const path = (0, import_node_path38.join)(repoPath, ".worktreeinclude");
14535
- if (!(0, import_node_fs38.existsSync)(path)) return [];
14536
- return (0, import_node_fs38.readFileSync)(path, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
14595
+ const path = (0, import_node_path39.join)(repoPath, ".worktreeinclude");
14596
+ if (!(0, import_node_fs39.existsSync)(path)) return [];
14597
+ return (0, import_node_fs39.readFileSync)(path, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
14537
14598
  }
14538
14599
  function resolveFilesToCopy(repoPath) {
14539
14600
  const fromInclude = readWorktreeInclude(repoPath);
@@ -14543,10 +14604,10 @@ function resolveFilesToCopy(repoPath) {
14543
14604
  if (settings?.fileIncludeGlobs?.length) {
14544
14605
  const matched = [];
14545
14606
  try {
14546
- for (const entry of (0, import_node_fs38.readdirSync)(repoPath, { withFileTypes: true })) {
14607
+ for (const entry of (0, import_node_fs39.readdirSync)(repoPath, { withFileTypes: true })) {
14547
14608
  if (!entry.isFile()) continue;
14548
14609
  for (const glob of settings.fileIncludeGlobs) {
14549
- if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path38.basename)(glob), entry.name)) {
14610
+ if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path39.basename)(glob), entry.name)) {
14550
14611
  matched.push(entry.name);
14551
14612
  break;
14552
14613
  }
@@ -14558,7 +14619,7 @@ function resolveFilesToCopy(repoPath) {
14558
14619
  }
14559
14620
  const defaults = [];
14560
14621
  try {
14561
- for (const entry of (0, import_node_fs38.readdirSync)(repoPath, { withFileTypes: true })) {
14622
+ for (const entry of (0, import_node_fs39.readdirSync)(repoPath, { withFileTypes: true })) {
14562
14623
  if (entry.isFile() && entry.name.startsWith(".env")) {
14563
14624
  defaults.push(entry.name);
14564
14625
  }
@@ -14572,11 +14633,11 @@ function copyConfiguredFiles(repoPath, worktreePath) {
14572
14633
  const patterns = resolveFilesToCopy(repoPath);
14573
14634
  const copied = [];
14574
14635
  for (const rel of patterns) {
14575
- const src = (0, import_node_path38.join)(repoPath, rel);
14576
- if (!(0, import_node_fs38.existsSync)(src)) continue;
14577
- const dest = (0, import_node_path38.join)(worktreePath, rel);
14578
- (0, import_node_fs38.mkdirSync)((0, import_node_path38.dirname)(dest), { recursive: true });
14579
- (0, import_node_fs38.copyFileSync)(src, dest);
14636
+ const src = (0, import_node_path39.join)(repoPath, rel);
14637
+ if (!(0, import_node_fs39.existsSync)(src)) continue;
14638
+ const dest = (0, import_node_path39.join)(worktreePath, rel);
14639
+ (0, import_node_fs39.mkdirSync)((0, import_node_path39.dirname)(dest), { recursive: true });
14640
+ (0, import_node_fs39.copyFileSync)(src, dest);
14580
14641
  copied.push(rel);
14581
14642
  }
14582
14643
  return copied;
@@ -14611,7 +14672,7 @@ function buildWorkspaceScriptEnv(opts, baseEnv) {
14611
14672
  const env = stripNestedElectronEnv({
14612
14673
  ...baseEnv ?? process.env
14613
14674
  });
14614
- const name = opts.workspaceName ?? (0, import_node_path38.basename)(opts.worktreePath);
14675
+ const name = opts.workspaceName ?? (0, import_node_path39.basename)(opts.worktreePath);
14615
14676
  const ports = opts.ports ?? [];
14616
14677
  const primary = ports[0];
14617
14678
  env.SIDEBOARD_WORKSPACE_NAME = name;
@@ -14651,6 +14712,57 @@ function killableListenerPids(raw, selfPid = process.pid) {
14651
14712
  }
14652
14713
  return pids;
14653
14714
  }
14715
+ function listUnixListenerPids(port, selfPid) {
14716
+ try {
14717
+ const raw = (0, import_node_child_process4.execFileSync)("lsof", [`-tiTCP:${port}`, "-sTCP:LISTEN"], {
14718
+ encoding: "utf8",
14719
+ stdio: ["ignore", "pipe", "ignore"],
14720
+ timeout: 2e3
14721
+ });
14722
+ return killableListenerPids(raw, selfPid);
14723
+ } catch {
14724
+ return [];
14725
+ }
14726
+ }
14727
+ function listenerCwd(pid) {
14728
+ if (!Number.isFinite(pid) || pid <= 0) return null;
14729
+ try {
14730
+ const raw = (0, import_node_child_process4.execFileSync)("lsof", ["-a", "-p", String(pid), "-d", "cwd", "-Fn"], {
14731
+ encoding: "utf8",
14732
+ stdio: ["ignore", "pipe", "ignore"],
14733
+ timeout: 2e3
14734
+ });
14735
+ for (const line of raw.split("\n")) {
14736
+ if (line.startsWith("n") && line.length > 1) return line.slice(1);
14737
+ }
14738
+ } catch {
14739
+ }
14740
+ return null;
14741
+ }
14742
+ function realpathOrResolve(path) {
14743
+ try {
14744
+ return (0, import_node_fs39.realpathSync)(path);
14745
+ } catch {
14746
+ return (0, import_node_path39.resolve)(path);
14747
+ }
14748
+ }
14749
+ function isOtherWorktreeListenerCwd(cwd, worktreePath) {
14750
+ const wt = realpathOrResolve(worktreePath);
14751
+ const c = realpathOrResolve(cwd);
14752
+ if (c === wt || c.startsWith(wt + import_node_path39.sep)) return false;
14753
+ const parent = (0, import_node_path39.dirname)(wt);
14754
+ const thisName = (0, import_node_path39.basename)(wt);
14755
+ if (!thisName || c === parent) return false;
14756
+ if (!c.startsWith(parent + import_node_path39.sep)) return false;
14757
+ const first = c.slice(parent.length + 1).split(import_node_path39.sep)[0];
14758
+ return Boolean(first) && first !== thisName;
14759
+ }
14760
+ function signalPid(pid, signal) {
14761
+ try {
14762
+ process.kill(pid, signal);
14763
+ } catch {
14764
+ }
14765
+ }
14654
14766
  function killListenersOnPorts(ports) {
14655
14767
  const selfPid = process.pid;
14656
14768
  for (const port of ports) {
@@ -14668,26 +14780,32 @@ function killListenersOnPorts(ports) {
14668
14780
  );
14669
14781
  continue;
14670
14782
  }
14671
- let raw = "";
14672
- try {
14673
- raw = (0, import_node_child_process4.execFileSync)("lsof", [`-tiTCP:${port}`, "-sTCP:LISTEN"], {
14674
- encoding: "utf8",
14675
- stdio: ["ignore", "pipe", "ignore"],
14676
- timeout: 2e3
14677
- });
14678
- } catch {
14679
- continue;
14680
- }
14681
- for (const pid of killableListenerPids(raw, selfPid)) {
14682
- try {
14683
- process.kill(pid, "SIGTERM");
14684
- } catch {
14685
- }
14783
+ for (const pid of listUnixListenerPids(port, selfPid)) {
14784
+ signalPid(pid, "SIGTERM");
14686
14785
  }
14687
14786
  } catch {
14688
14787
  }
14689
14788
  }
14690
14789
  }
14790
+ function killStaleWorktreeListeners(ports, worktreePath, signal = "SIGTERM") {
14791
+ if (!worktreePath.trim()) {
14792
+ killListenersOnPorts(ports);
14793
+ return;
14794
+ }
14795
+ if (process.platform === "win32") {
14796
+ killListenersOnPorts(ports);
14797
+ return;
14798
+ }
14799
+ const selfPid = process.pid;
14800
+ for (const port of ports) {
14801
+ if (!Number.isFinite(port) || port <= 0) continue;
14802
+ for (const pid of listUnixListenerPids(port, selfPid)) {
14803
+ const cwd = listenerCwd(pid);
14804
+ if (cwd && isOtherWorktreeListenerCwd(cwd, worktreePath)) continue;
14805
+ signalPid(pid, signal);
14806
+ }
14807
+ }
14808
+ }
14691
14809
  function killScriptTree(child, ports = []) {
14692
14810
  const pid = child.pid;
14693
14811
  if (pid) {
@@ -14849,7 +14967,7 @@ function getRunMode(worktreePath, repoPath) {
14849
14967
  return loadWorkspaceSettings(worktreePath, repoPath)?.runMode ?? "concurrent";
14850
14968
  }
14851
14969
  async function reservePort() {
14852
- return new Promise((resolve, reject) => {
14970
+ return new Promise((resolve2, reject) => {
14853
14971
  const server = (0, import_node_net.createServer)();
14854
14972
  let released = false;
14855
14973
  const release = () => new Promise((res) => {
@@ -14866,13 +14984,14 @@ async function reservePort() {
14866
14984
  void release().then(() => reject(new Error("Failed to allocate port")));
14867
14985
  return;
14868
14986
  }
14869
- resolve({ port: addr.port, release });
14987
+ resolve2({ port: addr.port, release });
14870
14988
  });
14871
14989
  server.on("error", reject);
14872
14990
  });
14873
14991
  }
14874
14992
  async function tryReservePort(port) {
14875
- return new Promise((resolve) => {
14993
+ if (!Number.isInteger(port) || port <= 0 || port > 65535) return null;
14994
+ return new Promise((resolve2) => {
14876
14995
  const server = (0, import_node_net.createServer)();
14877
14996
  let released = false;
14878
14997
  const release = () => new Promise((res) => {
@@ -14883,24 +15002,54 @@ async function tryReservePort(port) {
14883
15002
  released = true;
14884
15003
  server.close(() => res());
14885
15004
  });
14886
- server.once("error", () => resolve(null));
15005
+ server.once("error", () => {
15006
+ try {
15007
+ server.close();
15008
+ } catch {
15009
+ }
15010
+ resolve2(null);
15011
+ });
14887
15012
  server.listen(port, "127.0.0.1", () => {
14888
- resolve({ port, release });
15013
+ resolve2({ port, release });
14889
15014
  });
14890
15015
  });
14891
15016
  }
14892
- async function reservePortRange(size = PORT_RANGE_SIZE) {
14893
- const held = [await reservePort()];
14894
- const base = held[0].port;
15017
+ async function tryReservePorts(ports) {
15018
+ const held = [];
15019
+ for (const port of ports) {
15020
+ const next = await tryReservePort(port);
15021
+ if (!next) {
15022
+ await Promise.all(held.map((h) => h.release()));
15023
+ return null;
15024
+ }
15025
+ held.push(next);
15026
+ }
15027
+ return held;
15028
+ }
15029
+ function normalizePreferredPorts(ports, size) {
15030
+ if (!ports?.length) return [];
15031
+ const seen = /* @__PURE__ */ new Set();
15032
+ const out = [];
15033
+ for (const p of ports) {
15034
+ if (!Number.isInteger(p) || p <= 0 || p > 65535 || seen.has(p)) continue;
15035
+ seen.add(p);
15036
+ out.push(p);
15037
+ if (out.length >= size) break;
15038
+ }
15039
+ return out;
15040
+ }
15041
+ function delay(ms) {
15042
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
15043
+ }
15044
+ async function fillPortRange(held, size) {
15045
+ if (held.length >= size) return held;
15046
+ const base = held[0]?.port;
14895
15047
  try {
14896
- for (let i = 1; i < size; i++) {
14897
- const candidate = base + i;
14898
- const next = await tryReservePort(candidate);
14899
- if (next) {
14900
- held.push(next);
14901
- } else {
14902
- held.push(await reservePort());
14903
- }
15048
+ for (let i = held.length; i < size; i++) {
15049
+ const candidate = base != null ? base + i : null;
15050
+ const next = candidate != null ? await tryReservePort(candidate) : null;
15051
+ if (next) held.push(next);
15052
+ else held.push(await reservePort());
14904
15053
  }
14905
15054
  return held;
14906
15055
  } catch (err) {
@@ -14908,11 +15057,43 @@ async function reservePortRange(size = PORT_RANGE_SIZE) {
14908
15057
  throw err;
14909
15058
  }
14910
15059
  }
15060
+ async function reclaimPreferredPorts(ports, worktreePath) {
15061
+ let held = await tryReservePorts(ports);
15062
+ if (held) return held;
15063
+ if (worktreePath) {
15064
+ killStaleWorktreeListeners(ports, worktreePath, "SIGTERM");
15065
+ } else {
15066
+ killListenersOnPorts(ports);
15067
+ }
15068
+ for (let i = 0; i < RECLAIM_TRIES; i++) {
15069
+ await delay(RECLAIM_RETRY_DELAY_MS);
15070
+ held = await tryReservePorts(ports);
15071
+ if (held) return held;
15072
+ if (i === 2 && worktreePath) {
15073
+ killStaleWorktreeListeners(ports, worktreePath, "SIGKILL");
15074
+ }
15075
+ }
15076
+ return null;
15077
+ }
15078
+ async function reservePortRange(size = PORT_RANGE_SIZE, opts) {
15079
+ const preferred = normalizePreferredPorts(opts?.preferred, size);
15080
+ if (preferred.length) {
15081
+ const reused = await reclaimPreferredPorts(preferred, opts?.worktreePath);
15082
+ if (reused) return fillPortRange(reused, size);
15083
+ }
15084
+ const held = [await reservePort()];
15085
+ return fillPortRange(held, size);
15086
+ }
14911
15087
  async function startDevServer(repoPath, worktreePath, onLine, opts) {
14912
15088
  const script = getRunScript(worktreePath, repoPath, opts?.scriptName);
14913
15089
  if (!script) return null;
14914
- const held = await reservePortRange(PORT_RANGE_SIZE);
15090
+ const preferred = loadWorktreeRunPorts(worktreePath, script.name) ?? opts?.preferredPorts;
15091
+ const held = await reservePortRange(PORT_RANGE_SIZE, {
15092
+ preferred: preferred ?? void 0,
15093
+ worktreePath
15094
+ });
14915
15095
  const ports = held.map((h) => h.port);
15096
+ saveWorktreeRunPorts(worktreePath, script.name, ports);
14916
15097
  try {
14917
15098
  const handle = await spawnWorkspaceScript(script.command, {
14918
15099
  worktreePath,
@@ -14935,14 +15116,14 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
14935
15116
  throw err;
14936
15117
  }
14937
15118
  }
14938
- var import_node_fs38, import_node_child_process4, import_node_net, import_node_path38, import_execa4, import_node_readline3, PORT_RANGE_SIZE, cachedLoginEnv;
15119
+ var import_node_fs39, import_node_child_process4, import_node_net, import_node_path39, import_execa4, import_node_readline3, PORT_RANGE_SIZE, RECLAIM_RETRY_DELAY_MS, RECLAIM_TRIES, cachedLoginEnv;
14939
15120
  var init_conductor = __esm({
14940
15121
  "src/hook/conductor.ts"() {
14941
15122
  "use strict";
14942
- import_node_fs38 = require("fs");
15123
+ import_node_fs39 = require("fs");
14943
15124
  import_node_child_process4 = require("child_process");
14944
15125
  import_node_net = require("net");
14945
- import_node_path38 = require("path");
15126
+ import_node_path39 = require("path");
14946
15127
  import_execa4 = require("execa");
14947
15128
  import_node_readline3 = require("readline");
14948
15129
  init_settings();
@@ -14953,8 +15134,12 @@ var init_conductor = __esm({
14953
15134
  init_git_auth_mode();
14954
15135
  init_request_review();
14955
15136
  init_worktree_exclude();
15137
+ init_worktree_run_ports();
15138
+ init_worktree_run_ports();
14956
15139
  init_nested_electron_env();
14957
15140
  PORT_RANGE_SIZE = 10;
15141
+ RECLAIM_RETRY_DELAY_MS = 40;
15142
+ RECLAIM_TRIES = 8;
14958
15143
  cachedLoginEnv = null;
14959
15144
  }
14960
15145
  });
@@ -14992,7 +15177,7 @@ function materialize(mem) {
14992
15177
  };
14993
15178
  }
14994
15179
  function setupLogPath(threadId) {
14995
- return (0, import_node_path39.join)(threadsDir(), `${threadId}.setup.log.json`);
15180
+ return (0, import_node_path40.join)(threadsDir(), `${threadId}.setup.log.json`);
14996
15181
  }
14997
15182
  function setupLogKeyForWorktree(worktreePath) {
14998
15183
  const norm = normalizeWorktreePath(worktreePath);
@@ -15010,7 +15195,7 @@ function persistNow(threadId) {
15010
15195
  const mem = memory.get(threadId);
15011
15196
  if (!mem) return;
15012
15197
  try {
15013
- (0, import_node_fs39.writeFileSync)(
15198
+ (0, import_node_fs40.writeFileSync)(
15014
15199
  setupLogPath(threadId),
15015
15200
  `${JSON.stringify(materialize(mem))}
15016
15201
  `,
@@ -15031,9 +15216,9 @@ function schedulePersist(threadId) {
15031
15216
  }
15032
15217
  function loadFromDisk(threadId) {
15033
15218
  const path = setupLogPath(threadId);
15034
- if (!(0, import_node_fs39.existsSync)(path)) return null;
15219
+ if (!(0, import_node_fs40.existsSync)(path)) return null;
15035
15220
  try {
15036
- const raw = JSON.parse((0, import_node_fs39.readFileSync)(path, "utf8"));
15221
+ const raw = JSON.parse((0, import_node_fs40.readFileSync)(path, "utf8"));
15037
15222
  return {
15038
15223
  output: typeof raw.output === "string" ? raw.output : "",
15039
15224
  running: Boolean(raw.running),
@@ -15089,13 +15274,13 @@ function finishSetupLog(threadId, exitCode, source) {
15089
15274
  persistNow(threadId);
15090
15275
  return materialize(mem);
15091
15276
  }
15092
- var import_node_crypto8, import_node_fs39, import_node_path39, EMPTY, MAX_SETUP_LOG_CHARS, memory, persistTimers, PERSIST_DEBOUNCE_MS;
15277
+ var import_node_crypto8, import_node_fs40, import_node_path40, EMPTY, MAX_SETUP_LOG_CHARS, memory, persistTimers, PERSIST_DEBOUNCE_MS;
15093
15278
  var init_setup_log = __esm({
15094
15279
  "src/store/setup-log.ts"() {
15095
15280
  "use strict";
15096
15281
  import_node_crypto8 = require("crypto");
15097
- import_node_fs39 = require("fs");
15098
- import_node_path39 = require("path");
15282
+ import_node_fs40 = require("fs");
15283
+ import_node_path40 = require("path");
15099
15284
  init_worktree_labels();
15100
15285
  init_paths();
15101
15286
  EMPTY = {
@@ -15140,7 +15325,7 @@ function safeScriptToken(scriptName) {
15140
15325
  return token || "dev";
15141
15326
  }
15142
15327
  function runLogPath(key) {
15143
- return (0, import_node_path40.join)(threadsDir(), `${key}.run.log.json`);
15328
+ return (0, import_node_path41.join)(threadsDir(), `${key}.run.log.json`);
15144
15329
  }
15145
15330
  function runLogKeyForWorktree(worktreePath, scriptName) {
15146
15331
  const norm = normalizeWorktreePath(worktreePath);
@@ -15168,7 +15353,7 @@ function persistNow2(key) {
15168
15353
  const mem = memory2.get(key);
15169
15354
  if (!mem) return;
15170
15355
  try {
15171
- (0, import_node_fs40.writeFileSync)(runLogPath(key), `${JSON.stringify(materialize2(mem))}
15356
+ (0, import_node_fs41.writeFileSync)(runLogPath(key), `${JSON.stringify(materialize2(mem))}
15172
15357
  `, "utf8");
15173
15358
  } catch {
15174
15359
  }
@@ -15185,9 +15370,9 @@ function schedulePersist2(key) {
15185
15370
  }
15186
15371
  function loadFromDisk2(key) {
15187
15372
  const path = runLogPath(key);
15188
- if (!(0, import_node_fs40.existsSync)(path)) return null;
15373
+ if (!(0, import_node_fs41.existsSync)(path)) return null;
15189
15374
  try {
15190
- const raw = JSON.parse((0, import_node_fs40.readFileSync)(path, "utf8"));
15375
+ const raw = JSON.parse((0, import_node_fs41.readFileSync)(path, "utf8"));
15191
15376
  return {
15192
15377
  output: typeof raw.output === "string" ? raw.output : "",
15193
15378
  running: Boolean(raw.running),
@@ -15245,13 +15430,13 @@ function finishRunLog(key, exitCode) {
15245
15430
  function flushRunLog(key) {
15246
15431
  persistNow2(key);
15247
15432
  }
15248
- var import_node_crypto9, import_node_fs40, import_node_path40, EMPTY2, MAX_RUN_LOG_CHARS, DEFAULT_RUN_LOG_TAIL_CHARS, memory2, persistTimers2, PERSIST_DEBOUNCE_MS2;
15433
+ var import_node_crypto9, import_node_fs41, import_node_path41, EMPTY2, MAX_RUN_LOG_CHARS, DEFAULT_RUN_LOG_TAIL_CHARS, memory2, persistTimers2, PERSIST_DEBOUNCE_MS2;
15249
15434
  var init_run_log = __esm({
15250
15435
  "src/store/run-log.ts"() {
15251
15436
  "use strict";
15252
15437
  import_node_crypto9 = require("crypto");
15253
- import_node_fs40 = require("fs");
15254
- import_node_path40 = require("path");
15438
+ import_node_fs41 = require("fs");
15439
+ import_node_path41 = require("path");
15255
15440
  init_worktree_labels();
15256
15441
  init_setup_log();
15257
15442
  init_paths();
@@ -15280,9 +15465,9 @@ async function findOrphanWorktrees(repoPaths) {
15280
15465
  repoPaths?.length ? repoPaths : threads.map((t) => t.repoPath).filter(Boolean)
15281
15466
  );
15282
15467
  const homeRoot = sideboardWorkspacesDir();
15283
- if ((0, import_node_fs41.existsSync)(homeRoot)) {
15468
+ if ((0, import_node_fs42.existsSync)(homeRoot)) {
15284
15469
  try {
15285
- for (const entry of (0, import_node_fs41.readdirSync)(homeRoot, { withFileTypes: true })) {
15470
+ for (const entry of (0, import_node_fs42.readdirSync)(homeRoot, { withFileTypes: true })) {
15286
15471
  if (!entry.isDirectory()) continue;
15287
15472
  void entry;
15288
15473
  }
@@ -15292,7 +15477,7 @@ async function findOrphanWorktrees(repoPaths) {
15292
15477
  const orphans = [];
15293
15478
  const seen = /* @__PURE__ */ new Set();
15294
15479
  for (const repoPath of repos) {
15295
- if (!repoPath || !(0, import_node_fs41.existsSync)(repoPath)) continue;
15480
+ if (!repoPath || !(0, import_node_fs42.existsSync)(repoPath)) continue;
15296
15481
  try {
15297
15482
  const wts = await listWorktrees(repoPath);
15298
15483
  for (const wt of wts) {
@@ -15303,7 +15488,7 @@ async function findOrphanWorktrees(repoPaths) {
15303
15488
  seen.add(path);
15304
15489
  let mtimeMs = 0;
15305
15490
  try {
15306
- mtimeMs = (0, import_node_fs41.statSync)(path).mtimeMs;
15491
+ mtimeMs = (0, import_node_fs42.statSync)(path).mtimeMs;
15307
15492
  } catch {
15308
15493
  mtimeMs = 0;
15309
15494
  }
@@ -15313,16 +15498,16 @@ async function findOrphanWorktrees(repoPaths) {
15313
15498
  }
15314
15499
  try {
15315
15500
  const root = worktreesRoot(repoPath);
15316
- if ((0, import_node_fs41.existsSync)(root)) {
15317
- for (const entry of (0, import_node_fs41.readdirSync)(root, { withFileTypes: true })) {
15501
+ if ((0, import_node_fs42.existsSync)(root)) {
15502
+ for (const entry of (0, import_node_fs42.readdirSync)(root, { withFileTypes: true })) {
15318
15503
  if (!entry.isDirectory()) continue;
15319
- const path = (0, import_node_path41.join)(root, entry.name).replace(/\/$/, "");
15504
+ const path = (0, import_node_path42.join)(root, entry.name).replace(/\/$/, "");
15320
15505
  if (known.has(path) || seen.has(path)) continue;
15321
- if (!(0, import_node_fs41.existsSync)((0, import_node_path41.join)(path, ".git"))) continue;
15506
+ if (!(0, import_node_fs42.existsSync)((0, import_node_path42.join)(path, ".git"))) continue;
15322
15507
  seen.add(path);
15323
15508
  let mtimeMs = 0;
15324
15509
  try {
15325
- mtimeMs = (0, import_node_fs41.statSync)(path).mtimeMs;
15510
+ mtimeMs = (0, import_node_fs42.statSync)(path).mtimeMs;
15326
15511
  } catch {
15327
15512
  mtimeMs = Date.now();
15328
15513
  }
@@ -15374,12 +15559,12 @@ function shouldRunWorktreeCleanup(settings = loadAppSettings()) {
15374
15559
  const elapsed = Date.now() - Date.parse(last);
15375
15560
  return elapsed >= intervalHours * 36e5;
15376
15561
  }
15377
- var import_node_fs41, import_node_path41;
15562
+ var import_node_fs42, import_node_path42;
15378
15563
  var init_orphan_cleanup = __esm({
15379
15564
  "src/git/orphan-cleanup.ts"() {
15380
15565
  "use strict";
15381
- import_node_fs41 = require("fs");
15382
- import_node_path41 = require("path");
15566
+ import_node_fs42 = require("fs");
15567
+ import_node_path42 = require("path");
15383
15568
  init_worktree();
15384
15569
  init_thread_store();
15385
15570
  init_paths();
@@ -15554,12 +15739,12 @@ async function cloneRepoIntoSideboard(opts) {
15554
15739
  if (!url) throw new Error("Clone URL is required");
15555
15740
  let name = opts.name?.trim();
15556
15741
  if (!name) {
15557
- const leaf = (0, import_node_path42.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
15742
+ const leaf = (0, import_node_path43.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
15558
15743
  name = leaf || "repo";
15559
15744
  }
15560
15745
  name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
15561
- const dest = (0, import_node_path42.join)(sideboardReposDir(), name);
15562
- if ((0, import_node_fs42.existsSync)(dest)) {
15746
+ const dest = (0, import_node_path43.join)(sideboardReposDir(), name);
15747
+ if ((0, import_node_fs43.existsSync)(dest)) {
15563
15748
  const repoPath2 = await resolveRepoRoot(dest);
15564
15749
  const workspace2 = await ensureWorkspace(repoPath2);
15565
15750
  return { repoPath: repoPath2, workspace: workspace2 };
@@ -15574,12 +15759,12 @@ async function cloneRepoIntoSideboard(opts) {
15574
15759
  const workspace = await ensureWorkspace(repoPath);
15575
15760
  return { repoPath, workspace };
15576
15761
  }
15577
- var import_node_fs42, import_node_path42, import_execa6;
15762
+ var import_node_fs43, import_node_path43, import_execa6;
15578
15763
  var init_clone_repo = __esm({
15579
15764
  "src/git/clone-repo.ts"() {
15580
15765
  "use strict";
15581
- import_node_fs42 = require("fs");
15582
- import_node_path42 = require("path");
15766
+ import_node_fs43 = require("fs");
15767
+ import_node_path43 = require("path");
15583
15768
  import_execa6 = require("execa");
15584
15769
  init_paths();
15585
15770
  init_workspaces();
@@ -15599,11 +15784,11 @@ var init_thread = __esm({
15599
15784
 
15600
15785
  // src/store/desktop-host.ts
15601
15786
  function desktopHostPidPath() {
15602
- return (0, import_node_path43.join)(appDataDir(), "desktop-host.pid");
15787
+ return (0, import_node_path44.join)(appDataDir(), "desktop-host.pid");
15603
15788
  }
15604
15789
  function readDesktopHostPid() {
15605
15790
  try {
15606
- const pid = Number.parseInt((0, import_node_fs43.readFileSync)(desktopHostPidPath(), "utf8").trim(), 10);
15791
+ const pid = Number.parseInt((0, import_node_fs44.readFileSync)(desktopHostPidPath(), "utf8").trim(), 10);
15607
15792
  if (!Number.isFinite(pid) || pid <= 0) return null;
15608
15793
  return pid;
15609
15794
  } catch {
@@ -15629,12 +15814,12 @@ function thisProcessShouldDrainAgentQueues() {
15629
15814
  if (isThisProcessDesktopHost()) return true;
15630
15815
  return !isDesktopHostAlive();
15631
15816
  }
15632
- var import_node_fs43, import_node_path43;
15817
+ var import_node_fs44, import_node_path44;
15633
15818
  var init_desktop_host = __esm({
15634
15819
  "src/store/desktop-host.ts"() {
15635
15820
  "use strict";
15636
- import_node_fs43 = require("fs");
15637
- import_node_path43 = require("path");
15821
+ import_node_fs44 = require("fs");
15822
+ import_node_path44 = require("path");
15638
15823
  init_paths();
15639
15824
  }
15640
15825
  });
@@ -15760,24 +15945,24 @@ function jobTreeAlive(pid) {
15760
15945
  return jobAlive(pid) || processGroupAlive(pid);
15761
15946
  }
15762
15947
  function readIntFile(file) {
15763
- if (!(0, import_node_fs44.existsSync)(file)) return null;
15764
- const n = Number.parseInt((0, import_node_fs44.readFileSync)(file, "utf8").trim(), 10);
15948
+ if (!(0, import_node_fs45.existsSync)(file)) return null;
15949
+ const n = Number.parseInt((0, import_node_fs45.readFileSync)(file, "utf8").trim(), 10);
15765
15950
  return Number.isInteger(n) ? n : null;
15766
15951
  }
15767
15952
  function jobDir(root, id, legacy = false) {
15768
- return (0, import_node_path44.join)(root, legacy ? LEGACY_DETACHED_JOBS_DIR : DETACHED_JOBS_DIR, id);
15953
+ return (0, import_node_path45.join)(root, legacy ? LEGACY_DETACHED_JOBS_DIR : DETACHED_JOBS_DIR, id);
15769
15954
  }
15770
15955
  function resolveJobDir(root, id) {
15771
15956
  const modern = jobDir(root, id, false);
15772
- if ((0, import_node_fs44.existsSync)(modern)) return modern;
15957
+ if ((0, import_node_fs45.existsSync)(modern)) return modern;
15773
15958
  const legacy = jobDir(root, id, true);
15774
- if ((0, import_node_fs44.existsSync)(legacy)) return legacy;
15959
+ if ((0, import_node_fs45.existsSync)(legacy)) return legacy;
15775
15960
  return modern;
15776
15961
  }
15777
15962
  function listJobIdsIn(root, rel) {
15778
- const dir = (0, import_node_path44.join)(root, rel);
15779
- if (!(0, import_node_fs44.existsSync)(dir)) return [];
15780
- return (0, import_node_fs44.readdirSync)(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && JOB_ID_RE.test(e.name)).map((e) => e.name);
15963
+ const dir = (0, import_node_path45.join)(root, rel);
15964
+ if (!(0, import_node_fs45.existsSync)(dir)) return [];
15965
+ return (0, import_node_fs45.readdirSync)(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && JOB_ID_RE.test(e.name)).map((e) => e.name);
15781
15966
  }
15782
15967
  function listRunningDetachedJobs(worktreePath) {
15783
15968
  const root = worktreePath.trim();
@@ -15789,7 +15974,7 @@ function listRunningDetachedJobs(worktreePath) {
15789
15974
  const running = [];
15790
15975
  for (const id of ids) {
15791
15976
  const dir = resolveJobDir(root, id);
15792
- const pid = readIntFile((0, import_node_path44.join)(dir, "pid"));
15977
+ const pid = readIntFile((0, import_node_path45.join)(dir, "pid"));
15793
15978
  if (jobTreeAlive(pid)) running.push(id);
15794
15979
  }
15795
15980
  return running.sort();
@@ -15872,8 +16057,8 @@ function planJobContinue(opts) {
15872
16057
  return { action: "none" };
15873
16058
  }
15874
16059
  function tailProgress(logFile, maxLines = 12) {
15875
- if (!(0, import_node_fs44.existsSync)(logFile)) return "(no log yet)";
15876
- const lines = (0, import_node_fs44.readFileSync)(logFile, "utf8").split("\n");
16060
+ if (!(0, import_node_fs45.existsSync)(logFile)) return "(no log yet)";
16061
+ const lines = (0, import_node_fs45.readFileSync)(logFile, "utf8").split("\n");
15877
16062
  return lines.slice(-maxLines).join("\n");
15878
16063
  }
15879
16064
  function lastProgressLine(progress) {
@@ -15881,8 +16066,8 @@ function lastProgressLine(progress) {
15881
16066
  return last ? last.slice(0, 72) : void 0;
15882
16067
  }
15883
16068
  function readLogLines(file) {
15884
- if (!(0, import_node_fs44.existsSync)(file)) return [];
15885
- const lines = (0, import_node_fs44.readFileSync)(file, "utf8").split("\n");
16069
+ if (!(0, import_node_fs45.existsSync)(file)) return [];
16070
+ const lines = (0, import_node_fs45.readFileSync)(file, "utf8").split("\n");
15886
16071
  if (lines.length && lines[lines.length - 1] === "") lines.pop();
15887
16072
  return lines;
15888
16073
  }
@@ -15893,15 +16078,15 @@ function takeDelta(logFile, cursorFile) {
15893
16078
  return { delta: capJobLogDelta(lines.slice(start).join("\n")), nextCursor: lines.length };
15894
16079
  }
15895
16080
  function snapshotJob(dir) {
15896
- const pid = readIntFile((0, import_node_path44.join)(dir, "pid"));
16081
+ const pid = readIntFile((0, import_node_path45.join)(dir, "pid"));
15897
16082
  const running = jobTreeAlive(pid);
15898
16083
  return {
15899
16084
  pid,
15900
16085
  running,
15901
- exitCode: readIntFile((0, import_node_path44.join)(dir, "exit")),
15902
- log: (0, import_node_path44.join)(dir, "log"),
15903
- cursor: (0, import_node_path44.join)(dir, "present.cursor"),
15904
- progress: tailProgress((0, import_node_path44.join)(dir, "log"))
16086
+ exitCode: readIntFile((0, import_node_path45.join)(dir, "exit")),
16087
+ log: (0, import_node_path45.join)(dir, "log"),
16088
+ cursor: (0, import_node_path45.join)(dir, "present.cursor"),
16089
+ progress: tailProgress((0, import_node_path45.join)(dir, "log"))
15905
16090
  };
15906
16091
  }
15907
16092
  function toResult(id, snap, extra) {
@@ -15910,8 +16095,8 @@ function toResult(id, snap, extra) {
15910
16095
  const stillRunning = snap.running && !ok;
15911
16096
  const { delta, nextCursor } = takeDelta(snap.log, snap.cursor);
15912
16097
  try {
15913
- (0, import_node_fs44.mkdirSync)((0, import_node_path44.dirname)(snap.cursor), { recursive: true });
15914
- (0, import_node_fs44.writeFileSync)(snap.cursor, `${nextCursor}
16098
+ (0, import_node_fs45.mkdirSync)((0, import_node_path45.dirname)(snap.cursor), { recursive: true });
16099
+ (0, import_node_fs45.writeFileSync)(snap.cursor, `${nextCursor}
15915
16100
  `);
15916
16101
  } catch {
15917
16102
  }
@@ -15932,7 +16117,7 @@ function toResult(id, snap, extra) {
15932
16117
  };
15933
16118
  }
15934
16119
  async function sleepMs(ms) {
15935
- await new Promise((resolve) => setTimeout(resolve, ms));
16120
+ await new Promise((resolve2) => setTimeout(resolve2, ms));
15936
16121
  }
15937
16122
  async function waitForDetachedJob(cwd, id, opts) {
15938
16123
  const jobId = sanitizeDetachedJobId(id);
@@ -15940,7 +16125,7 @@ async function waitForDetachedJob(cwd, id, opts) {
15940
16125
  const dir = resolveJobDir(root, jobId);
15941
16126
  const timeoutMs = mcpWaitForJobTimeoutMs(opts?.timeoutMs);
15942
16127
  const sleep = opts?.sleep ?? sleepMs;
15943
- if (!(0, import_node_fs44.existsSync)(dir)) {
16128
+ if (!(0, import_node_fs45.existsSync)(dir)) {
15944
16129
  return {
15945
16130
  stillRunning: false,
15946
16131
  ok: false,
@@ -15986,10 +16171,10 @@ function killProcessTree(pid, signal) {
15986
16171
  }
15987
16172
  function appendJobLog(logFile, line) {
15988
16173
  try {
15989
- (0, import_node_fs44.mkdirSync)((0, import_node_path44.dirname)(logFile), { recursive: true });
16174
+ (0, import_node_fs45.mkdirSync)((0, import_node_path45.dirname)(logFile), { recursive: true });
15990
16175
  const body = line.endsWith("\n") ? line : `${line}
15991
16176
  `;
15992
- (0, import_node_fs44.appendFileSync)(logFile, body);
16177
+ (0, import_node_fs45.appendFileSync)(logFile, body);
15993
16178
  } catch {
15994
16179
  }
15995
16180
  }
@@ -15999,7 +16184,7 @@ async function stopDetachedJob(cwd, id, opts) {
15999
16184
  const dir = resolveJobDir(root, jobId);
16000
16185
  const sleep = opts?.sleep ?? sleepMs;
16001
16186
  const why = opts?.reason?.trim() ?? "";
16002
- if (!(0, import_node_fs44.existsSync)(dir)) {
16187
+ if (!(0, import_node_fs45.existsSync)(dir)) {
16003
16188
  return {
16004
16189
  stillRunning: false,
16005
16190
  ok: false,
@@ -16035,10 +16220,10 @@ async function stopDetachedJob(cwd, id, opts) {
16035
16220
  killProcessTree(targetPid, "SIGKILL");
16036
16221
  await sleep(100);
16037
16222
  }
16038
- const exitFile = (0, import_node_path44.join)(dir, "exit");
16039
- if (!(0, import_node_fs44.existsSync)(exitFile)) {
16223
+ const exitFile = (0, import_node_path45.join)(dir, "exit");
16224
+ if (!(0, import_node_fs45.existsSync)(exitFile)) {
16040
16225
  try {
16041
- (0, import_node_fs44.writeFileSync)(exitFile, "1\n");
16226
+ (0, import_node_fs45.writeFileSync)(exitFile, "1\n");
16042
16227
  } catch {
16043
16228
  }
16044
16229
  }
@@ -16058,12 +16243,12 @@ async function stopDetachedJob(cwd, id, opts) {
16058
16243
  hint: stopped ? MCP_STOP_JOB_HINT : MCP_WAIT_JOB_STILL_RUNNING_HINT
16059
16244
  };
16060
16245
  }
16061
- var import_node_fs44, import_node_path44, 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;
16246
+ var import_node_fs45, import_node_path45, 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;
16062
16247
  var init_wait_for_job = __esm({
16063
16248
  "src/mcp/wait-for-job.ts"() {
16064
16249
  "use strict";
16065
- import_node_fs44 = require("fs");
16066
- import_node_path44 = require("path");
16250
+ import_node_fs45 = require("fs");
16251
+ import_node_path45 = require("path");
16067
16252
  init_workspace_scratch();
16068
16253
  init_wait_for_turn();
16069
16254
  MAX_JOB_CONTINUES = 8;
@@ -16798,14 +16983,14 @@ async function startAbleTimeOAuth(opts) {
16798
16983
  const pkce = createAbleTimePkce();
16799
16984
  const authorizeUrl = ableTimeOAuthAuthorizeUrl(clientId, state, pkce.challenge, host);
16800
16985
  const timeoutMs = opts?.timeoutMs ?? 5 * 6e4;
16801
- const code = await new Promise((resolve, reject) => {
16986
+ const code = await new Promise((resolve2, reject) => {
16802
16987
  let settled = false;
16803
16988
  const finish = (err, value) => {
16804
16989
  if (settled) return;
16805
16990
  settled = true;
16806
16991
  cleanup();
16807
16992
  if (err) reject(err);
16808
- else resolve(value);
16993
+ else resolve2(value);
16809
16994
  };
16810
16995
  const server = (0, import_node_http.createServer)((req, res) => {
16811
16996
  try {
@@ -18098,7 +18283,7 @@ function reuseLiveThread(input, repoPath, match) {
18098
18283
  }
18099
18284
  async function createThread(input, _onSetupLine) {
18100
18285
  const repoPath = await resolveRepoRoot(input.repoPath);
18101
- if (!(0, import_node_fs45.existsSync)(repoPath)) {
18286
+ if (!(0, import_node_fs46.existsSync)(repoPath)) {
18102
18287
  throw new Error(`Repo not found: ${repoPath}`);
18103
18288
  }
18104
18289
  const reused = reuseLiveThread(input, repoPath, {
@@ -18274,11 +18459,11 @@ async function createThread(input, _onSetupLine) {
18274
18459
  await ensureWorkspace(repoPath);
18275
18460
  return readThread(thread.id) ?? thread;
18276
18461
  }
18277
- var import_node_fs45;
18462
+ var import_node_fs46;
18278
18463
  var init_create = __esm({
18279
18464
  "src/threads/create.ts"() {
18280
18465
  "use strict";
18281
- import_node_fs45 = require("fs");
18466
+ import_node_fs46 = require("fs");
18282
18467
  init_detect();
18283
18468
  init_worktree();
18284
18469
  init_home_board();
@@ -18430,20 +18615,20 @@ function writeTurnLive(threadId, progress) {
18430
18615
  const path = threadLivePath(threadId);
18431
18616
  const tmp = `${path}.${process.pid}.tmp`;
18432
18617
  try {
18433
- (0, import_node_fs46.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
18434
- (0, import_node_fs46.renameSync)(tmp, path);
18618
+ (0, import_node_fs47.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
18619
+ (0, import_node_fs47.renameSync)(tmp, path);
18435
18620
  } catch {
18436
18621
  try {
18437
- (0, import_node_fs46.unlinkSync)(tmp);
18622
+ (0, import_node_fs47.unlinkSync)(tmp);
18438
18623
  } catch {
18439
18624
  }
18440
18625
  }
18441
18626
  }
18442
18627
  function readTurnLive(threadId) {
18443
18628
  const path = threadLivePath(threadId);
18444
- if (!(0, import_node_fs46.existsSync)(path)) return null;
18629
+ if (!(0, import_node_fs47.existsSync)(path)) return null;
18445
18630
  try {
18446
- const raw = JSON.parse((0, import_node_fs46.readFileSync)(path, "utf8"));
18631
+ const raw = JSON.parse((0, import_node_fs47.readFileSync)(path, "utf8"));
18447
18632
  if (!raw || typeof raw.summary !== "string") return null;
18448
18633
  return raw;
18449
18634
  } catch {
@@ -18455,17 +18640,17 @@ function clearTurnLive(threadId) {
18455
18640
  if (buf?.timer) clearTimeout(buf.timer);
18456
18641
  buffers.delete(threadId);
18457
18642
  const path = threadLivePath(threadId);
18458
- if (!(0, import_node_fs46.existsSync)(path)) return;
18643
+ if (!(0, import_node_fs47.existsSync)(path)) return;
18459
18644
  try {
18460
- (0, import_node_fs46.unlinkSync)(path);
18645
+ (0, import_node_fs47.unlinkSync)(path);
18461
18646
  } catch {
18462
18647
  }
18463
18648
  }
18464
- var import_node_fs46, buffers, FLUSH_MS, MAX_PARTS;
18649
+ var import_node_fs47, buffers, FLUSH_MS, MAX_PARTS;
18465
18650
  var init_turn_live = __esm({
18466
18651
  "src/store/turn-live.ts"() {
18467
18652
  "use strict";
18468
- import_node_fs46 = require("fs");
18653
+ import_node_fs47 = require("fs");
18469
18654
  init_message_parts();
18470
18655
  init_paths();
18471
18656
  buffers = /* @__PURE__ */ new Map();
@@ -18706,7 +18891,7 @@ var init_quota_failover = __esm({
18706
18891
  // src/threads/adopt.ts
18707
18892
  function thisModuleFile2() {
18708
18893
  const cjsFile = typeof __filename !== "undefined" ? __filename : "";
18709
- return cjsFile || process.argv[1] || (0, import_node_path45.join)(process.cwd(), "package.json");
18894
+ return cjsFile || process.argv[1] || (0, import_node_path46.join)(process.cwd(), "package.json");
18710
18895
  }
18711
18896
  function openReadonlySqlite(file) {
18712
18897
  const req = (0, import_node_module5.createRequire)(thisModuleFile2());
@@ -18724,21 +18909,21 @@ function mapAgentType(raw) {
18724
18909
  return null;
18725
18910
  }
18726
18911
  function resolveConductorCursorAgentId(workspacePath) {
18727
- if (!workspacePath || !(0, import_node_fs47.existsSync)(CURSOR_SDK_STORE)) return null;
18912
+ if (!workspacePath || !(0, import_node_fs48.existsSync)(CURSOR_SDK_STORE)) return null;
18728
18913
  const normalized = workspacePath.replace(/\/$/, "");
18729
18914
  let best = null;
18730
18915
  let hashes;
18731
18916
  try {
18732
- hashes = (0, import_node_fs47.readdirSync)(CURSOR_SDK_STORE);
18917
+ hashes = (0, import_node_fs48.readdirSync)(CURSOR_SDK_STORE);
18733
18918
  } catch {
18734
18919
  return null;
18735
18920
  }
18736
18921
  for (const hash of hashes) {
18737
- const agentsFile = (0, import_node_path45.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
18738
- if (!(0, import_node_fs47.existsSync)(agentsFile)) continue;
18922
+ const agentsFile = (0, import_node_path46.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
18923
+ if (!(0, import_node_fs48.existsSync)(agentsFile)) continue;
18739
18924
  let text7;
18740
18925
  try {
18741
- text7 = (0, import_node_fs47.readFileSync)(agentsFile, "utf8");
18926
+ text7 = (0, import_node_fs48.readFileSync)(agentsFile, "utf8");
18742
18927
  } catch {
18743
18928
  continue;
18744
18929
  }
@@ -18762,7 +18947,7 @@ function resolveConductorCursorAgentId(workspacePath) {
18762
18947
  return best?.agentId ?? null;
18763
18948
  }
18764
18949
  async function adoptThread(input) {
18765
- if (!(0, import_node_fs47.existsSync)(input.worktreePath)) {
18950
+ if (!(0, import_node_fs48.existsSync)(input.worktreePath)) {
18766
18951
  throw new Error(`Worktree not found: ${input.worktreePath}`);
18767
18952
  }
18768
18953
  const repoPath = await resolveRepoRoot(input.worktreePath);
@@ -18788,18 +18973,18 @@ async function adoptThread(input) {
18788
18973
  return thread;
18789
18974
  }
18790
18975
  function listConductorWorkspaces() {
18791
- if (!(0, import_node_fs47.existsSync)(CONDUCTOR_DB)) {
18976
+ if (!(0, import_node_fs48.existsSync)(CONDUCTOR_DB)) {
18792
18977
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
18793
18978
  }
18794
- const tmp = (0, import_node_fs47.mkdtempSync)((0, import_node_path45.join)((0, import_node_os14.tmpdir)(), "sideboard-conductor-"));
18795
- const snapshot = (0, import_node_path45.join)(tmp, "conductor.db");
18979
+ const tmp = (0, import_node_fs48.mkdtempSync)((0, import_node_path46.join)((0, import_node_os14.tmpdir)(), "sideboard-conductor-"));
18980
+ const snapshot = (0, import_node_path46.join)(tmp, "conductor.db");
18796
18981
  try {
18797
- (0, import_node_fs47.copyFileSync)(CONDUCTOR_DB, snapshot);
18982
+ (0, import_node_fs48.copyFileSync)(CONDUCTOR_DB, snapshot);
18798
18983
  for (const suffix of ["-wal", "-shm"]) {
18799
18984
  const src = `${CONDUCTOR_DB}${suffix}`;
18800
- if ((0, import_node_fs47.existsSync)(src)) {
18985
+ if ((0, import_node_fs48.existsSync)(src)) {
18801
18986
  try {
18802
- (0, import_node_fs47.copyFileSync)(src, `${snapshot}${suffix}`);
18987
+ (0, import_node_fs48.copyFileSync)(src, `${snapshot}${suffix}`);
18803
18988
  } catch {
18804
18989
  }
18805
18990
  }
@@ -18875,22 +19060,22 @@ function listConductorWorkspaces() {
18875
19060
  db.close();
18876
19061
  }
18877
19062
  } finally {
18878
- (0, import_node_fs47.rmSync)(tmp, { recursive: true, force: true });
19063
+ (0, import_node_fs48.rmSync)(tmp, { recursive: true, force: true });
18879
19064
  }
18880
19065
  }
18881
19066
  function importConductorWorkspace(workspaceId) {
18882
- if (!(0, import_node_fs47.existsSync)(CONDUCTOR_DB)) {
19067
+ if (!(0, import_node_fs48.existsSync)(CONDUCTOR_DB)) {
18883
19068
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
18884
19069
  }
18885
- const tmp = (0, import_node_fs47.mkdtempSync)((0, import_node_path45.join)((0, import_node_os14.tmpdir)(), "sideboard-conductor-"));
18886
- const snapshot = (0, import_node_path45.join)(tmp, "conductor.db");
19070
+ const tmp = (0, import_node_fs48.mkdtempSync)((0, import_node_path46.join)((0, import_node_os14.tmpdir)(), "sideboard-conductor-"));
19071
+ const snapshot = (0, import_node_path46.join)(tmp, "conductor.db");
18887
19072
  try {
18888
- (0, import_node_fs47.copyFileSync)(CONDUCTOR_DB, snapshot);
19073
+ (0, import_node_fs48.copyFileSync)(CONDUCTOR_DB, snapshot);
18889
19074
  for (const suffix of ["-wal", "-shm"]) {
18890
19075
  const src = `${CONDUCTOR_DB}${suffix}`;
18891
- if ((0, import_node_fs47.existsSync)(src)) {
19076
+ if ((0, import_node_fs48.existsSync)(src)) {
18892
19077
  try {
18893
- (0, import_node_fs47.copyFileSync)(src, `${snapshot}${suffix}`);
19078
+ (0, import_node_fs48.copyFileSync)(src, `${snapshot}${suffix}`);
18894
19079
  } catch {
18895
19080
  }
18896
19081
  }
@@ -18908,7 +19093,7 @@ function importConductorWorkspace(workspaceId) {
18908
19093
  ).get(workspaceId);
18909
19094
  if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
18910
19095
  const worktreePath = String(row.workspacePath);
18911
- if (!(0, import_node_fs47.existsSync)(worktreePath)) {
19096
+ if (!(0, import_node_fs48.existsSync)(worktreePath)) {
18912
19097
  throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
18913
19098
  }
18914
19099
  let sessionId = null;
@@ -18971,31 +19156,31 @@ function importConductorWorkspace(workspaceId) {
18971
19156
  db.close();
18972
19157
  }
18973
19158
  } finally {
18974
- (0, import_node_fs47.rmSync)(tmp, { recursive: true, force: true });
19159
+ (0, import_node_fs48.rmSync)(tmp, { recursive: true, force: true });
18975
19160
  }
18976
19161
  }
18977
19162
  async function importConductorWorkspaceAsync(workspaceId) {
18978
19163
  return importConductorWorkspace(workspaceId);
18979
19164
  }
18980
- var import_node_child_process5, import_node_fs47, import_node_os14, import_node_path45, import_node_module5, CONDUCTOR_APP_SUPPORT, CONDUCTOR_DB, CURSOR_SDK_STORE;
19165
+ var import_node_child_process5, import_node_fs48, import_node_os14, import_node_path46, import_node_module5, CONDUCTOR_APP_SUPPORT, CONDUCTOR_DB, CURSOR_SDK_STORE;
18981
19166
  var init_adopt = __esm({
18982
19167
  "src/threads/adopt.ts"() {
18983
19168
  "use strict";
18984
19169
  import_node_child_process5 = require("child_process");
18985
- import_node_fs47 = require("fs");
19170
+ import_node_fs48 = require("fs");
18986
19171
  import_node_os14 = require("os");
18987
- import_node_path45 = require("path");
19172
+ import_node_path46 = require("path");
18988
19173
  import_node_module5 = require("module");
18989
19174
  init_worktree();
18990
19175
  init_thread_store();
18991
- CONDUCTOR_APP_SUPPORT = (0, import_node_path45.join)(
19176
+ CONDUCTOR_APP_SUPPORT = (0, import_node_path46.join)(
18992
19177
  process.env.HOME ?? "",
18993
19178
  "Library",
18994
19179
  "Application Support",
18995
19180
  "com.conductor.app"
18996
19181
  );
18997
- CONDUCTOR_DB = (0, import_node_path45.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
18998
- CURSOR_SDK_STORE = (0, import_node_path45.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
19182
+ CONDUCTOR_DB = (0, import_node_path46.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
19183
+ CURSOR_SDK_STORE = (0, import_node_path46.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
18999
19184
  }
19000
19185
  });
19001
19186
 
@@ -19062,7 +19247,7 @@ async function openStackLayer(input, _onSetupLine) {
19062
19247
  let createdWorktree = false;
19063
19248
  const trees = await listWorktrees(repoPath);
19064
19249
  const checkedOut = trees.find((w) => w.branch === branchName);
19065
- if (checkedOut?.path && (0, import_node_fs48.existsSync)(checkedOut.path)) {
19250
+ if (checkedOut?.path && (0, import_node_fs49.existsSync)(checkedOut.path)) {
19066
19251
  if (input.reuseExistingWorktree !== false) {
19067
19252
  worktreePath = checkedOut.path;
19068
19253
  } else {
@@ -19204,7 +19389,7 @@ async function initStackFromThread(input, onSetupLine) {
19204
19389
  async function createPrStack(input, onSetupLine) {
19205
19390
  await requireAgent(input.agent);
19206
19391
  const repoPath = await resolveRepoRoot(input.repoPath);
19207
- if (!(0, import_node_fs48.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
19392
+ if (!(0, import_node_fs49.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
19208
19393
  if (!input.branches.length) throw new Error("At least one branch name required");
19209
19394
  const status = await detectGhStack(repoPath);
19210
19395
  if (!status.available) throw new Error(status.reason);
@@ -19271,7 +19456,7 @@ async function createPrStack(input, onSetupLine) {
19271
19456
  }
19272
19457
  }
19273
19458
  const claimed = new Set(threads.map((t) => t.worktreePath));
19274
- if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs48.existsSync)(bootstrap.worktreePath)) {
19459
+ if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs49.existsSync)(bootstrap.worktreePath)) {
19275
19460
  try {
19276
19461
  await removeWorktree(repoPath, bootstrap.worktreePath, {
19277
19462
  deleteBranch: bootstrap.branchName
@@ -19281,11 +19466,11 @@ async function createPrStack(input, onSetupLine) {
19281
19466
  }
19282
19467
  return { stack, threads, createdThreadIds };
19283
19468
  }
19284
- var import_node_fs48;
19469
+ var import_node_fs49;
19285
19470
  var init_stack_layers = __esm({
19286
19471
  "src/threads/stack-layers.ts"() {
19287
19472
  "use strict";
19288
- import_node_fs48 = require("fs");
19473
+ import_node_fs49 = require("fs");
19289
19474
  init_detect();
19290
19475
  init_run();
19291
19476
  init_stack();
@@ -19298,7 +19483,7 @@ var init_stack_layers = __esm({
19298
19483
 
19299
19484
  // src/diff/diff.ts
19300
19485
  async function inspectGitWorktree(worktreePath) {
19301
- if (!worktreePath || !(0, import_node_fs49.existsSync)(worktreePath)) return "missing_worktree";
19486
+ if (!worktreePath || !(0, import_node_fs50.existsSync)(worktreePath)) return "missing_worktree";
19302
19487
  const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
19303
19488
  reject: false
19304
19489
  });
@@ -19306,7 +19491,7 @@ async function inspectGitWorktree(worktreePath) {
19306
19491
  return "ok";
19307
19492
  }
19308
19493
  async function initializeGitRepository(worktreePath) {
19309
- if (!worktreePath || !(0, import_node_fs49.existsSync)(worktreePath)) {
19494
+ if (!worktreePath || !(0, import_node_fs50.existsSync)(worktreePath)) {
19310
19495
  throw new Error("Worktree not found");
19311
19496
  }
19312
19497
  const status = await inspectGitWorktree(worktreePath);
@@ -19440,11 +19625,11 @@ new file mode 100644
19440
19625
  };
19441
19626
  }
19442
19627
  async function untrackedPatch(worktreePath, path, maxHunk) {
19443
- const abs = (0, import_node_path46.join)(worktreePath, path);
19628
+ const abs = (0, import_node_path47.join)(worktreePath, path);
19444
19629
  try {
19445
- const st = (0, import_node_fs49.statSync)(abs);
19630
+ const st = (0, import_node_fs50.statSync)(abs);
19446
19631
  if (st.isFile() && st.size > maxHunk) {
19447
- const buf = (0, import_node_fs49.readFileSync)(abs).subarray(0, maxHunk);
19632
+ const buf = (0, import_node_fs50.readFileSync)(abs).subarray(0, maxHunk);
19448
19633
  return syntheticAddPatch(path, buf.toString("utf8"), maxHunk);
19449
19634
  }
19450
19635
  } catch {
@@ -19911,9 +20096,9 @@ async function getDiff(worktreePath, repoPath, opts) {
19911
20096
  }
19912
20097
  function statWorktreePath(worktreePath, relativePath) {
19913
20098
  assertSafeRelativePath(relativePath);
19914
- const abs = (0, import_node_path46.join)(worktreePath, relativePath);
19915
- if (!(0, import_node_fs49.existsSync)(abs)) return "missing";
19916
- const st = (0, import_node_fs49.statSync)(abs);
20099
+ const abs = (0, import_node_path47.join)(worktreePath, relativePath);
20100
+ if (!(0, import_node_fs50.existsSync)(abs)) return "missing";
20101
+ const st = (0, import_node_fs50.statSync)(abs);
19917
20102
  if (st.isDirectory()) return "dir";
19918
20103
  if (st.isFile()) return "file";
19919
20104
  return "missing";
@@ -19942,8 +20127,8 @@ function isImageRelativePath(relativePath) {
19942
20127
  function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
19943
20128
  assertSafeRelativePath(relativePath);
19944
20129
  const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
19945
- const abs = (0, import_node_path46.join)(worktreePath, relativePath);
19946
- const st = (0, import_node_fs49.statSync)(abs);
20130
+ const abs = (0, import_node_path47.join)(worktreePath, relativePath);
20131
+ const st = (0, import_node_fs50.statSync)(abs);
19947
20132
  if (!st.isFile()) {
19948
20133
  throw new Error(`Not a file: ${relativePath}`);
19949
20134
  }
@@ -19952,7 +20137,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
19952
20137
  `File too large to upload (${st.size} bytes; max ${maxBytes})`
19953
20138
  );
19954
20139
  }
19955
- const buf = (0, import_node_fs49.readFileSync)(abs);
20140
+ const buf = (0, import_node_fs50.readFileSync)(abs);
19956
20141
  return {
19957
20142
  path: relativePath,
19958
20143
  contentBase64: buf.toString("base64"),
@@ -19962,12 +20147,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
19962
20147
  function readWorktreeFile(worktreePath, relativePath, opts) {
19963
20148
  assertSafeRelativePath(relativePath);
19964
20149
  const maxBytes = opts?.maxBytes ?? 2e5;
19965
- const abs = (0, import_node_path46.join)(worktreePath, relativePath);
19966
- const st = (0, import_node_fs49.statSync)(abs);
20150
+ const abs = (0, import_node_path47.join)(worktreePath, relativePath);
20151
+ const st = (0, import_node_fs50.statSync)(abs);
19967
20152
  if (!st.isFile()) {
19968
20153
  throw new Error(`Not a file: ${relativePath}`);
19969
20154
  }
19970
- const buf = (0, import_node_fs49.readFileSync)(abs);
20155
+ const buf = (0, import_node_fs50.readFileSync)(abs);
19971
20156
  if (isImageRelativePath(relativePath)) {
19972
20157
  const maxImageBytes = Math.max(maxBytes, 15e6);
19973
20158
  const truncated2 = buf.length > maxImageBytes;
@@ -20010,9 +20195,9 @@ function assertSafeRelativePath(relativePath) {
20010
20195
  }
20011
20196
  function writeWorktreeFile(worktreePath, relativePath, content) {
20012
20197
  assertSafeRelativePath(relativePath);
20013
- const abs = (0, import_node_path46.join)(worktreePath, relativePath);
20014
- (0, import_node_fs49.mkdirSync)((0, import_node_path46.dirname)(abs), { recursive: true });
20015
- (0, import_node_fs49.writeFileSync)(abs, content, "utf8");
20198
+ const abs = (0, import_node_path47.join)(worktreePath, relativePath);
20199
+ (0, import_node_fs50.mkdirSync)((0, import_node_path47.dirname)(abs), { recursive: true });
20200
+ (0, import_node_fs50.writeFileSync)(abs, content, "utf8");
20016
20201
  return { path: relativePath };
20017
20202
  }
20018
20203
  async function getWorktreeDirtyStat(worktreePath) {
@@ -20052,12 +20237,12 @@ async function getDiffSummary(worktreePath, repoPath, opts) {
20052
20237
  truncated: full.files.length > maxFiles
20053
20238
  };
20054
20239
  }
20055
- var import_node_fs49, import_node_path46, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS2, DEFAULT_UPLOAD_MAX_BYTES;
20240
+ var import_node_fs50, import_node_path47, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS2, DEFAULT_UPLOAD_MAX_BYTES;
20056
20241
  var init_diff = __esm({
20057
20242
  "src/diff/diff.ts"() {
20058
20243
  "use strict";
20059
- import_node_fs49 = require("fs");
20060
- import_node_path46 = require("path");
20244
+ import_node_fs50 = require("fs");
20245
+ import_node_path47 = require("path");
20061
20246
  init_run();
20062
20247
  init_worktree();
20063
20248
  mergeBaseCache = /* @__PURE__ */ new Map();
@@ -20414,7 +20599,7 @@ function parseFrontmatter(content) {
20414
20599
  }
20415
20600
  function readSkill(skillMd, source) {
20416
20601
  try {
20417
- const content = (0, import_node_fs50.readFileSync)(skillMd, "utf8");
20602
+ const content = (0, import_node_fs51.readFileSync)(skillMd, "utf8");
20418
20603
  const { name: fmName, description } = parseFrontmatter(content);
20419
20604
  const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
20420
20605
  const name = fmName || dirName;
@@ -20433,19 +20618,19 @@ function readSkill(skillMd, source) {
20433
20618
  }
20434
20619
  }
20435
20620
  function scanSkillsDir(dir, source, out) {
20436
- if (!(0, import_node_fs50.existsSync)(dir)) return;
20621
+ if (!(0, import_node_fs51.existsSync)(dir)) return;
20437
20622
  let entries;
20438
20623
  try {
20439
- entries = (0, import_node_fs50.readdirSync)(dir);
20624
+ entries = (0, import_node_fs51.readdirSync)(dir);
20440
20625
  } catch {
20441
20626
  return;
20442
20627
  }
20443
20628
  for (const entry of entries) {
20444
20629
  if (entry.startsWith(".")) continue;
20445
- const skillMd = (0, import_node_path47.join)(dir, entry, "SKILL.md");
20446
- if (!(0, import_node_fs50.existsSync)(skillMd)) continue;
20630
+ const skillMd = (0, import_node_path48.join)(dir, entry, "SKILL.md");
20631
+ if (!(0, import_node_fs51.existsSync)(skillMd)) continue;
20447
20632
  try {
20448
- if (!(0, import_node_fs50.statSync)(skillMd).isFile()) continue;
20633
+ if (!(0, import_node_fs51.statSync)(skillMd).isFile()) continue;
20449
20634
  } catch {
20450
20635
  continue;
20451
20636
  }
@@ -20454,24 +20639,24 @@ function scanSkillsDir(dir, source, out) {
20454
20639
  }
20455
20640
  }
20456
20641
  function scanClaudePluginSkills(pluginsRoot, out) {
20457
- if (!(0, import_node_fs50.existsSync)(pluginsRoot)) return;
20642
+ if (!(0, import_node_fs51.existsSync)(pluginsRoot)) return;
20458
20643
  const walk = (dir, depth, lookingForSkillsDir) => {
20459
20644
  if (depth > 7) return;
20460
20645
  let entries;
20461
20646
  try {
20462
- entries = (0, import_node_fs50.readdirSync)(dir);
20647
+ entries = (0, import_node_fs51.readdirSync)(dir);
20463
20648
  } catch {
20464
20649
  return;
20465
20650
  }
20466
20651
  if (lookingForSkillsDir && entries.includes("SKILL.md")) {
20467
- const skill = readSkill((0, import_node_path47.join)(dir, "SKILL.md"), "cli");
20652
+ const skill = readSkill((0, import_node_path48.join)(dir, "SKILL.md"), "cli");
20468
20653
  if (skill) out.push(skill);
20469
20654
  }
20470
20655
  for (const entry of entries) {
20471
20656
  if (entry === "node_modules" || entry === ".git") continue;
20472
- const full = (0, import_node_path47.join)(dir, entry);
20657
+ const full = (0, import_node_path48.join)(dir, entry);
20473
20658
  try {
20474
- if (!(0, import_node_fs50.statSync)(full).isDirectory()) continue;
20659
+ if (!(0, import_node_fs51.statSync)(full).isDirectory()) continue;
20475
20660
  } catch {
20476
20661
  continue;
20477
20662
  }
@@ -20489,17 +20674,17 @@ function discoverSkills(worktreePath) {
20489
20674
  const home = (0, import_node_os15.homedir)();
20490
20675
  const collected = [];
20491
20676
  for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
20492
- scanSkillsDir((0, import_node_path47.join)(worktreePath, rel), "workspace", collected);
20677
+ scanSkillsDir((0, import_node_path48.join)(worktreePath, rel), "workspace", collected);
20493
20678
  }
20494
20679
  for (const abs of [
20495
- (0, import_node_path47.join)(home, ".claude/skills"),
20496
- (0, import_node_path47.join)(home, ".cursor/skills"),
20497
- (0, import_node_path47.join)(home, ".sideboard/skills"),
20498
- (0, import_node_path47.join)(home, ".brightsy/skills")
20680
+ (0, import_node_path48.join)(home, ".claude/skills"),
20681
+ (0, import_node_path48.join)(home, ".cursor/skills"),
20682
+ (0, import_node_path48.join)(home, ".sideboard/skills"),
20683
+ (0, import_node_path48.join)(home, ".brightsy/skills")
20499
20684
  ]) {
20500
20685
  scanSkillsDir(abs, "user", collected);
20501
20686
  }
20502
- scanClaudePluginSkills((0, import_node_path47.join)(home, ".claude/plugins"), collected);
20687
+ scanClaudePluginSkills((0, import_node_path48.join)(home, ".claude/plugins"), collected);
20503
20688
  collected.push(...bundledSkills());
20504
20689
  const rank = {
20505
20690
  workspace: 0,
@@ -20525,7 +20710,7 @@ function readSkillBody(skillPath, maxChars = 12e3) {
20525
20710
  \u2026(truncated)` : body;
20526
20711
  }
20527
20712
  }
20528
- const raw = (0, import_node_fs50.readFileSync)(skillPath, "utf8");
20713
+ const raw = (0, import_node_fs51.readFileSync)(skillPath, "utf8");
20529
20714
  if (raw.startsWith("---")) {
20530
20715
  const end = raw.indexOf("\n---", 3);
20531
20716
  if (end >= 0) {
@@ -20539,13 +20724,13 @@ function readSkillBody(skillPath, maxChars = 12e3) {
20539
20724
 
20540
20725
  \u2026(truncated)` : raw;
20541
20726
  }
20542
- var import_node_fs50, import_node_os15, import_node_path47, BUNDLED_SKILL_PREFIX;
20727
+ var import_node_fs51, import_node_os15, import_node_path48, BUNDLED_SKILL_PREFIX;
20543
20728
  var init_discover = __esm({
20544
20729
  "src/skills/discover.ts"() {
20545
20730
  "use strict";
20546
- import_node_fs50 = require("fs");
20731
+ import_node_fs51 = require("fs");
20547
20732
  import_node_os15 = require("os");
20548
- import_node_path47 = require("path");
20733
+ import_node_path48 = require("path");
20549
20734
  init_long_running();
20550
20735
  BUNDLED_SKILL_PREFIX = "bundled:";
20551
20736
  }
@@ -20700,7 +20885,7 @@ function compiledModuleDir() {
20700
20885
  try {
20701
20886
  const url = import_meta4.url;
20702
20887
  if (typeof url === "string" && url.length > 0) {
20703
- return (0, import_node_path48.dirname)((0, import_node_url4.fileURLToPath)(url));
20888
+ return (0, import_node_path49.dirname)((0, import_node_url4.fileURLToPath)(url));
20704
20889
  }
20705
20890
  } catch {
20706
20891
  }
@@ -20708,8 +20893,8 @@ function compiledModuleDir() {
20708
20893
  }
20709
20894
  function detachedJobScriptIn(dir) {
20710
20895
  for (const name of DETACHED_JOB_FILENAMES) {
20711
- const script = (0, import_node_path48.join)(dir, "scripts", name);
20712
- if ((0, import_node_fs51.existsSync)(script)) return script;
20896
+ const script = (0, import_node_path49.join)(dir, "scripts", name);
20897
+ if ((0, import_node_fs52.existsSync)(script)) return script;
20713
20898
  }
20714
20899
  return null;
20715
20900
  }
@@ -20726,7 +20911,7 @@ function resolveDetachedJobScript() {
20726
20911
  for (let i = 0; i < 8; i++) {
20727
20912
  const candidate = detachedJobScriptIn(dir);
20728
20913
  if (candidate) return candidate;
20729
- const parent = (0, import_node_path48.dirname)(dir);
20914
+ const parent = (0, import_node_path49.dirname)(dir);
20730
20915
  if (parent === dir) break;
20731
20916
  dir = parent;
20732
20917
  }
@@ -20737,12 +20922,12 @@ function formatDetachedJobInvoke(scriptPath) {
20737
20922
  if (resolved) return `node ${JSON.stringify(resolved)}`;
20738
20923
  return "node scripts/detached-job.cjs";
20739
20924
  }
20740
- var import_node_fs51, import_node_path48, import_node_url4, import_meta4, DETACHED_JOB_FILENAMES;
20925
+ var import_node_fs52, import_node_path49, import_node_url4, import_meta4, DETACHED_JOB_FILENAMES;
20741
20926
  var init_detached_job_path = __esm({
20742
20927
  "src/skills/detached-job-path.ts"() {
20743
20928
  "use strict";
20744
- import_node_fs51 = require("fs");
20745
- import_node_path48 = require("path");
20929
+ import_node_fs52 = require("fs");
20930
+ import_node_path49 = require("path");
20746
20931
  import_node_url4 = require("url");
20747
20932
  init_packaged_runtime();
20748
20933
  import_meta4 = {};
@@ -20843,9 +21028,9 @@ function formatWorktreeDirective(thread, opts) {
20843
21028
  );
20844
21029
  } else {
20845
21030
  const slug = opts?.githubSlug ?? "<origin-owner/name>";
20846
- const resolve = opts?.githubSlug ? "" : " Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree.";
21031
+ const resolve2 = opts?.githubSlug ? "" : " Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree.";
20847
21032
  lines.push(
20848
- `- 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\`.`
21033
+ `- 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\`.`
20849
21034
  );
20850
21035
  }
20851
21036
  lines.push(
@@ -20932,9 +21117,9 @@ function formatPrGateDirective() {
20932
21117
  }
20933
21118
  function formatProcessGuideDirective(opts) {
20934
21119
  const worktree = opts?.worktreePath?.trim();
20935
- const hasGraphSkill = !!worktree && (0, import_node_fs52.existsSync)((0, import_node_path49.join)(worktree, ".claude/skills/graph-engineering/SKILL.md"));
20936
- const hasReviewSkill = !!worktree && (0, import_node_fs52.existsSync)((0, import_node_path49.join)(worktree, ".claude/skills/review/SKILL.md"));
20937
- const hasInstallSkill = !!worktree && (0, import_node_fs52.existsSync)((0, import_node_path49.join)(worktree, ".claude/skills/worktree-install/SKILL.md"));
21120
+ const hasGraphSkill = !!worktree && (0, import_node_fs53.existsSync)((0, import_node_path50.join)(worktree, ".claude/skills/graph-engineering/SKILL.md"));
21121
+ const hasReviewSkill = !!worktree && (0, import_node_fs53.existsSync)((0, import_node_path50.join)(worktree, ".claude/skills/review/SKILL.md"));
21122
+ const hasInstallSkill = !!worktree && (0, import_node_fs53.existsSync)((0, import_node_path50.join)(worktree, ".claude/skills/worktree-install/SKILL.md"));
20938
21123
  return [
20939
21124
  "Process guides (recurring work only):",
20940
21125
  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,
@@ -20973,12 +21158,12 @@ function formatArtifactDirective() {
20973
21158
  function formatUiReminder() {
20974
21159
  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.";
20975
21160
  }
20976
- var import_node_fs52, import_node_path49, PR_GOAL_RE, GITHUB_TICKET_REF, KEYED_TICKET_REF;
21161
+ var import_node_fs53, import_node_path50, PR_GOAL_RE, GITHUB_TICKET_REF, KEYED_TICKET_REF;
20977
21162
  var init_instructions = __esm({
20978
21163
  "src/agents/instructions.ts"() {
20979
21164
  "use strict";
20980
- import_node_fs52 = require("fs");
20981
- import_node_path49 = require("path");
21165
+ import_node_fs53 = require("fs");
21166
+ import_node_path50 = require("path");
20982
21167
  init_git_auth_mode();
20983
21168
  init_branch_prefix();
20984
21169
  init_worktree_labels();
@@ -21202,40 +21387,40 @@ __export(plan_file_exports, {
21202
21387
  writePlanFile: () => writePlanFile
21203
21388
  });
21204
21389
  function ensureAttachmentsGitignore(worktreePath) {
21205
- const gitignoreAbs = (0, import_node_path50.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
21206
- if ((0, import_node_fs53.existsSync)(gitignoreAbs)) return;
21207
- (0, import_node_fs53.mkdirSync)((0, import_node_path50.dirname)(gitignoreAbs), { recursive: true });
21208
- (0, import_node_fs53.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
21390
+ const gitignoreAbs = (0, import_node_path51.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
21391
+ if ((0, import_node_fs54.existsSync)(gitignoreAbs)) return;
21392
+ (0, import_node_fs54.mkdirSync)((0, import_node_path51.dirname)(gitignoreAbs), { recursive: true });
21393
+ (0, import_node_fs54.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
21209
21394
  }
21210
21395
  function planFileAbs(worktreePath) {
21211
- return (0, import_node_path50.join)(worktreePath, PLAN_FILE_REL);
21396
+ return (0, import_node_path51.join)(worktreePath, PLAN_FILE_REL);
21212
21397
  }
21213
21398
  function readTextIfPresent2(abs) {
21214
- if (!(0, import_node_fs53.existsSync)(abs)) return null;
21399
+ if (!(0, import_node_fs54.existsSync)(abs)) return null;
21215
21400
  try {
21216
- const content = (0, import_node_fs53.readFileSync)(abs, "utf8");
21401
+ const content = (0, import_node_fs54.readFileSync)(abs, "utf8");
21217
21402
  return content.trim() ? content : null;
21218
21403
  } catch {
21219
21404
  return null;
21220
21405
  }
21221
21406
  }
21222
21407
  function readPlanFile(worktreePath) {
21223
- return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path50.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path50.join)(worktreePath, LEGACY_PLAN_FILE_REL));
21408
+ return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path51.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path51.join)(worktreePath, LEGACY_PLAN_FILE_REL));
21224
21409
  }
21225
21410
  function writePlanFile(worktreePath, content) {
21226
21411
  ensureAttachmentsGitignore(worktreePath);
21227
21412
  const abs = planFileAbs(worktreePath);
21228
- (0, import_node_fs53.mkdirSync)((0, import_node_path50.dirname)(abs), { recursive: true });
21413
+ (0, import_node_fs54.mkdirSync)((0, import_node_path51.dirname)(abs), { recursive: true });
21229
21414
  const body = content.trimEnd() + (content.endsWith("\n") ? "" : "\n");
21230
- (0, import_node_fs53.writeFileSync)(abs, body, "utf8");
21415
+ (0, import_node_fs54.writeFileSync)(abs, body, "utf8");
21231
21416
  return PLAN_FILE_REL;
21232
21417
  }
21233
- var import_node_fs53, import_node_path50;
21418
+ var import_node_fs54, import_node_path51;
21234
21419
  var init_plan_file = __esm({
21235
21420
  "src/plan/plan-file.ts"() {
21236
21421
  "use strict";
21237
- import_node_fs53 = require("fs");
21238
- import_node_path50 = require("path");
21422
+ import_node_fs54 = require("fs");
21423
+ import_node_path51 = require("path");
21239
21424
  init_workspace_scratch();
21240
21425
  init_plan_present();
21241
21426
  init_plan_present();
@@ -21295,7 +21480,7 @@ function setCaffeinateHoldHooks(next) {
21295
21480
  hooks = next;
21296
21481
  }
21297
21482
  function caffeinateHoldPath() {
21298
- return (0, import_node_path51.join)(appDataDir(), "caffeinate-hold.json");
21483
+ return (0, import_node_path52.join)(appDataDir(), "caffeinate-hold.json");
21299
21484
  }
21300
21485
  function processAlive(pid) {
21301
21486
  if (hooks.processAlive) return hooks.processAlive(pid);
@@ -21329,9 +21514,9 @@ function uniqueIds(ids) {
21329
21514
  }
21330
21515
  function readHold() {
21331
21516
  const path = caffeinateHoldPath();
21332
- if (!(0, import_node_fs54.existsSync)(path)) return null;
21517
+ if (!(0, import_node_fs55.existsSync)(path)) return null;
21333
21518
  try {
21334
- const parsed = JSON.parse((0, import_node_fs54.readFileSync)(path, "utf8"));
21519
+ const parsed = JSON.parse((0, import_node_fs55.readFileSync)(path, "utf8"));
21335
21520
  if (typeof parsed?.pid === "number" && parsed.pid > 0) {
21336
21521
  return {
21337
21522
  pid: parsed.pid,
@@ -21353,7 +21538,7 @@ function writeHold(pid, threadIds) {
21353
21538
  }
21354
21539
  function clearHold() {
21355
21540
  try {
21356
- (0, import_node_fs54.unlinkSync)(caffeinateHoldPath());
21541
+ (0, import_node_fs55.unlinkSync)(caffeinateHoldPath());
21357
21542
  } catch {
21358
21543
  }
21359
21544
  }
@@ -21438,13 +21623,13 @@ function releaseCaffeinateHoldForThread(threadId) {
21438
21623
  }
21439
21624
  return setCaffeinateHold(false, { threadId: id });
21440
21625
  }
21441
- var import_node_child_process6, import_node_fs54, import_node_path51, hooks;
21626
+ var import_node_child_process6, import_node_fs55, import_node_path52, hooks;
21442
21627
  var init_caffeinate_hold = __esm({
21443
21628
  "src/store/caffeinate-hold.ts"() {
21444
21629
  "use strict";
21445
21630
  import_node_child_process6 = require("child_process");
21446
- import_node_fs54 = require("fs");
21447
- import_node_path51 = require("path");
21631
+ import_node_fs55 = require("fs");
21632
+ import_node_path52 = require("path");
21448
21633
  init_paths();
21449
21634
  init_private_file();
21450
21635
  hooks = {};
@@ -21453,7 +21638,7 @@ var init_caffeinate_hold = __esm({
21453
21638
 
21454
21639
  // src/store/schedules.ts
21455
21640
  function schedulesPath() {
21456
- return (0, import_node_path52.join)(appDataDir(), "schedules.json");
21641
+ return (0, import_node_path53.join)(appDataDir(), "schedules.json");
21457
21642
  }
21458
21643
  function parseDurationMs(every) {
21459
21644
  const m = every.trim().match(DURATION_RE);
@@ -21553,9 +21738,9 @@ function normalizeTask(raw) {
21553
21738
  }
21554
21739
  function readAll2() {
21555
21740
  const path = schedulesPath();
21556
- if (!(0, import_node_fs55.existsSync)(path)) return [];
21741
+ if (!(0, import_node_fs56.existsSync)(path)) return [];
21557
21742
  try {
21558
- const parsed = JSON.parse((0, import_node_fs55.readFileSync)(path, "utf8"));
21743
+ const parsed = JSON.parse((0, import_node_fs56.readFileSync)(path, "utf8"));
21559
21744
  if (!Array.isArray(parsed)) return [];
21560
21745
  return parsed.map((row) => {
21561
21746
  try {
@@ -21667,13 +21852,13 @@ function recordScheduleRun(id, result) {
21667
21852
  writeAll2(rows);
21668
21853
  return next;
21669
21854
  }
21670
- var import_node_crypto12, import_node_fs55, import_node_path52, import_croner, DURATION_RE, UNIT_MS;
21855
+ var import_node_crypto12, import_node_fs56, import_node_path53, import_croner, DURATION_RE, UNIT_MS;
21671
21856
  var init_schedules = __esm({
21672
21857
  "src/store/schedules.ts"() {
21673
21858
  "use strict";
21674
21859
  import_node_crypto12 = require("crypto");
21675
- import_node_fs55 = require("fs");
21676
- import_node_path52 = require("path");
21860
+ import_node_fs56 = require("fs");
21861
+ import_node_path53 = require("path");
21677
21862
  import_croner = require("croner");
21678
21863
  init_orchestrator_capable();
21679
21864
  init_paths();
@@ -21759,14 +21944,14 @@ function armOne(schedule) {
21759
21944
  if (!schedule.enabled) return;
21760
21945
  const at = new Date(schedule.nextRunAt);
21761
21946
  if (Number.isNaN(at.getTime())) return;
21762
- const delay = Math.max(0, at.getTime() - Date.now());
21763
- if (delay <= 250) {
21947
+ const delay2 = Math.max(0, at.getTime() - Date.now());
21948
+ if (delay2 <= 250) {
21764
21949
  void fireSchedule(schedule.id).then(() => {
21765
21950
  if (isThisProcessDesktopHost()) armSchedules();
21766
21951
  });
21767
21952
  return;
21768
21953
  }
21769
- const capped = Math.min(delay, SET_TIMEOUT_MAX);
21954
+ const capped = Math.min(delay2, SET_TIMEOUT_MAX);
21770
21955
  const timer = setTimeout(() => {
21771
21956
  timers.delete(schedule.id);
21772
21957
  const live = getSchedule(schedule.id);
@@ -21829,9 +22014,9 @@ function recoverFinishedCursorRun(opts) {
21829
22014
  return best;
21830
22015
  }
21831
22016
  function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
21832
- if (!(0, import_node_fs56.existsSync)(runsPath)) return null;
22017
+ if (!(0, import_node_fs57.existsSync)(runsPath)) return null;
21833
22018
  try {
21834
- const lines = (0, import_node_fs56.readFileSync)(runsPath, "utf8").split("\n");
22019
+ const lines = (0, import_node_fs57.readFileSync)(runsPath, "utf8").split("\n");
21835
22020
  let best = null;
21836
22021
  for (const line of lines) {
21837
22022
  const trimmed = line.trim();
@@ -21857,11 +22042,11 @@ function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
21857
22042
  return null;
21858
22043
  }
21859
22044
  }
21860
- var import_node_fs56;
22045
+ var import_node_fs57;
21861
22046
  var init_cursor_recover = __esm({
21862
22047
  "src/agents/cursor-recover.ts"() {
21863
22048
  "use strict";
21864
- import_node_fs56 = require("fs");
22049
+ import_node_fs57 = require("fs");
21865
22050
  init_cursor_store();
21866
22051
  }
21867
22052
  });
@@ -22015,7 +22200,7 @@ async function startOrchestration(opts) {
22015
22200
  }
22016
22201
  return updated;
22017
22202
  }
22018
- var import_node_events, import_node_crypto13, import_node_fs57, LIVE_TURN_SPAWN_GRACE_MS, RUN_SCRIPT_DESKTOP_ADOPT_MS, STALE_AGENT_PID_WAIT_MS, LIGHT_RECONCILE_THROTTLE_MS, Orchestrator, singleton;
22203
+ 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;
22019
22204
  var init_orchestrator = __esm({
22020
22205
  "src/orchestrator/orchestrator.ts"() {
22021
22206
  "use strict";
@@ -22023,7 +22208,7 @@ var init_orchestrator = __esm({
22023
22208
  init_injected_notices();
22024
22209
  init_task_state();
22025
22210
  import_node_crypto13 = require("crypto");
22026
- import_node_fs57 = require("fs");
22211
+ import_node_fs58 = require("fs");
22027
22212
  init_error_detail();
22028
22213
  init_run();
22029
22214
  init_stale_lock();
@@ -22202,7 +22387,7 @@ var init_orchestrator = __esm({
22202
22387
  this.lightReconcileAt.set(repoPath, Date.now());
22203
22388
  for (const thread of listThreads()) {
22204
22389
  if (isGlobalThread(thread) || thread.repoPath !== repoPath) continue;
22205
- if (!(0, import_node_fs57.existsSync)(thread.worktreePath)) {
22390
+ if (!(0, import_node_fs58.existsSync)(thread.worktreePath)) {
22206
22391
  setStatus(thread.id, "broken", "Worktree missing on disk");
22207
22392
  this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
22208
22393
  }
@@ -22231,7 +22416,7 @@ var init_orchestrator = __esm({
22231
22416
  }
22232
22417
  continue;
22233
22418
  }
22234
- if (!(0, import_node_fs57.existsSync)(thread.worktreePath)) {
22419
+ if (!(0, import_node_fs58.existsSync)(thread.worktreePath)) {
22235
22420
  setStatus(thread.id, "broken", "Worktree missing on disk");
22236
22421
  this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
22237
22422
  continue;
@@ -22399,8 +22584,8 @@ var init_orchestrator = __esm({
22399
22584
  scheduleQuotaResume(threadId, resumeAt) {
22400
22585
  this.clearQuotaResumeTimer(threadId);
22401
22586
  updateThread(threadId, { quotaResumeAt: resumeAt.toISOString() });
22402
- const delay = Math.max(5e3, resumeAt.getTime() - Date.now());
22403
- const capped = Math.min(delay, 2147483647);
22587
+ const delay2 = Math.max(5e3, resumeAt.getTime() - Date.now());
22588
+ const capped = Math.min(delay2, 2147483647);
22404
22589
  const timer = setTimeout(() => {
22405
22590
  this.quotaResumeTimers.delete(threadId);
22406
22591
  void this.resumeAfterQuotaWait(threadId);
@@ -23455,6 +23640,7 @@ var init_orchestrator = __esm({
23455
23640
  return { port: shared.devPort, scriptName: resolvedName, ports: [shared.devPort] };
23456
23641
  }
23457
23642
  }
23643
+ const preferredPorts = active?.ports?.length ? active.ports : active?.port != null ? [active.port] : void 0;
23458
23644
  if (active && !existing) {
23459
23645
  killListenersOnPorts(collectActiveRunPorts([active]));
23460
23646
  this.syncWorktreeRuns(
@@ -23493,7 +23679,7 @@ var init_orchestrator = __esm({
23493
23679
  thread.repoPath,
23494
23680
  thread.worktreePath,
23495
23681
  runOutput.push,
23496
- { scriptName: resolvedName }
23682
+ { scriptName: resolvedName, preferredPorts }
23497
23683
  );
23498
23684
  } catch (err) {
23499
23685
  runOutput.flush();
@@ -23942,7 +24128,7 @@ var init_orchestrator = __esm({
23942
24128
  return thread;
23943
24129
  }
23944
24130
  const start = Date.now();
23945
- return new Promise((resolve, reject) => {
24131
+ return new Promise((resolve2, reject) => {
23946
24132
  let settled = false;
23947
24133
  let timer;
23948
24134
  const finish = (fn) => {
@@ -23960,7 +24146,7 @@ var init_orchestrator = __esm({
23960
24146
  finish(() => reject(new Error(`Thread not found: ${thread.id}`)));
23961
24147
  return;
23962
24148
  }
23963
- finish(() => resolve(latest));
24149
+ finish(() => resolve2(latest));
23964
24150
  return;
23965
24151
  }
23966
24152
  if (event.type === "status_changed") {
@@ -23970,7 +24156,7 @@ var init_orchestrator = __esm({
23970
24156
  return;
23971
24157
  }
23972
24158
  if (!["running", "queued"].includes(latest.status)) {
23973
- finish(() => resolve(latest));
24159
+ finish(() => resolve2(latest));
23974
24160
  }
23975
24161
  }
23976
24162
  });
@@ -23982,12 +24168,12 @@ var init_orchestrator = __esm({
23982
24168
  }
23983
24169
  const current = this.healStaleReportedActivity(raw);
23984
24170
  if (!this.threadLooksLive(current)) {
23985
- finish(() => resolve(current));
24171
+ finish(() => resolve2(current));
23986
24172
  return;
23987
24173
  }
23988
24174
  if (Date.now() - start > timeoutMs) {
23989
24175
  if (opts?.resolveIfStillRunning) {
23990
- finish(() => resolve(current));
24176
+ finish(() => resolve2(current));
23991
24177
  } else {
23992
24178
  finish(() => reject(new Error("wait_for_turn timed out")));
23993
24179
  }
@@ -24579,7 +24765,7 @@ var init_orchestrator = __esm({
24579
24765
  this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
24580
24766
  return restored2;
24581
24767
  }
24582
- if (!(0, import_node_fs57.existsSync)(thread.worktreePath)) {
24768
+ if (!(0, import_node_fs58.existsSync)(thread.worktreePath)) {
24583
24769
  if (isCowboyThread(thread) || isPrimaryCheckoutThread(thread)) {
24584
24770
  throw new Error(
24585
24771
  `Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
@@ -24663,7 +24849,7 @@ var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
24663
24849
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
24664
24850
  var import_zod9 = require("zod");
24665
24851
  var import_node_crypto16 = require("crypto");
24666
- var import_node_path58 = require("path");
24852
+ var import_node_path59 = require("path");
24667
24853
  init_orchestrator();
24668
24854
  init_task_state();
24669
24855
  init_worktree();
@@ -26778,8 +26964,8 @@ ${link}` : link;
26778
26964
  }
26779
26965
 
26780
26966
  // src/slack/outbound-watch.ts
26781
- var import_node_fs59 = require("fs");
26782
- var import_node_path55 = require("path");
26967
+ var import_node_fs60 = require("fs");
26968
+ var import_node_path56 = require("path");
26783
26969
  init_paths();
26784
26970
  init_private_file();
26785
26971
  init_secure_file();
@@ -26787,19 +26973,19 @@ init_thread_store();
26787
26973
  init_injected_notices();
26788
26974
 
26789
26975
  // src/slack/reply-target.ts
26790
- var import_node_fs58 = require("fs");
26791
- var import_node_path53 = require("path");
26976
+ var import_node_fs59 = require("fs");
26977
+ var import_node_path54 = require("path");
26792
26978
  init_paths();
26793
26979
  init_private_file();
26794
26980
  init_secure_file();
26795
26981
  function storePath2() {
26796
- return (0, import_node_path53.join)(appDataDir(), "slack-reply-to.json");
26982
+ return (0, import_node_path54.join)(appDataDir(), "slack-reply-to.json");
26797
26983
  }
26798
26984
  function readStore2() {
26799
26985
  const path = storePath2();
26800
- if (!(0, import_node_fs58.existsSync)(path)) return {};
26986
+ if (!(0, import_node_fs59.existsSync)(path)) return {};
26801
26987
  try {
26802
- const parsed = isSecureFileEncrypted(path) ? readSecureJson(path) : JSON.parse((0, import_node_fs58.readFileSync)(path, "utf8"));
26988
+ const parsed = isSecureFileEncrypted(path) ? readSecureJson(path) : JSON.parse((0, import_node_fs59.readFileSync)(path, "utf8"));
26803
26989
  return parsed?.targets && typeof parsed.targets === "object" ? parsed.targets : {};
26804
26990
  } catch {
26805
26991
  return {};
@@ -26810,11 +26996,11 @@ function getSlackReplyTarget(threadId) {
26810
26996
  }
26811
26997
 
26812
26998
  // src/slack/workspaces.ts
26813
- var import_node_path54 = require("path");
26999
+ var import_node_path55 = require("path");
26814
27000
  init_paths();
26815
27001
  init_secure_file();
26816
27002
  function storePath3() {
26817
- return (0, import_node_path54.join)(appDataDir(), "slack-workspaces.json");
27003
+ return (0, import_node_path55.join)(appDataDir(), "slack-workspaces.json");
26818
27004
  }
26819
27005
  function readStore3() {
26820
27006
  try {
@@ -26884,7 +27070,7 @@ var POLL_INTERVAL_MS = 12e3;
26884
27070
  var lastPollMs = 0;
26885
27071
  var nameCache = /* @__PURE__ */ new Map();
26886
27072
  function storePath4() {
26887
- return (0, import_node_path55.join)(appDataDir(), "slack-outbound-watch.json");
27073
+ return (0, import_node_path56.join)(appDataDir(), "slack-outbound-watch.json");
26888
27074
  }
26889
27075
  function watchId(teamId, channelId, ts) {
26890
27076
  return `${teamId}:${channelId}:${ts}`;
@@ -26897,9 +27083,9 @@ function tsNewer(a, b) {
26897
27083
  }
26898
27084
  function readStore4() {
26899
27085
  const path = storePath4();
26900
- if (!(0, import_node_fs59.existsSync)(path)) return [];
27086
+ if (!(0, import_node_fs60.existsSync)(path)) return [];
26901
27087
  try {
26902
- const parsed = isSecureFileEncrypted(path) ? readSecureJson(path) : JSON.parse((0, import_node_fs59.readFileSync)(path, "utf8"));
27088
+ const parsed = isSecureFileEncrypted(path) ? readSecureJson(path) : JSON.parse((0, import_node_fs60.readFileSync)(path, "utf8"));
26903
27089
  return Array.isArray(parsed?.watches) ? parsed.watches : [];
26904
27090
  } catch {
26905
27091
  return [];
@@ -28641,27 +28827,27 @@ init_gh_errors();
28641
28827
  init_git_auth_mode();
28642
28828
 
28643
28829
  // src/board/load-home-board.ts
28644
- var import_node_fs61 = require("fs");
28645
- var import_node_path57 = require("path");
28830
+ var import_node_fs62 = require("fs");
28831
+ var import_node_path58 = require("path");
28646
28832
  init_worktree();
28647
28833
  init_paths();
28648
28834
 
28649
28835
  // src/board/board-pins.ts
28650
28836
  var import_node_crypto15 = require("crypto");
28651
- var import_node_fs60 = require("fs");
28652
- var import_node_path56 = require("path");
28837
+ var import_node_fs61 = require("fs");
28838
+ var import_node_path57 = require("path");
28653
28839
  init_paths();
28654
28840
  init_home_board();
28655
28841
  var FILE = "home-board-pins.json";
28656
28842
  var VERSION = 1;
28657
28843
  function pinsFile() {
28658
- return (0, import_node_path56.join)(appDataDir(), FILE);
28844
+ return (0, import_node_path57.join)(appDataDir(), FILE);
28659
28845
  }
28660
28846
  function readDisk() {
28661
28847
  const path = pinsFile();
28662
- if (!(0, import_node_fs60.existsSync)(path)) return [];
28848
+ if (!(0, import_node_fs61.existsSync)(path)) return [];
28663
28849
  try {
28664
- const raw = JSON.parse((0, import_node_fs60.readFileSync)(path, "utf8"));
28850
+ const raw = JSON.parse((0, import_node_fs61.readFileSync)(path, "utf8"));
28665
28851
  if (raw?.version !== VERSION || !Array.isArray(raw.items)) return [];
28666
28852
  return raw.items.filter((item) => item?.id && item.kind && item.ref);
28667
28853
  } catch {
@@ -28669,8 +28855,8 @@ function readDisk() {
28669
28855
  }
28670
28856
  }
28671
28857
  function writeDisk(items) {
28672
- (0, import_node_fs60.mkdirSync)(appDataDir(), { recursive: true });
28673
- (0, import_node_fs60.writeFileSync)(pinsFile(), JSON.stringify({ version: VERSION, items }, null, 2), "utf8");
28858
+ (0, import_node_fs61.mkdirSync)(appDataDir(), { recursive: true });
28859
+ (0, import_node_fs61.writeFileSync)(pinsFile(), JSON.stringify({ version: VERSION, items }, null, 2), "utf8");
28674
28860
  }
28675
28861
  function listBoardPins() {
28676
28862
  return readDisk();
@@ -28691,7 +28877,7 @@ function homeBoardWorkspaceKey(workspaces) {
28691
28877
  return workspaces.map((w) => w.path).filter(Boolean).sort().join("\n");
28692
28878
  }
28693
28879
  function cacheFile() {
28694
- return (0, import_node_path57.join)(appDataDir(), "home-board-cache.json");
28880
+ return (0, import_node_path58.join)(appDataDir(), "home-board-cache.json");
28695
28881
  }
28696
28882
  function emptyInputs() {
28697
28883
  return {
@@ -28717,9 +28903,9 @@ function shouldCacheHomeBoardInputs(inputs) {
28717
28903
  }
28718
28904
  function readDiskCache() {
28719
28905
  const path = cacheFile();
28720
- if (!(0, import_node_fs61.existsSync)(path)) return null;
28906
+ if (!(0, import_node_fs62.existsSync)(path)) return null;
28721
28907
  try {
28722
- const raw = JSON.parse((0, import_node_fs61.readFileSync)(path, "utf8"));
28908
+ const raw = JSON.parse((0, import_node_fs62.readFileSync)(path, "utf8"));
28723
28909
  if (raw?.version !== CACHE_VERSION || typeof raw.fetchedAt !== "number") {
28724
28910
  return null;
28725
28911
  }
@@ -28733,8 +28919,8 @@ function readDiskCache() {
28733
28919
  }
28734
28920
  function writeDiskCache(entry) {
28735
28921
  try {
28736
- (0, import_node_fs61.mkdirSync)(appDataDir(), { recursive: true });
28737
- (0, import_node_fs61.writeFileSync)(cacheFile(), JSON.stringify(entry), "utf8");
28922
+ (0, import_node_fs62.mkdirSync)(appDataDir(), { recursive: true });
28923
+ (0, import_node_fs62.writeFileSync)(cacheFile(), JSON.stringify(entry), "utf8");
28738
28924
  } catch {
28739
28925
  }
28740
28926
  }
@@ -28958,14 +29144,14 @@ function orchCreateThreadAgentNote(input) {
28958
29144
  var MAX_ORCH_THREADS = 5;
28959
29145
  var CREATE_THREAD_TIMEOUT_MS = 9e4;
28960
29146
  function withTimeout2(promise, ms, label) {
28961
- return new Promise((resolve, reject) => {
29147
+ return new Promise((resolve2, reject) => {
28962
29148
  const timer = setTimeout(() => {
28963
29149
  reject(new Error(`${label} timed out after ${Math.round(ms / 1e3)}s`));
28964
29150
  }, ms);
28965
29151
  promise.then(
28966
29152
  (value) => {
28967
29153
  clearTimeout(timer);
28968
- resolve(value);
29154
+ resolve2(value);
28969
29155
  },
28970
29156
  (err) => {
28971
29157
  clearTimeout(timer);
@@ -29137,7 +29323,7 @@ async function startMcpServer() {
29137
29323
  async () => {
29138
29324
  const threads = orch.getThreads(true);
29139
29325
  const lines = threads.map((t) => {
29140
- const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path58.basename)(t.repoPath) || t.repoPath;
29326
+ const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path59.basename)(t.repoPath) || t.repoPath;
29141
29327
  const live = orch.threadLooksLive(t) ? readTurnLive(t.id) : null;
29142
29328
  const parent = t.parentThreadId ? ` parent:${t.parentThreadId.slice(0, 8)}` : "";
29143
29329
  const preview = lastMessagePreview(t.messages, 80);