@sideboard-ai/core 0.1.231 → 0.1.233

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/agents/cursor-runner.cjs +167 -62
  2. package/dist/agents/cursor-runner.js +16 -9
  3. package/dist/{agents-ENAQHQRZ.js → agents-J2CUJHPC.js} +16 -6
  4. package/dist/{agents-TCTEAK6M.js → agents-LDYMFW6N.js} +17 -7
  5. package/dist/{chunk-TQBUXKIB.js → chunk-26T43LBM.js} +97 -11
  6. package/dist/{chunk-PO4M4JAJ.js → chunk-2P4XKWV2.js} +1 -1
  7. package/dist/{chunk-ABOBTSO6.js → chunk-2UG25RMK.js} +18 -5
  8. package/dist/{chunk-4CZ25DO2.js → chunk-4VFOJZPS.js} +2 -2
  9. package/dist/{chunk-N5TX66CD.js → chunk-7H2CVVLF.js} +2 -2
  10. package/dist/{chunk-HZLZ34FK.js → chunk-BGHDWCAV.js} +69 -30
  11. package/dist/{chunk-SZJZEFTY.js → chunk-DD67JWTN.js} +1 -1
  12. package/dist/{chunk-JJRRLCCS.js → chunk-NLETJP7Z.js} +64 -30
  13. package/dist/{chunk-FA4CPYCY.js → chunk-PZQNE5X4.js} +81 -41
  14. package/dist/{chunk-HVUVQXZ2.js → chunk-QVN2WOKJ.js} +18 -5
  15. package/dist/{chunk-HZFLKVGC.js → chunk-S2OEFXST.js} +1 -1
  16. package/dist/{chunk-SXFRXNBM.js → chunk-SPAMHHJH.js} +1 -1
  17. package/dist/{chunk-ZXJMAKEP.js → chunk-TNVJPFHM.js} +5 -5
  18. package/dist/{chunk-UNTOZA3C.js → chunk-TWXSZYR2.js} +1 -1
  19. package/dist/{chunk-6L25K7BE.js → chunk-TXMFBL3X.js} +195 -73
  20. package/dist/{connected-teams-PIBQTOJU.js → connected-teams-JUJAQZZE.js} +2 -2
  21. package/dist/{connected-teams-RVD3PFAG.js → connected-teams-KQUDU7LZ.js} +2 -2
  22. package/dist/{coordinator-prompt-YKLXQTWH.js → coordinator-prompt-CE7MN6QY.js} +4 -4
  23. package/dist/{coordinator-prompt-DFXYTM6D.js → coordinator-prompt-IGDMFKCD.js} +4 -4
  24. package/dist/{global-workspace-EYZKYHAO.js → global-workspace-7WH24UFO.js} +4 -4
  25. package/dist/{global-workspace-4SPANNJT.js → global-workspace-NCIC2Y2U.js} +4 -4
  26. package/dist/index.cjs +542 -337
  27. package/dist/index.d.cts +32 -4
  28. package/dist/index.d.ts +32 -4
  29. package/dist/index.js +31 -8
  30. package/dist/mcp/run-stdio.cjs +465 -315
  31. package/dist/mcp/run-stdio.js +7 -7
  32. package/dist/{orchestrator-ZT3SJVKF.js → orchestrator-BXALNM4M.js} +8 -8
  33. package/dist/{orchestrator-HMJPNUN5.js → orchestrator-NLZMHTLX.js} +7 -7
  34. package/dist/{run-UEQM4JMZ.js → run-PCX5QWR4.js} +1 -1
  35. package/dist/{run-QDZCTP4Y.js → run-TB7RBII2.js} +1 -1
  36. package/dist/{workspaces-73Y7IJY2.js → workspaces-H2TRFDE2.js} +4 -4
  37. package/dist/{workspaces-FQCSCTNH.js → workspaces-NSQZSDQD.js} +4 -4
  38. package/dist/{worktree-DOPRKG7K.js → worktree-FMIX4BRV.js} +3 -3
  39. package/dist/{worktree-36VEFUJN.js → worktree-W7BSI4GU.js} +3 -3
  40. package/dist/{worktree-exclude-K7QK4RI5.js → worktree-exclude-5N2KTYIT.js} +2 -2
  41. package/dist/{worktree-exclude-L32WEBX6.js → worktree-exclude-RXZPTCNH.js} +2 -2
  42. package/package.json +2 -2
