@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.
@@ -42,7 +42,7 @@ import {
42
42
  summarizeTurnStderr,
43
43
  toolDescription,
44
44
  turnFailChatText
45
- } from "./chunk-WRUBICEF.js";
45
+ } from "./chunk-3Q4PVZ3U.js";
46
46
  import {
47
47
  SLACK_REPLY_FORMATTING,
48
48
  addWorkspace,
@@ -792,13 +792,14 @@ function shouldAutoArchiveOnPrMerge(opts) {
792
792
  import {
793
793
  copyFileSync,
794
794
  existsSync as existsSync3,
795
- mkdirSync as mkdirSync3,
795
+ mkdirSync as mkdirSync4,
796
796
  readdirSync,
797
- readFileSync as readFileSync2
797
+ readFileSync as readFileSync3,
798
+ realpathSync
798
799
  } from "fs";
799
800
  import { execFileSync } from "child_process";
800
801
  import { createServer } from "net";
801
- import { basename, dirname as dirname2, join as join4 } from "path";
802
+ import { basename, dirname as dirname3, join as join5, resolve, sep } from "path";
802
803
  import { execa as execa2 } from "execa";
803
804
  import { createInterface as createInterface2 } from "readline";
804
805
 
@@ -1658,16 +1659,73 @@ async function requestReview(threadRef, send) {
1658
1659
  return { tab: started, from };
1659
1660
  }
1660
1661
 
1662
+ // src/hook/worktree-run-ports.ts
1663
+ import { mkdirSync as mkdirSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
1664
+ import { dirname as dirname2, join as join4 } from "path";
1665
+ var RUN_PORTS_REL = ".context/.sideboard/run-ports.json";
1666
+ function worktreeRunPortsPath(worktreePath) {
1667
+ return join4(worktreePath, RUN_PORTS_REL);
1668
+ }
1669
+ function isPort(value) {
1670
+ return typeof value === "number" && Number.isInteger(value) && value > 0 && value <= 65535;
1671
+ }
1672
+ function parseFile(raw) {
1673
+ try {
1674
+ const parsed = JSON.parse(raw);
1675
+ if (!parsed || typeof parsed !== "object") return {};
1676
+ const scripts = parsed.scripts;
1677
+ if (!scripts || typeof scripts !== "object") return {};
1678
+ const next = {};
1679
+ for (const [name, ports] of Object.entries(scripts)) {
1680
+ if (!name || !Array.isArray(ports)) continue;
1681
+ const cleaned = ports.filter(isPort);
1682
+ if (cleaned.length) next[name] = cleaned;
1683
+ }
1684
+ return { scripts: next };
1685
+ } catch {
1686
+ return {};
1687
+ }
1688
+ }
1689
+ function loadWorktreeRunPorts(worktreePath, scriptName) {
1690
+ if (!worktreePath.trim() || !scriptName.trim()) return null;
1691
+ try {
1692
+ const raw = readFileSync2(worktreeRunPortsPath(worktreePath), "utf8");
1693
+ const ports = parseFile(raw).scripts?.[scriptName];
1694
+ return ports?.length ? ports : null;
1695
+ } catch {
1696
+ return null;
1697
+ }
1698
+ }
1699
+ function saveWorktreeRunPorts(worktreePath, scriptName, ports) {
1700
+ if (!worktreePath.trim() || !scriptName.trim()) return;
1701
+ const cleaned = ports.filter(isPort);
1702
+ if (!cleaned.length) return;
1703
+ const path = worktreeRunPortsPath(worktreePath);
1704
+ let current = {};
1705
+ try {
1706
+ current = parseFile(readFileSync2(path, "utf8"));
1707
+ } catch {
1708
+ current = {};
1709
+ }
1710
+ const scripts = { ...current.scripts ?? {} };
1711
+ scripts[scriptName] = cleaned;
1712
+ mkdirSync3(dirname2(path), { recursive: true });
1713
+ writeFileSync2(path, `${JSON.stringify({ scripts }, null, 2)}
1714
+ `, "utf8");
1715
+ }
1716
+
1661
1717
  // src/hook/conductor.ts
1662
1718
  var PORT_RANGE_SIZE = 10;
1719
+ var RECLAIM_RETRY_DELAY_MS = 40;
1720
+ var RECLAIM_TRIES = 8;
1663
1721
  function matchSimpleGlob(pattern, name) {
1664
1722
  const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
1665
1723
  return new RegExp(`^${escaped}$`).test(name);
1666
1724
  }
1667
1725
  function readWorktreeInclude(repoPath) {
1668
- const path = join4(repoPath, ".worktreeinclude");
1726
+ const path = join5(repoPath, ".worktreeinclude");
1669
1727
  if (!existsSync3(path)) return [];
1670
- return readFileSync2(path, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
1728
+ return readFileSync3(path, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
1671
1729
  }
1672
1730
  function resolveFilesToCopy(repoPath) {
1673
1731
  const fromInclude = readWorktreeInclude(repoPath);
@@ -1706,10 +1764,10 @@ function copyConfiguredFiles(repoPath, worktreePath) {
1706
1764
  const patterns = resolveFilesToCopy(repoPath);
1707
1765
  const copied = [];
1708
1766
  for (const rel of patterns) {
1709
- const src = join4(repoPath, rel);
1767
+ const src = join5(repoPath, rel);
1710
1768
  if (!existsSync3(src)) continue;
1711
- const dest = join4(worktreePath, rel);
1712
- mkdirSync3(dirname2(dest), { recursive: true });
1769
+ const dest = join5(worktreePath, rel);
1770
+ mkdirSync4(dirname3(dest), { recursive: true });
1713
1771
  copyFileSync(src, dest);
1714
1772
  copied.push(rel);
1715
1773
  }
@@ -1786,6 +1844,57 @@ function killableListenerPids(raw, selfPid = process.pid) {
1786
1844
  }
1787
1845
  return pids;
1788
1846
  }
1847
+ function listUnixListenerPids(port, selfPid) {
1848
+ try {
1849
+ const raw = execFileSync("lsof", [`-tiTCP:${port}`, "-sTCP:LISTEN"], {
1850
+ encoding: "utf8",
1851
+ stdio: ["ignore", "pipe", "ignore"],
1852
+ timeout: 2e3
1853
+ });
1854
+ return killableListenerPids(raw, selfPid);
1855
+ } catch {
1856
+ return [];
1857
+ }
1858
+ }
1859
+ function listenerCwd(pid) {
1860
+ if (!Number.isFinite(pid) || pid <= 0) return null;
1861
+ try {
1862
+ const raw = execFileSync("lsof", ["-a", "-p", String(pid), "-d", "cwd", "-Fn"], {
1863
+ encoding: "utf8",
1864
+ stdio: ["ignore", "pipe", "ignore"],
1865
+ timeout: 2e3
1866
+ });
1867
+ for (const line of raw.split("\n")) {
1868
+ if (line.startsWith("n") && line.length > 1) return line.slice(1);
1869
+ }
1870
+ } catch {
1871
+ }
1872
+ return null;
1873
+ }
1874
+ function realpathOrResolve(path) {
1875
+ try {
1876
+ return realpathSync(path);
1877
+ } catch {
1878
+ return resolve(path);
1879
+ }
1880
+ }
1881
+ function isOtherWorktreeListenerCwd(cwd, worktreePath) {
1882
+ const wt = realpathOrResolve(worktreePath);
1883
+ const c = realpathOrResolve(cwd);
1884
+ if (c === wt || c.startsWith(wt + sep)) return false;
1885
+ const parent = dirname3(wt);
1886
+ const thisName = basename(wt);
1887
+ if (!thisName || c === parent) return false;
1888
+ if (!c.startsWith(parent + sep)) return false;
1889
+ const first = c.slice(parent.length + 1).split(sep)[0];
1890
+ return Boolean(first) && first !== thisName;
1891
+ }
1892
+ function signalPid(pid, signal) {
1893
+ try {
1894
+ process.kill(pid, signal);
1895
+ } catch {
1896
+ }
1897
+ }
1789
1898
  function killListenersOnPorts(ports) {
1790
1899
  const selfPid = process.pid;
1791
1900
  for (const port of ports) {
@@ -1803,26 +1912,32 @@ function killListenersOnPorts(ports) {
1803
1912
  );
1804
1913
  continue;
1805
1914
  }
1806
- let raw = "";
1807
- try {
1808
- raw = execFileSync("lsof", [`-tiTCP:${port}`, "-sTCP:LISTEN"], {
1809
- encoding: "utf8",
1810
- stdio: ["ignore", "pipe", "ignore"],
1811
- timeout: 2e3
1812
- });
1813
- } catch {
1814
- continue;
1815
- }
1816
- for (const pid of killableListenerPids(raw, selfPid)) {
1817
- try {
1818
- process.kill(pid, "SIGTERM");
1819
- } catch {
1820
- }
1915
+ for (const pid of listUnixListenerPids(port, selfPid)) {
1916
+ signalPid(pid, "SIGTERM");
1821
1917
  }
1822
1918
  } catch {
1823
1919
  }
1824
1920
  }
1825
1921
  }
1922
+ function killStaleWorktreeListeners(ports, worktreePath, signal = "SIGTERM") {
1923
+ if (!worktreePath.trim()) {
1924
+ killListenersOnPorts(ports);
1925
+ return;
1926
+ }
1927
+ if (process.platform === "win32") {
1928
+ killListenersOnPorts(ports);
1929
+ return;
1930
+ }
1931
+ const selfPid = process.pid;
1932
+ for (const port of ports) {
1933
+ if (!Number.isFinite(port) || port <= 0) continue;
1934
+ for (const pid of listUnixListenerPids(port, selfPid)) {
1935
+ const cwd = listenerCwd(pid);
1936
+ if (cwd && isOtherWorktreeListenerCwd(cwd, worktreePath)) continue;
1937
+ signalPid(pid, signal);
1938
+ }
1939
+ }
1940
+ }
1826
1941
  function killScriptTree(child, ports = []) {
1827
1942
  const pid = child.pid;
1828
1943
  if (pid) {
@@ -1984,7 +2099,7 @@ function getRunMode(worktreePath, repoPath) {
1984
2099
  return loadWorkspaceSettings(worktreePath, repoPath)?.runMode ?? "concurrent";
1985
2100
  }
1986
2101
  async function reservePort() {
1987
- return new Promise((resolve, reject) => {
2102
+ return new Promise((resolve2, reject) => {
1988
2103
  const server = createServer();
1989
2104
  let released = false;
1990
2105
  const release = () => new Promise((res) => {
@@ -2001,13 +2116,14 @@ async function reservePort() {
2001
2116
  void release().then(() => reject(new Error("Failed to allocate port")));
2002
2117
  return;
2003
2118
  }
2004
- resolve({ port: addr.port, release });
2119
+ resolve2({ port: addr.port, release });
2005
2120
  });
2006
2121
  server.on("error", reject);
2007
2122
  });
2008
2123
  }
2009
2124
  async function tryReservePort(port) {
2010
- return new Promise((resolve) => {
2125
+ if (!Number.isInteger(port) || port <= 0 || port > 65535) return null;
2126
+ return new Promise((resolve2) => {
2011
2127
  const server = createServer();
2012
2128
  let released = false;
2013
2129
  const release = () => new Promise((res) => {
@@ -2018,23 +2134,51 @@ async function tryReservePort(port) {
2018
2134
  released = true;
2019
2135
  server.close(() => res());
2020
2136
  });
2021
- server.once("error", () => resolve(null));
2137
+ server.once("error", () => {
2138
+ try {
2139
+ server.close();
2140
+ } catch {
2141
+ }
2142
+ resolve2(null);
2143
+ });
2022
2144
  server.listen(port, "127.0.0.1", () => {
2023
- resolve({ port, release });
2145
+ resolve2({ port, release });
2024
2146
  });
2025
2147
  });
2026
2148
  }
2027
- async function reservePortRange(size = PORT_RANGE_SIZE) {
2028
- const held = [await reservePort()];
2029
- const base = held[0].port;
2149
+ function normalizePreferredPorts(ports, size) {
2150
+ if (!ports?.length) return [];
2151
+ const seen = /* @__PURE__ */ new Set();
2152
+ const out = [];
2153
+ for (const p of ports) {
2154
+ if (!Number.isInteger(p) || p <= 0 || p > 65535 || seen.has(p)) continue;
2155
+ seen.add(p);
2156
+ out.push(p);
2157
+ if (out.length >= size) break;
2158
+ }
2159
+ return out;
2160
+ }
2161
+ function delay(ms) {
2162
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
2163
+ }
2164
+ async function fillPortRange(held, size) {
2165
+ if (held.length >= size) return held;
2166
+ const base = held[0]?.port;
2167
+ const taken = new Set(held.map((h) => h.port));
2030
2168
  try {
2031
- for (let i = 1; i < size; i++) {
2032
- const candidate = base + i;
2033
- const next = await tryReservePort(candidate);
2169
+ let offset = 0;
2170
+ while (held.length < size) {
2171
+ const candidate = base != null ? base + offset : null;
2172
+ offset += 1;
2173
+ if (candidate != null && taken.has(candidate)) continue;
2174
+ const next = candidate != null ? await tryReservePort(candidate) : null;
2034
2175
  if (next) {
2035
2176
  held.push(next);
2177
+ taken.add(next.port);
2036
2178
  } else {
2037
- held.push(await reservePort());
2179
+ const ephemeral = await reservePort();
2180
+ held.push(ephemeral);
2181
+ taken.add(ephemeral.port);
2038
2182
  }
2039
2183
  }
2040
2184
  return held;
@@ -2043,11 +2187,59 @@ async function reservePortRange(size = PORT_RANGE_SIZE) {
2043
2187
  throw err;
2044
2188
  }
2045
2189
  }
2190
+ async function tryReserveAvailablePorts(ports) {
2191
+ const held = [];
2192
+ for (const port of ports) {
2193
+ const next = await tryReservePort(port);
2194
+ if (next) held.push(next);
2195
+ }
2196
+ return held;
2197
+ }
2198
+ async function reclaimPreferredPorts(ports, worktreePath) {
2199
+ const primary = ports[0];
2200
+ if (primary == null) return null;
2201
+ const takePrimary = async () => {
2202
+ const held2 = await tryReserveAvailablePorts(ports);
2203
+ if (held2.some((h) => h.port === primary)) return held2;
2204
+ await Promise.all(held2.map((h) => h.release()));
2205
+ return null;
2206
+ };
2207
+ let held = await takePrimary();
2208
+ if (held) return held;
2209
+ if (worktreePath) {
2210
+ killStaleWorktreeListeners(ports, worktreePath, "SIGTERM");
2211
+ } else {
2212
+ killListenersOnPorts(ports);
2213
+ }
2214
+ for (let i = 0; i < RECLAIM_TRIES; i++) {
2215
+ await delay(RECLAIM_RETRY_DELAY_MS);
2216
+ held = await takePrimary();
2217
+ if (held) return held;
2218
+ if (i === 2 && worktreePath) {
2219
+ killStaleWorktreeListeners(ports, worktreePath, "SIGKILL");
2220
+ }
2221
+ }
2222
+ return null;
2223
+ }
2224
+ async function reservePortRange(size = PORT_RANGE_SIZE, opts) {
2225
+ const preferred = normalizePreferredPorts(opts?.preferred, size);
2226
+ if (preferred.length) {
2227
+ const reused = await reclaimPreferredPorts(preferred, opts?.worktreePath);
2228
+ if (reused) return fillPortRange(reused, size);
2229
+ }
2230
+ const held = [await reservePort()];
2231
+ return fillPortRange(held, size);
2232
+ }
2046
2233
  async function startDevServer(repoPath, worktreePath, onLine, opts) {
2047
2234
  const script = getRunScript(worktreePath, repoPath, opts?.scriptName);
2048
2235
  if (!script) return null;
2049
- const held = await reservePortRange(PORT_RANGE_SIZE);
2236
+ const preferred = loadWorktreeRunPorts(worktreePath, script.name) ?? opts?.preferredPorts;
2237
+ const held = await reservePortRange(PORT_RANGE_SIZE, {
2238
+ preferred: preferred ?? void 0,
2239
+ worktreePath
2240
+ });
2050
2241
  const ports = held.map((h) => h.port);
2242
+ saveWorktreeRunPorts(worktreePath, script.name, ports);
2051
2243
  try {
2052
2244
  const handle = await spawnWorkspaceScript(script.command, {
2053
2245
  worktreePath,
@@ -2073,8 +2265,8 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
2073
2265
 
2074
2266
  // src/store/setup-log.ts
2075
2267
  import { createHash } from "crypto";
2076
- import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
2077
- import { join as join5 } from "path";
2268
+ import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
2269
+ import { join as join6 } from "path";
2078
2270
  var EMPTY = {
2079
2271
  output: "",
2080
2272
  running: false,
@@ -2116,7 +2308,7 @@ function materialize(mem) {
2116
2308
  };
2117
2309
  }
2118
2310
  function setupLogPath(threadId) {
2119
- return join5(threadsDir(), `${threadId}.setup.log.json`);
2311
+ return join6(threadsDir(), `${threadId}.setup.log.json`);
2120
2312
  }
2121
2313
  function setupLogKeyForWorktree(worktreePath) {
2122
2314
  const norm = normalizeWorktreePath(worktreePath);
@@ -2135,7 +2327,7 @@ function persistNow(threadId) {
2135
2327
  const mem = memory.get(threadId);
2136
2328
  if (!mem) return;
2137
2329
  try {
2138
- writeFileSync2(
2330
+ writeFileSync3(
2139
2331
  setupLogPath(threadId),
2140
2332
  `${JSON.stringify(materialize(mem))}
2141
2333
  `,
@@ -2158,7 +2350,7 @@ function loadFromDisk(threadId) {
2158
2350
  const path = setupLogPath(threadId);
2159
2351
  if (!existsSync4(path)) return null;
2160
2352
  try {
2161
- const raw = JSON.parse(readFileSync3(path, "utf8"));
2353
+ const raw = JSON.parse(readFileSync4(path, "utf8"));
2162
2354
  return {
2163
2355
  output: typeof raw.output === "string" ? raw.output : "",
2164
2356
  running: Boolean(raw.running),
@@ -2217,8 +2409,8 @@ function finishSetupLog(threadId, exitCode, source) {
2217
2409
 
2218
2410
  // src/store/run-log.ts
2219
2411
  import { createHash as createHash2 } from "crypto";
2220
- import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
2221
- import { join as join6 } from "path";
2412
+ import { existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
2413
+ import { join as join7 } from "path";
2222
2414
  var EMPTY2 = {
2223
2415
  output: "",
2224
2416
  running: false,
@@ -2257,7 +2449,7 @@ function safeScriptToken(scriptName) {
2257
2449
  return token || "dev";
2258
2450
  }
2259
2451
  function runLogPath(key) {
2260
- return join6(threadsDir(), `${key}.run.log.json`);
2452
+ return join7(threadsDir(), `${key}.run.log.json`);
2261
2453
  }
2262
2454
  function runLogKeyForWorktree(worktreePath, scriptName) {
2263
2455
  const norm = normalizeWorktreePath(worktreePath);
@@ -2286,7 +2478,7 @@ function persistNow2(key) {
2286
2478
  const mem = memory2.get(key);
2287
2479
  if (!mem) return;
2288
2480
  try {
2289
- writeFileSync3(runLogPath(key), `${JSON.stringify(materialize2(mem))}
2481
+ writeFileSync4(runLogPath(key), `${JSON.stringify(materialize2(mem))}
2290
2482
  `, "utf8");
2291
2483
  } catch {
2292
2484
  }
@@ -2305,7 +2497,7 @@ function loadFromDisk2(key) {
2305
2497
  const path = runLogPath(key);
2306
2498
  if (!existsSync5(path)) return null;
2307
2499
  try {
2308
- const raw = JSON.parse(readFileSync4(path, "utf8"));
2500
+ const raw = JSON.parse(readFileSync5(path, "utf8"));
2309
2501
  return {
2310
2502
  output: typeof raw.output === "string" ? raw.output : "",
2311
2503
  running: Boolean(raw.running),
@@ -2366,7 +2558,7 @@ function flushRunLog(key) {
2366
2558
 
2367
2559
  // src/git/orphan-cleanup.ts
2368
2560
  import { existsSync as existsSync6, readdirSync as readdirSync2, statSync } from "fs";
2369
- import { join as join7 } from "path";
2561
+ import { join as join8 } from "path";
2370
2562
  function isSideboardWorktreePath(path) {
2371
2563
  return path.includes("/.sideboard/worktrees/") || path.includes("/sideboard/workspaces/");
2372
2564
  }
@@ -2413,9 +2605,9 @@ async function findOrphanWorktrees(repoPaths) {
2413
2605
  if (existsSync6(root)) {
2414
2606
  for (const entry of readdirSync2(root, { withFileTypes: true })) {
2415
2607
  if (!entry.isDirectory()) continue;
2416
- const path = join7(root, entry.name).replace(/\/$/, "");
2608
+ const path = join8(root, entry.name).replace(/\/$/, "");
2417
2609
  if (known.has(path) || seen.has(path)) continue;
2418
- if (!existsSync6(join7(path, ".git"))) continue;
2610
+ if (!existsSync6(join8(path, ".git"))) continue;
2419
2611
  seen.add(path);
2420
2612
  let mtimeMs = 0;
2421
2613
  try {
@@ -2620,7 +2812,7 @@ async function applyThreadIntoMain(thread, opts) {
2620
2812
 
2621
2813
  // src/git/clone-repo.ts
2622
2814
  import { existsSync as existsSync7 } from "fs";
2623
- import { basename as basename2, join as join8 } from "path";
2815
+ import { basename as basename2, join as join9 } from "path";
2624
2816
  import { execa as execa4 } from "execa";
2625
2817
  async function cloneRepoIntoSideboard(opts) {
2626
2818
  const url = opts.url.trim();
@@ -2631,7 +2823,7 @@ async function cloneRepoIntoSideboard(opts) {
2631
2823
  name = leaf || "repo";
2632
2824
  }
2633
2825
  name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
2634
- const dest = join8(sideboardReposDir(), name);
2826
+ const dest = join9(sideboardReposDir(), name);
2635
2827
  if (existsSync7(dest)) {
2636
2828
  const repoPath2 = await resolveRepoRoot(dest);
2637
2829
  const workspace2 = await ensureWorkspace(repoPath2);
@@ -2654,14 +2846,14 @@ function isAdoptableRunScriptRequest(req) {
2654
2846
  }
2655
2847
 
2656
2848
  // src/store/desktop-host.ts
2657
- import { readFileSync as readFileSync5, unlinkSync, writeFileSync as writeFileSync4 } from "fs";
2658
- import { join as join9 } from "path";
2849
+ import { readFileSync as readFileSync6, unlinkSync, writeFileSync as writeFileSync5 } from "fs";
2850
+ import { join as join10 } from "path";
2659
2851
  function desktopHostPidPath() {
2660
- return join9(appDataDir(), "desktop-host.pid");
2852
+ return join10(appDataDir(), "desktop-host.pid");
2661
2853
  }
2662
2854
  function readDesktopHostPid() {
2663
2855
  try {
2664
- const pid = Number.parseInt(readFileSync5(desktopHostPidPath(), "utf8").trim(), 10);
2856
+ const pid = Number.parseInt(readFileSync6(desktopHostPidPath(), "utf8").trim(), 10);
2665
2857
  if (!Number.isFinite(pid) || pid <= 0) return null;
2666
2858
  return pid;
2667
2859
  } catch {
@@ -2734,12 +2926,12 @@ function notifyParentOfChildHalt(child, status, send) {
2734
2926
  import {
2735
2927
  appendFileSync as appendFileSync2,
2736
2928
  existsSync as existsSync8,
2737
- mkdirSync as mkdirSync4,
2929
+ mkdirSync as mkdirSync5,
2738
2930
  readdirSync as readdirSync3,
2739
- readFileSync as readFileSync6,
2740
- writeFileSync as writeFileSync5
2931
+ readFileSync as readFileSync7,
2932
+ writeFileSync as writeFileSync6
2741
2933
  } from "fs";
2742
- import { dirname as dirname3, join as join10 } from "path";
2934
+ import { dirname as dirname4, join as join11 } from "path";
2743
2935
 
2744
2936
  // src/mcp/wait-for-turn.ts
2745
2937
  var MCP_WAIT_FOR_TURN_MAX_MS = 45e3;
@@ -2815,11 +3007,11 @@ function jobTreeAlive(pid) {
2815
3007
  }
2816
3008
  function readIntFile(file) {
2817
3009
  if (!existsSync8(file)) return null;
2818
- const n = Number.parseInt(readFileSync6(file, "utf8").trim(), 10);
3010
+ const n = Number.parseInt(readFileSync7(file, "utf8").trim(), 10);
2819
3011
  return Number.isInteger(n) ? n : null;
2820
3012
  }
2821
3013
  function jobDir(root, id, legacy = false) {
2822
- return join10(root, legacy ? LEGACY_DETACHED_JOBS_DIR : DETACHED_JOBS_DIR, id);
3014
+ return join11(root, legacy ? LEGACY_DETACHED_JOBS_DIR : DETACHED_JOBS_DIR, id);
2823
3015
  }
2824
3016
  function resolveJobDir(root, id) {
2825
3017
  const modern = jobDir(root, id, false);
@@ -2829,7 +3021,7 @@ function resolveJobDir(root, id) {
2829
3021
  return modern;
2830
3022
  }
2831
3023
  function listJobIdsIn(root, rel) {
2832
- const dir = join10(root, rel);
3024
+ const dir = join11(root, rel);
2833
3025
  if (!existsSync8(dir)) return [];
2834
3026
  return readdirSync3(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && JOB_ID_RE.test(e.name)).map((e) => e.name);
2835
3027
  }
@@ -2843,7 +3035,7 @@ function listRunningDetachedJobs(worktreePath) {
2843
3035
  const running = [];
2844
3036
  for (const id of ids) {
2845
3037
  const dir = resolveJobDir(root, id);
2846
- const pid = readIntFile(join10(dir, "pid"));
3038
+ const pid = readIntFile(join11(dir, "pid"));
2847
3039
  if (jobTreeAlive(pid)) running.push(id);
2848
3040
  }
2849
3041
  return running.sort();
@@ -2927,7 +3119,7 @@ function planJobContinue(opts) {
2927
3119
  }
2928
3120
  function tailProgress(logFile, maxLines = 12) {
2929
3121
  if (!existsSync8(logFile)) return "(no log yet)";
2930
- const lines = readFileSync6(logFile, "utf8").split("\n");
3122
+ const lines = readFileSync7(logFile, "utf8").split("\n");
2931
3123
  return lines.slice(-maxLines).join("\n");
2932
3124
  }
2933
3125
  function lastProgressLine(progress) {
@@ -2936,7 +3128,7 @@ function lastProgressLine(progress) {
2936
3128
  }
2937
3129
  function readLogLines(file) {
2938
3130
  if (!existsSync8(file)) return [];
2939
- const lines = readFileSync6(file, "utf8").split("\n");
3131
+ const lines = readFileSync7(file, "utf8").split("\n");
2940
3132
  if (lines.length && lines[lines.length - 1] === "") lines.pop();
2941
3133
  return lines;
2942
3134
  }
@@ -2947,15 +3139,15 @@ function takeDelta(logFile, cursorFile) {
2947
3139
  return { delta: capJobLogDelta(lines.slice(start).join("\n")), nextCursor: lines.length };
2948
3140
  }
2949
3141
  function snapshotJob(dir) {
2950
- const pid = readIntFile(join10(dir, "pid"));
3142
+ const pid = readIntFile(join11(dir, "pid"));
2951
3143
  const running = jobTreeAlive(pid);
2952
3144
  return {
2953
3145
  pid,
2954
3146
  running,
2955
- exitCode: readIntFile(join10(dir, "exit")),
2956
- log: join10(dir, "log"),
2957
- cursor: join10(dir, "present.cursor"),
2958
- progress: tailProgress(join10(dir, "log"))
3147
+ exitCode: readIntFile(join11(dir, "exit")),
3148
+ log: join11(dir, "log"),
3149
+ cursor: join11(dir, "present.cursor"),
3150
+ progress: tailProgress(join11(dir, "log"))
2959
3151
  };
2960
3152
  }
2961
3153
  function toResult(id, snap, extra) {
@@ -2964,8 +3156,8 @@ function toResult(id, snap, extra) {
2964
3156
  const stillRunning = snap.running && !ok;
2965
3157
  const { delta, nextCursor } = takeDelta(snap.log, snap.cursor);
2966
3158
  try {
2967
- mkdirSync4(dirname3(snap.cursor), { recursive: true });
2968
- writeFileSync5(snap.cursor, `${nextCursor}
3159
+ mkdirSync5(dirname4(snap.cursor), { recursive: true });
3160
+ writeFileSync6(snap.cursor, `${nextCursor}
2969
3161
  `);
2970
3162
  } catch {
2971
3163
  }
@@ -2986,7 +3178,7 @@ function toResult(id, snap, extra) {
2986
3178
  };
2987
3179
  }
2988
3180
  async function sleepMs(ms) {
2989
- await new Promise((resolve) => setTimeout(resolve, ms));
3181
+ await new Promise((resolve2) => setTimeout(resolve2, ms));
2990
3182
  }
2991
3183
  async function waitForDetachedJob(cwd, id, opts) {
2992
3184
  const jobId = sanitizeDetachedJobId(id);
@@ -3040,7 +3232,7 @@ function killProcessTree(pid, signal) {
3040
3232
  }
3041
3233
  function appendJobLog(logFile, line) {
3042
3234
  try {
3043
- mkdirSync4(dirname3(logFile), { recursive: true });
3235
+ mkdirSync5(dirname4(logFile), { recursive: true });
3044
3236
  const body = line.endsWith("\n") ? line : `${line}
3045
3237
  `;
3046
3238
  appendFileSync2(logFile, body);
@@ -3089,10 +3281,10 @@ async function stopDetachedJob(cwd, id, opts) {
3089
3281
  killProcessTree(targetPid, "SIGKILL");
3090
3282
  await sleep(100);
3091
3283
  }
3092
- const exitFile = join10(dir, "exit");
3284
+ const exitFile = join11(dir, "exit");
3093
3285
  if (!existsSync8(exitFile)) {
3094
3286
  try {
3095
- writeFileSync5(exitFile, "1\n");
3287
+ writeFileSync6(exitFile, "1\n");
3096
3288
  } catch {
3097
3289
  }
3098
3290
  }
@@ -3899,8 +4091,8 @@ import {
3899
4091
  existsSync as existsSync10,
3900
4092
  renameSync,
3901
4093
  unlinkSync as unlinkSync2,
3902
- writeFileSync as writeFileSync6,
3903
- readFileSync as readFileSync7
4094
+ writeFileSync as writeFileSync7,
4095
+ readFileSync as readFileSync8
3904
4096
  } from "fs";
3905
4097
  var buffers = /* @__PURE__ */ new Map();
3906
4098
  var FLUSH_MS = 800;
@@ -3977,7 +4169,7 @@ function writeTurnLive(threadId, progress) {
3977
4169
  const path = threadLivePath(threadId);
3978
4170
  const tmp = `${path}.${process.pid}.tmp`;
3979
4171
  try {
3980
- writeFileSync6(tmp, JSON.stringify(progress), "utf8");
4172
+ writeFileSync7(tmp, JSON.stringify(progress), "utf8");
3981
4173
  renameSync(tmp, path);
3982
4174
  } catch {
3983
4175
  try {
@@ -3990,7 +4182,7 @@ function readTurnLive(threadId) {
3990
4182
  const path = threadLivePath(threadId);
3991
4183
  if (!existsSync10(path)) return null;
3992
4184
  try {
3993
- const raw = JSON.parse(readFileSync7(path, "utf8"));
4185
+ const raw = JSON.parse(readFileSync8(path, "utf8"));
3994
4186
  if (!raw || typeof raw.summary !== "string") return null;
3995
4187
  return raw;
3996
4188
  } catch {
@@ -4214,23 +4406,23 @@ import {
4214
4406
  existsSync as existsSync11,
4215
4407
  mkdtempSync,
4216
4408
  readdirSync as readdirSync4,
4217
- readFileSync as readFileSync8,
4409
+ readFileSync as readFileSync9,
4218
4410
  rmSync
4219
4411
  } from "fs";
4220
4412
  import { tmpdir } from "os";
4221
- import { join as join11 } from "path";
4413
+ import { join as join12 } from "path";
4222
4414
  import { createRequire } from "module";
4223
- var CONDUCTOR_APP_SUPPORT = join11(
4415
+ var CONDUCTOR_APP_SUPPORT = join12(
4224
4416
  process.env.HOME ?? "",
4225
4417
  "Library",
4226
4418
  "Application Support",
4227
4419
  "com.conductor.app"
4228
4420
  );
4229
- var CONDUCTOR_DB = join11(CONDUCTOR_APP_SUPPORT, "conductor.db");
4230
- var CURSOR_SDK_STORE = join11(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
4421
+ var CONDUCTOR_DB = join12(CONDUCTOR_APP_SUPPORT, "conductor.db");
4422
+ var CURSOR_SDK_STORE = join12(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
4231
4423
  function thisModuleFile() {
4232
4424
  const cjsFile = typeof __filename !== "undefined" ? __filename : "";
4233
- return cjsFile || process.argv[1] || join11(process.cwd(), "package.json");
4425
+ return cjsFile || process.argv[1] || join12(process.cwd(), "package.json");
4234
4426
  }
4235
4427
  function openReadonlySqlite(file) {
4236
4428
  const req = createRequire(thisModuleFile());
@@ -4258,11 +4450,11 @@ function resolveConductorCursorAgentId(workspacePath) {
4258
4450
  return null;
4259
4451
  }
4260
4452
  for (const hash of hashes) {
4261
- const agentsFile = join11(CURSOR_SDK_STORE, hash, "agents.ndjson");
4453
+ const agentsFile = join12(CURSOR_SDK_STORE, hash, "agents.ndjson");
4262
4454
  if (!existsSync11(agentsFile)) continue;
4263
4455
  let text;
4264
4456
  try {
4265
- text = readFileSync8(agentsFile, "utf8");
4457
+ text = readFileSync9(agentsFile, "utf8");
4266
4458
  } catch {
4267
4459
  continue;
4268
4460
  }
@@ -4315,8 +4507,8 @@ function listConductorWorkspaces() {
4315
4507
  if (!existsSync11(CONDUCTOR_DB)) {
4316
4508
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
4317
4509
  }
4318
- const tmp = mkdtempSync(join11(tmpdir(), "sideboard-conductor-"));
4319
- const snapshot = join11(tmp, "conductor.db");
4510
+ const tmp = mkdtempSync(join12(tmpdir(), "sideboard-conductor-"));
4511
+ const snapshot = join12(tmp, "conductor.db");
4320
4512
  try {
4321
4513
  copyFileSync2(CONDUCTOR_DB, snapshot);
4322
4514
  for (const suffix of ["-wal", "-shm"]) {
@@ -4406,8 +4598,8 @@ function importConductorWorkspace(workspaceId) {
4406
4598
  if (!existsSync11(CONDUCTOR_DB)) {
4407
4599
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
4408
4600
  }
4409
- const tmp = mkdtempSync(join11(tmpdir(), "sideboard-conductor-"));
4410
- const snapshot = join11(tmp, "conductor.db");
4601
+ const tmp = mkdtempSync(join12(tmpdir(), "sideboard-conductor-"));
4602
+ const snapshot = join12(tmp, "conductor.db");
4411
4603
  try {
4412
4604
  copyFileSync2(CONDUCTOR_DB, snapshot);
4413
4605
  for (const suffix of ["-wal", "-shm"]) {
@@ -4787,8 +4979,8 @@ async function createPrStack(input, onSetupLine) {
4787
4979
  }
4788
4980
 
4789
4981
  // src/diff/diff.ts
4790
- import { existsSync as existsSync13, mkdirSync as mkdirSync5, readFileSync as readFileSync9, statSync as statSync2, writeFileSync as writeFileSync7 } from "fs";
4791
- import { dirname as dirname4, join as join12 } from "path";
4982
+ import { existsSync as existsSync13, mkdirSync as mkdirSync6, readFileSync as readFileSync10, statSync as statSync2, writeFileSync as writeFileSync8 } from "fs";
4983
+ import { dirname as dirname5, join as join13 } from "path";
4792
4984
  async function inspectGitWorktree(worktreePath) {
4793
4985
  if (!worktreePath || !existsSync13(worktreePath)) return "missing_worktree";
4794
4986
  const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
@@ -4934,11 +5126,11 @@ new file mode 100644
4934
5126
  };
4935
5127
  }
4936
5128
  async function untrackedPatch(worktreePath, path, maxHunk) {
4937
- const abs = join12(worktreePath, path);
5129
+ const abs = join13(worktreePath, path);
4938
5130
  try {
4939
5131
  const st = statSync2(abs);
4940
5132
  if (st.isFile() && st.size > maxHunk) {
4941
- const buf = readFileSync9(abs).subarray(0, maxHunk);
5133
+ const buf = readFileSync10(abs).subarray(0, maxHunk);
4942
5134
  return syntheticAddPatch(path, buf.toString("utf8"), maxHunk);
4943
5135
  }
4944
5136
  } catch {
@@ -5406,7 +5598,7 @@ async function getDiff(worktreePath, repoPath, opts) {
5406
5598
  }
5407
5599
  function statWorktreePath(worktreePath, relativePath) {
5408
5600
  assertSafeRelativePath(relativePath);
5409
- const abs = join12(worktreePath, relativePath);
5601
+ const abs = join13(worktreePath, relativePath);
5410
5602
  if (!existsSync13(abs)) return "missing";
5411
5603
  const st = statSync2(abs);
5412
5604
  if (st.isDirectory()) return "dir";
@@ -5448,7 +5640,7 @@ var DEFAULT_UPLOAD_MAX_BYTES = 5e7;
5448
5640
  function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
5449
5641
  assertSafeRelativePath(relativePath);
5450
5642
  const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
5451
- const abs = join12(worktreePath, relativePath);
5643
+ const abs = join13(worktreePath, relativePath);
5452
5644
  const st = statSync2(abs);
5453
5645
  if (!st.isFile()) {
5454
5646
  throw new Error(`Not a file: ${relativePath}`);
@@ -5458,7 +5650,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
5458
5650
  `File too large to upload (${st.size} bytes; max ${maxBytes})`
5459
5651
  );
5460
5652
  }
5461
- const buf = readFileSync9(abs);
5653
+ const buf = readFileSync10(abs);
5462
5654
  return {
5463
5655
  path: relativePath,
5464
5656
  contentBase64: buf.toString("base64"),
@@ -5468,12 +5660,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
5468
5660
  function readWorktreeFile(worktreePath, relativePath, opts) {
5469
5661
  assertSafeRelativePath(relativePath);
5470
5662
  const maxBytes = opts?.maxBytes ?? 2e5;
5471
- const abs = join12(worktreePath, relativePath);
5663
+ const abs = join13(worktreePath, relativePath);
5472
5664
  const st = statSync2(abs);
5473
5665
  if (!st.isFile()) {
5474
5666
  throw new Error(`Not a file: ${relativePath}`);
5475
5667
  }
5476
- const buf = readFileSync9(abs);
5668
+ const buf = readFileSync10(abs);
5477
5669
  if (isImageRelativePath(relativePath)) {
5478
5670
  const maxImageBytes = Math.max(maxBytes, 15e6);
5479
5671
  const truncated2 = buf.length > maxImageBytes;
@@ -5516,9 +5708,9 @@ function assertSafeRelativePath(relativePath) {
5516
5708
  }
5517
5709
  function writeWorktreeFile(worktreePath, relativePath, content) {
5518
5710
  assertSafeRelativePath(relativePath);
5519
- const abs = join12(worktreePath, relativePath);
5520
- mkdirSync5(dirname4(abs), { recursive: true });
5521
- writeFileSync7(abs, content, "utf8");
5711
+ const abs = join13(worktreePath, relativePath);
5712
+ mkdirSync6(dirname5(abs), { recursive: true });
5713
+ writeFileSync8(abs, content, "utf8");
5522
5714
  return { path: relativePath };
5523
5715
  }
5524
5716
  async function getWorktreeDirtyStat(worktreePath) {
@@ -5740,9 +5932,9 @@ async function confirmLand(thread, opts) {
5740
5932
  }
5741
5933
 
5742
5934
  // src/skills/discover.ts
5743
- import { existsSync as existsSync14, readdirSync as readdirSync5, readFileSync as readFileSync10, statSync as statSync3 } from "fs";
5935
+ import { existsSync as existsSync14, readdirSync as readdirSync5, readFileSync as readFileSync11, statSync as statSync3 } from "fs";
5744
5936
  import { homedir } from "os";
5745
- import { join as join13 } from "path";
5937
+ import { join as join14 } from "path";
5746
5938
 
5747
5939
  // src/skills/bundled/long-running.ts
5748
5940
  var LONG_RUNNING_SKILL_COMMAND = "long-running";
@@ -5879,7 +6071,7 @@ function parseFrontmatter(content) {
5879
6071
  }
5880
6072
  function readSkill(skillMd, source) {
5881
6073
  try {
5882
- const content = readFileSync10(skillMd, "utf8");
6074
+ const content = readFileSync11(skillMd, "utf8");
5883
6075
  const { name: fmName, description } = parseFrontmatter(content);
5884
6076
  const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
5885
6077
  const name = fmName || dirName;
@@ -5907,7 +6099,7 @@ function scanSkillsDir(dir, source, out) {
5907
6099
  }
5908
6100
  for (const entry of entries) {
5909
6101
  if (entry.startsWith(".")) continue;
5910
- const skillMd = join13(dir, entry, "SKILL.md");
6102
+ const skillMd = join14(dir, entry, "SKILL.md");
5911
6103
  if (!existsSync14(skillMd)) continue;
5912
6104
  try {
5913
6105
  if (!statSync3(skillMd).isFile()) continue;
@@ -5929,12 +6121,12 @@ function scanClaudePluginSkills(pluginsRoot, out) {
5929
6121
  return;
5930
6122
  }
5931
6123
  if (lookingForSkillsDir && entries.includes("SKILL.md")) {
5932
- const skill = readSkill(join13(dir, "SKILL.md"), "cli");
6124
+ const skill = readSkill(join14(dir, "SKILL.md"), "cli");
5933
6125
  if (skill) out.push(skill);
5934
6126
  }
5935
6127
  for (const entry of entries) {
5936
6128
  if (entry === "node_modules" || entry === ".git") continue;
5937
- const full = join13(dir, entry);
6129
+ const full = join14(dir, entry);
5938
6130
  try {
5939
6131
  if (!statSync3(full).isDirectory()) continue;
5940
6132
  } catch {
@@ -5954,17 +6146,17 @@ function discoverSkills(worktreePath) {
5954
6146
  const home = homedir();
5955
6147
  const collected = [];
5956
6148
  for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
5957
- scanSkillsDir(join13(worktreePath, rel), "workspace", collected);
6149
+ scanSkillsDir(join14(worktreePath, rel), "workspace", collected);
5958
6150
  }
5959
6151
  for (const abs of [
5960
- join13(home, ".claude/skills"),
5961
- join13(home, ".cursor/skills"),
5962
- join13(home, ".sideboard/skills"),
5963
- join13(home, ".brightsy/skills")
6152
+ join14(home, ".claude/skills"),
6153
+ join14(home, ".cursor/skills"),
6154
+ join14(home, ".sideboard/skills"),
6155
+ join14(home, ".brightsy/skills")
5964
6156
  ]) {
5965
6157
  scanSkillsDir(abs, "user", collected);
5966
6158
  }
5967
- scanClaudePluginSkills(join13(home, ".claude/plugins"), collected);
6159
+ scanClaudePluginSkills(join14(home, ".claude/plugins"), collected);
5968
6160
  collected.push(...bundledSkills());
5969
6161
  const rank = {
5970
6162
  workspace: 0,
@@ -5990,7 +6182,7 @@ function readSkillBody(skillPath, maxChars = 12e3) {
5990
6182
  \u2026(truncated)` : body;
5991
6183
  }
5992
6184
  }
5993
- const raw = readFileSync10(skillPath, "utf8");
6185
+ const raw = readFileSync11(skillPath, "utf8");
5994
6186
  if (raw.startsWith("---")) {
5995
6187
  const end = raw.indexOf("\n---", 3);
5996
6188
  if (end >= 0) {
@@ -6136,11 +6328,11 @@ function shiftQueuedItem(queue, queueAttachments) {
6136
6328
 
6137
6329
  // src/agents/instructions.ts
6138
6330
  import { existsSync as existsSync16 } from "fs";
6139
- import { join as join15 } from "path";
6331
+ import { join as join16 } from "path";
6140
6332
 
6141
6333
  // src/skills/detached-job-path.ts
6142
6334
  import { existsSync as existsSync15 } from "fs";
6143
- import { dirname as dirname5, join as join14 } from "path";
6335
+ import { dirname as dirname6, join as join15 } from "path";
6144
6336
  import { fileURLToPath } from "url";
6145
6337
  var DETACHED_JOB_FILENAMES = ["detached-job.cjs", "detached-job.js"];
6146
6338
  function compiledModuleDir() {
@@ -6149,7 +6341,7 @@ function compiledModuleDir() {
6149
6341
  try {
6150
6342
  const url = import.meta.url;
6151
6343
  if (typeof url === "string" && url.length > 0) {
6152
- return dirname5(fileURLToPath(url));
6344
+ return dirname6(fileURLToPath(url));
6153
6345
  }
6154
6346
  } catch {
6155
6347
  }
@@ -6157,7 +6349,7 @@ function compiledModuleDir() {
6157
6349
  }
6158
6350
  function detachedJobScriptIn(dir) {
6159
6351
  for (const name of DETACHED_JOB_FILENAMES) {
6160
- const script = join14(dir, "scripts", name);
6352
+ const script = join15(dir, "scripts", name);
6161
6353
  if (existsSync15(script)) return script;
6162
6354
  }
6163
6355
  return null;
@@ -6175,7 +6367,7 @@ function resolveDetachedJobScript() {
6175
6367
  for (let i = 0; i < 8; i++) {
6176
6368
  const candidate = detachedJobScriptIn(dir);
6177
6369
  if (candidate) return candidate;
6178
- const parent = dirname5(dir);
6370
+ const parent = dirname6(dir);
6179
6371
  if (parent === dir) break;
6180
6372
  dir = parent;
6181
6373
  }
@@ -6280,9 +6472,9 @@ function formatWorktreeDirective(thread, opts) {
6280
6472
  );
6281
6473
  } else {
6282
6474
  const slug = opts?.githubSlug ?? "<origin-owner/name>";
6283
- const resolve = opts?.githubSlug ? "" : " Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree.";
6475
+ const resolve2 = opts?.githubSlug ? "" : " Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree.";
6284
6476
  lines.push(
6285
- `- 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\`.`
6477
+ `- 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\`.`
6286
6478
  );
6287
6479
  }
6288
6480
  lines.push(
@@ -6372,9 +6564,9 @@ function formatPrGateDirective() {
6372
6564
  }
6373
6565
  function formatProcessGuideDirective(opts) {
6374
6566
  const worktree = opts?.worktreePath?.trim();
6375
- const hasGraphSkill = !!worktree && existsSync16(join15(worktree, ".claude/skills/graph-engineering/SKILL.md"));
6376
- const hasReviewSkill = !!worktree && existsSync16(join15(worktree, ".claude/skills/review/SKILL.md"));
6377
- const hasInstallSkill = !!worktree && existsSync16(join15(worktree, ".claude/skills/worktree-install/SKILL.md"));
6567
+ const hasGraphSkill = !!worktree && existsSync16(join16(worktree, ".claude/skills/graph-engineering/SKILL.md"));
6568
+ const hasReviewSkill = !!worktree && existsSync16(join16(worktree, ".claude/skills/review/SKILL.md"));
6569
+ const hasInstallSkill = !!worktree && existsSync16(join16(worktree, ".claude/skills/worktree-install/SKILL.md"));
6378
6570
  return [
6379
6571
  "Process guides (recurring work only):",
6380
6572
  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,
@@ -6575,8 +6767,8 @@ async function syncThreadBranchFromGit(threadId) {
6575
6767
 
6576
6768
  // src/store/schedules.ts
6577
6769
  import { randomUUID as randomUUID4 } from "crypto";
6578
- import { existsSync as existsSync17, readFileSync as readFileSync11 } from "fs";
6579
- import { join as join16 } from "path";
6770
+ import { existsSync as existsSync17, readFileSync as readFileSync12 } from "fs";
6771
+ import { join as join17 } from "path";
6580
6772
  import { Cron } from "croner";
6581
6773
  var DURATION_RE = /^(\d+)(s|m|h|d)$/i;
6582
6774
  var UNIT_MS = {
@@ -6586,7 +6778,7 @@ var UNIT_MS = {
6586
6778
  d: 864e5
6587
6779
  };
6588
6780
  function schedulesPath() {
6589
- return join16(appDataDir(), "schedules.json");
6781
+ return join17(appDataDir(), "schedules.json");
6590
6782
  }
6591
6783
  function parseDurationMs(every) {
6592
6784
  const m = every.trim().match(DURATION_RE);
@@ -6688,7 +6880,7 @@ function readAll() {
6688
6880
  const path = schedulesPath();
6689
6881
  if (!existsSync17(path)) return [];
6690
6882
  try {
6691
- const parsed = JSON.parse(readFileSync11(path, "utf8"));
6883
+ const parsed = JSON.parse(readFileSync12(path, "utf8"));
6692
6884
  if (!Array.isArray(parsed)) return [];
6693
6885
  return parsed.map((row) => {
6694
6886
  try {
@@ -6811,7 +7003,7 @@ function formatScheduledPrompt(name, prompt) {
6811
7003
  ${prompt}`;
6812
7004
  }
6813
7005
  async function defaultDeps() {
6814
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-AAYKR4AI.js");
7006
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-MIIKXPHH.js");
6815
7007
  const orch = getOrchestrator2();
6816
7008
  return {
6817
7009
  findThread: (id) => findThreadByRef(id),
@@ -6876,14 +7068,14 @@ function armOne(schedule) {
6876
7068
  if (!schedule.enabled) return;
6877
7069
  const at = new Date(schedule.nextRunAt);
6878
7070
  if (Number.isNaN(at.getTime())) return;
6879
- const delay = Math.max(0, at.getTime() - Date.now());
6880
- if (delay <= 250) {
7071
+ const delay2 = Math.max(0, at.getTime() - Date.now());
7072
+ if (delay2 <= 250) {
6881
7073
  void fireSchedule(schedule.id).then(() => {
6882
7074
  if (isThisProcessDesktopHost()) armSchedules();
6883
7075
  });
6884
7076
  return;
6885
7077
  }
6886
- const capped = Math.min(delay, SET_TIMEOUT_MAX);
7078
+ const capped = Math.min(delay2, SET_TIMEOUT_MAX);
6887
7079
  const timer = setTimeout(() => {
6888
7080
  timers.delete(schedule.id);
6889
7081
  const live = getSchedule(schedule.id);
@@ -7267,8 +7459,8 @@ var Orchestrator = class {
7267
7459
  scheduleQuotaResume(threadId, resumeAt) {
7268
7460
  this.clearQuotaResumeTimer(threadId);
7269
7461
  updateThread(threadId, { quotaResumeAt: resumeAt.toISOString() });
7270
- const delay = Math.max(5e3, resumeAt.getTime() - Date.now());
7271
- const capped = Math.min(delay, 2147483647);
7462
+ const delay2 = Math.max(5e3, resumeAt.getTime() - Date.now());
7463
+ const capped = Math.min(delay2, 2147483647);
7272
7464
  const timer = setTimeout(() => {
7273
7465
  this.quotaResumeTimers.delete(threadId);
7274
7466
  void this.resumeAfterQuotaWait(threadId);
@@ -8323,6 +8515,7 @@ var Orchestrator = class {
8323
8515
  return { port: shared.devPort, scriptName: resolvedName, ports: [shared.devPort] };
8324
8516
  }
8325
8517
  }
8518
+ const preferredPorts = active?.ports?.length ? active.ports : active?.port != null ? [active.port] : void 0;
8326
8519
  if (active && !existing) {
8327
8520
  killListenersOnPorts(collectActiveRunPorts([active]));
8328
8521
  this.syncWorktreeRuns(
@@ -8361,7 +8554,7 @@ var Orchestrator = class {
8361
8554
  thread.repoPath,
8362
8555
  thread.worktreePath,
8363
8556
  runOutput.push,
8364
- { scriptName: resolvedName }
8557
+ { scriptName: resolvedName, preferredPorts }
8365
8558
  );
8366
8559
  } catch (err) {
8367
8560
  runOutput.flush();
@@ -8810,7 +9003,7 @@ var Orchestrator = class {
8810
9003
  return thread;
8811
9004
  }
8812
9005
  const start = Date.now();
8813
- return new Promise((resolve, reject) => {
9006
+ return new Promise((resolve2, reject) => {
8814
9007
  let settled = false;
8815
9008
  let timer;
8816
9009
  const finish = (fn) => {
@@ -8828,7 +9021,7 @@ var Orchestrator = class {
8828
9021
  finish(() => reject(new Error(`Thread not found: ${thread.id}`)));
8829
9022
  return;
8830
9023
  }
8831
- finish(() => resolve(latest));
9024
+ finish(() => resolve2(latest));
8832
9025
  return;
8833
9026
  }
8834
9027
  if (event.type === "status_changed") {
@@ -8838,7 +9031,7 @@ var Orchestrator = class {
8838
9031
  return;
8839
9032
  }
8840
9033
  if (!["running", "queued"].includes(latest.status)) {
8841
- finish(() => resolve(latest));
9034
+ finish(() => resolve2(latest));
8842
9035
  }
8843
9036
  }
8844
9037
  });
@@ -8850,12 +9043,12 @@ var Orchestrator = class {
8850
9043
  }
8851
9044
  const current = this.healStaleReportedActivity(raw);
8852
9045
  if (!this.threadLooksLive(current)) {
8853
- finish(() => resolve(current));
9046
+ finish(() => resolve2(current));
8854
9047
  return;
8855
9048
  }
8856
9049
  if (Date.now() - start > timeoutMs) {
8857
9050
  if (opts?.resolveIfStillRunning) {
8858
- finish(() => resolve(current));
9051
+ finish(() => resolve2(current));
8859
9052
  } else {
8860
9053
  finish(() => reject(new Error("wait_for_turn timed out")));
8861
9054
  }