@sideboard-ai/core 0.1.238 → 0.1.240

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -24,7 +24,7 @@ import {
24
24
  resolveQuotaFallbackAgent,
25
25
  stripBrightsyNdjsonNoise,
26
26
  toolDescription
27
- } from "./chunk-K6UTJOE6.js";
27
+ } from "./chunk-QXYWLO6W.js";
28
28
  import {
29
29
  SLACK_REPLY_FORMATTING,
30
30
  addWorkspace,
@@ -745,13 +745,14 @@ function shouldAutoArchiveOnPrMerge(opts) {
745
745
  import {
746
746
  copyFileSync,
747
747
  existsSync as existsSync3,
748
- mkdirSync as mkdirSync3,
748
+ mkdirSync as mkdirSync4,
749
749
  readdirSync,
750
- readFileSync as readFileSync2
750
+ readFileSync as readFileSync3,
751
+ realpathSync
751
752
  } from "fs";
752
753
  import { execFileSync } from "child_process";
753
754
  import { createServer } from "net";
754
- import { basename, dirname as dirname2, join as join4 } from "path";
755
+ import { basename, dirname as dirname3, join as join5, resolve, sep } from "path";
755
756
  import { execa as execa2 } from "execa";
756
757
  import { createInterface as createInterface2 } from "readline";
757
758
 
@@ -1664,16 +1665,73 @@ async function requestReview(threadRef, send) {
1664
1665
  return { tab: started, from };
1665
1666
  }
1666
1667
 
1668
+ // src/hook/worktree-run-ports.ts
1669
+ import { mkdirSync as mkdirSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
1670
+ import { dirname as dirname2, join as join4 } from "path";
1671
+ var RUN_PORTS_REL = ".context/.sideboard/run-ports.json";
1672
+ function worktreeRunPortsPath(worktreePath) {
1673
+ return join4(worktreePath, RUN_PORTS_REL);
1674
+ }
1675
+ function isPort(value) {
1676
+ return typeof value === "number" && Number.isInteger(value) && value > 0 && value <= 65535;
1677
+ }
1678
+ function parseFile(raw) {
1679
+ try {
1680
+ const parsed = JSON.parse(raw);
1681
+ if (!parsed || typeof parsed !== "object") return {};
1682
+ const scripts = parsed.scripts;
1683
+ if (!scripts || typeof scripts !== "object") return {};
1684
+ const next = {};
1685
+ for (const [name, ports] of Object.entries(scripts)) {
1686
+ if (!name || !Array.isArray(ports)) continue;
1687
+ const cleaned = ports.filter(isPort);
1688
+ if (cleaned.length) next[name] = cleaned;
1689
+ }
1690
+ return { scripts: next };
1691
+ } catch {
1692
+ return {};
1693
+ }
1694
+ }
1695
+ function loadWorktreeRunPorts(worktreePath, scriptName) {
1696
+ if (!worktreePath.trim() || !scriptName.trim()) return null;
1697
+ try {
1698
+ const raw = readFileSync2(worktreeRunPortsPath(worktreePath), "utf8");
1699
+ const ports = parseFile(raw).scripts?.[scriptName];
1700
+ return ports?.length ? ports : null;
1701
+ } catch {
1702
+ return null;
1703
+ }
1704
+ }
1705
+ function saveWorktreeRunPorts(worktreePath, scriptName, ports) {
1706
+ if (!worktreePath.trim() || !scriptName.trim()) return;
1707
+ const cleaned = ports.filter(isPort);
1708
+ if (!cleaned.length) return;
1709
+ const path = worktreeRunPortsPath(worktreePath);
1710
+ let current = {};
1711
+ try {
1712
+ current = parseFile(readFileSync2(path, "utf8"));
1713
+ } catch {
1714
+ current = {};
1715
+ }
1716
+ const scripts = { ...current.scripts ?? {} };
1717
+ scripts[scriptName] = cleaned;
1718
+ mkdirSync3(dirname2(path), { recursive: true });
1719
+ writeFileSync2(path, `${JSON.stringify({ scripts }, null, 2)}
1720
+ `, "utf8");
1721
+ }
1722
+
1667
1723
  // src/hook/conductor.ts
1668
1724
  var PORT_RANGE_SIZE = 10;
1725
+ var RECLAIM_RETRY_DELAY_MS = 40;
1726
+ var RECLAIM_TRIES = 8;
1669
1727
  function matchSimpleGlob(pattern, name) {
1670
1728
  const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
1671
1729
  return new RegExp(`^${escaped}$`).test(name);
1672
1730
  }
1673
1731
  function readWorktreeInclude(repoPath) {
1674
- const path = join4(repoPath, ".worktreeinclude");
1732
+ const path = join5(repoPath, ".worktreeinclude");
1675
1733
  if (!existsSync3(path)) return [];
1676
- return readFileSync2(path, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
1734
+ return readFileSync3(path, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
1677
1735
  }
1678
1736
  function resolveFilesToCopy(repoPath) {
1679
1737
  const fromInclude = readWorktreeInclude(repoPath);
@@ -1712,10 +1770,10 @@ function copyConfiguredFiles(repoPath, worktreePath) {
1712
1770
  const patterns = resolveFilesToCopy(repoPath);
1713
1771
  const copied = [];
1714
1772
  for (const rel of patterns) {
1715
- const src = join4(repoPath, rel);
1773
+ const src = join5(repoPath, rel);
1716
1774
  if (!existsSync3(src)) continue;
1717
- const dest = join4(worktreePath, rel);
1718
- mkdirSync3(dirname2(dest), { recursive: true });
1775
+ const dest = join5(worktreePath, rel);
1776
+ mkdirSync4(dirname3(dest), { recursive: true });
1719
1777
  copyFileSync(src, dest);
1720
1778
  copied.push(rel);
1721
1779
  }
@@ -1792,6 +1850,57 @@ function killableListenerPids(raw, selfPid = process.pid) {
1792
1850
  }
1793
1851
  return pids;
1794
1852
  }
1853
+ function listUnixListenerPids(port, selfPid) {
1854
+ try {
1855
+ const raw = execFileSync("lsof", [`-tiTCP:${port}`, "-sTCP:LISTEN"], {
1856
+ encoding: "utf8",
1857
+ stdio: ["ignore", "pipe", "ignore"],
1858
+ timeout: 2e3
1859
+ });
1860
+ return killableListenerPids(raw, selfPid);
1861
+ } catch {
1862
+ return [];
1863
+ }
1864
+ }
1865
+ function listenerCwd(pid) {
1866
+ if (!Number.isFinite(pid) || pid <= 0) return null;
1867
+ try {
1868
+ const raw = execFileSync("lsof", ["-a", "-p", String(pid), "-d", "cwd", "-Fn"], {
1869
+ encoding: "utf8",
1870
+ stdio: ["ignore", "pipe", "ignore"],
1871
+ timeout: 2e3
1872
+ });
1873
+ for (const line of raw.split("\n")) {
1874
+ if (line.startsWith("n") && line.length > 1) return line.slice(1);
1875
+ }
1876
+ } catch {
1877
+ }
1878
+ return null;
1879
+ }
1880
+ function realpathOrResolve(path) {
1881
+ try {
1882
+ return realpathSync(path);
1883
+ } catch {
1884
+ return resolve(path);
1885
+ }
1886
+ }
1887
+ function isOtherWorktreeListenerCwd(cwd, worktreePath) {
1888
+ const wt = realpathOrResolve(worktreePath);
1889
+ const c = realpathOrResolve(cwd);
1890
+ if (c === wt || c.startsWith(wt + sep)) return false;
1891
+ const parent = dirname3(wt);
1892
+ const thisName = basename(wt);
1893
+ if (!thisName || c === parent) return false;
1894
+ if (!c.startsWith(parent + sep)) return false;
1895
+ const first = c.slice(parent.length + 1).split(sep)[0];
1896
+ return Boolean(first) && first !== thisName;
1897
+ }
1898
+ function signalPid(pid, signal) {
1899
+ try {
1900
+ process.kill(pid, signal);
1901
+ } catch {
1902
+ }
1903
+ }
1795
1904
  function killListenersOnPorts(ports) {
1796
1905
  const selfPid = process.pid;
1797
1906
  for (const port of ports) {
@@ -1809,26 +1918,32 @@ function killListenersOnPorts(ports) {
1809
1918
  );
1810
1919
  continue;
1811
1920
  }
1812
- let raw = "";
1813
- try {
1814
- raw = execFileSync("lsof", [`-tiTCP:${port}`, "-sTCP:LISTEN"], {
1815
- encoding: "utf8",
1816
- stdio: ["ignore", "pipe", "ignore"],
1817
- timeout: 2e3
1818
- });
1819
- } catch {
1820
- continue;
1821
- }
1822
- for (const pid of killableListenerPids(raw, selfPid)) {
1823
- try {
1824
- process.kill(pid, "SIGTERM");
1825
- } catch {
1826
- }
1921
+ for (const pid of listUnixListenerPids(port, selfPid)) {
1922
+ signalPid(pid, "SIGTERM");
1827
1923
  }
1828
1924
  } catch {
1829
1925
  }
1830
1926
  }
1831
1927
  }
1928
+ function killStaleWorktreeListeners(ports, worktreePath, signal = "SIGTERM") {
1929
+ if (!worktreePath.trim()) {
1930
+ killListenersOnPorts(ports);
1931
+ return;
1932
+ }
1933
+ if (process.platform === "win32") {
1934
+ killListenersOnPorts(ports);
1935
+ return;
1936
+ }
1937
+ const selfPid = process.pid;
1938
+ for (const port of ports) {
1939
+ if (!Number.isFinite(port) || port <= 0) continue;
1940
+ for (const pid of listUnixListenerPids(port, selfPid)) {
1941
+ const cwd = listenerCwd(pid);
1942
+ if (cwd && isOtherWorktreeListenerCwd(cwd, worktreePath)) continue;
1943
+ signalPid(pid, signal);
1944
+ }
1945
+ }
1946
+ }
1832
1947
  function killScriptTree(child, ports = []) {
1833
1948
  const pid = child.pid;
1834
1949
  if (pid) {
@@ -1990,7 +2105,7 @@ function getRunMode(worktreePath, repoPath) {
1990
2105
  return loadWorkspaceSettings(worktreePath, repoPath)?.runMode ?? "concurrent";
1991
2106
  }
1992
2107
  async function reservePort() {
1993
- return new Promise((resolve, reject) => {
2108
+ return new Promise((resolve2, reject) => {
1994
2109
  const server = createServer();
1995
2110
  let released = false;
1996
2111
  const release = () => new Promise((res) => {
@@ -2007,7 +2122,7 @@ async function reservePort() {
2007
2122
  void release().then(() => reject(new Error("Failed to allocate port")));
2008
2123
  return;
2009
2124
  }
2010
- resolve({ port: addr.port, release });
2125
+ resolve2({ port: addr.port, release });
2011
2126
  });
2012
2127
  server.on("error", reject);
2013
2128
  });
@@ -2018,7 +2133,8 @@ async function allocatePort() {
2018
2133
  return held.port;
2019
2134
  }
2020
2135
  async function tryReservePort(port) {
2021
- return new Promise((resolve) => {
2136
+ if (!Number.isInteger(port) || port <= 0 || port > 65535) return null;
2137
+ return new Promise((resolve2) => {
2022
2138
  const server = createServer();
2023
2139
  let released = false;
2024
2140
  const release = () => new Promise((res) => {
@@ -2029,23 +2145,63 @@ async function tryReservePort(port) {
2029
2145
  released = true;
2030
2146
  server.close(() => res());
2031
2147
  });
2032
- server.once("error", () => resolve(null));
2148
+ server.once("error", () => {
2149
+ try {
2150
+ server.close();
2151
+ } catch {
2152
+ }
2153
+ resolve2(null);
2154
+ });
2033
2155
  server.listen(port, "127.0.0.1", () => {
2034
- resolve({ port, release });
2156
+ resolve2({ port, release });
2035
2157
  });
2036
2158
  });
2037
2159
  }
2038
- async function reservePortRange(size = PORT_RANGE_SIZE) {
2039
- const held = [await reservePort()];
2040
- const base = held[0].port;
2160
+ async function tryReservePorts(ports) {
2161
+ const held = [];
2162
+ for (const port of ports) {
2163
+ const next = await tryReservePort(port);
2164
+ if (!next) {
2165
+ await Promise.all(held.map((h) => h.release()));
2166
+ return null;
2167
+ }
2168
+ held.push(next);
2169
+ }
2170
+ return held;
2171
+ }
2172
+ function normalizePreferredPorts(ports, size) {
2173
+ if (!ports?.length) return [];
2174
+ const seen = /* @__PURE__ */ new Set();
2175
+ const out = [];
2176
+ for (const p of ports) {
2177
+ if (!Number.isInteger(p) || p <= 0 || p > 65535 || seen.has(p)) continue;
2178
+ seen.add(p);
2179
+ out.push(p);
2180
+ if (out.length >= size) break;
2181
+ }
2182
+ return out;
2183
+ }
2184
+ function delay(ms) {
2185
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
2186
+ }
2187
+ async function fillPortRange(held, size) {
2188
+ if (held.length >= size) return held;
2189
+ const base = held[0]?.port;
2190
+ const taken = new Set(held.map((h) => h.port));
2041
2191
  try {
2042
- for (let i = 1; i < size; i++) {
2043
- const candidate = base + i;
2044
- const next = await tryReservePort(candidate);
2192
+ let offset = 0;
2193
+ while (held.length < size) {
2194
+ const candidate = base != null ? base + offset : null;
2195
+ offset += 1;
2196
+ if (candidate != null && taken.has(candidate)) continue;
2197
+ const next = candidate != null ? await tryReservePort(candidate) : null;
2045
2198
  if (next) {
2046
2199
  held.push(next);
2200
+ taken.add(next.port);
2047
2201
  } else {
2048
- held.push(await reservePort());
2202
+ const ephemeral = await reservePort();
2203
+ held.push(ephemeral);
2204
+ taken.add(ephemeral.port);
2049
2205
  }
2050
2206
  }
2051
2207
  return held;
@@ -2054,6 +2210,49 @@ async function reservePortRange(size = PORT_RANGE_SIZE) {
2054
2210
  throw err;
2055
2211
  }
2056
2212
  }
2213
+ async function tryReserveAvailablePorts(ports) {
2214
+ const held = [];
2215
+ for (const port of ports) {
2216
+ const next = await tryReservePort(port);
2217
+ if (next) held.push(next);
2218
+ }
2219
+ return held;
2220
+ }
2221
+ async function reclaimPreferredPorts(ports, worktreePath) {
2222
+ const primary = ports[0];
2223
+ if (primary == null) return null;
2224
+ const takePrimary = async () => {
2225
+ const held2 = await tryReserveAvailablePorts(ports);
2226
+ if (held2.some((h) => h.port === primary)) return held2;
2227
+ await Promise.all(held2.map((h) => h.release()));
2228
+ return null;
2229
+ };
2230
+ let held = await takePrimary();
2231
+ if (held) return held;
2232
+ if (worktreePath) {
2233
+ killStaleWorktreeListeners(ports, worktreePath, "SIGTERM");
2234
+ } else {
2235
+ killListenersOnPorts(ports);
2236
+ }
2237
+ for (let i = 0; i < RECLAIM_TRIES; i++) {
2238
+ await delay(RECLAIM_RETRY_DELAY_MS);
2239
+ held = await takePrimary();
2240
+ if (held) return held;
2241
+ if (i === 2 && worktreePath) {
2242
+ killStaleWorktreeListeners(ports, worktreePath, "SIGKILL");
2243
+ }
2244
+ }
2245
+ return null;
2246
+ }
2247
+ async function reservePortRange(size = PORT_RANGE_SIZE, opts) {
2248
+ const preferred = normalizePreferredPorts(opts?.preferred, size);
2249
+ if (preferred.length) {
2250
+ const reused = await reclaimPreferredPorts(preferred, opts?.worktreePath);
2251
+ if (reused) return fillPortRange(reused, size);
2252
+ }
2253
+ const held = [await reservePort()];
2254
+ return fillPortRange(held, size);
2255
+ }
2057
2256
  async function allocatePortRange(size = PORT_RANGE_SIZE) {
2058
2257
  const held = await reservePortRange(size);
2059
2258
  const ports = held.map((h) => h.port);
@@ -2063,8 +2262,13 @@ async function allocatePortRange(size = PORT_RANGE_SIZE) {
2063
2262
  async function startDevServer(repoPath, worktreePath, onLine, opts) {
2064
2263
  const script = getRunScript(worktreePath, repoPath, opts?.scriptName);
2065
2264
  if (!script) return null;
2066
- const held = await reservePortRange(PORT_RANGE_SIZE);
2265
+ const preferred = loadWorktreeRunPorts(worktreePath, script.name) ?? opts?.preferredPorts;
2266
+ const held = await reservePortRange(PORT_RANGE_SIZE, {
2267
+ preferred: preferred ?? void 0,
2268
+ worktreePath
2269
+ });
2067
2270
  const ports = held.map((h) => h.port);
2271
+ saveWorktreeRunPorts(worktreePath, script.name, ports);
2068
2272
  try {
2069
2273
  const handle = await spawnWorkspaceScript(script.command, {
2070
2274
  worktreePath,
@@ -2090,8 +2294,8 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
2090
2294
 
2091
2295
  // src/store/setup-log.ts
2092
2296
  import { createHash } from "crypto";
2093
- import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
2094
- import { join as join5 } from "path";
2297
+ import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
2298
+ import { join as join6 } from "path";
2095
2299
  var EMPTY = {
2096
2300
  output: "",
2097
2301
  running: false,
@@ -2133,7 +2337,7 @@ function materialize(mem) {
2133
2337
  };
2134
2338
  }
2135
2339
  function setupLogPath(threadId) {
2136
- return join5(threadsDir(), `${threadId}.setup.log.json`);
2340
+ return join6(threadsDir(), `${threadId}.setup.log.json`);
2137
2341
  }
2138
2342
  function setupLogKeyForWorktree(worktreePath) {
2139
2343
  const norm = normalizeWorktreePath(worktreePath);
@@ -2160,7 +2364,7 @@ function persistNow(threadId) {
2160
2364
  const mem = memory.get(threadId);
2161
2365
  if (!mem) return;
2162
2366
  try {
2163
- writeFileSync2(
2367
+ writeFileSync3(
2164
2368
  setupLogPath(threadId),
2165
2369
  `${JSON.stringify(materialize(mem))}
2166
2370
  `,
@@ -2183,7 +2387,7 @@ function loadFromDisk(threadId) {
2183
2387
  const path = setupLogPath(threadId);
2184
2388
  if (!existsSync4(path)) return null;
2185
2389
  try {
2186
- const raw = JSON.parse(readFileSync3(path, "utf8"));
2390
+ const raw = JSON.parse(readFileSync4(path, "utf8"));
2187
2391
  return {
2188
2392
  output: typeof raw.output === "string" ? raw.output : "",
2189
2393
  running: Boolean(raw.running),
@@ -2242,8 +2446,8 @@ function finishSetupLog(threadId, exitCode, source) {
2242
2446
 
2243
2447
  // src/store/run-log.ts
2244
2448
  import { createHash as createHash2 } from "crypto";
2245
- import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
2246
- import { join as join6 } from "path";
2449
+ import { existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
2450
+ import { join as join7 } from "path";
2247
2451
  var EMPTY2 = {
2248
2452
  output: "",
2249
2453
  running: false,
@@ -2282,7 +2486,7 @@ function safeScriptToken(scriptName) {
2282
2486
  return token || "dev";
2283
2487
  }
2284
2488
  function runLogPath(key) {
2285
- return join6(threadsDir(), `${key}.run.log.json`);
2489
+ return join7(threadsDir(), `${key}.run.log.json`);
2286
2490
  }
2287
2491
  function runLogKeyForWorktree(worktreePath, scriptName) {
2288
2492
  const norm = normalizeWorktreePath(worktreePath);
@@ -2311,7 +2515,7 @@ function persistNow2(key) {
2311
2515
  const mem = memory2.get(key);
2312
2516
  if (!mem) return;
2313
2517
  try {
2314
- writeFileSync3(runLogPath(key), `${JSON.stringify(materialize2(mem))}
2518
+ writeFileSync4(runLogPath(key), `${JSON.stringify(materialize2(mem))}
2315
2519
  `, "utf8");
2316
2520
  } catch {
2317
2521
  }
@@ -2330,7 +2534,7 @@ function loadFromDisk2(key) {
2330
2534
  const path = runLogPath(key);
2331
2535
  if (!existsSync5(path)) return null;
2332
2536
  try {
2333
- const raw = JSON.parse(readFileSync4(path, "utf8"));
2537
+ const raw = JSON.parse(readFileSync5(path, "utf8"));
2334
2538
  return {
2335
2539
  output: typeof raw.output === "string" ? raw.output : "",
2336
2540
  running: Boolean(raw.running),
@@ -2391,7 +2595,7 @@ function flushRunLog(key) {
2391
2595
 
2392
2596
  // src/git/orphan-cleanup.ts
2393
2597
  import { existsSync as existsSync6, readdirSync as readdirSync2, statSync } from "fs";
2394
- import { join as join7 } from "path";
2598
+ import { join as join8 } from "path";
2395
2599
  function isSideboardWorktreePath(path) {
2396
2600
  return path.includes("/.sideboard/worktrees/") || path.includes("/sideboard/workspaces/");
2397
2601
  }
@@ -2438,9 +2642,9 @@ async function findOrphanWorktrees(repoPaths) {
2438
2642
  if (existsSync6(root)) {
2439
2643
  for (const entry of readdirSync2(root, { withFileTypes: true })) {
2440
2644
  if (!entry.isDirectory()) continue;
2441
- const path = join7(root, entry.name).replace(/\/$/, "");
2645
+ const path = join8(root, entry.name).replace(/\/$/, "");
2442
2646
  if (known.has(path) || seen.has(path)) continue;
2443
- if (!existsSync6(join7(path, ".git"))) continue;
2647
+ if (!existsSync6(join8(path, ".git"))) continue;
2444
2648
  seen.add(path);
2445
2649
  let mtimeMs = 0;
2446
2650
  try {
@@ -2654,7 +2858,7 @@ async function applyThreadIntoMain(thread, opts) {
2654
2858
 
2655
2859
  // src/git/clone-repo.ts
2656
2860
  import { existsSync as existsSync7 } from "fs";
2657
- import { basename as basename2, join as join8 } from "path";
2861
+ import { basename as basename2, join as join9 } from "path";
2658
2862
  import { execa as execa4 } from "execa";
2659
2863
  async function cloneRepoIntoSideboard(opts) {
2660
2864
  const url = opts.url.trim();
@@ -2665,7 +2869,7 @@ async function cloneRepoIntoSideboard(opts) {
2665
2869
  name = leaf || "repo";
2666
2870
  }
2667
2871
  name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
2668
- const dest = join8(sideboardReposDir(), name);
2872
+ const dest = join9(sideboardReposDir(), name);
2669
2873
  if (existsSync7(dest)) {
2670
2874
  const repoPath2 = await resolveRepoRoot(dest);
2671
2875
  const workspace2 = await ensureWorkspace(repoPath2);
@@ -2691,13 +2895,13 @@ function isAdoptableRunScriptRequest(req) {
2691
2895
  }
2692
2896
 
2693
2897
  // src/store/desktop-host.ts
2694
- import { readFileSync as readFileSync5, unlinkSync, writeFileSync as writeFileSync4 } from "fs";
2695
- import { join as join9 } from "path";
2898
+ import { readFileSync as readFileSync6, unlinkSync, writeFileSync as writeFileSync5 } from "fs";
2899
+ import { join as join10 } from "path";
2696
2900
  function desktopHostPidPath() {
2697
- return join9(appDataDir(), "desktop-host.pid");
2901
+ return join10(appDataDir(), "desktop-host.pid");
2698
2902
  }
2699
2903
  function claimDesktopHost(pid = process.pid) {
2700
- writeFileSync4(desktopHostPidPath(), `${pid}
2904
+ writeFileSync5(desktopHostPidPath(), `${pid}
2701
2905
  `, "utf8");
2702
2906
  }
2703
2907
  function releaseDesktopHost(pid = process.pid) {
@@ -2709,7 +2913,7 @@ function releaseDesktopHost(pid = process.pid) {
2709
2913
  }
2710
2914
  function readDesktopHostPid() {
2711
2915
  try {
2712
- const pid = Number.parseInt(readFileSync5(desktopHostPidPath(), "utf8").trim(), 10);
2916
+ const pid = Number.parseInt(readFileSync6(desktopHostPidPath(), "utf8").trim(), 10);
2713
2917
  if (!Number.isFinite(pid) || pid <= 0) return null;
2714
2918
  return pid;
2715
2919
  } catch {
@@ -2782,12 +2986,12 @@ function notifyParentOfChildHalt(child, status, send) {
2782
2986
  import {
2783
2987
  appendFileSync as appendFileSync2,
2784
2988
  existsSync as existsSync8,
2785
- mkdirSync as mkdirSync4,
2989
+ mkdirSync as mkdirSync5,
2786
2990
  readdirSync as readdirSync3,
2787
- readFileSync as readFileSync6,
2788
- writeFileSync as writeFileSync5
2991
+ readFileSync as readFileSync7,
2992
+ writeFileSync as writeFileSync6
2789
2993
  } from "fs";
2790
- import { dirname as dirname3, join as join10 } from "path";
2994
+ import { dirname as dirname4, join as join11 } from "path";
2791
2995
 
2792
2996
  // src/mcp/wait-for-turn.ts
2793
2997
  var MCP_WAIT_FOR_TURN_MAX_MS = 45e3;
@@ -2863,11 +3067,11 @@ function jobTreeAlive(pid) {
2863
3067
  }
2864
3068
  function readIntFile(file) {
2865
3069
  if (!existsSync8(file)) return null;
2866
- const n = Number.parseInt(readFileSync6(file, "utf8").trim(), 10);
3070
+ const n = Number.parseInt(readFileSync7(file, "utf8").trim(), 10);
2867
3071
  return Number.isInteger(n) ? n : null;
2868
3072
  }
2869
3073
  function jobDir(root, id, legacy = false) {
2870
- return join10(root, legacy ? LEGACY_DETACHED_JOBS_DIR : DETACHED_JOBS_DIR, id);
3074
+ return join11(root, legacy ? LEGACY_DETACHED_JOBS_DIR : DETACHED_JOBS_DIR, id);
2871
3075
  }
2872
3076
  function resolveJobDir(root, id) {
2873
3077
  const modern = jobDir(root, id, false);
@@ -2877,7 +3081,7 @@ function resolveJobDir(root, id) {
2877
3081
  return modern;
2878
3082
  }
2879
3083
  function listJobIdsIn(root, rel) {
2880
- const dir = join10(root, rel);
3084
+ const dir = join11(root, rel);
2881
3085
  if (!existsSync8(dir)) return [];
2882
3086
  return readdirSync3(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && JOB_ID_RE.test(e.name)).map((e) => e.name);
2883
3087
  }
@@ -2891,7 +3095,7 @@ function listRunningDetachedJobs(worktreePath) {
2891
3095
  const running = [];
2892
3096
  for (const id of ids) {
2893
3097
  const dir = resolveJobDir(root, id);
2894
- const pid = readIntFile(join10(dir, "pid"));
3098
+ const pid = readIntFile(join11(dir, "pid"));
2895
3099
  if (jobTreeAlive(pid)) running.push(id);
2896
3100
  }
2897
3101
  return running.sort();
@@ -2975,7 +3179,7 @@ function planJobContinue(opts) {
2975
3179
  }
2976
3180
  function tailProgress(logFile, maxLines = 12) {
2977
3181
  if (!existsSync8(logFile)) return "(no log yet)";
2978
- const lines = readFileSync6(logFile, "utf8").split("\n");
3182
+ const lines = readFileSync7(logFile, "utf8").split("\n");
2979
3183
  return lines.slice(-maxLines).join("\n");
2980
3184
  }
2981
3185
  function lastProgressLine(progress) {
@@ -2984,7 +3188,7 @@ function lastProgressLine(progress) {
2984
3188
  }
2985
3189
  function readLogLines(file) {
2986
3190
  if (!existsSync8(file)) return [];
2987
- const lines = readFileSync6(file, "utf8").split("\n");
3191
+ const lines = readFileSync7(file, "utf8").split("\n");
2988
3192
  if (lines.length && lines[lines.length - 1] === "") lines.pop();
2989
3193
  return lines;
2990
3194
  }
@@ -2995,15 +3199,15 @@ function takeDelta(logFile, cursorFile) {
2995
3199
  return { delta: capJobLogDelta(lines.slice(start).join("\n")), nextCursor: lines.length };
2996
3200
  }
2997
3201
  function snapshotJob(dir) {
2998
- const pid = readIntFile(join10(dir, "pid"));
3202
+ const pid = readIntFile(join11(dir, "pid"));
2999
3203
  const running = jobTreeAlive(pid);
3000
3204
  return {
3001
3205
  pid,
3002
3206
  running,
3003
- exitCode: readIntFile(join10(dir, "exit")),
3004
- log: join10(dir, "log"),
3005
- cursor: join10(dir, "present.cursor"),
3006
- progress: tailProgress(join10(dir, "log"))
3207
+ exitCode: readIntFile(join11(dir, "exit")),
3208
+ log: join11(dir, "log"),
3209
+ cursor: join11(dir, "present.cursor"),
3210
+ progress: tailProgress(join11(dir, "log"))
3007
3211
  };
3008
3212
  }
3009
3213
  function toResult(id, snap, extra) {
@@ -3012,8 +3216,8 @@ function toResult(id, snap, extra) {
3012
3216
  const stillRunning = snap.running && !ok;
3013
3217
  const { delta, nextCursor } = takeDelta(snap.log, snap.cursor);
3014
3218
  try {
3015
- mkdirSync4(dirname3(snap.cursor), { recursive: true });
3016
- writeFileSync5(snap.cursor, `${nextCursor}
3219
+ mkdirSync5(dirname4(snap.cursor), { recursive: true });
3220
+ writeFileSync6(snap.cursor, `${nextCursor}
3017
3221
  `);
3018
3222
  } catch {
3019
3223
  }
@@ -3034,7 +3238,7 @@ function toResult(id, snap, extra) {
3034
3238
  };
3035
3239
  }
3036
3240
  async function sleepMs(ms) {
3037
- await new Promise((resolve) => setTimeout(resolve, ms));
3241
+ await new Promise((resolve2) => setTimeout(resolve2, ms));
3038
3242
  }
3039
3243
  async function waitForDetachedJob(cwd, id, opts) {
3040
3244
  const jobId = sanitizeDetachedJobId(id);
@@ -3088,7 +3292,7 @@ function killProcessTree(pid, signal) {
3088
3292
  }
3089
3293
  function appendJobLog(logFile, line) {
3090
3294
  try {
3091
- mkdirSync4(dirname3(logFile), { recursive: true });
3295
+ mkdirSync5(dirname4(logFile), { recursive: true });
3092
3296
  const body = line.endsWith("\n") ? line : `${line}
3093
3297
  `;
3094
3298
  appendFileSync2(logFile, body);
@@ -3137,10 +3341,10 @@ async function stopDetachedJob(cwd, id, opts) {
3137
3341
  killProcessTree(targetPid, "SIGKILL");
3138
3342
  await sleep(100);
3139
3343
  }
3140
- const exitFile = join10(dir, "exit");
3344
+ const exitFile = join11(dir, "exit");
3141
3345
  if (!existsSync8(exitFile)) {
3142
3346
  try {
3143
- writeFileSync5(exitFile, "1\n");
3347
+ writeFileSync6(exitFile, "1\n");
3144
3348
  } catch {
3145
3349
  }
3146
3350
  }
@@ -3963,7 +4167,7 @@ async function createThread(input, _onSetupLine) {
3963
4167
  return readThread(thread.id) ?? thread;
3964
4168
  }
3965
4169
  async function listLinearIssues(agent, repoPath) {
3966
- const { getAdapter: getAdapter2 } = await import("./agents-6NAPLJU2.js");
4170
+ const { getAdapter: getAdapter2 } = await import("./agents-CDQCQVWU.js");
3967
4171
  await requireAgent(agent, { requireLinear: true });
3968
4172
  const adapter = getAdapter2(agent);
3969
4173
  if (!adapter.listLinearIssues) {
@@ -4027,8 +4231,8 @@ import {
4027
4231
  existsSync as existsSync10,
4028
4232
  renameSync,
4029
4233
  unlinkSync as unlinkSync2,
4030
- writeFileSync as writeFileSync6,
4031
- readFileSync as readFileSync7
4234
+ writeFileSync as writeFileSync7,
4235
+ readFileSync as readFileSync8
4032
4236
  } from "fs";
4033
4237
  var buffers = /* @__PURE__ */ new Map();
4034
4238
  var FLUSH_MS = 800;
@@ -4105,7 +4309,7 @@ function writeTurnLive(threadId, progress) {
4105
4309
  const path = threadLivePath(threadId);
4106
4310
  const tmp = `${path}.${process.pid}.tmp`;
4107
4311
  try {
4108
- writeFileSync6(tmp, JSON.stringify(progress), "utf8");
4312
+ writeFileSync7(tmp, JSON.stringify(progress), "utf8");
4109
4313
  renameSync(tmp, path);
4110
4314
  } catch {
4111
4315
  try {
@@ -4118,7 +4322,7 @@ function readTurnLive(threadId) {
4118
4322
  const path = threadLivePath(threadId);
4119
4323
  if (!existsSync10(path)) return null;
4120
4324
  try {
4121
- const raw = JSON.parse(readFileSync7(path, "utf8"));
4325
+ const raw = JSON.parse(readFileSync8(path, "utf8"));
4122
4326
  if (!raw || typeof raw.summary !== "string") return null;
4123
4327
  return raw;
4124
4328
  } catch {
@@ -4345,23 +4549,23 @@ import {
4345
4549
  existsSync as existsSync11,
4346
4550
  mkdtempSync,
4347
4551
  readdirSync as readdirSync4,
4348
- readFileSync as readFileSync8,
4552
+ readFileSync as readFileSync9,
4349
4553
  rmSync
4350
4554
  } from "fs";
4351
4555
  import { tmpdir } from "os";
4352
- import { join as join11 } from "path";
4556
+ import { join as join12 } from "path";
4353
4557
  import { createRequire } from "module";
4354
- var CONDUCTOR_APP_SUPPORT = join11(
4558
+ var CONDUCTOR_APP_SUPPORT = join12(
4355
4559
  process.env.HOME ?? "",
4356
4560
  "Library",
4357
4561
  "Application Support",
4358
4562
  "com.conductor.app"
4359
4563
  );
4360
- var CONDUCTOR_DB = join11(CONDUCTOR_APP_SUPPORT, "conductor.db");
4361
- var CURSOR_SDK_STORE = join11(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
4564
+ var CONDUCTOR_DB = join12(CONDUCTOR_APP_SUPPORT, "conductor.db");
4565
+ var CURSOR_SDK_STORE = join12(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
4362
4566
  function thisModuleFile() {
4363
4567
  const cjsFile = typeof __filename !== "undefined" ? __filename : "";
4364
- return cjsFile || process.argv[1] || join11(process.cwd(), "package.json");
4568
+ return cjsFile || process.argv[1] || join12(process.cwd(), "package.json");
4365
4569
  }
4366
4570
  function openReadonlySqlite(file) {
4367
4571
  const req = createRequire(thisModuleFile());
@@ -4389,11 +4593,11 @@ function resolveConductorCursorAgentId(workspacePath) {
4389
4593
  return null;
4390
4594
  }
4391
4595
  for (const hash of hashes) {
4392
- const agentsFile = join11(CURSOR_SDK_STORE, hash, "agents.ndjson");
4596
+ const agentsFile = join12(CURSOR_SDK_STORE, hash, "agents.ndjson");
4393
4597
  if (!existsSync11(agentsFile)) continue;
4394
4598
  let text;
4395
4599
  try {
4396
- text = readFileSync8(agentsFile, "utf8");
4600
+ text = readFileSync9(agentsFile, "utf8");
4397
4601
  } catch {
4398
4602
  continue;
4399
4603
  }
@@ -4449,8 +4653,8 @@ function listConductorWorkspaces() {
4449
4653
  if (!existsSync11(CONDUCTOR_DB)) {
4450
4654
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
4451
4655
  }
4452
- const tmp = mkdtempSync(join11(tmpdir(), "sideboard-conductor-"));
4453
- const snapshot = join11(tmp, "conductor.db");
4656
+ const tmp = mkdtempSync(join12(tmpdir(), "sideboard-conductor-"));
4657
+ const snapshot = join12(tmp, "conductor.db");
4454
4658
  try {
4455
4659
  copyFileSync2(CONDUCTOR_DB, snapshot);
4456
4660
  for (const suffix of ["-wal", "-shm"]) {
@@ -4540,8 +4744,8 @@ function importConductorWorkspace(workspaceId) {
4540
4744
  if (!existsSync11(CONDUCTOR_DB)) {
4541
4745
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
4542
4746
  }
4543
- const tmp = mkdtempSync(join11(tmpdir(), "sideboard-conductor-"));
4544
- const snapshot = join11(tmp, "conductor.db");
4747
+ const tmp = mkdtempSync(join12(tmpdir(), "sideboard-conductor-"));
4748
+ const snapshot = join12(tmp, "conductor.db");
4545
4749
  try {
4546
4750
  copyFileSync2(CONDUCTOR_DB, snapshot);
4547
4751
  for (const suffix of ["-wal", "-shm"]) {
@@ -4931,8 +5135,8 @@ function stackAgentDefaultsFrom(input) {
4931
5135
  }
4932
5136
 
4933
5137
  // src/diff/diff.ts
4934
- import { existsSync as existsSync13, mkdirSync as mkdirSync5, readFileSync as readFileSync9, statSync as statSync2, writeFileSync as writeFileSync7 } from "fs";
4935
- import { dirname as dirname4, join as join12 } from "path";
5138
+ import { existsSync as existsSync13, mkdirSync as mkdirSync6, readFileSync as readFileSync10, statSync as statSync2, writeFileSync as writeFileSync8 } from "fs";
5139
+ import { dirname as dirname5, join as join13 } from "path";
4936
5140
  async function inspectGitWorktree(worktreePath) {
4937
5141
  if (!worktreePath || !existsSync13(worktreePath)) return "missing_worktree";
4938
5142
  const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
@@ -5078,11 +5282,11 @@ new file mode 100644
5078
5282
  };
5079
5283
  }
5080
5284
  async function untrackedPatch(worktreePath, path, maxHunk) {
5081
- const abs = join12(worktreePath, path);
5285
+ const abs = join13(worktreePath, path);
5082
5286
  try {
5083
5287
  const st = statSync2(abs);
5084
5288
  if (st.isFile() && st.size > maxHunk) {
5085
- const buf = readFileSync9(abs).subarray(0, maxHunk);
5289
+ const buf = readFileSync10(abs).subarray(0, maxHunk);
5086
5290
  return syntheticAddPatch(path, buf.toString("utf8"), maxHunk);
5087
5291
  }
5088
5292
  } catch {
@@ -5550,7 +5754,7 @@ async function getDiff(worktreePath, repoPath, opts) {
5550
5754
  }
5551
5755
  function statWorktreePath(worktreePath, relativePath) {
5552
5756
  assertSafeRelativePath(relativePath);
5553
- const abs = join12(worktreePath, relativePath);
5757
+ const abs = join13(worktreePath, relativePath);
5554
5758
  if (!existsSync13(abs)) return "missing";
5555
5759
  const st = statSync2(abs);
5556
5760
  if (st.isDirectory()) return "dir";
@@ -5592,7 +5796,7 @@ var DEFAULT_UPLOAD_MAX_BYTES = 5e7;
5592
5796
  function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
5593
5797
  assertSafeRelativePath(relativePath);
5594
5798
  const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
5595
- const abs = join12(worktreePath, relativePath);
5799
+ const abs = join13(worktreePath, relativePath);
5596
5800
  const st = statSync2(abs);
5597
5801
  if (!st.isFile()) {
5598
5802
  throw new Error(`Not a file: ${relativePath}`);
@@ -5602,7 +5806,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
5602
5806
  `File too large to upload (${st.size} bytes; max ${maxBytes})`
5603
5807
  );
5604
5808
  }
5605
- const buf = readFileSync9(abs);
5809
+ const buf = readFileSync10(abs);
5606
5810
  return {
5607
5811
  path: relativePath,
5608
5812
  contentBase64: buf.toString("base64"),
@@ -5612,12 +5816,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
5612
5816
  function readWorktreeFile(worktreePath, relativePath, opts) {
5613
5817
  assertSafeRelativePath(relativePath);
5614
5818
  const maxBytes = opts?.maxBytes ?? 2e5;
5615
- const abs = join12(worktreePath, relativePath);
5819
+ const abs = join13(worktreePath, relativePath);
5616
5820
  const st = statSync2(abs);
5617
5821
  if (!st.isFile()) {
5618
5822
  throw new Error(`Not a file: ${relativePath}`);
5619
5823
  }
5620
- const buf = readFileSync9(abs);
5824
+ const buf = readFileSync10(abs);
5621
5825
  if (isImageRelativePath(relativePath)) {
5622
5826
  const maxImageBytes = Math.max(maxBytes, 15e6);
5623
5827
  const truncated2 = buf.length > maxImageBytes;
@@ -5660,9 +5864,9 @@ function assertSafeRelativePath(relativePath) {
5660
5864
  }
5661
5865
  function writeWorktreeFile(worktreePath, relativePath, content) {
5662
5866
  assertSafeRelativePath(relativePath);
5663
- const abs = join12(worktreePath, relativePath);
5664
- mkdirSync5(dirname4(abs), { recursive: true });
5665
- writeFileSync7(abs, content, "utf8");
5867
+ const abs = join13(worktreePath, relativePath);
5868
+ mkdirSync6(dirname5(abs), { recursive: true });
5869
+ writeFileSync8(abs, content, "utf8");
5666
5870
  return { path: relativePath };
5667
5871
  }
5668
5872
  async function getWorktreeDirtyStat(worktreePath) {
@@ -5884,9 +6088,9 @@ async function confirmLand(thread, opts) {
5884
6088
  }
5885
6089
 
5886
6090
  // src/skills/discover.ts
5887
- import { existsSync as existsSync14, readdirSync as readdirSync5, readFileSync as readFileSync10, statSync as statSync3 } from "fs";
6091
+ import { existsSync as existsSync14, readdirSync as readdirSync5, readFileSync as readFileSync11, statSync as statSync3 } from "fs";
5888
6092
  import { homedir } from "os";
5889
- import { join as join13 } from "path";
6093
+ import { join as join14 } from "path";
5890
6094
 
5891
6095
  // src/skills/bundled/long-running.ts
5892
6096
  var LONG_RUNNING_SKILL_COMMAND = "long-running";
@@ -6023,7 +6227,7 @@ function parseFrontmatter(content) {
6023
6227
  }
6024
6228
  function readSkill(skillMd, source) {
6025
6229
  try {
6026
- const content = readFileSync10(skillMd, "utf8");
6230
+ const content = readFileSync11(skillMd, "utf8");
6027
6231
  const { name: fmName, description } = parseFrontmatter(content);
6028
6232
  const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
6029
6233
  const name = fmName || dirName;
@@ -6051,7 +6255,7 @@ function scanSkillsDir(dir, source, out) {
6051
6255
  }
6052
6256
  for (const entry of entries) {
6053
6257
  if (entry.startsWith(".")) continue;
6054
- const skillMd = join13(dir, entry, "SKILL.md");
6258
+ const skillMd = join14(dir, entry, "SKILL.md");
6055
6259
  if (!existsSync14(skillMd)) continue;
6056
6260
  try {
6057
6261
  if (!statSync3(skillMd).isFile()) continue;
@@ -6073,12 +6277,12 @@ function scanClaudePluginSkills(pluginsRoot, out) {
6073
6277
  return;
6074
6278
  }
6075
6279
  if (lookingForSkillsDir && entries.includes("SKILL.md")) {
6076
- const skill = readSkill(join13(dir, "SKILL.md"), "cli");
6280
+ const skill = readSkill(join14(dir, "SKILL.md"), "cli");
6077
6281
  if (skill) out.push(skill);
6078
6282
  }
6079
6283
  for (const entry of entries) {
6080
6284
  if (entry === "node_modules" || entry === ".git") continue;
6081
- const full = join13(dir, entry);
6285
+ const full = join14(dir, entry);
6082
6286
  try {
6083
6287
  if (!statSync3(full).isDirectory()) continue;
6084
6288
  } catch {
@@ -6098,17 +6302,17 @@ function discoverSkills(worktreePath) {
6098
6302
  const home = homedir();
6099
6303
  const collected = [];
6100
6304
  for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
6101
- scanSkillsDir(join13(worktreePath, rel), "workspace", collected);
6305
+ scanSkillsDir(join14(worktreePath, rel), "workspace", collected);
6102
6306
  }
6103
6307
  for (const abs of [
6104
- join13(home, ".claude/skills"),
6105
- join13(home, ".cursor/skills"),
6106
- join13(home, ".sideboard/skills"),
6107
- join13(home, ".brightsy/skills")
6308
+ join14(home, ".claude/skills"),
6309
+ join14(home, ".cursor/skills"),
6310
+ join14(home, ".sideboard/skills"),
6311
+ join14(home, ".brightsy/skills")
6108
6312
  ]) {
6109
6313
  scanSkillsDir(abs, "user", collected);
6110
6314
  }
6111
- scanClaudePluginSkills(join13(home, ".claude/plugins"), collected);
6315
+ scanClaudePluginSkills(join14(home, ".claude/plugins"), collected);
6112
6316
  collected.push(...bundledSkills());
6113
6317
  const rank = {
6114
6318
  workspace: 0,
@@ -6134,7 +6338,7 @@ function readSkillBody(skillPath, maxChars = 12e3) {
6134
6338
  \u2026(truncated)` : body;
6135
6339
  }
6136
6340
  }
6137
- const raw = readFileSync10(skillPath, "utf8");
6341
+ const raw = readFileSync11(skillPath, "utf8");
6138
6342
  if (raw.startsWith("---")) {
6139
6343
  const end = raw.indexOf("\n---", 3);
6140
6344
  if (end >= 0) {
@@ -6280,11 +6484,11 @@ function shiftQueuedItem(queue, queueAttachments) {
6280
6484
 
6281
6485
  // src/agents/instructions.ts
6282
6486
  import { existsSync as existsSync16 } from "fs";
6283
- import { join as join15 } from "path";
6487
+ import { join as join16 } from "path";
6284
6488
 
6285
6489
  // src/skills/detached-job-path.ts
6286
6490
  import { existsSync as existsSync15 } from "fs";
6287
- import { dirname as dirname5, join as join14 } from "path";
6491
+ import { dirname as dirname6, join as join15 } from "path";
6288
6492
  import { fileURLToPath } from "url";
6289
6493
  var DETACHED_JOB_FILENAMES = ["detached-job.cjs", "detached-job.js"];
6290
6494
  function compiledModuleDir() {
@@ -6293,7 +6497,7 @@ function compiledModuleDir() {
6293
6497
  try {
6294
6498
  const url = import.meta.url;
6295
6499
  if (typeof url === "string" && url.length > 0) {
6296
- return dirname5(fileURLToPath(url));
6500
+ return dirname6(fileURLToPath(url));
6297
6501
  }
6298
6502
  } catch {
6299
6503
  }
@@ -6301,7 +6505,7 @@ function compiledModuleDir() {
6301
6505
  }
6302
6506
  function detachedJobScriptIn(dir) {
6303
6507
  for (const name of DETACHED_JOB_FILENAMES) {
6304
- const script = join14(dir, "scripts", name);
6508
+ const script = join15(dir, "scripts", name);
6305
6509
  if (existsSync15(script)) return script;
6306
6510
  }
6307
6511
  return null;
@@ -6319,7 +6523,7 @@ function resolveDetachedJobScript() {
6319
6523
  for (let i = 0; i < 8; i++) {
6320
6524
  const candidate = detachedJobScriptIn(dir);
6321
6525
  if (candidate) return candidate;
6322
- const parent = dirname5(dir);
6526
+ const parent = dirname6(dir);
6323
6527
  if (parent === dir) break;
6324
6528
  dir = parent;
6325
6529
  }
@@ -6424,9 +6628,9 @@ function formatWorktreeDirective(thread, opts) {
6424
6628
  );
6425
6629
  } else {
6426
6630
  const slug = opts?.githubSlug ?? "<origin-owner/name>";
6427
- const resolve = opts?.githubSlug ? "" : " Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree.";
6631
+ const resolve2 = opts?.githubSlug ? "" : " Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree.";
6428
6632
  lines.push(
6429
- `- 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\`.`
6633
+ `- 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\`.`
6430
6634
  );
6431
6635
  }
6432
6636
  lines.push(
@@ -6538,9 +6742,9 @@ function formatPrGateDirective() {
6538
6742
  }
6539
6743
  function formatProcessGuideDirective(opts) {
6540
6744
  const worktree = opts?.worktreePath?.trim();
6541
- const hasGraphSkill = !!worktree && existsSync16(join15(worktree, ".claude/skills/graph-engineering/SKILL.md"));
6542
- const hasReviewSkill = !!worktree && existsSync16(join15(worktree, ".claude/skills/review/SKILL.md"));
6543
- const hasInstallSkill = !!worktree && existsSync16(join15(worktree, ".claude/skills/worktree-install/SKILL.md"));
6745
+ const hasGraphSkill = !!worktree && existsSync16(join16(worktree, ".claude/skills/graph-engineering/SKILL.md"));
6746
+ const hasReviewSkill = !!worktree && existsSync16(join16(worktree, ".claude/skills/review/SKILL.md"));
6747
+ const hasInstallSkill = !!worktree && existsSync16(join16(worktree, ".claude/skills/worktree-install/SKILL.md"));
6544
6748
  return [
6545
6749
  "Process guides (recurring work only):",
6546
6750
  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,
@@ -6903,8 +7107,8 @@ async function syncThreadBranchFromGit(threadId) {
6903
7107
 
6904
7108
  // src/store/schedules.ts
6905
7109
  import { randomUUID as randomUUID4 } from "crypto";
6906
- import { existsSync as existsSync17, readFileSync as readFileSync11 } from "fs";
6907
- import { join as join16 } from "path";
7110
+ import { existsSync as existsSync17, readFileSync as readFileSync12 } from "fs";
7111
+ import { join as join17 } from "path";
6908
7112
  import { Cron } from "croner";
6909
7113
  var DURATION_RE = /^(\d+)(s|m|h|d)$/i;
6910
7114
  var UNIT_MS = {
@@ -6914,7 +7118,7 @@ var UNIT_MS = {
6914
7118
  d: 864e5
6915
7119
  };
6916
7120
  function schedulesPath() {
6917
- return join16(appDataDir(), "schedules.json");
7121
+ return join17(appDataDir(), "schedules.json");
6918
7122
  }
6919
7123
  function parseDurationMs(every) {
6920
7124
  const m = every.trim().match(DURATION_RE);
@@ -7022,7 +7226,7 @@ function readAll() {
7022
7226
  const path = schedulesPath();
7023
7227
  if (!existsSync17(path)) return [];
7024
7228
  try {
7025
- const parsed = JSON.parse(readFileSync11(path, "utf8"));
7229
+ const parsed = JSON.parse(readFileSync12(path, "utf8"));
7026
7230
  if (!Array.isArray(parsed)) return [];
7027
7231
  return parsed.map((row) => {
7028
7232
  try {
@@ -7148,7 +7352,7 @@ function formatScheduledPrompt(name, prompt) {
7148
7352
  ${prompt}`;
7149
7353
  }
7150
7354
  async function defaultDeps() {
7151
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-HPMDB2SG.js");
7355
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-A2Q5O4W2.js");
7152
7356
  const orch = getOrchestrator2();
7153
7357
  return {
7154
7358
  findThread: (id) => findThreadByRef(id),
@@ -7213,14 +7417,14 @@ function armOne(schedule) {
7213
7417
  if (!schedule.enabled) return;
7214
7418
  const at = new Date(schedule.nextRunAt);
7215
7419
  if (Number.isNaN(at.getTime())) return;
7216
- const delay = Math.max(0, at.getTime() - Date.now());
7217
- if (delay <= 250) {
7420
+ const delay2 = Math.max(0, at.getTime() - Date.now());
7421
+ if (delay2 <= 250) {
7218
7422
  void fireSchedule(schedule.id).then(() => {
7219
7423
  if (isThisProcessDesktopHost()) armSchedules();
7220
7424
  });
7221
7425
  return;
7222
7426
  }
7223
- const capped = Math.min(delay, SET_TIMEOUT_MAX);
7427
+ const capped = Math.min(delay2, SET_TIMEOUT_MAX);
7224
7428
  const timer = setTimeout(() => {
7225
7429
  timers.delete(schedule.id);
7226
7430
  const live = getSchedule(schedule.id);
@@ -7604,8 +7808,8 @@ var Orchestrator = class {
7604
7808
  scheduleQuotaResume(threadId, resumeAt) {
7605
7809
  this.clearQuotaResumeTimer(threadId);
7606
7810
  updateThread(threadId, { quotaResumeAt: resumeAt.toISOString() });
7607
- const delay = Math.max(5e3, resumeAt.getTime() - Date.now());
7608
- const capped = Math.min(delay, 2147483647);
7811
+ const delay2 = Math.max(5e3, resumeAt.getTime() - Date.now());
7812
+ const capped = Math.min(delay2, 2147483647);
7609
7813
  const timer = setTimeout(() => {
7610
7814
  this.quotaResumeTimers.delete(threadId);
7611
7815
  void this.resumeAfterQuotaWait(threadId);
@@ -8660,6 +8864,7 @@ var Orchestrator = class {
8660
8864
  return { port: shared.devPort, scriptName: resolvedName, ports: [shared.devPort] };
8661
8865
  }
8662
8866
  }
8867
+ const preferredPorts = active?.ports?.length ? active.ports : active?.port != null ? [active.port] : void 0;
8663
8868
  if (active && !existing) {
8664
8869
  killListenersOnPorts(collectActiveRunPorts([active]));
8665
8870
  this.syncWorktreeRuns(
@@ -8698,7 +8903,7 @@ var Orchestrator = class {
8698
8903
  thread.repoPath,
8699
8904
  thread.worktreePath,
8700
8905
  runOutput.push,
8701
- { scriptName: resolvedName }
8906
+ { scriptName: resolvedName, preferredPorts }
8702
8907
  );
8703
8908
  } catch (err) {
8704
8909
  runOutput.flush();
@@ -9147,7 +9352,7 @@ var Orchestrator = class {
9147
9352
  return thread;
9148
9353
  }
9149
9354
  const start = Date.now();
9150
- return new Promise((resolve, reject) => {
9355
+ return new Promise((resolve2, reject) => {
9151
9356
  let settled = false;
9152
9357
  let timer;
9153
9358
  const finish = (fn) => {
@@ -9165,7 +9370,7 @@ var Orchestrator = class {
9165
9370
  finish(() => reject(new Error(`Thread not found: ${thread.id}`)));
9166
9371
  return;
9167
9372
  }
9168
- finish(() => resolve(latest));
9373
+ finish(() => resolve2(latest));
9169
9374
  return;
9170
9375
  }
9171
9376
  if (event.type === "status_changed") {
@@ -9175,7 +9380,7 @@ var Orchestrator = class {
9175
9380
  return;
9176
9381
  }
9177
9382
  if (!["running", "queued"].includes(latest.status)) {
9178
- finish(() => resolve(latest));
9383
+ finish(() => resolve2(latest));
9179
9384
  }
9180
9385
  }
9181
9386
  });
@@ -9187,12 +9392,12 @@ var Orchestrator = class {
9187
9392
  }
9188
9393
  const current = this.healStaleReportedActivity(raw);
9189
9394
  if (!this.threadLooksLive(current)) {
9190
- finish(() => resolve(current));
9395
+ finish(() => resolve2(current));
9191
9396
  return;
9192
9397
  }
9193
9398
  if (Date.now() - start > timeoutMs) {
9194
9399
  if (opts?.resolveIfStillRunning) {
9195
- finish(() => resolve(current));
9400
+ finish(() => resolve2(current));
9196
9401
  } else {
9197
9402
  finish(() => reject(new Error("wait_for_turn timed out")));
9198
9403
  }
@@ -10045,13 +10250,21 @@ export {
10045
10250
  buildReviewRequestAttachment,
10046
10251
  readExistingReviewRequestFile,
10047
10252
  requestReview,
10253
+ RUN_PORTS_REL,
10254
+ worktreeRunPortsPath,
10255
+ loadWorktreeRunPorts,
10256
+ saveWorktreeRunPorts,
10257
+ PORT_RANGE_SIZE,
10048
10258
  readWorktreeInclude,
10049
10259
  resolveFilesToCopy,
10050
10260
  copyConfiguredFiles,
10051
10261
  captureLoginEnv,
10052
10262
  buildWorkspaceScriptEnv,
10053
10263
  killableListenerPids,
10264
+ listenerCwd,
10265
+ isOtherWorktreeListenerCwd,
10054
10266
  killListenersOnPorts,
10267
+ killStaleWorktreeListeners,
10055
10268
  runSetupScript,
10056
10269
  runConventionSetup,
10057
10270
  runWorkspaceSetup,
@@ -10062,6 +10275,8 @@ export {
10062
10275
  getRunMode,
10063
10276
  reservePort,
10064
10277
  allocatePort,
10278
+ tryReservePort,
10279
+ tryReservePorts,
10065
10280
  reservePortRange,
10066
10281
  allocatePortRange,
10067
10282
  startDevServer,