@@ -2,8 +2,9 @@ import {
2
2
  appDataDir
3
3
  } from "./chunk-WFUDY6PC.js";
4
4
  import {
5
+ npmGlobalNodeModules,
5
6
  run
6
- } from "./chunk-HVUVQXZ2.js";
7
+ } from "./chunk-QVN2WOKJ.js";
7
8
  import {
8
9
  isElectronLikeCommand,
9
10
  wrapElectronAsNodeLaunch
@@ -750,6 +751,87 @@ async function resolveNodeLaunch(scriptPath) {
750
751
  };
751
752
  }
752
753
 
754
+ // src/agents/cursor-sdk-resolve.ts
755
+ import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
756
+ import { createRequire } from "module";
757
+ import { basename, dirname as dirname2, join as join4 } from "path";
758
+ import { fileURLToPath, pathToFileURL } from "url";
759
+ var CURSOR_SDK_INSTALL_HINT = "Cursor SDK is not installed. Settings \u2192 Agents \u2192 Cursor \u2192 Install (`npm i -g @cursor/sdk`). Sideboard does not ship the SDK \u2014 update it anytime without a new Sideboard build.";
760
+ function thisModuleFile() {
761
+ const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
762
+ if (cjsDir) return join4(cjsDir, "cursor-sdk-resolve.js");
763
+ try {
764
+ return fileURLToPath(import.meta.url);
765
+ } catch {
766
+ return join4(process.cwd(), "package.json");
767
+ }
768
+ }
769
+ function packageRootLooksLikeSdk(dir) {
770
+ try {
771
+ const raw = readFileSync2(join4(dir, "package.json"), "utf8");
772
+ const pkg = JSON.parse(raw);
773
+ return pkg.name === "@cursor/sdk" && existsSync4(dir);
774
+ } catch {
775
+ return false;
776
+ }
777
+ }
778
+ function resolvedPackageRoot(fromFile) {
779
+ try {
780
+ const req = createRequire(fromFile);
781
+ const pkgJson = req.resolve("@cursor/sdk/package.json");
782
+ const root = dirname2(pkgJson);
783
+ return packageRootLooksLikeSdk(root) ? root : null;
784
+ } catch {
785
+ return null;
786
+ }
787
+ }
788
+ function resolveCursorSdkRoot(opts) {
789
+ const env = opts?.env ?? process.env;
790
+ const override = env.SIDEBOARD_CURSOR_SDK?.trim();
791
+ if (override) {
792
+ return packageRootLooksLikeSdk(override) ? override : null;
793
+ }
794
+ const globalNm = npmGlobalNodeModules(env);
795
+ if (globalNm) {
796
+ const globalRoot = join4(globalNm, "@cursor/sdk");
797
+ if (packageRootLooksLikeSdk(globalRoot)) return globalRoot;
798
+ }
799
+ const cwdPkg = join4(process.cwd(), "package.json");
800
+ return resolvedPackageRoot(thisModuleFile()) ?? resolvedPackageRoot(cwdPkg);
801
+ }
802
+ function isCursorSdkInstalled(opts) {
803
+ return Boolean(resolveCursorSdkRoot(opts));
804
+ }
805
+ async function importCursorSdk(opts) {
806
+ const root = resolveCursorSdkRoot(opts);
807
+ if (!root) return null;
808
+ try {
809
+ const req = createRequire(join4(root, "package.json"));
810
+ const entry = req.resolve("@cursor/sdk");
811
+ return await import(pathToFileURL(entry).href);
812
+ } catch {
813
+ return null;
814
+ }
815
+ }
816
+ function cursorSdkPlatformRipgrepPackage() {
817
+ return `@cursor/sdk-${process.platform}-${process.arch}`;
818
+ }
819
+ function nodeModulesDirForPackageRoot(packageRoot) {
820
+ const parent = dirname2(packageRoot);
821
+ return basename(parent).startsWith("@") ? dirname2(parent) : parent;
822
+ }
823
+ function cursorSdkRipgrepCandidate(opts) {
824
+ const root = resolveCursorSdkRoot(opts);
825
+ if (!root) return null;
826
+ const nm = nodeModulesDirForPackageRoot(root);
827
+ const pkg = cursorSdkPlatformRipgrepPackage();
828
+ const bin = process.platform === "win32" ? "rg.exe" : "rg";
829
+ const sibling = join4(nm, pkg, "bin", bin);
830
+ if (existsSync4(sibling)) return sibling;
831
+ const nested = join4(root, "node_modules", pkg, "bin", bin);
832
+ return existsSync4(nested) ? nested : null;
833
+ }
834
+
753
835
  // src/agents/cursor-events.ts
754
836
  function usageFromCursor(usage) {
755
837
  if (!usage) return null;
@@ -1059,9 +1141,9 @@ function parseCursorRunnerLine(line) {
1059
1141
  }
1060
1142
 
1061
1143
  // src/agents/cursor-ripgrep.ts
1062
- import { existsSync as existsSync4 } from "fs";
1063
- import { createRequire } from "module";
1064
- import { dirname as dirname2, isAbsolute, join as join4, parse, resolve as resolvePath } from "path";
1144
+ import { existsSync as existsSync5 } from "fs";
1145
+ import { createRequire as createRequire2 } from "module";
1146
+ import { dirname as dirname3, isAbsolute, join as join5, parse, resolve as resolvePath } from "path";
1065
1147
  var RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
1066
1148
  function rgBinaryName() {
1067
1149
  return process.platform === "win32" ? "rg.exe" : "rg";
@@ -1073,19 +1155,19 @@ function usableRipgrepPath(candidate) {
1073
1155
  const raw = candidate?.trim();
1074
1156
  if (!raw || !isAbsolute(raw)) return null;
1075
1157
  const readable = nodeReadableScriptPath(raw);
1076
- if (!existsSync4(readable) || isAsarPath(readable)) return null;
1158
+ if (!existsSync5(readable) || isAsarPath(readable)) return null;
1077
1159
  return readable;
1078
1160
  }
1079
1161
  function walkForBundledRipgrep(startFile) {
1080
1162
  if (!startFile) return null;
1081
1163
  const pkg = platformRipgrepPackage();
1082
1164
  const name = rgBinaryName();
1083
- let dir = dirname2(resolvePath(startFile));
1165
+ let dir = dirname3(resolvePath(startFile));
1084
1166
  const root = parse(dir).root;
1085
1167
  while (dir !== root) {
1086
- const hit = usableRipgrepPath(join4(dir, "node_modules", pkg, "bin", name));
1168
+ const hit = usableRipgrepPath(join5(dir, "node_modules", pkg, "bin", name));
1087
1169
  if (hit) return hit;
1088
- const next = dirname2(dir);
1170
+ const next = dirname3(dir);
1089
1171
  if (next === dir) break;
1090
1172
  dir = next;
1091
1173
  }
@@ -1093,9 +1175,9 @@ function walkForBundledRipgrep(startFile) {
1093
1175
  }
1094
1176
  function requireResolveBundledRipgrep(fromFile) {
1095
1177
  try {
1096
- const req = createRequire(fromFile);
1178
+ const req = createRequire2(fromFile);
1097
1179
  const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
1098
- return usableRipgrepPath(join4(dirname2(pkgJson), "bin", rgBinaryName()));
1180
+ return usableRipgrepPath(join5(dirname3(pkgJson), "bin", rgBinaryName()));
1099
1181
  } catch {
1100
1182
  return null;
1101
1183
  }
@@ -1111,7 +1193,7 @@ function resolveCursorRipgrepPath(opts) {
1111
1193
  const start = opts?.startFile?.trim() || process.argv[1] || // CJS bundle only — ESM has no __filename; argv[1] is the running script.
1112
1194
  // eslint-disable-next-line camelcase
1113
1195
  (typeof __filename !== "undefined" ? __filename : "");
1114
- return walkForBundledRipgrep(start) ?? requireResolveBundledRipgrep(start);
1196
+ return walkForBundledRipgrep(start) ?? usableRipgrepPath(cursorSdkRipgrepCandidate({ env })) ?? requireResolveBundledRipgrep(start);
1115
1197
  }
1116
1198
  function cursorRipgrepEnv(opts) {
1117
1199
  const path = resolveCursorRipgrepPath(opts);
@@ -1154,6 +1236,10 @@ export {
1154
1236
  isAsarPath,
1155
1237
  applyNodeLaunch,
1156
1238
  resolveNodeLaunch,
1239
+ CURSOR_SDK_INSTALL_HINT,
1240
+ resolveCursorSdkRoot,
1241
+ isCursorSdkInstalled,
1242
+ importCursorSdk,
1157
1243
  preferredCursorCostCents,
1158
1244
  turnCostUsdFromCursorUsage,
1159
1245
  fetchCursorTurnCostUsd,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  git
3
- } from "./chunk-HVUVQXZ2.js";
3
+ } from "./chunk-QVN2WOKJ.js";
4
4
 
5
5
  // src/git/worktree-exclude.ts
6
6
  import { mkdirSync, readFileSync, writeFileSync } from "fs";
@@ -65,6 +65,14 @@ function ensureAgentPath(env = process.env) {
65
65
  }
66
66
  function enrichPathWithNpmGlobalBin(env = process.env) {
67
67
  ensureAgentPath(env);
68
+ const prefix = npmGlobalPrefix(env);
69
+ if (prefix) {
70
+ const binDir = process.platform === "win32" ? prefix : join(prefix, "bin");
71
+ prependPathDir(env, binDir);
72
+ }
73
+ return env.PATH ?? "";
74
+ }
75
+ function npmGlobalPrefix(env = process.env) {
68
76
  try {
69
77
  const prefix = execFileSync("npm", ["prefix", "-g"], {
70
78
  encoding: "utf8",
@@ -72,13 +80,16 @@ function enrichPathWithNpmGlobalBin(env = process.env) {
72
80
  timeout: 8e3,
73
81
  stdio: ["ignore", "pipe", "ignore"]
74
82
  }).trim().split(/\r?\n/).find(Boolean);
75
- if (prefix) {
76
- const binDir = process.platform === "win32" ? prefix : join(prefix, "bin");
77
- prependPathDir(env, binDir);
78
- }
83
+ return prefix || null;
79
84
  } catch {
85
+ return null;
80
86
  }
81
- return env.PATH ?? "";
87
+ }
88
+ function npmGlobalNodeModules(env = process.env) {
89
+ const prefix = npmGlobalPrefix(env);
90
+ if (!prefix) return null;
91
+ const dir = process.platform === "win32" ? join(prefix, "node_modules") : join(prefix, "lib", "node_modules");
92
+ return existsSync(dir) ? dir : null;
82
93
  }
83
94
  function posixShellSingleQuote(value) {
84
95
  return `'${value.replace(/'/g, `'\\''`)}'`;
@@ -309,6 +320,8 @@ export {
309
320
  isConductorBundledCli,
310
321
  ensureAgentPath,
311
322
  enrichPathWithNpmGlobalBin,
323
+ npmGlobalPrefix,
324
+ npmGlobalNodeModules,
312
325
  posixShellSingleQuote,
313
326
  resolveCommandBinarySync,
314
327
  withExportedPath,
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-XJETIO4K.js";
9
9
  import {
10
10
  ensureWorktreeSideboardIgnored
11
- } from "./chunk-SZJZEFTY.js";
11
+ } from "./chunk-DD67JWTN.js";
12
12
  import {
13
13
  gh,
14
14
  git,
@@ -18,7 +18,7 @@ import {
18
18
  githubGhConfigEnv,
19
19
  materializeGithubAgentAuth,
20
20
  resolveGhAuthToken
21
- } from "./chunk-ABOBTSO6.js";
21
+ } from "./chunk-2UG25RMK.js";
22
22
  import {
23
23
  getGithubGitAuthMode,
24
24
  getGithubPat
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-6K64FJDD.js";
4
4
  import {
5
5
  ensureWorktreeSideboardIgnored
6
- } from "./chunk-PO4M4JAJ.js";
6
+ } from "./chunk-2P4XKWV2.js";
7
7
  import {
8
8
  getGithubGitAuthMode,
9
9
  getGithubPat
@@ -23,7 +23,7 @@ import {
23
23
  githubGhConfigEnv,
24
24
  materializeGithubAgentAuth,
25
25
  resolveGhAuthToken
26
- } from "./chunk-HVUVQXZ2.js";
26
+ } from "./chunk-QVN2WOKJ.js";
27
27
 
28
28
  // src/git/worktree.ts
29
29
  import { randomBytes } from "crypto";
@@ -24,7 +24,7 @@ import {
24
24
  resolveQuotaFallbackAgent,
25
25
  stripBrightsyNdjsonNoise,
26
26
  toolDescription
27
- } from "./chunk-FA4CPYCY.js";
27
+ } from "./chunk-PZQNE5X4.js";
28
28
  import {
29
29
  SLACK_REPLY_FORMATTING,
30
30
  addWorkspace,
@@ -47,7 +47,7 @@ import {
47
47
  stageAbsolutePathsAsAttachments,
48
48
  stageBuffersAsAttachments,
49
49
  syncWorkspacesFromThreads
50
- } from "./chunk-HZFLKVGC.js";
50
+ } from "./chunk-S2OEFXST.js";
51
51
  import {
52
52
  addPrStackLayer,
53
53
  allocateTeamName,
@@ -96,7 +96,7 @@ import {
96
96
  worktreeDisplayLabelForGroup,
97
97
  worktreeNameFromPath,
98
98
  worktreeSlugForTicket
99
- } from "./chunk-N5TX66CD.js";
99
+ } from "./chunk-7H2CVVLF.js";
100
100
  import {
101
101
  ATTACHMENTS_DIR,
102
102
  DETACHED_JOBS_DIR,
@@ -105,7 +105,7 @@ import {
105
105
  } from "./chunk-6K64FJDD.js";
106
106
  import {
107
107
  ensureWorktreeSideboardIgnored
108
- } from "./chunk-PO4M4JAJ.js";
108
+ } from "./chunk-2P4XKWV2.js";
109
109
  import {
110
110
  httpFetch
111
111
  } from "./chunk-N7WZ6NIN.js";
@@ -128,7 +128,7 @@ import {
128
128
  shouldRetryFailedAgentTurn,
129
129
  summarizeTurnStderr,
130
130
  turnFailChatText
131
- } from "./chunk-TQBUXKIB.js";
131
+ } from "./chunk-26T43LBM.js";
132
132
  import {
133
133
  HISTORY_CLEANUP_INTERVAL_HOURS_DEFAULT,
134
134
  applyTurnUsage,
@@ -206,7 +206,7 @@ import {
206
206
  git,
207
207
  resolveGitDirsForLockRecovery,
208
208
  run
209
- } from "./chunk-HVUVQXZ2.js";
209
+ } from "./chunk-QVN2WOKJ.js";
210
210
  import {
211
211
  stripNestedElectronEnv
212
212
  } from "./chunk-4TR3HZFT.js";
@@ -482,7 +482,7 @@ async function continueSourceThread(threadId, prompt) {
482
482
  await continueOnReply(threadId, prompt);
483
483
  return;
484
484
  }
485
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-ZT3SJVKF.js");
485
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-BXALNM4M.js");
486
486
  await getOrchestrator2().send(threadId, prompt);
487
487
  } catch {
488
488
  }
@@ -901,9 +901,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
901
901
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
902
902
  );
903
903
  }
904
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-4SPANNJT.js");
904
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-NCIC2Y2U.js");
905
905
  if (isGlobalThread2(thread)) {
906
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-DFXYTM6D.js");
906
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-IGDMFKCD.js");
907
907
  ensureGlobalCoordinatorCwd2(
908
908
  isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
909
909
  );
@@ -2243,7 +2243,17 @@ function pipeLines(stream, onLine) {
2243
2243
  const rl = createInterface2({ input: stream });
2244
2244
  rl.on("line", onLine);
2245
2245
  }
2246
+ function killableListenerPids(raw, selfPid = process.pid) {
2247
+ const pids = [];
2248
+ for (const token of raw.trim().split(/\s+/)) {
2249
+ const pid = Number(token);
2250
+ if (!Number.isFinite(pid) || pid <= 0 || pid === selfPid) continue;
2251
+ pids.push(pid);
2252
+ }
2253
+ return pids;
2254
+ }
2246
2255
  function killListenersOnPorts(ports) {
2256
+ const selfPid = process.pid;
2247
2257
  for (const port of ports) {
2248
2258
  if (!Number.isFinite(port) || port <= 0) continue;
2249
2259
  try {
@@ -2253,7 +2263,7 @@ function killListenersOnPorts(ports) {
2253
2263
  [
2254
2264
  "-NoProfile",
2255
2265
  "-Command",
2256
- `Get-NetTCPConnection -LocalPort ${port} -ErrorAction SilentlyContinue | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force -ErrorAction SilentlyContinue }`
2266
+ `Get-NetTCPConnection -LocalPort ${port} -ErrorAction SilentlyContinue | Where-Object { $_.OwningProcess -ne ${selfPid} } | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force -ErrorAction SilentlyContinue }`
2257
2267
  ],
2258
2268
  { stdio: "ignore", timeout: 3e3 }
2259
2269
  );
@@ -2269,9 +2279,7 @@ function killListenersOnPorts(ports) {
2269
2279
  } catch {
2270
2280
  continue;
2271
2281
  }
2272
- for (const token of raw.trim().split(/\s+/)) {
2273
- const pid = Number(token);
2274
- if (!Number.isFinite(pid) || pid <= 0) continue;
2282
+ for (const pid of killableListenerPids(raw, selfPid)) {
2275
2283
  try {
2276
2284
  process.kill(pid, "SIGTERM");
2277
2285
  } catch {
@@ -2324,6 +2332,9 @@ async function spawnWorkspaceScript(command, opts) {
2324
2332
  );
2325
2333
  } catch {
2326
2334
  }
2335
+ if (opts.heldPorts?.length) {
2336
+ await Promise.all(opts.heldPorts.map((h) => h.release()));
2337
+ }
2327
2338
  const shell = process.platform === "darwin" ? "zsh" : "bash";
2328
2339
  const child = execa2(shell, ["-lc", command], {
2329
2340
  cwd: opts.worktreePath,
@@ -2515,11 +2526,11 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
2515
2526
  const held = await reservePortRange(PORT_RANGE_SIZE);
2516
2527
  const ports = held.map((h) => h.port);
2517
2528
  try {
2518
- await Promise.all(held.map((h) => h.release()));
2519
2529
  const handle = await spawnWorkspaceScript(script.command, {
2520
2530
  worktreePath,
2521
2531
  repoPath,
2522
2532
  ports,
2533
+ heldPorts: held,
2523
2534
  defaultBranch: opts?.defaultBranch,
2524
2535
  onLine
2525
2536
  });
@@ -2986,6 +2997,9 @@ async function cloneRepoIntoSideboard(opts) {
2986
2997
  function isUnclaimedRunScriptRequest(req) {
2987
2998
  return Boolean(req && !req.claimedAt && !req.fulfilledAt && !req.error);
2988
2999
  }
3000
+ function isAdoptableRunScriptRequest(req) {
3001
+ return Boolean(req && !req.fulfilledAt && !req.error);
3002
+ }
2989
3003
 
2990
3004
  // src/store/desktop-host.ts
2991
3005
  import { readFileSync as readFileSync6, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
@@ -4252,7 +4266,7 @@ async function createThread(input, _onSetupLine) {
4252
4266
  return readThread(thread.id) ?? thread;
4253
4267
  }
4254
4268
  async function listLinearIssues(agent, repoPath) {
4255
- const { getAdapter: getAdapter2 } = await import("./agents-TCTEAK6M.js");
4269
+ const { getAdapter: getAdapter2 } = await import("./agents-LDYMFW6N.js");
4256
4270
  await requireAgent(agent, { requireLinear: true });
4257
4271
  const adapter = getAdapter2(agent);
4258
4272
  if (!adapter.listLinearIssues) {
@@ -4710,7 +4724,7 @@ async function adoptThread(input) {
4710
4724
  throw new Error(`Worktree not found: ${input.worktreePath}`);
4711
4725
  }
4712
4726
  const repoPath = await resolveRepoRoot(input.worktreePath);
4713
- const { stdout: branch } = await import("./run-UEQM4JMZ.js").then(
4727
+ const { stdout: branch } = await import("./run-PCX5QWR4.js").then(
4714
4728
  ({ git: git2 }) => git2(["rev-parse", "--abbrev-ref", "HEAD"], input.worktreePath)
4715
4729
  );
4716
4730
  const thread = createEmptyThread({
@@ -4725,9 +4739,9 @@ async function adoptThread(input) {
4725
4739
  messages: input.messages ?? []
4726
4740
  });
4727
4741
  writeThread(thread);
4728
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-73Y7IJY2.js");
4742
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-H2TRFDE2.js");
4729
4743
  await ensureWorkspace2(repoPath);
4730
- const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-L32WEBX6.js");
4744
+ const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-RXZPTCNH.js");
4731
4745
  await ensureWorktreeSideboardIgnored2(input.worktreePath);
4732
4746
  return thread;
4733
4747
  }
@@ -6143,7 +6157,7 @@ async function confirmLand(thread, opts) {
6143
6157
  if (preview.dirty) {
6144
6158
  committed = await commitAll(thread.worktreePath, meta.commitMessage);
6145
6159
  }
6146
- const { git: git2 } = await import("./run-UEQM4JMZ.js");
6160
+ const { git: git2 } = await import("./run-PCX5QWR4.js");
6147
6161
  const { stdout: headOut } = await git2(
6148
6162
  ["rev-parse", "--abbrev-ref", "HEAD"],
6149
6163
  thread.worktreePath,
@@ -7407,7 +7421,7 @@ function formatScheduledPrompt(name, prompt) {
7407
7421
  ${prompt}`;
7408
7422
  }
7409
7423
  async function defaultDeps() {
7410
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-ZT3SJVKF.js");
7424
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-BXALNM4M.js");
7411
7425
  const orch = getOrchestrator2();
7412
7426
  return {
7413
7427
  findThread: (id) => findThreadByRef(id),
@@ -7591,6 +7605,8 @@ var Orchestrator = class {
7591
7605
  jobContinueNudged = /* @__PURE__ */ new Set();
7592
7606
  /** In-flight startDev per worktree run key — agent MCP + UI Start must not double-spawn. */
7593
7607
  startingDev = /* @__PURE__ */ new Map();
7608
+ /** Serialize desktop apply of `runScriptRequest` per thread (start then stop). */
7609
+ applyingRunScriptThreads = /* @__PURE__ */ new Set();
7594
7610
  /**
7595
7611
  * MCP/CLI poll budget while Electron main adopts `runScriptRequest`.
7596
7612
  * Tests shorten this so a missing desktop does not wait 20s.
@@ -7777,11 +7793,19 @@ var Orchestrator = class {
7777
7793
  for (const thread of listThreads()) {
7778
7794
  if (thread.status === "archived") continue;
7779
7795
  const req = thread.runScriptRequest;
7780
- if (!isUnclaimedRunScriptRequest(req) || !req) continue;
7781
- const claimedAt = (/* @__PURE__ */ new Date()).toISOString();
7796
+ if (!isAdoptableRunScriptRequest(req) || !req) continue;
7797
+ if (this.applyingRunScriptThreads.has(thread.id)) continue;
7798
+ const claimedAt = req.claimedAt ?? (/* @__PURE__ */ new Date()).toISOString();
7782
7799
  const claimed = { ...req, claimedAt };
7800
+ this.applyingRunScriptThreads.add(thread.id);
7783
7801
  updateThread(thread.id, { runScriptRequest: claimed });
7784
- void this.applyRunScriptRequest(thread.id, claimed);
7802
+ void this.applyRunScriptRequest(thread.id, claimed).finally(() => {
7803
+ this.applyingRunScriptThreads.delete(thread.id);
7804
+ const latest = readThread(thread.id)?.runScriptRequest;
7805
+ if (latest && latest.requestId !== req.requestId && isAdoptableRunScriptRequest(latest)) {
7806
+ this.adoptPersistedRunScripts();
7807
+ }
7808
+ });
7785
7809
  }
7786
7810
  }
7787
7811
  async applyRunScriptRequest(threadId, req) {
@@ -9037,9 +9061,8 @@ var Orchestrator = class {
9037
9061
  if (fulfilled && !run2) {
9038
9062
  throw new Error("Desktop reported the run script started, but it is not active.");
9039
9063
  }
9040
- } else {
9041
- const gone = scriptName ? !run2 : shared.activeRuns.length === 0;
9042
- if (fulfilled || gone) return null;
9064
+ } else if (fulfilled) {
9065
+ return null;
9043
9066
  }
9044
9067
  await new Promise((r) => setTimeout(r, 40));
9045
9068
  }
@@ -9047,12 +9070,26 @@ var Orchestrator = class {
9047
9070
  op === "start" ? "Desktop did not start the run script in time. Is Sideboard.app running this worktree?" : "Desktop did not stop the run script in time."
9048
9071
  );
9049
9072
  }
9073
+ async awaitStartingDev(worktreePath, scriptName) {
9074
+ const keys = scriptName ? [worktreeRunProcessKey(worktreePath, scriptName)] : [...this.startingDev.keys()].filter((k) => isWorktreeRunProcessKey(k, worktreePath));
9075
+ await Promise.all(
9076
+ keys.map(async (key) => {
9077
+ const pending = this.startingDev.get(key);
9078
+ if (!pending) return;
9079
+ try {
9080
+ await pending;
9081
+ } catch {
9082
+ }
9083
+ })
9084
+ );
9085
+ }
9050
9086
  async stopDev(threadRef, scriptName) {
9051
9087
  const thread = this.requireThread(threadRef);
9052
9088
  if (!this.shouldOwnRunScripts()) {
9053
9089
  await this.requestDesktopRunScript(thread, "stop", scriptName);
9054
9090
  return;
9055
9091
  }
9092
+ await this.awaitStartingDev(thread.worktreePath, scriptName);
9056
9093
  const siblings = threadsSharingWorktree(thread.worktreePath);
9057
9094
  const shared = mergeWorktreeActiveRuns(siblings);
9058
9095
  if (scriptName) {
@@ -9915,7 +9952,7 @@ var Orchestrator = class {
9915
9952
  this.enforceHistoryRetention();
9916
9953
  if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
9917
9954
  try {
9918
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-73Y7IJY2.js");
9955
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-H2TRFDE2.js");
9919
9956
  await ensureWorkspace2(thread.repoPath);
9920
9957
  } catch {
9921
9958
  }
@@ -9969,13 +10006,13 @@ var Orchestrator = class {
9969
10006
  `Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
9970
10007
  );
9971
10008
  }
9972
- const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-36VEFUJN.js");
10009
+ const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-W7BSI4GU.js");
9973
10010
  const slug = thread.worktreePath.split("/").pop();
9974
10011
  const dest = thread.worktreePath;
9975
10012
  await withRepoGitLock(thread.repoPath, async () => {
9976
10013
  await git(["worktree", "add", dest, thread.branchName], thread.repoPath);
9977
10014
  });
9978
- const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-L32WEBX6.js");
10015
+ const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-RXZPTCNH.js");
9979
10016
  await ensureWorktreeSideboardIgnored2(dest);
9980
10017
  void createThreadWorktree2;
9981
10018
  void slug;
@@ -10079,7 +10116,7 @@ async function startOrchestration(opts) {
10079
10116
  sourceRef: "default",
10080
10117
  ...createOpts
10081
10118
  }).catch(async () => {
10082
- const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-36VEFUJN.js");
10119
+ const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-W7BSI4GU.js");
10083
10120
  const repo = await resolveRepoRoot2(repoPath);
10084
10121
  const def = await resolveDefaultBranch2(repo);
10085
10122
  return orch.createThread({
@@ -10102,6 +10139,7 @@ async function startOrchestration(opts) {
10102
10139
 
10103
10140
  export {
10104
10141
  isUnclaimedRunScriptRequest,
10142
+ isAdoptableRunScriptRequest,
10105
10143
  isHomeBoardThread,
10106
10144
  BOARD_COLUMN_DEFS,
10107
10145
  HOME_BOARD_CACHE_TTL_MS,
@@ -10234,6 +10272,7 @@ export {
10234
10272
  copyConfiguredFiles,
10235
10273
  captureLoginEnv,
10236
10274
  buildWorkspaceScriptEnv,
10275
+ killableListenerPids,
10237
10276
  killListenersOnPorts,
10238
10277
  runSetupScript,
10239
10278
  runConventionSetup,
@@ -2,7 +2,7 @@
2
2
 
3
3
  import {
4
4
  git
5
- } from "./chunk-ABOBTSO6.js";
5
+ } from "./chunk-2UG25RMK.js";
6
6
 
7
7
  // src/git/worktree-exclude.ts
8
8
  import { mkdirSync, readFileSync, writeFileSync } from "fs";