@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
package/dist/index.cjs CHANGED
@@ -34,6 +34,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
34
34
  function isUnclaimedRunScriptRequest(req) {
35
35
  return Boolean(req && !req.claimedAt && !req.fulfilledAt && !req.error);
36
36
  }
37
+ function isAdoptableRunScriptRequest(req) {
38
+ return Boolean(req && !req.fulfilledAt && !req.error);
39
+ }
37
40
  var init_thread = __esm({
38
41
  "src/types/thread.ts"() {
39
42
  "use strict";
@@ -6772,6 +6775,14 @@ function ensureAgentPath(env = process.env) {
6772
6775
  }
6773
6776
  function enrichPathWithNpmGlobalBin(env = process.env) {
6774
6777
  ensureAgentPath(env);
6778
+ const prefix = npmGlobalPrefix(env);
6779
+ if (prefix) {
6780
+ const binDir = process.platform === "win32" ? prefix : (0, import_node_path17.join)(prefix, "bin");
6781
+ prependPathDir(env, binDir);
6782
+ }
6783
+ return env.PATH ?? "";
6784
+ }
6785
+ function npmGlobalPrefix(env = process.env) {
6775
6786
  try {
6776
6787
  const prefix = (0, import_node_child_process3.execFileSync)("npm", ["prefix", "-g"], {
6777
6788
  encoding: "utf8",
@@ -6779,13 +6790,16 @@ function enrichPathWithNpmGlobalBin(env = process.env) {
6779
6790
  timeout: 8e3,
6780
6791
  stdio: ["ignore", "pipe", "ignore"]
6781
6792
  }).trim().split(/\r?\n/).find(Boolean);
6782
- if (prefix) {
6783
- const binDir = process.platform === "win32" ? prefix : (0, import_node_path17.join)(prefix, "bin");
6784
- prependPathDir(env, binDir);
6785
- }
6793
+ return prefix || null;
6786
6794
  } catch {
6795
+ return null;
6787
6796
  }
6788
- return env.PATH ?? "";
6797
+ }
6798
+ function npmGlobalNodeModules(env = process.env) {
6799
+ const prefix = npmGlobalPrefix(env);
6800
+ if (!prefix) return null;
6801
+ const dir = process.platform === "win32" ? (0, import_node_path17.join)(prefix, "node_modules") : (0, import_node_path17.join)(prefix, "lib", "node_modules");
6802
+ return (0, import_node_fs15.existsSync)(dir) ? dir : null;
6789
6803
  }
6790
6804
  function posixShellSingleQuote(value) {
6791
6805
  return `'${value.replace(/'/g, `'\\''`)}'`;
@@ -13911,6 +13925,95 @@ var init_codex = __esm({
13911
13925
  }
13912
13926
  });
13913
13927
 
13928
+ // src/agents/cursor-sdk-resolve.ts
13929
+ function thisModuleFile() {
13930
+ const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
13931
+ if (cjsDir) return (0, import_node_path38.join)(cjsDir, "cursor-sdk-resolve.js");
13932
+ try {
13933
+ return (0, import_node_url2.fileURLToPath)(import_meta2.url);
13934
+ } catch {
13935
+ return (0, import_node_path38.join)(process.cwd(), "package.json");
13936
+ }
13937
+ }
13938
+ function packageRootLooksLikeSdk(dir) {
13939
+ try {
13940
+ const raw = (0, import_node_fs36.readFileSync)((0, import_node_path38.join)(dir, "package.json"), "utf8");
13941
+ const pkg = JSON.parse(raw);
13942
+ return pkg.name === "@cursor/sdk" && (0, import_node_fs36.existsSync)(dir);
13943
+ } catch {
13944
+ return false;
13945
+ }
13946
+ }
13947
+ function resolvedPackageRoot(fromFile) {
13948
+ try {
13949
+ const req = (0, import_node_module2.createRequire)(fromFile);
13950
+ const pkgJson = req.resolve("@cursor/sdk/package.json");
13951
+ const root = (0, import_node_path38.dirname)(pkgJson);
13952
+ return packageRootLooksLikeSdk(root) ? root : null;
13953
+ } catch {
13954
+ return null;
13955
+ }
13956
+ }
13957
+ function resolveCursorSdkRoot(opts) {
13958
+ const env = opts?.env ?? process.env;
13959
+ const override = env.SIDEBOARD_CURSOR_SDK?.trim();
13960
+ if (override) {
13961
+ return packageRootLooksLikeSdk(override) ? override : null;
13962
+ }
13963
+ const globalNm = npmGlobalNodeModules(env);
13964
+ if (globalNm) {
13965
+ const globalRoot = (0, import_node_path38.join)(globalNm, "@cursor/sdk");
13966
+ if (packageRootLooksLikeSdk(globalRoot)) return globalRoot;
13967
+ }
13968
+ const cwdPkg = (0, import_node_path38.join)(process.cwd(), "package.json");
13969
+ return resolvedPackageRoot(thisModuleFile()) ?? resolvedPackageRoot(cwdPkg);
13970
+ }
13971
+ function isCursorSdkInstalled(opts) {
13972
+ return Boolean(resolveCursorSdkRoot(opts));
13973
+ }
13974
+ async function importCursorSdk(opts) {
13975
+ const root = resolveCursorSdkRoot(opts);
13976
+ if (!root) return null;
13977
+ try {
13978
+ const req = (0, import_node_module2.createRequire)((0, import_node_path38.join)(root, "package.json"));
13979
+ const entry = req.resolve("@cursor/sdk");
13980
+ return await import((0, import_node_url2.pathToFileURL)(entry).href);
13981
+ } catch {
13982
+ return null;
13983
+ }
13984
+ }
13985
+ function cursorSdkPlatformRipgrepPackage() {
13986
+ return `@cursor/sdk-${process.platform}-${process.arch}`;
13987
+ }
13988
+ function nodeModulesDirForPackageRoot(packageRoot) {
13989
+ const parent = (0, import_node_path38.dirname)(packageRoot);
13990
+ return (0, import_node_path38.basename)(parent).startsWith("@") ? (0, import_node_path38.dirname)(parent) : parent;
13991
+ }
13992
+ function cursorSdkRipgrepCandidate(opts) {
13993
+ const root = resolveCursorSdkRoot(opts);
13994
+ if (!root) return null;
13995
+ const nm = nodeModulesDirForPackageRoot(root);
13996
+ const pkg = cursorSdkPlatformRipgrepPackage();
13997
+ const bin = process.platform === "win32" ? "rg.exe" : "rg";
13998
+ const sibling = (0, import_node_path38.join)(nm, pkg, "bin", bin);
13999
+ if ((0, import_node_fs36.existsSync)(sibling)) return sibling;
14000
+ const nested = (0, import_node_path38.join)(root, "node_modules", pkg, "bin", bin);
14001
+ return (0, import_node_fs36.existsSync)(nested) ? nested : null;
14002
+ }
14003
+ var import_node_fs36, import_node_module2, import_node_path38, import_node_url2, import_meta2, CURSOR_SDK_INSTALL_HINT;
14004
+ var init_cursor_sdk_resolve = __esm({
14005
+ "src/agents/cursor-sdk-resolve.ts"() {
14006
+ "use strict";
14007
+ import_node_fs36 = require("fs");
14008
+ import_node_module2 = require("module");
14009
+ import_node_path38 = require("path");
14010
+ import_node_url2 = require("url");
14011
+ init_path();
14012
+ import_meta2 = {};
14013
+ 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.";
14014
+ }
14015
+ });
14016
+
13914
14017
  // src/agents/cursor-events.ts
13915
14018
  function usageFromCursor(usage) {
13916
14019
  if (!usage) return null;
@@ -14137,21 +14240,21 @@ function platformRipgrepPackage() {
14137
14240
  }
14138
14241
  function usableRipgrepPath(candidate) {
14139
14242
  const raw = candidate?.trim();
14140
- if (!raw || !(0, import_node_path38.isAbsolute)(raw)) return null;
14243
+ if (!raw || !(0, import_node_path39.isAbsolute)(raw)) return null;
14141
14244
  const readable = nodeReadableScriptPath(raw);
14142
- if (!(0, import_node_fs36.existsSync)(readable) || isAsarPath(readable)) return null;
14245
+ if (!(0, import_node_fs37.existsSync)(readable) || isAsarPath(readable)) return null;
14143
14246
  return readable;
14144
14247
  }
14145
14248
  function walkForBundledRipgrep(startFile) {
14146
14249
  if (!startFile) return null;
14147
14250
  const pkg = platformRipgrepPackage();
14148
14251
  const name = rgBinaryName();
14149
- let dir = (0, import_node_path38.dirname)((0, import_node_path38.resolve)(startFile));
14150
- const root = (0, import_node_path38.parse)(dir).root;
14252
+ let dir = (0, import_node_path39.dirname)((0, import_node_path39.resolve)(startFile));
14253
+ const root = (0, import_node_path39.parse)(dir).root;
14151
14254
  while (dir !== root) {
14152
- const hit = usableRipgrepPath((0, import_node_path38.join)(dir, "node_modules", pkg, "bin", name));
14255
+ const hit = usableRipgrepPath((0, import_node_path39.join)(dir, "node_modules", pkg, "bin", name));
14153
14256
  if (hit) return hit;
14154
- const next = (0, import_node_path38.dirname)(dir);
14257
+ const next = (0, import_node_path39.dirname)(dir);
14155
14258
  if (next === dir) break;
14156
14259
  dir = next;
14157
14260
  }
@@ -14159,9 +14262,9 @@ function walkForBundledRipgrep(startFile) {
14159
14262
  }
14160
14263
  function requireResolveBundledRipgrep(fromFile) {
14161
14264
  try {
14162
- const req = (0, import_node_module2.createRequire)(fromFile);
14265
+ const req = (0, import_node_module3.createRequire)(fromFile);
14163
14266
  const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
14164
- return usableRipgrepPath((0, import_node_path38.join)((0, import_node_path38.dirname)(pkgJson), "bin", rgBinaryName()));
14267
+ return usableRipgrepPath((0, import_node_path39.join)((0, import_node_path39.dirname)(pkgJson), "bin", rgBinaryName()));
14165
14268
  } catch {
14166
14269
  return null;
14167
14270
  }
@@ -14177,19 +14280,20 @@ function resolveCursorRipgrepPath(opts) {
14177
14280
  const start = opts?.startFile?.trim() || process.argv[1] || // CJS bundle only — ESM has no __filename; argv[1] is the running script.
14178
14281
  // eslint-disable-next-line camelcase
14179
14282
  (typeof __filename !== "undefined" ? __filename : "");
14180
- return walkForBundledRipgrep(start) ?? requireResolveBundledRipgrep(start);
14283
+ return walkForBundledRipgrep(start) ?? usableRipgrepPath(cursorSdkRipgrepCandidate({ env })) ?? requireResolveBundledRipgrep(start);
14181
14284
  }
14182
14285
  function cursorRipgrepEnv(opts) {
14183
14286
  const path2 = resolveCursorRipgrepPath(opts);
14184
14287
  return path2 ? { [RIPGREP_ENV]: path2 } : {};
14185
14288
  }
14186
- var import_node_fs36, import_node_module2, import_node_path38, RIPGREP_ENV;
14289
+ var import_node_fs37, import_node_module3, import_node_path39, RIPGREP_ENV;
14187
14290
  var init_cursor_ripgrep = __esm({
14188
14291
  "src/agents/cursor-ripgrep.ts"() {
14189
14292
  "use strict";
14190
- import_node_fs36 = require("fs");
14191
- import_node_module2 = require("module");
14192
- import_node_path38 = require("path");
14293
+ import_node_fs37 = require("fs");
14294
+ import_node_module3 = require("module");
14295
+ import_node_path39 = require("path");
14296
+ init_cursor_sdk_resolve();
14193
14297
  init_node_launch();
14194
14298
  init_packaged_runtime();
14195
14299
  RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
@@ -14220,8 +14324,10 @@ async function listCursorModels() {
14220
14324
  }
14221
14325
  const apiKey = resolveCursorApiKey();
14222
14326
  if (!apiKey) return FALLBACK_CURSOR_MODELS;
14327
+ const sdk = await importCursorSdk();
14328
+ if (!sdk) return FALLBACK_CURSOR_MODELS;
14223
14329
  try {
14224
- const listed = await import_sdk.Cursor.models.list({ apiKey });
14330
+ const listed = await sdk.Cursor.models.list({ apiKey });
14225
14331
  const models = listed.map((m) => ({
14226
14332
  id: m.id,
14227
14333
  displayName: m.displayName || m.id,
@@ -14238,11 +14344,11 @@ function entryDir() {
14238
14344
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
14239
14345
  if (cjsDir) return cjsDir;
14240
14346
  try {
14241
- return (0, import_node_path39.dirname)((0, import_node_url2.fileURLToPath)(import_meta2.url));
14347
+ return (0, import_node_path40.dirname)((0, import_node_url3.fileURLToPath)(import_meta3.url));
14242
14348
  } catch {
14243
14349
  try {
14244
- const req = (0, import_node_module3.createRequire)(process.cwd() + "/");
14245
- return (0, import_node_path39.dirname)(req.resolve("@sideboard-ai/core"));
14350
+ const req = (0, import_node_module4.createRequire)(process.cwd() + "/");
14351
+ return (0, import_node_path40.dirname)(req.resolve("@sideboard-ai/core"));
14246
14352
  } catch {
14247
14353
  return process.cwd();
14248
14354
  }
@@ -14253,32 +14359,32 @@ function cursorRunnerPath() {
14253
14359
  if (packaged) return packaged;
14254
14360
  const root = entryDir();
14255
14361
  const candidates = [
14256
- (0, import_node_path39.join)(root, "agents", "cursor-runner.js"),
14257
- (0, import_node_path39.join)(root, "agents", "cursor-runner.cjs"),
14362
+ (0, import_node_path40.join)(root, "agents", "cursor-runner.js"),
14363
+ (0, import_node_path40.join)(root, "agents", "cursor-runner.cjs"),
14258
14364
  // If somehow resolved from package root instead of dist/
14259
- (0, import_node_path39.join)(root, "dist", "agents", "cursor-runner.js"),
14260
- (0, import_node_path39.join)(root, "dist", "agents", "cursor-runner.cjs"),
14365
+ (0, import_node_path40.join)(root, "dist", "agents", "cursor-runner.js"),
14366
+ (0, import_node_path40.join)(root, "dist", "agents", "cursor-runner.cjs"),
14261
14367
  // Source tree (dev): packages/core/src/agents/cursor-runner.ts
14262
- (0, import_node_path39.join)(root, "cursor-runner.ts"),
14263
- (0, import_node_path39.join)(root, "src", "agents", "cursor-runner.ts")
14368
+ (0, import_node_path40.join)(root, "cursor-runner.ts"),
14369
+ (0, import_node_path40.join)(root, "src", "agents", "cursor-runner.ts")
14264
14370
  ];
14265
14371
  for (const candidate of candidates) {
14266
- if ((0, import_node_fs37.existsSync)(candidate)) return candidate;
14372
+ if ((0, import_node_fs38.existsSync)(candidate)) return candidate;
14267
14373
  }
14268
14374
  return candidates[0];
14269
14375
  }
14270
- var import_node_fs37, import_node_module3, import_node_path39, import_node_url2, import_sdk, import_meta2, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
14376
+ var import_node_fs38, import_node_module4, import_node_path40, import_node_url3, import_meta3, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
14271
14377
  var init_cursor = __esm({
14272
14378
  "src/agents/cursor.ts"() {
14273
14379
  "use strict";
14274
- import_node_fs37 = require("fs");
14275
- import_node_module3 = require("module");
14276
- import_node_path39 = require("path");
14277
- import_node_url2 = require("url");
14278
- import_sdk = require("@cursor/sdk");
14380
+ import_node_fs38 = require("fs");
14381
+ import_node_module4 = require("module");
14382
+ import_node_path40 = require("path");
14383
+ import_node_url3 = require("url");
14279
14384
  init_run();
14280
14385
  init_app_settings();
14281
14386
  init_global_workspace();
14387
+ init_cursor_sdk_resolve();
14282
14388
  init_cursor_events();
14283
14389
  init_injected_mcp();
14284
14390
  init_cursor_ripgrep();
@@ -14286,7 +14392,7 @@ var init_cursor = __esm({
14286
14392
  init_packaged_runtime();
14287
14393
  init_turn_input();
14288
14394
  init_cursor_events();
14289
- import_meta2 = {};
14395
+ import_meta3 = {};
14290
14396
  FALLBACK_CURSOR_MODELS = [
14291
14397
  { id: "default", displayName: "Auto" },
14292
14398
  { id: "composer-2.5", displayName: "Composer 2.5" },
@@ -14297,6 +14403,16 @@ var init_cursor = __esm({
14297
14403
  cursorAdapter = {
14298
14404
  kind: "cursor",
14299
14405
  async detect() {
14406
+ if (!isCursorSdkInstalled()) {
14407
+ return {
14408
+ agent: "cursor",
14409
+ installed: false,
14410
+ authenticated: false,
14411
+ linearMcp: false,
14412
+ warnings: [],
14413
+ reason: CURSOR_SDK_INSTALL_HINT
14414
+ };
14415
+ }
14300
14416
  const apiKey = resolveCursorApiKey();
14301
14417
  if (!apiKey) {
14302
14418
  return {
@@ -14425,7 +14541,7 @@ async function listOpencodeModels() {
14425
14541
  if (opencode === "opencode") {
14426
14542
  const which = await run("which", ["opencode"], { reject: false });
14427
14543
  if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
14428
- } else if (!(0, import_node_fs38.existsSync)(opencode)) {
14544
+ } else if (!(0, import_node_fs39.existsSync)(opencode)) {
14429
14545
  return FALLBACK_OPENCODE_MODELS;
14430
14546
  }
14431
14547
  const listed = await run(opencode, ["models"], { reject: false });
@@ -14455,11 +14571,11 @@ function usageFromOpencode(tokens) {
14455
14571
  cacheWriteTokens: tokens.cache?.write ? Number(tokens.cache.write) : void 0
14456
14572
  };
14457
14573
  }
14458
- var import_node_fs38, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
14574
+ var import_node_fs39, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
14459
14575
  var init_opencode = __esm({
14460
14576
  "src/agents/opencode.ts"() {
14461
14577
  "use strict";
14462
- import_node_fs38 = require("fs");
14578
+ import_node_fs39 = require("fs");
14463
14579
  init_run();
14464
14580
  init_app_settings();
14465
14581
  init_global_workspace();
@@ -14487,7 +14603,7 @@ var init_opencode = __esm({
14487
14603
  async detect() {
14488
14604
  const opencode = resolveAgentExecutable("opencode");
14489
14605
  if (opencode !== "opencode") {
14490
- if (!(0, import_node_fs38.existsSync)(opencode)) {
14606
+ if (!(0, import_node_fs39.existsSync)(opencode)) {
14491
14607
  return {
14492
14608
  agent: "opencode",
14493
14609
  installed: false,
@@ -15206,14 +15322,14 @@ function accessTokenFromCredentialsJson(raw) {
15206
15322
  }
15207
15323
  }
15208
15324
  function claudeCredentialsPath() {
15209
- const root = process.env.CLAUDE_CONFIG_DIR?.trim() || (0, import_node_path40.join)((0, import_node_os13.homedir)(), ".claude");
15210
- return (0, import_node_path40.join)(root, ".credentials.json");
15325
+ const root = process.env.CLAUDE_CONFIG_DIR?.trim() || (0, import_node_path41.join)((0, import_node_os13.homedir)(), ".claude");
15326
+ return (0, import_node_path41.join)(root, ".credentials.json");
15211
15327
  }
15212
15328
  async function readFileAccessToken() {
15213
15329
  const path2 = claudeCredentialsPath();
15214
- if (!(0, import_node_fs39.existsSync)(path2)) return null;
15330
+ if (!(0, import_node_fs40.existsSync)(path2)) return null;
15215
15331
  try {
15216
- return accessTokenFromCredentialsJson((0, import_node_fs39.readFileSync)(path2, "utf8"));
15332
+ return accessTokenFromCredentialsJson((0, import_node_fs40.readFileSync)(path2, "utf8"));
15217
15333
  } catch {
15218
15334
  return null;
15219
15335
  }
@@ -15317,13 +15433,13 @@ async function getClaudePlanUsage(opts = {}) {
15317
15433
  })();
15318
15434
  return inflight;
15319
15435
  }
15320
- var import_node_fs39, import_node_os13, import_node_path40, CLAUDE_OAUTH_USAGE_URL, CLAUDE_USAGE_TTL_MS, CLAUDE_USAGE_ERROR_TTL_MS, CLAUDE_USAGE_STALE_OK_MS, KEYCHAIN_SERVICES, cache, errorUntil, inflight, lastGood, claudeVersion;
15436
+ var import_node_fs40, import_node_os13, import_node_path41, CLAUDE_OAUTH_USAGE_URL, CLAUDE_USAGE_TTL_MS, CLAUDE_USAGE_ERROR_TTL_MS, CLAUDE_USAGE_STALE_OK_MS, KEYCHAIN_SERVICES, cache, errorUntil, inflight, lastGood, claudeVersion;
15321
15437
  var init_claude_usage_client = __esm({
15322
15438
  "src/agents/claude-usage-client.ts"() {
15323
15439
  "use strict";
15324
- import_node_fs39 = require("fs");
15440
+ import_node_fs40 = require("fs");
15325
15441
  import_node_os13 = require("os");
15326
- import_node_path40 = require("path");
15442
+ import_node_path41 = require("path");
15327
15443
  init_run();
15328
15444
  init_fetch();
15329
15445
  init_app_settings();
@@ -15419,16 +15535,6 @@ async function whichOnPath(bin) {
15419
15535
  }
15420
15536
  async function installNpmGlobalPackage(opts) {
15421
15537
  enrichPathWithNpmGlobalBin();
15422
- if (opts.cliBin) {
15423
- const existing = await whichOnPath(opts.cliBin);
15424
- if (existing) {
15425
- return {
15426
- ok: true,
15427
- command: existing,
15428
- message: isConductorBundledCli(existing) ? `Using Conductor\u2019s ${opts.cliBin} at ${existing}. No extra install \u2014 Log in only if auth is missing.` : `Already on PATH: ${existing}`
15429
- };
15430
- }
15431
- }
15432
15538
  const result = await run("npm", ["install", "-g", opts.npmPackage], { reject: false });
15433
15539
  const ok = result.exitCode === 0;
15434
15540
  if (!ok) {
@@ -15465,6 +15571,33 @@ async function installNpmGlobalPackage(opts) {
15465
15571
  message: binPath ? `Installed ${opts.npmPackage} \u2192 ${binPath}` : `Installed ${opts.npmPackage} (CLI not yet on PATH)`
15466
15572
  };
15467
15573
  }
15574
+ async function resolveExistingCli(agent) {
15575
+ if (agent === "cursor") return null;
15576
+ const exe = resolveAgentExecutable(agent);
15577
+ if ((exe.includes("/") || exe.includes("\\")) && (0, import_node_fs41.existsSync)(exe)) return exe;
15578
+ enrichPathWithNpmGlobalBin();
15579
+ return whichOnPath(CLI_BIN[agent]);
15580
+ }
15581
+ async function runVendorUpdate(existing, updateArgs) {
15582
+ const result = await run(existing, updateArgs, {
15583
+ reject: false,
15584
+ timeoutMs: 12e4
15585
+ });
15586
+ const command = `${existing} ${updateArgs.join(" ")}`;
15587
+ const ok = result.exitCode === 0;
15588
+ const detail = result.stdout.trim() || result.stderr.trim() || `exit ${result.exitCode}`;
15589
+ return {
15590
+ ok,
15591
+ command,
15592
+ exitCode: result.exitCode,
15593
+ stdout: result.stdout,
15594
+ stderr: result.stderr,
15595
+ message: ok ? isConductorBundledCli(existing) ? `Updated Conductor\u2019s CLI at ${existing}. ${detail}` : `Updated ${command}. ${detail}` : `Update failed (${command}): ${detail}`
15596
+ };
15597
+ }
15598
+ function isCurlInstaller(command) {
15599
+ return /curl\s| \|\s*bash/.test(command);
15600
+ }
15468
15601
  async function installAgent(agent) {
15469
15602
  const info = getAgentSetupInfo(agent);
15470
15603
  if (info.kind === "bundled-sdk" || info.kind === "api-key") {
@@ -15476,21 +15609,25 @@ async function installAgent(agent) {
15476
15609
  if (!info.installCommand) {
15477
15610
  return { ok: false, message: `No install command for ${agent}` };
15478
15611
  }
15479
- if (/curl\s| \|\s*bash/.test(info.installCommand) || !info.npmPackage) {
15480
- await openInSystemTerminal(info.installCommand);
15481
- return {
15482
- ok: true,
15483
- openedTerminal: true,
15484
- command: info.installCommand,
15485
- message: `Opened Terminal to run: ${info.installCommand}`
15486
- };
15612
+ const existing = await resolveExistingCli(agent);
15613
+ if (existing && info.updateArgs?.length) {
15614
+ return runVendorUpdate(existing, info.updateArgs);
15487
15615
  }
15488
- const cliBin = agent === "cursor" ? null : CLI_BIN[agent];
15489
- return installNpmGlobalPackage({
15490
- npmPackage: info.npmPackage,
15491
- installCommand: info.installCommand,
15492
- cliBin
15493
- });
15616
+ if (info.npmPackage && !isCurlInstaller(info.installCommand)) {
15617
+ const cliBin = agent === "cursor" ? null : CLI_BIN[agent];
15618
+ return installNpmGlobalPackage({
15619
+ npmPackage: info.npmPackage,
15620
+ installCommand: info.installCommand,
15621
+ cliBin
15622
+ });
15623
+ }
15624
+ await openInSystemTerminal(info.installCommand);
15625
+ return {
15626
+ ok: true,
15627
+ openedTerminal: true,
15628
+ command: info.installCommand,
15629
+ message: `Opened Terminal to run: ${info.installCommand}`
15630
+ };
15494
15631
  }
15495
15632
  async function loginAgent(agent) {
15496
15633
  const info = getAgentSetupInfo(agent);
@@ -15510,10 +15647,11 @@ async function loginAgent(agent) {
15510
15647
  message: `Opened Terminal to run: ${prepared}`
15511
15648
  };
15512
15649
  }
15513
- var SETUP, CLI_BIN, CLI_LOGIN_AGENTS;
15650
+ var import_node_fs41, SETUP, CLI_BIN, CLI_LOGIN_AGENTS;
15514
15651
  var init_install = __esm({
15515
15652
  "src/agents/install.ts"() {
15516
15653
  "use strict";
15654
+ import_node_fs41 = require("fs");
15517
15655
  init_run();
15518
15656
  init_app_settings();
15519
15657
  init_path();
@@ -15525,7 +15663,8 @@ var init_install = __esm({
15525
15663
  docsUrl: "https://code.claude.com/docs/en/install",
15526
15664
  installCommand: "npm install -g @anthropic-ai/claude-code",
15527
15665
  loginCommand: "claude auth login",
15528
- npmPackage: "@anthropic-ai/claude-code"
15666
+ npmPackage: "@anthropic-ai/claude-code",
15667
+ updateArgs: ["update"]
15529
15668
  },
15530
15669
  codex: {
15531
15670
  agent: "codex",
@@ -15534,7 +15673,8 @@ var init_install = __esm({
15534
15673
  docsUrl: "https://github.com/openai/codex",
15535
15674
  installCommand: "npm install -g @openai/codex",
15536
15675
  loginCommand: "codex login",
15537
- npmPackage: "@openai/codex"
15676
+ npmPackage: "@openai/codex",
15677
+ updateArgs: ["update"]
15538
15678
  },
15539
15679
  opencode: {
15540
15680
  agent: "opencode",
@@ -15544,20 +15684,22 @@ var init_install = __esm({
15544
15684
  // Prefer the official installer; npm package name is opencode-ai.
15545
15685
  installCommand: "curl -fsSL https://opencode.ai/install | bash",
15546
15686
  loginCommand: "opencode auth login",
15547
- npmPackage: "opencode-ai@latest"
15687
+ npmPackage: "opencode-ai@latest",
15688
+ updateArgs: ["upgrade"]
15548
15689
  },
15549
15690
  cursor: {
15550
15691
  agent: "cursor",
15551
- kind: "bundled-sdk",
15552
- summary: "No CLI install \u2014 Sideboard ships the Cursor SDK. Add a CURSOR_API_KEY from the Cursor dashboard.",
15553
- docsUrl: "https://cursor.com/dashboard/integrations",
15554
- installCommand: null,
15555
- loginCommand: null
15692
+ kind: "cli",
15693
+ summary: "Install (or update) @cursor/sdk with npm \u2014 Sideboard does not pin it in the app. Then add a CURSOR_API_KEY.",
15694
+ docsUrl: "https://www.npmjs.com/package/@cursor/sdk",
15695
+ installCommand: "npm install -g @cursor/sdk",
15696
+ loginCommand: null,
15697
+ npmPackage: "@cursor/sdk"
15556
15698
  },
15557
15699
  brightsy: {
15558
15700
  agent: "brightsy",
15559
15701
  kind: "cli",
15560
- summary: "Install the Brightsy CLI, then run `brightsy login`.",
15702
+ summary: "Install (or update) the Brightsy CLI with npm, then run `brightsy login`.",
15561
15703
  docsUrl: "https://www.npmjs.com/package/@brightsy/cli",
15562
15704
  installCommand: "npm install -g @brightsy/cli",
15563
15705
  loginCommand: "brightsy login",
@@ -15583,6 +15725,7 @@ var init_install = __esm({
15583
15725
  var agents_exports = {};
15584
15726
  __export(agents_exports, {
15585
15727
  CLAUDE_MODEL_CATALOG: () => CLAUDE_MODEL_CATALOG,
15728
+ CURSOR_SDK_INSTALL_HINT: () => CURSOR_SDK_INSTALL_HINT,
15586
15729
  ORCHESTRATOR_AGENT_KINDS: () => ORCHESTRATOR_AGENT_KINDS,
15587
15730
  PLAN_MODE_INSTRUCTION: () => PLAN_MODE_INSTRUCTION,
15588
15731
  allAdapters: () => allAdapters,
@@ -15616,6 +15759,7 @@ __export(agents_exports, {
15616
15759
  isConductorBundledCli: () => isConductorBundledCli,
15617
15760
  isCursorApiKeyConfigured: () => isCursorApiKeyConfigured,
15618
15761
  isCursorAutoModel: () => isCursorAutoModel,
15762
+ isCursorSdkInstalled: () => isCursorSdkInstalled,
15619
15763
  isOrchestratorCapableAgent: () => isOrchestratorCapableAgent,
15620
15764
  isSessionQuotaLimit: () => isSessionQuotaLimit,
15621
15765
  listAgentSetupInfo: () => listAgentSetupInfo,
@@ -15626,6 +15770,8 @@ __export(agents_exports, {
15626
15770
  listOpencodeModels: () => listOpencodeModels,
15627
15771
  loginAgent: () => loginAgent,
15628
15772
  mcpStatusThinkingFromClaudeInit: () => mcpStatusThinkingFromClaudeInit,
15773
+ npmGlobalNodeModules: () => npmGlobalNodeModules,
15774
+ npmGlobalPrefix: () => npmGlobalPrefix,
15629
15775
  openInSystemTerminal: () => openInSystemTerminal,
15630
15776
  opencodeAdapter: () => opencodeAdapter,
15631
15777
  parseClaudeUsagePayload: () => parseClaudeUsagePayload,
@@ -15637,6 +15783,7 @@ __export(agents_exports, {
15637
15783
  prepareTerminalCommand: () => prepareTerminalCommand,
15638
15784
  resolveCommandBinarySync: () => resolveCommandBinarySync,
15639
15785
  resolveCursorModelId: () => resolveCursorModelId,
15786
+ resolveCursorSdkRoot: () => resolveCursorSdkRoot,
15640
15787
  resolveLoginCommand: () => resolveLoginCommand,
15641
15788
  resolveQuotaFallbackAgent: () => resolveQuotaFallbackAgent,
15642
15789
  turnCostUsdFromCursorUsage: () => turnCostUsdFromCursorUsage,
@@ -15673,6 +15820,7 @@ var init_agents = __esm({
15673
15820
  init_claude_usage_client();
15674
15821
  init_orchestrator_capable();
15675
15822
  init_path();
15823
+ init_cursor_sdk_resolve();
15676
15824
  init_install();
15677
15825
  adapters = {
15678
15826
  claude: claudeAdapter,
@@ -15691,7 +15839,7 @@ function isAgentHostEnvKey(key) {
15691
15839
  }
15692
15840
  function stripHostToolingPath(pathValue) {
15693
15841
  if (!pathValue?.trim()) return "";
15694
- return pathValue.split(import_node_path41.delimiter).filter((part) => part && !HOST_PATH_NOISE.test(part.replace(/\\/g, "/"))).join(import_node_path41.delimiter);
15842
+ return pathValue.split(import_node_path42.delimiter).filter((part) => part && !HOST_PATH_NOISE.test(part.replace(/\\/g, "/"))).join(import_node_path42.delimiter);
15695
15843
  }
15696
15844
  function sanitizeAgentHostEnv(env, cwd) {
15697
15845
  for (const key of Object.keys(env)) {
@@ -15705,11 +15853,11 @@ function sanitizeAgentHostEnv(env, cwd) {
15705
15853
  }
15706
15854
  return env;
15707
15855
  }
15708
- var import_node_path41, DROP_EXACT, DROP_PREFIXES, HOST_PATH_NOISE;
15856
+ var import_node_path42, DROP_EXACT, DROP_PREFIXES, HOST_PATH_NOISE;
15709
15857
  var init_agent_host_env = __esm({
15710
15858
  "src/hook/agent-host-env.ts"() {
15711
15859
  "use strict";
15712
- import_node_path41 = require("path");
15860
+ import_node_path42 = require("path");
15713
15861
  DROP_EXACT = /* @__PURE__ */ new Set([
15714
15862
  "NODE_PATH",
15715
15863
  "NODE_ENV_ELECTRON_VITE",
@@ -15748,15 +15896,15 @@ var init_agent_host_env = __esm({
15748
15896
 
15749
15897
  // src/hook/worktree-pkg-cache.ts
15750
15898
  function worktreePkgCacheRoot(worktreePath) {
15751
- return (0, import_node_path42.join)(worktreePath, WORKTREE_PKG_CACHE_REL);
15899
+ return (0, import_node_path43.join)(worktreePath, WORKTREE_PKG_CACHE_REL);
15752
15900
  }
15753
15901
  function worktreePkgCacheEnv(worktreePath) {
15754
15902
  const root = worktreePkgCacheRoot(worktreePath);
15755
- const store = (0, import_node_path42.join)(root, "pnpm-store");
15756
- const pnpmCache = (0, import_node_path42.join)(root, "pnpm");
15757
- const npmCache = (0, import_node_path42.join)(root, "npm");
15758
- const nodeGyp = (0, import_node_path42.join)(root, "node-gyp");
15759
- const electron = (0, import_node_path42.join)(root, "electron");
15903
+ const store = (0, import_node_path43.join)(root, "pnpm-store");
15904
+ const pnpmCache = (0, import_node_path43.join)(root, "pnpm");
15905
+ const npmCache = (0, import_node_path43.join)(root, "npm");
15906
+ const nodeGyp = (0, import_node_path43.join)(root, "node-gyp");
15907
+ const electron = (0, import_node_path43.join)(root, "electron");
15760
15908
  return {
15761
15909
  npm_config_store_dir: store,
15762
15910
  PNPM_STORE_DIR: store,
@@ -15778,8 +15926,8 @@ function fillGroup(env, keys, values) {
15778
15926
  }
15779
15927
  }
15780
15928
  function ensureWorktreePkgCacheDirs(worktreePath) {
15781
- if (!(0, import_node_fs40.existsSync)(worktreePath)) return;
15782
- (0, import_node_fs40.mkdirSync)(worktreePkgCacheRoot(worktreePath), { recursive: true });
15929
+ if (!(0, import_node_fs42.existsSync)(worktreePath)) return;
15930
+ (0, import_node_fs42.mkdirSync)(worktreePkgCacheRoot(worktreePath), { recursive: true });
15783
15931
  }
15784
15932
  function applyWorktreePkgCacheEnv(env, worktreePath) {
15785
15933
  const cwd = worktreePath.trim();
@@ -15792,12 +15940,12 @@ function applyWorktreePkgCacheEnv(env, worktreePath) {
15792
15940
  fillGroup(env, ["electron_config_cache"], next);
15793
15941
  ensureWorktreePkgCacheDirs(cwd);
15794
15942
  }
15795
- var import_node_fs40, import_node_path42, WORKTREE_PKG_CACHE_REL;
15943
+ var import_node_fs42, import_node_path43, WORKTREE_PKG_CACHE_REL;
15796
15944
  var init_worktree_pkg_cache = __esm({
15797
15945
  "src/hook/worktree-pkg-cache.ts"() {
15798
15946
  "use strict";
15799
- import_node_fs40 = require("fs");
15800
- import_node_path42 = require("path");
15947
+ import_node_fs42 = require("fs");
15948
+ import_node_path43 = require("path");
15801
15949
  WORKTREE_PKG_CACHE_REL = ".context/.sideboard/pkg-cache";
15802
15950
  }
15803
15951
  });
@@ -17038,21 +17186,21 @@ function shouldRefreshReviewRequestTemplate(content) {
17038
17186
  return LEGACY_REVIEW_TEMPLATE_MARKERS.every((m) => trimmed.includes(m));
17039
17187
  }
17040
17188
  function readTextIfPresent(abs) {
17041
- if (!(0, import_node_fs41.existsSync)(abs)) return null;
17189
+ if (!(0, import_node_fs43.existsSync)(abs)) return null;
17042
17190
  try {
17043
- const content = (0, import_node_fs41.readFileSync)(abs, "utf8");
17191
+ const content = (0, import_node_fs43.readFileSync)(abs, "utf8");
17044
17192
  return content.trim() ? content : null;
17045
17193
  } catch {
17046
17194
  return null;
17047
17195
  }
17048
17196
  }
17049
17197
  function readLocalGuidelines(worktreePath) {
17050
- const localAbs = (0, import_node_path43.join)(worktreePath, REVIEW_REQUEST_PATH);
17198
+ const localAbs = (0, import_node_path44.join)(worktreePath, REVIEW_REQUEST_PATH);
17051
17199
  const localContent = readTextIfPresent(localAbs);
17052
17200
  if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
17053
17201
  return { path: REVIEW_REQUEST_PATH, content: localContent };
17054
17202
  }
17055
- const legacyAbs = (0, import_node_path43.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
17203
+ const legacyAbs = (0, import_node_path44.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
17056
17204
  const legacyContent = readTextIfPresent(legacyAbs);
17057
17205
  if (legacyContent && !shouldRefreshReviewRequestTemplate(legacyContent)) {
17058
17206
  return { path: LEGACY_REVIEW_REQUEST_PATH, content: legacyContent };
@@ -17076,27 +17224,27 @@ function contextGuidelines(content, source) {
17076
17224
  };
17077
17225
  }
17078
17226
  function writeContextGuidelines(worktreePath, content) {
17079
- const abs = (0, import_node_path43.join)(worktreePath, CONTEXT_REVIEW_PATH);
17080
- (0, import_node_fs41.mkdirSync)((0, import_node_path43.dirname)(abs), { recursive: true });
17227
+ const abs = (0, import_node_path44.join)(worktreePath, CONTEXT_REVIEW_PATH);
17228
+ (0, import_node_fs43.mkdirSync)((0, import_node_path44.dirname)(abs), { recursive: true });
17081
17229
  const body = content.endsWith("\n") ? content : `${content}
17082
17230
  `;
17083
- (0, import_node_fs41.writeFileSync)(abs, body, "utf8");
17231
+ (0, import_node_fs43.writeFileSync)(abs, body, "utf8");
17084
17232
  return body;
17085
17233
  }
17086
17234
  function readSideboardReview(worktreePath, repoPath) {
17087
- const fromWorktree = readTextIfPresent((0, import_node_path43.join)(worktreePath, REPO_REVIEW_PATH));
17235
+ const fromWorktree = readTextIfPresent((0, import_node_path44.join)(worktreePath, REPO_REVIEW_PATH));
17088
17236
  if (fromWorktree) return fromWorktree;
17089
17237
  const repo = repoPath?.replace(/\/+$/, "");
17090
17238
  const wt = worktreePath.replace(/\/+$/, "");
17091
17239
  if (!repo || repo === wt) return null;
17092
- return readTextIfPresent((0, import_node_path43.join)(repo, REPO_REVIEW_PATH));
17240
+ return readTextIfPresent((0, import_node_path44.join)(repo, REPO_REVIEW_PATH));
17093
17241
  }
17094
17242
  function ensureReviewGuidelinesFile(worktreePath, repoPath) {
17095
- const skillContent = readTextIfPresent((0, import_node_path43.join)(worktreePath, REVIEW_SKILL_PATH));
17243
+ const skillContent = readTextIfPresent((0, import_node_path44.join)(worktreePath, REVIEW_SKILL_PATH));
17096
17244
  if (skillContent) {
17097
17245
  return { ...skillGuidelines(skillContent, "skill"), wrote: false };
17098
17246
  }
17099
- const contextContent = readTextIfPresent((0, import_node_path43.join)(worktreePath, CONTEXT_REVIEW_PATH));
17247
+ const contextContent = readTextIfPresent((0, import_node_path44.join)(worktreePath, CONTEXT_REVIEW_PATH));
17100
17248
  if (contextContent && !shouldRefreshReviewRequestTemplate(contextContent)) {
17101
17249
  return { ...contextGuidelines(contextContent, "local"), wrote: false };
17102
17250
  }
@@ -17134,7 +17282,7 @@ function buildReviewRequestAttachment(content, opts) {
17134
17282
  };
17135
17283
  }
17136
17284
  function readExistingReviewRequestFile(worktreePath) {
17137
- return readTextIfPresent((0, import_node_path43.join)(worktreePath, REVIEW_SKILL_PATH)) ?? readTextIfPresent((0, import_node_path43.join)(worktreePath, CONTEXT_REVIEW_PATH)) ?? readTextIfPresent((0, import_node_path43.join)(worktreePath, REPO_REVIEW_PATH)) ?? readTextIfPresent((0, import_node_path43.join)(worktreePath, REVIEW_REQUEST_PATH)) ?? readTextIfPresent((0, import_node_path43.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH));
17285
+ return readTextIfPresent((0, import_node_path44.join)(worktreePath, REVIEW_SKILL_PATH)) ?? readTextIfPresent((0, import_node_path44.join)(worktreePath, CONTEXT_REVIEW_PATH)) ?? readTextIfPresent((0, import_node_path44.join)(worktreePath, REPO_REVIEW_PATH)) ?? readTextIfPresent((0, import_node_path44.join)(worktreePath, REVIEW_REQUEST_PATH)) ?? readTextIfPresent((0, import_node_path44.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH));
17138
17286
  }
17139
17287
  async function requestReview(threadRef, send2) {
17140
17288
  const from = findThreadByRef(threadRef);
@@ -17161,13 +17309,13 @@ async function requestReview(threadRef, send2) {
17161
17309
  const started = await send2(tab.id, REVIEW_REQUEST_PREFILL);
17162
17310
  return { tab: started, from };
17163
17311
  }
17164
- var import_node_crypto9, import_node_fs41, import_node_path43, REPO_REVIEW_PATH, REPO_REVIEW_NAME, CONTEXT_REVIEW_PATH, REVIEW_REQUEST_PATH, LEGACY_REVIEW_REQUEST_PATH, REVIEW_REQUEST_NAME, REVIEW_REQUEST_PREFILL, LEGACY_REVIEW_TEMPLATE_MARKERS;
17312
+ var import_node_crypto9, import_node_fs43, import_node_path44, REPO_REVIEW_PATH, REPO_REVIEW_NAME, CONTEXT_REVIEW_PATH, REVIEW_REQUEST_PATH, LEGACY_REVIEW_REQUEST_PATH, REVIEW_REQUEST_NAME, REVIEW_REQUEST_PREFILL, LEGACY_REVIEW_TEMPLATE_MARKERS;
17165
17313
  var init_request_review = __esm({
17166
17314
  "src/review/request-review.ts"() {
17167
17315
  "use strict";
17168
17316
  import_node_crypto9 = require("crypto");
17169
- import_node_fs41 = require("fs");
17170
- import_node_path43 = require("path");
17317
+ import_node_fs43 = require("fs");
17318
+ import_node_path44 = require("path");
17171
17319
  init_global_workspace();
17172
17320
  init_chat_tabs();
17173
17321
  init_thread_store();
@@ -17193,9 +17341,9 @@ function matchSimpleGlob(pattern, name) {
17193
17341
  return new RegExp(`^${escaped}$`).test(name);
17194
17342
  }
17195
17343
  function readWorktreeInclude(repoPath) {
17196
- const path2 = (0, import_node_path44.join)(repoPath, ".worktreeinclude");
17197
- if (!(0, import_node_fs42.existsSync)(path2)) return [];
17198
- return (0, import_node_fs42.readFileSync)(path2, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
17344
+ const path2 = (0, import_node_path45.join)(repoPath, ".worktreeinclude");
17345
+ if (!(0, import_node_fs44.existsSync)(path2)) return [];
17346
+ return (0, import_node_fs44.readFileSync)(path2, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
17199
17347
  }
17200
17348
  function resolveFilesToCopy(repoPath) {
17201
17349
  const fromInclude = readWorktreeInclude(repoPath);
@@ -17205,10 +17353,10 @@ function resolveFilesToCopy(repoPath) {
17205
17353
  if (settings?.fileIncludeGlobs?.length) {
17206
17354
  const matched = [];
17207
17355
  try {
17208
- for (const entry of (0, import_node_fs42.readdirSync)(repoPath, { withFileTypes: true })) {
17356
+ for (const entry of (0, import_node_fs44.readdirSync)(repoPath, { withFileTypes: true })) {
17209
17357
  if (!entry.isFile()) continue;
17210
17358
  for (const glob of settings.fileIncludeGlobs) {
17211
- if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path44.basename)(glob), entry.name)) {
17359
+ if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path45.basename)(glob), entry.name)) {
17212
17360
  matched.push(entry.name);
17213
17361
  break;
17214
17362
  }
@@ -17220,7 +17368,7 @@ function resolveFilesToCopy(repoPath) {
17220
17368
  }
17221
17369
  const defaults = [];
17222
17370
  try {
17223
- for (const entry of (0, import_node_fs42.readdirSync)(repoPath, { withFileTypes: true })) {
17371
+ for (const entry of (0, import_node_fs44.readdirSync)(repoPath, { withFileTypes: true })) {
17224
17372
  if (entry.isFile() && entry.name.startsWith(".env")) {
17225
17373
  defaults.push(entry.name);
17226
17374
  }
@@ -17234,11 +17382,11 @@ function copyConfiguredFiles(repoPath, worktreePath) {
17234
17382
  const patterns = resolveFilesToCopy(repoPath);
17235
17383
  const copied = [];
17236
17384
  for (const rel of patterns) {
17237
- const src = (0, import_node_path44.join)(repoPath, rel);
17238
- if (!(0, import_node_fs42.existsSync)(src)) continue;
17239
- const dest = (0, import_node_path44.join)(worktreePath, rel);
17240
- (0, import_node_fs42.mkdirSync)((0, import_node_path44.dirname)(dest), { recursive: true });
17241
- (0, import_node_fs42.copyFileSync)(src, dest);
17385
+ const src = (0, import_node_path45.join)(repoPath, rel);
17386
+ if (!(0, import_node_fs44.existsSync)(src)) continue;
17387
+ const dest = (0, import_node_path45.join)(worktreePath, rel);
17388
+ (0, import_node_fs44.mkdirSync)((0, import_node_path45.dirname)(dest), { recursive: true });
17389
+ (0, import_node_fs44.copyFileSync)(src, dest);
17242
17390
  copied.push(rel);
17243
17391
  }
17244
17392
  return copied;
@@ -17273,7 +17421,7 @@ function buildWorkspaceScriptEnv(opts, baseEnv) {
17273
17421
  const env = stripNestedElectronEnv({
17274
17422
  ...baseEnv ?? process.env
17275
17423
  });
17276
- const name = opts.workspaceName ?? (0, import_node_path44.basename)(opts.worktreePath);
17424
+ const name = opts.workspaceName ?? (0, import_node_path45.basename)(opts.worktreePath);
17277
17425
  const ports = opts.ports ?? [];
17278
17426
  const primary = ports[0];
17279
17427
  env.SIDEBOARD_WORKSPACE_NAME = name;
@@ -17304,7 +17452,17 @@ function pipeLines(stream, onLine) {
17304
17452
  const rl = (0, import_node_readline3.createInterface)({ input: stream });
17305
17453
  rl.on("line", onLine);
17306
17454
  }
17455
+ function killableListenerPids(raw, selfPid = process.pid) {
17456
+ const pids = [];
17457
+ for (const token of raw.trim().split(/\s+/)) {
17458
+ const pid = Number(token);
17459
+ if (!Number.isFinite(pid) || pid <= 0 || pid === selfPid) continue;
17460
+ pids.push(pid);
17461
+ }
17462
+ return pids;
17463
+ }
17307
17464
  function killListenersOnPorts(ports) {
17465
+ const selfPid = process.pid;
17308
17466
  for (const port of ports) {
17309
17467
  if (!Number.isFinite(port) || port <= 0) continue;
17310
17468
  try {
@@ -17314,7 +17472,7 @@ function killListenersOnPorts(ports) {
17314
17472
  [
17315
17473
  "-NoProfile",
17316
17474
  "-Command",
17317
- `Get-NetTCPConnection -LocalPort ${port} -ErrorAction SilentlyContinue | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force -ErrorAction SilentlyContinue }`
17475
+ `Get-NetTCPConnection -LocalPort ${port} -ErrorAction SilentlyContinue | Where-Object { $_.OwningProcess -ne ${selfPid} } | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force -ErrorAction SilentlyContinue }`
17318
17476
  ],
17319
17477
  { stdio: "ignore", timeout: 3e3 }
17320
17478
  );
@@ -17330,9 +17488,7 @@ function killListenersOnPorts(ports) {
17330
17488
  } catch {
17331
17489
  continue;
17332
17490
  }
17333
- for (const token of raw.trim().split(/\s+/)) {
17334
- const pid = Number(token);
17335
- if (!Number.isFinite(pid) || pid <= 0) continue;
17491
+ for (const pid of killableListenerPids(raw, selfPid)) {
17336
17492
  try {
17337
17493
  process.kill(pid, "SIGTERM");
17338
17494
  } catch {
@@ -17385,6 +17541,9 @@ async function spawnWorkspaceScript(command, opts) {
17385
17541
  );
17386
17542
  } catch {
17387
17543
  }
17544
+ if (opts.heldPorts?.length) {
17545
+ await Promise.all(opts.heldPorts.map((h) => h.release()));
17546
+ }
17388
17547
  const shell = process.platform === "darwin" ? "zsh" : "bash";
17389
17548
  const child = (0, import_execa4.execa)(shell, ["-lc", command], {
17390
17549
  cwd: opts.worktreePath,
@@ -17576,11 +17735,11 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
17576
17735
  const held = await reservePortRange(PORT_RANGE_SIZE);
17577
17736
  const ports = held.map((h) => h.port);
17578
17737
  try {
17579
- await Promise.all(held.map((h) => h.release()));
17580
17738
  const handle = await spawnWorkspaceScript(script.command, {
17581
17739
  worktreePath,
17582
17740
  repoPath,
17583
17741
  ports,
17742
+ heldPorts: held,
17584
17743
  defaultBranch: opts?.defaultBranch,
17585
17744
  onLine
17586
17745
  });
@@ -17597,14 +17756,14 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
17597
17756
  throw err;
17598
17757
  }
17599
17758
  }
17600
- var import_node_fs42, import_node_child_process5, import_node_net, import_node_path44, import_execa4, import_node_readline3, PORT_RANGE_SIZE, cachedLoginEnv;
17759
+ var import_node_fs44, import_node_child_process5, import_node_net, import_node_path45, import_execa4, import_node_readline3, PORT_RANGE_SIZE, cachedLoginEnv;
17601
17760
  var init_conductor = __esm({
17602
17761
  "src/hook/conductor.ts"() {
17603
17762
  "use strict";
17604
- import_node_fs42 = require("fs");
17763
+ import_node_fs44 = require("fs");
17605
17764
  import_node_child_process5 = require("child_process");
17606
17765
  import_node_net = require("net");
17607
- import_node_path44 = require("path");
17766
+ import_node_path45 = require("path");
17608
17767
  import_execa4 = require("execa");
17609
17768
  import_node_readline3 = require("readline");
17610
17769
  init_settings();
@@ -17632,9 +17791,9 @@ async function findOrphanWorktrees(repoPaths) {
17632
17791
  repoPaths?.length ? repoPaths : threads.map((t) => t.repoPath).filter(Boolean)
17633
17792
  );
17634
17793
  const homeRoot = sideboardWorkspacesDir();
17635
- if ((0, import_node_fs43.existsSync)(homeRoot)) {
17794
+ if ((0, import_node_fs45.existsSync)(homeRoot)) {
17636
17795
  try {
17637
- for (const entry of (0, import_node_fs43.readdirSync)(homeRoot, { withFileTypes: true })) {
17796
+ for (const entry of (0, import_node_fs45.readdirSync)(homeRoot, { withFileTypes: true })) {
17638
17797
  if (!entry.isDirectory()) continue;
17639
17798
  void entry;
17640
17799
  }
@@ -17644,7 +17803,7 @@ async function findOrphanWorktrees(repoPaths) {
17644
17803
  const orphans = [];
17645
17804
  const seen = /* @__PURE__ */ new Set();
17646
17805
  for (const repoPath of repos) {
17647
- if (!repoPath || !(0, import_node_fs43.existsSync)(repoPath)) continue;
17806
+ if (!repoPath || !(0, import_node_fs45.existsSync)(repoPath)) continue;
17648
17807
  try {
17649
17808
  const wts = await listWorktrees(repoPath);
17650
17809
  for (const wt of wts) {
@@ -17655,7 +17814,7 @@ async function findOrphanWorktrees(repoPaths) {
17655
17814
  seen.add(path2);
17656
17815
  let mtimeMs = 0;
17657
17816
  try {
17658
- mtimeMs = (0, import_node_fs43.statSync)(path2).mtimeMs;
17817
+ mtimeMs = (0, import_node_fs45.statSync)(path2).mtimeMs;
17659
17818
  } catch {
17660
17819
  mtimeMs = 0;
17661
17820
  }
@@ -17665,16 +17824,16 @@ async function findOrphanWorktrees(repoPaths) {
17665
17824
  }
17666
17825
  try {
17667
17826
  const root = worktreesRoot(repoPath);
17668
- if ((0, import_node_fs43.existsSync)(root)) {
17669
- for (const entry of (0, import_node_fs43.readdirSync)(root, { withFileTypes: true })) {
17827
+ if ((0, import_node_fs45.existsSync)(root)) {
17828
+ for (const entry of (0, import_node_fs45.readdirSync)(root, { withFileTypes: true })) {
17670
17829
  if (!entry.isDirectory()) continue;
17671
- const path2 = (0, import_node_path45.join)(root, entry.name).replace(/\/$/, "");
17830
+ const path2 = (0, import_node_path46.join)(root, entry.name).replace(/\/$/, "");
17672
17831
  if (known.has(path2) || seen.has(path2)) continue;
17673
- if (!(0, import_node_fs43.existsSync)((0, import_node_path45.join)(path2, ".git"))) continue;
17832
+ if (!(0, import_node_fs45.existsSync)((0, import_node_path46.join)(path2, ".git"))) continue;
17674
17833
  seen.add(path2);
17675
17834
  let mtimeMs = 0;
17676
17835
  try {
17677
- mtimeMs = (0, import_node_fs43.statSync)(path2).mtimeMs;
17836
+ mtimeMs = (0, import_node_fs45.statSync)(path2).mtimeMs;
17678
17837
  } catch {
17679
17838
  mtimeMs = Date.now();
17680
17839
  }
@@ -17735,12 +17894,12 @@ function worktreeCleanupSettings() {
17735
17894
  autoCleanupOrphans: a.autoCleanupOrphans
17736
17895
  };
17737
17896
  }
17738
- var import_node_fs43, import_node_path45;
17897
+ var import_node_fs45, import_node_path46;
17739
17898
  var init_orphan_cleanup = __esm({
17740
17899
  "src/git/orphan-cleanup.ts"() {
17741
17900
  "use strict";
17742
- import_node_fs43 = require("fs");
17743
- import_node_path45 = require("path");
17901
+ import_node_fs45 = require("fs");
17902
+ import_node_path46 = require("path");
17744
17903
  init_worktree();
17745
17904
  init_thread_store();
17746
17905
  init_paths();
@@ -17915,12 +18074,12 @@ async function cloneRepoIntoSideboard(opts) {
17915
18074
  if (!url) throw new Error("Clone URL is required");
17916
18075
  let name = opts.name?.trim();
17917
18076
  if (!name) {
17918
- const leaf = (0, import_node_path46.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
18077
+ const leaf = (0, import_node_path47.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
17919
18078
  name = leaf || "repo";
17920
18079
  }
17921
18080
  name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
17922
- const dest = (0, import_node_path46.join)(sideboardReposDir(), name);
17923
- if ((0, import_node_fs44.existsSync)(dest)) {
18081
+ const dest = (0, import_node_path47.join)(sideboardReposDir(), name);
18082
+ if ((0, import_node_fs46.existsSync)(dest)) {
17924
18083
  const repoPath2 = await resolveRepoRoot(dest);
17925
18084
  const workspace2 = await ensureWorkspace(repoPath2);
17926
18085
  return { repoPath: repoPath2, workspace: workspace2 };
@@ -17935,12 +18094,12 @@ async function cloneRepoIntoSideboard(opts) {
17935
18094
  const workspace = await ensureWorkspace(repoPath);
17936
18095
  return { repoPath, workspace };
17937
18096
  }
17938
- var import_node_fs44, import_node_path46, import_execa6;
18097
+ var import_node_fs46, import_node_path47, import_execa6;
17939
18098
  var init_clone_repo = __esm({
17940
18099
  "src/git/clone-repo.ts"() {
17941
18100
  "use strict";
17942
- import_node_fs44 = require("fs");
17943
- import_node_path46 = require("path");
18101
+ import_node_fs46 = require("fs");
18102
+ import_node_path47 = require("path");
17944
18103
  import_execa6 = require("execa");
17945
18104
  init_paths();
17946
18105
  init_workspaces();
@@ -18061,24 +18220,24 @@ function jobTreeAlive(pid) {
18061
18220
  return jobAlive(pid) || processGroupAlive(pid);
18062
18221
  }
18063
18222
  function readIntFile(file) {
18064
- if (!(0, import_node_fs45.existsSync)(file)) return null;
18065
- const n = Number.parseInt((0, import_node_fs45.readFileSync)(file, "utf8").trim(), 10);
18223
+ if (!(0, import_node_fs47.existsSync)(file)) return null;
18224
+ const n = Number.parseInt((0, import_node_fs47.readFileSync)(file, "utf8").trim(), 10);
18066
18225
  return Number.isInteger(n) ? n : null;
18067
18226
  }
18068
18227
  function jobDir(root, id, legacy = false) {
18069
- return (0, import_node_path47.join)(root, legacy ? LEGACY_DETACHED_JOBS_DIR : DETACHED_JOBS_DIR, id);
18228
+ return (0, import_node_path48.join)(root, legacy ? LEGACY_DETACHED_JOBS_DIR : DETACHED_JOBS_DIR, id);
18070
18229
  }
18071
18230
  function resolveJobDir(root, id) {
18072
18231
  const modern = jobDir(root, id, false);
18073
- if ((0, import_node_fs45.existsSync)(modern)) return modern;
18232
+ if ((0, import_node_fs47.existsSync)(modern)) return modern;
18074
18233
  const legacy = jobDir(root, id, true);
18075
- if ((0, import_node_fs45.existsSync)(legacy)) return legacy;
18234
+ if ((0, import_node_fs47.existsSync)(legacy)) return legacy;
18076
18235
  return modern;
18077
18236
  }
18078
18237
  function listJobIdsIn(root, rel) {
18079
- const dir = (0, import_node_path47.join)(root, rel);
18080
- if (!(0, import_node_fs45.existsSync)(dir)) return [];
18081
- return (0, import_node_fs45.readdirSync)(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && JOB_ID_RE.test(e.name)).map((e) => e.name);
18238
+ const dir = (0, import_node_path48.join)(root, rel);
18239
+ if (!(0, import_node_fs47.existsSync)(dir)) return [];
18240
+ return (0, import_node_fs47.readdirSync)(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && JOB_ID_RE.test(e.name)).map((e) => e.name);
18082
18241
  }
18083
18242
  function listRunningDetachedJobs(worktreePath) {
18084
18243
  const root = worktreePath.trim();
@@ -18090,7 +18249,7 @@ function listRunningDetachedJobs(worktreePath) {
18090
18249
  const running = [];
18091
18250
  for (const id of ids) {
18092
18251
  const dir = resolveJobDir(root, id);
18093
- const pid = readIntFile((0, import_node_path47.join)(dir, "pid"));
18252
+ const pid = readIntFile((0, import_node_path48.join)(dir, "pid"));
18094
18253
  if (jobTreeAlive(pid)) running.push(id);
18095
18254
  }
18096
18255
  return running.sort();
@@ -18173,8 +18332,8 @@ function planJobContinue(opts) {
18173
18332
  return { action: "none" };
18174
18333
  }
18175
18334
  function tailProgress(logFile, maxLines = 12) {
18176
- if (!(0, import_node_fs45.existsSync)(logFile)) return "(no log yet)";
18177
- const lines = (0, import_node_fs45.readFileSync)(logFile, "utf8").split("\n");
18335
+ if (!(0, import_node_fs47.existsSync)(logFile)) return "(no log yet)";
18336
+ const lines = (0, import_node_fs47.readFileSync)(logFile, "utf8").split("\n");
18178
18337
  return lines.slice(-maxLines).join("\n");
18179
18338
  }
18180
18339
  function lastProgressLine(progress) {
@@ -18182,8 +18341,8 @@ function lastProgressLine(progress) {
18182
18341
  return last ? last.slice(0, 72) : void 0;
18183
18342
  }
18184
18343
  function readLogLines(file) {
18185
- if (!(0, import_node_fs45.existsSync)(file)) return [];
18186
- const lines = (0, import_node_fs45.readFileSync)(file, "utf8").split("\n");
18344
+ if (!(0, import_node_fs47.existsSync)(file)) return [];
18345
+ const lines = (0, import_node_fs47.readFileSync)(file, "utf8").split("\n");
18187
18346
  if (lines.length && lines[lines.length - 1] === "") lines.pop();
18188
18347
  return lines;
18189
18348
  }
@@ -18194,15 +18353,15 @@ function takeDelta(logFile, cursorFile) {
18194
18353
  return { delta: capJobLogDelta(lines.slice(start).join("\n")), nextCursor: lines.length };
18195
18354
  }
18196
18355
  function snapshotJob(dir) {
18197
- const pid = readIntFile((0, import_node_path47.join)(dir, "pid"));
18356
+ const pid = readIntFile((0, import_node_path48.join)(dir, "pid"));
18198
18357
  const running = jobTreeAlive(pid);
18199
18358
  return {
18200
18359
  pid,
18201
18360
  running,
18202
- exitCode: readIntFile((0, import_node_path47.join)(dir, "exit")),
18203
- log: (0, import_node_path47.join)(dir, "log"),
18204
- cursor: (0, import_node_path47.join)(dir, "present.cursor"),
18205
- progress: tailProgress((0, import_node_path47.join)(dir, "log"))
18361
+ exitCode: readIntFile((0, import_node_path48.join)(dir, "exit")),
18362
+ log: (0, import_node_path48.join)(dir, "log"),
18363
+ cursor: (0, import_node_path48.join)(dir, "present.cursor"),
18364
+ progress: tailProgress((0, import_node_path48.join)(dir, "log"))
18206
18365
  };
18207
18366
  }
18208
18367
  function toResult(id, snap, extra) {
@@ -18211,8 +18370,8 @@ function toResult(id, snap, extra) {
18211
18370
  const stillRunning = snap.running && !ok;
18212
18371
  const { delta, nextCursor } = takeDelta(snap.log, snap.cursor);
18213
18372
  try {
18214
- (0, import_node_fs45.mkdirSync)((0, import_node_path47.dirname)(snap.cursor), { recursive: true });
18215
- (0, import_node_fs45.writeFileSync)(snap.cursor, `${nextCursor}
18373
+ (0, import_node_fs47.mkdirSync)((0, import_node_path48.dirname)(snap.cursor), { recursive: true });
18374
+ (0, import_node_fs47.writeFileSync)(snap.cursor, `${nextCursor}
18216
18375
  `);
18217
18376
  } catch {
18218
18377
  }
@@ -18241,7 +18400,7 @@ async function waitForDetachedJob(cwd, id, opts) {
18241
18400
  const dir = resolveJobDir(root, jobId);
18242
18401
  const timeoutMs = mcpWaitForJobTimeoutMs(opts?.timeoutMs);
18243
18402
  const sleep2 = opts?.sleep ?? sleepMs;
18244
- if (!(0, import_node_fs45.existsSync)(dir)) {
18403
+ if (!(0, import_node_fs47.existsSync)(dir)) {
18245
18404
  return {
18246
18405
  stillRunning: false,
18247
18406
  ok: false,
@@ -18287,10 +18446,10 @@ function killProcessTree(pid, signal) {
18287
18446
  }
18288
18447
  function appendJobLog(logFile, line) {
18289
18448
  try {
18290
- (0, import_node_fs45.mkdirSync)((0, import_node_path47.dirname)(logFile), { recursive: true });
18449
+ (0, import_node_fs47.mkdirSync)((0, import_node_path48.dirname)(logFile), { recursive: true });
18291
18450
  const body = line.endsWith("\n") ? line : `${line}
18292
18451
  `;
18293
- (0, import_node_fs45.appendFileSync)(logFile, body);
18452
+ (0, import_node_fs47.appendFileSync)(logFile, body);
18294
18453
  } catch {
18295
18454
  }
18296
18455
  }
@@ -18300,7 +18459,7 @@ async function stopDetachedJob(cwd, id, opts) {
18300
18459
  const dir = resolveJobDir(root, jobId);
18301
18460
  const sleep2 = opts?.sleep ?? sleepMs;
18302
18461
  const why = opts?.reason?.trim() ?? "";
18303
- if (!(0, import_node_fs45.existsSync)(dir)) {
18462
+ if (!(0, import_node_fs47.existsSync)(dir)) {
18304
18463
  return {
18305
18464
  stillRunning: false,
18306
18465
  ok: false,
@@ -18336,10 +18495,10 @@ async function stopDetachedJob(cwd, id, opts) {
18336
18495
  killProcessTree(targetPid, "SIGKILL");
18337
18496
  await sleep2(100);
18338
18497
  }
18339
- const exitFile = (0, import_node_path47.join)(dir, "exit");
18340
- if (!(0, import_node_fs45.existsSync)(exitFile)) {
18498
+ const exitFile = (0, import_node_path48.join)(dir, "exit");
18499
+ if (!(0, import_node_fs47.existsSync)(exitFile)) {
18341
18500
  try {
18342
- (0, import_node_fs45.writeFileSync)(exitFile, "1\n");
18501
+ (0, import_node_fs47.writeFileSync)(exitFile, "1\n");
18343
18502
  } catch {
18344
18503
  }
18345
18504
  }
@@ -18359,12 +18518,12 @@ async function stopDetachedJob(cwd, id, opts) {
18359
18518
  hint: stopped ? MCP_STOP_JOB_HINT : MCP_WAIT_JOB_STILL_RUNNING_HINT
18360
18519
  };
18361
18520
  }
18362
- var import_node_fs45, import_node_path47, MAX_JOB_CONTINUES, MAX_JOB_DELTA_LINES, MAX_JOB_DELTA_CHARS, DEFERRED_DONE_MAX_CHARS, GH_WATCH_REFRESH, MCP_WAIT_JOB_STILL_RUNNING_HINT, MCP_STOP_JOB_HINT, JOB_ID_RE;
18521
+ var import_node_fs47, import_node_path48, MAX_JOB_CONTINUES, MAX_JOB_DELTA_LINES, MAX_JOB_DELTA_CHARS, DEFERRED_DONE_MAX_CHARS, GH_WATCH_REFRESH, MCP_WAIT_JOB_STILL_RUNNING_HINT, MCP_STOP_JOB_HINT, JOB_ID_RE;
18363
18522
  var init_wait_for_job = __esm({
18364
18523
  "src/mcp/wait-for-job.ts"() {
18365
18524
  "use strict";
18366
- import_node_fs45 = require("fs");
18367
- import_node_path47 = require("path");
18525
+ import_node_fs47 = require("fs");
18526
+ import_node_path48 = require("path");
18368
18527
  init_workspace_scratch();
18369
18528
  init_wait_for_turn();
18370
18529
  MAX_JOB_CONTINUES = 8;
@@ -19909,7 +20068,7 @@ function reuseLiveThread(input, repoPath, match) {
19909
20068
  }
19910
20069
  async function createThread(input, _onSetupLine) {
19911
20070
  const repoPath = await resolveRepoRoot(input.repoPath);
19912
- if (!(0, import_node_fs46.existsSync)(repoPath)) {
20071
+ if (!(0, import_node_fs48.existsSync)(repoPath)) {
19913
20072
  throw new Error(`Repo not found: ${repoPath}`);
19914
20073
  }
19915
20074
  const reused = reuseLiveThread(input, repoPath, {
@@ -20094,11 +20253,11 @@ async function listLinearIssues(agent, repoPath) {
20094
20253
  }
20095
20254
  return adapter.listLinearIssues(repoPath);
20096
20255
  }
20097
- var import_node_fs46;
20256
+ var import_node_fs48;
20098
20257
  var init_create = __esm({
20099
20258
  "src/threads/create.ts"() {
20100
20259
  "use strict";
20101
- import_node_fs46 = require("fs");
20260
+ import_node_fs48 = require("fs");
20102
20261
  init_detect();
20103
20262
  init_worktree();
20104
20263
  init_home_board();
@@ -20250,20 +20409,20 @@ function writeTurnLive(threadId, progress) {
20250
20409
  const path2 = threadLivePath(threadId);
20251
20410
  const tmp = `${path2}.${process.pid}.tmp`;
20252
20411
  try {
20253
- (0, import_node_fs47.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
20254
- (0, import_node_fs47.renameSync)(tmp, path2);
20412
+ (0, import_node_fs49.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
20413
+ (0, import_node_fs49.renameSync)(tmp, path2);
20255
20414
  } catch {
20256
20415
  try {
20257
- (0, import_node_fs47.unlinkSync)(tmp);
20416
+ (0, import_node_fs49.unlinkSync)(tmp);
20258
20417
  } catch {
20259
20418
  }
20260
20419
  }
20261
20420
  }
20262
20421
  function readTurnLive(threadId) {
20263
20422
  const path2 = threadLivePath(threadId);
20264
- if (!(0, import_node_fs47.existsSync)(path2)) return null;
20423
+ if (!(0, import_node_fs49.existsSync)(path2)) return null;
20265
20424
  try {
20266
- const raw = JSON.parse((0, import_node_fs47.readFileSync)(path2, "utf8"));
20425
+ const raw = JSON.parse((0, import_node_fs49.readFileSync)(path2, "utf8"));
20267
20426
  if (!raw || typeof raw.summary !== "string") return null;
20268
20427
  return raw;
20269
20428
  } catch {
@@ -20275,17 +20434,17 @@ function clearTurnLive(threadId) {
20275
20434
  if (buf?.timer) clearTimeout(buf.timer);
20276
20435
  buffers.delete(threadId);
20277
20436
  const path2 = threadLivePath(threadId);
20278
- if (!(0, import_node_fs47.existsSync)(path2)) return;
20437
+ if (!(0, import_node_fs49.existsSync)(path2)) return;
20279
20438
  try {
20280
- (0, import_node_fs47.unlinkSync)(path2);
20439
+ (0, import_node_fs49.unlinkSync)(path2);
20281
20440
  } catch {
20282
20441
  }
20283
20442
  }
20284
- var import_node_fs47, buffers, FLUSH_MS, MAX_PARTS;
20443
+ var import_node_fs49, buffers, FLUSH_MS, MAX_PARTS;
20285
20444
  var init_turn_live = __esm({
20286
20445
  "src/store/turn-live.ts"() {
20287
20446
  "use strict";
20288
- import_node_fs47 = require("fs");
20447
+ import_node_fs49 = require("fs");
20289
20448
  init_message_parts();
20290
20449
  init_paths();
20291
20450
  buffers = /* @__PURE__ */ new Map();
@@ -20527,12 +20686,12 @@ var init_quota_failover = __esm({
20527
20686
  });
20528
20687
 
20529
20688
  // src/threads/adopt.ts
20530
- function thisModuleFile() {
20689
+ function thisModuleFile2() {
20531
20690
  const cjsFile = typeof __filename !== "undefined" ? __filename : "";
20532
- return cjsFile || process.argv[1] || (0, import_node_path48.join)(process.cwd(), "package.json");
20691
+ return cjsFile || process.argv[1] || (0, import_node_path49.join)(process.cwd(), "package.json");
20533
20692
  }
20534
20693
  function openReadonlySqlite(file) {
20535
- const req = (0, import_node_module4.createRequire)(thisModuleFile());
20694
+ const req = (0, import_node_module5.createRequire)(thisModuleFile2());
20536
20695
  const Database = req("better-sqlite3");
20537
20696
  return new Database(file, { readonly: true, fileMustExist: true });
20538
20697
  }
@@ -20547,21 +20706,21 @@ function mapAgentType(raw) {
20547
20706
  return null;
20548
20707
  }
20549
20708
  function resolveConductorCursorAgentId(workspacePath) {
20550
- if (!workspacePath || !(0, import_node_fs48.existsSync)(CURSOR_SDK_STORE)) return null;
20709
+ if (!workspacePath || !(0, import_node_fs50.existsSync)(CURSOR_SDK_STORE)) return null;
20551
20710
  const normalized = workspacePath.replace(/\/$/, "");
20552
20711
  let best = null;
20553
20712
  let hashes;
20554
20713
  try {
20555
- hashes = (0, import_node_fs48.readdirSync)(CURSOR_SDK_STORE);
20714
+ hashes = (0, import_node_fs50.readdirSync)(CURSOR_SDK_STORE);
20556
20715
  } catch {
20557
20716
  return null;
20558
20717
  }
20559
20718
  for (const hash of hashes) {
20560
- const agentsFile = (0, import_node_path48.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
20561
- if (!(0, import_node_fs48.existsSync)(agentsFile)) continue;
20719
+ const agentsFile = (0, import_node_path49.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
20720
+ if (!(0, import_node_fs50.existsSync)(agentsFile)) continue;
20562
20721
  let text7;
20563
20722
  try {
20564
- text7 = (0, import_node_fs48.readFileSync)(agentsFile, "utf8");
20723
+ text7 = (0, import_node_fs50.readFileSync)(agentsFile, "utf8");
20565
20724
  } catch {
20566
20725
  continue;
20567
20726
  }
@@ -20585,7 +20744,7 @@ function resolveConductorCursorAgentId(workspacePath) {
20585
20744
  return best?.agentId ?? null;
20586
20745
  }
20587
20746
  async function adoptThread(input) {
20588
- if (!(0, import_node_fs48.existsSync)(input.worktreePath)) {
20747
+ if (!(0, import_node_fs50.existsSync)(input.worktreePath)) {
20589
20748
  throw new Error(`Worktree not found: ${input.worktreePath}`);
20590
20749
  }
20591
20750
  const repoPath = await resolveRepoRoot(input.worktreePath);
@@ -20614,18 +20773,18 @@ function conductorDbPath() {
20614
20773
  return CONDUCTOR_DB;
20615
20774
  }
20616
20775
  function listConductorWorkspaces() {
20617
- if (!(0, import_node_fs48.existsSync)(CONDUCTOR_DB)) {
20776
+ if (!(0, import_node_fs50.existsSync)(CONDUCTOR_DB)) {
20618
20777
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
20619
20778
  }
20620
- const tmp = (0, import_node_fs48.mkdtempSync)((0, import_node_path48.join)((0, import_node_os14.tmpdir)(), "sideboard-conductor-"));
20621
- const snapshot = (0, import_node_path48.join)(tmp, "conductor.db");
20779
+ const tmp = (0, import_node_fs50.mkdtempSync)((0, import_node_path49.join)((0, import_node_os14.tmpdir)(), "sideboard-conductor-"));
20780
+ const snapshot = (0, import_node_path49.join)(tmp, "conductor.db");
20622
20781
  try {
20623
- (0, import_node_fs48.copyFileSync)(CONDUCTOR_DB, snapshot);
20782
+ (0, import_node_fs50.copyFileSync)(CONDUCTOR_DB, snapshot);
20624
20783
  for (const suffix of ["-wal", "-shm"]) {
20625
20784
  const src = `${CONDUCTOR_DB}${suffix}`;
20626
- if ((0, import_node_fs48.existsSync)(src)) {
20785
+ if ((0, import_node_fs50.existsSync)(src)) {
20627
20786
  try {
20628
- (0, import_node_fs48.copyFileSync)(src, `${snapshot}${suffix}`);
20787
+ (0, import_node_fs50.copyFileSync)(src, `${snapshot}${suffix}`);
20629
20788
  } catch {
20630
20789
  }
20631
20790
  }
@@ -20701,22 +20860,22 @@ function listConductorWorkspaces() {
20701
20860
  db.close();
20702
20861
  }
20703
20862
  } finally {
20704
- (0, import_node_fs48.rmSync)(tmp, { recursive: true, force: true });
20863
+ (0, import_node_fs50.rmSync)(tmp, { recursive: true, force: true });
20705
20864
  }
20706
20865
  }
20707
20866
  function importConductorWorkspace(workspaceId) {
20708
- if (!(0, import_node_fs48.existsSync)(CONDUCTOR_DB)) {
20867
+ if (!(0, import_node_fs50.existsSync)(CONDUCTOR_DB)) {
20709
20868
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
20710
20869
  }
20711
- const tmp = (0, import_node_fs48.mkdtempSync)((0, import_node_path48.join)((0, import_node_os14.tmpdir)(), "sideboard-conductor-"));
20712
- const snapshot = (0, import_node_path48.join)(tmp, "conductor.db");
20870
+ const tmp = (0, import_node_fs50.mkdtempSync)((0, import_node_path49.join)((0, import_node_os14.tmpdir)(), "sideboard-conductor-"));
20871
+ const snapshot = (0, import_node_path49.join)(tmp, "conductor.db");
20713
20872
  try {
20714
- (0, import_node_fs48.copyFileSync)(CONDUCTOR_DB, snapshot);
20873
+ (0, import_node_fs50.copyFileSync)(CONDUCTOR_DB, snapshot);
20715
20874
  for (const suffix of ["-wal", "-shm"]) {
20716
20875
  const src = `${CONDUCTOR_DB}${suffix}`;
20717
- if ((0, import_node_fs48.existsSync)(src)) {
20876
+ if ((0, import_node_fs50.existsSync)(src)) {
20718
20877
  try {
20719
- (0, import_node_fs48.copyFileSync)(src, `${snapshot}${suffix}`);
20878
+ (0, import_node_fs50.copyFileSync)(src, `${snapshot}${suffix}`);
20720
20879
  } catch {
20721
20880
  }
20722
20881
  }
@@ -20734,7 +20893,7 @@ function importConductorWorkspace(workspaceId) {
20734
20893
  ).get(workspaceId);
20735
20894
  if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
20736
20895
  const worktreePath = String(row.workspacePath);
20737
- if (!(0, import_node_fs48.existsSync)(worktreePath)) {
20896
+ if (!(0, import_node_fs50.existsSync)(worktreePath)) {
20738
20897
  throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
20739
20898
  }
20740
20899
  let sessionId = null;
@@ -20797,31 +20956,31 @@ function importConductorWorkspace(workspaceId) {
20797
20956
  db.close();
20798
20957
  }
20799
20958
  } finally {
20800
- (0, import_node_fs48.rmSync)(tmp, { recursive: true, force: true });
20959
+ (0, import_node_fs50.rmSync)(tmp, { recursive: true, force: true });
20801
20960
  }
20802
20961
  }
20803
20962
  async function importConductorWorkspaceAsync(workspaceId) {
20804
20963
  return importConductorWorkspace(workspaceId);
20805
20964
  }
20806
- var import_node_child_process6, import_node_fs48, import_node_os14, import_node_path48, import_node_module4, CONDUCTOR_APP_SUPPORT, CONDUCTOR_DB, CURSOR_SDK_STORE;
20965
+ var import_node_child_process6, import_node_fs50, import_node_os14, import_node_path49, import_node_module5, CONDUCTOR_APP_SUPPORT, CONDUCTOR_DB, CURSOR_SDK_STORE;
20807
20966
  var init_adopt = __esm({
20808
20967
  "src/threads/adopt.ts"() {
20809
20968
  "use strict";
20810
20969
  import_node_child_process6 = require("child_process");
20811
- import_node_fs48 = require("fs");
20970
+ import_node_fs50 = require("fs");
20812
20971
  import_node_os14 = require("os");
20813
- import_node_path48 = require("path");
20814
- import_node_module4 = require("module");
20972
+ import_node_path49 = require("path");
20973
+ import_node_module5 = require("module");
20815
20974
  init_worktree();
20816
20975
  init_thread_store();
20817
- CONDUCTOR_APP_SUPPORT = (0, import_node_path48.join)(
20976
+ CONDUCTOR_APP_SUPPORT = (0, import_node_path49.join)(
20818
20977
  process.env.HOME ?? "",
20819
20978
  "Library",
20820
20979
  "Application Support",
20821
20980
  "com.conductor.app"
20822
20981
  );
20823
- CONDUCTOR_DB = (0, import_node_path48.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
20824
- CURSOR_SDK_STORE = (0, import_node_path48.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
20982
+ CONDUCTOR_DB = (0, import_node_path49.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
20983
+ CURSOR_SDK_STORE = (0, import_node_path49.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
20825
20984
  }
20826
20985
  });
20827
20986
 
@@ -20888,7 +21047,7 @@ async function openStackLayer(input, _onSetupLine) {
20888
21047
  let createdWorktree = false;
20889
21048
  const trees = await listWorktrees(repoPath);
20890
21049
  const checkedOut = trees.find((w) => w.branch === branchName);
20891
- if (checkedOut?.path && (0, import_node_fs49.existsSync)(checkedOut.path)) {
21050
+ if (checkedOut?.path && (0, import_node_fs51.existsSync)(checkedOut.path)) {
20892
21051
  if (input.reuseExistingWorktree !== false) {
20893
21052
  worktreePath = checkedOut.path;
20894
21053
  } else {
@@ -21030,7 +21189,7 @@ async function initStackFromThread(input, onSetupLine) {
21030
21189
  async function createPrStack(input, onSetupLine) {
21031
21190
  await requireAgent(input.agent);
21032
21191
  const repoPath = await resolveRepoRoot(input.repoPath);
21033
- if (!(0, import_node_fs49.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
21192
+ if (!(0, import_node_fs51.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
21034
21193
  if (!input.branches.length) throw new Error("At least one branch name required");
21035
21194
  const status = await detectGhStack(repoPath);
21036
21195
  if (!status.available) throw new Error(status.reason);
@@ -21097,7 +21256,7 @@ async function createPrStack(input, onSetupLine) {
21097
21256
  }
21098
21257
  }
21099
21258
  const claimed = new Set(threads.map((t) => t.worktreePath));
21100
- if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs49.existsSync)(bootstrap.worktreePath)) {
21259
+ if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs51.existsSync)(bootstrap.worktreePath)) {
21101
21260
  try {
21102
21261
  await removeWorktree(repoPath, bootstrap.worktreePath, {
21103
21262
  deleteBranch: bootstrap.branchName
@@ -21117,11 +21276,11 @@ function stackAgentDefaultsFrom(input) {
21117
21276
  planMode: input.planMode
21118
21277
  };
21119
21278
  }
21120
- var import_node_fs49;
21279
+ var import_node_fs51;
21121
21280
  var init_stack_layers = __esm({
21122
21281
  "src/threads/stack-layers.ts"() {
21123
21282
  "use strict";
21124
- import_node_fs49 = require("fs");
21283
+ import_node_fs51 = require("fs");
21125
21284
  init_detect();
21126
21285
  init_run();
21127
21286
  init_stack();
@@ -21134,7 +21293,7 @@ var init_stack_layers = __esm({
21134
21293
 
21135
21294
  // src/diff/diff.ts
21136
21295
  async function inspectGitWorktree(worktreePath) {
21137
- if (!worktreePath || !(0, import_node_fs50.existsSync)(worktreePath)) return "missing_worktree";
21296
+ if (!worktreePath || !(0, import_node_fs52.existsSync)(worktreePath)) return "missing_worktree";
21138
21297
  const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
21139
21298
  reject: false
21140
21299
  });
@@ -21142,7 +21301,7 @@ async function inspectGitWorktree(worktreePath) {
21142
21301
  return "ok";
21143
21302
  }
21144
21303
  async function initializeGitRepository(worktreePath) {
21145
- if (!worktreePath || !(0, import_node_fs50.existsSync)(worktreePath)) {
21304
+ if (!worktreePath || !(0, import_node_fs52.existsSync)(worktreePath)) {
21146
21305
  throw new Error("Worktree not found");
21147
21306
  }
21148
21307
  const status = await inspectGitWorktree(worktreePath);
@@ -21276,11 +21435,11 @@ new file mode 100644
21276
21435
  };
21277
21436
  }
21278
21437
  async function untrackedPatch(worktreePath, path2, maxHunk) {
21279
- const abs = (0, import_node_path49.join)(worktreePath, path2);
21438
+ const abs = (0, import_node_path50.join)(worktreePath, path2);
21280
21439
  try {
21281
- const st = (0, import_node_fs50.statSync)(abs);
21440
+ const st = (0, import_node_fs52.statSync)(abs);
21282
21441
  if (st.isFile() && st.size > maxHunk) {
21283
- const buf = (0, import_node_fs50.readFileSync)(abs).subarray(0, maxHunk);
21442
+ const buf = (0, import_node_fs52.readFileSync)(abs).subarray(0, maxHunk);
21284
21443
  return syntheticAddPatch(path2, buf.toString("utf8"), maxHunk);
21285
21444
  }
21286
21445
  } catch {
@@ -21747,9 +21906,9 @@ async function getDiff(worktreePath, repoPath, opts) {
21747
21906
  }
21748
21907
  function statWorktreePath(worktreePath, relativePath) {
21749
21908
  assertSafeRelativePath(relativePath);
21750
- const abs = (0, import_node_path49.join)(worktreePath, relativePath);
21751
- if (!(0, import_node_fs50.existsSync)(abs)) return "missing";
21752
- const st = (0, import_node_fs50.statSync)(abs);
21909
+ const abs = (0, import_node_path50.join)(worktreePath, relativePath);
21910
+ if (!(0, import_node_fs52.existsSync)(abs)) return "missing";
21911
+ const st = (0, import_node_fs52.statSync)(abs);
21753
21912
  if (st.isDirectory()) return "dir";
21754
21913
  if (st.isFile()) return "file";
21755
21914
  return "missing";
@@ -21778,8 +21937,8 @@ function isImageRelativePath(relativePath) {
21778
21937
  function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
21779
21938
  assertSafeRelativePath(relativePath);
21780
21939
  const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
21781
- const abs = (0, import_node_path49.join)(worktreePath, relativePath);
21782
- const st = (0, import_node_fs50.statSync)(abs);
21940
+ const abs = (0, import_node_path50.join)(worktreePath, relativePath);
21941
+ const st = (0, import_node_fs52.statSync)(abs);
21783
21942
  if (!st.isFile()) {
21784
21943
  throw new Error(`Not a file: ${relativePath}`);
21785
21944
  }
@@ -21788,7 +21947,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
21788
21947
  `File too large to upload (${st.size} bytes; max ${maxBytes})`
21789
21948
  );
21790
21949
  }
21791
- const buf = (0, import_node_fs50.readFileSync)(abs);
21950
+ const buf = (0, import_node_fs52.readFileSync)(abs);
21792
21951
  return {
21793
21952
  path: relativePath,
21794
21953
  contentBase64: buf.toString("base64"),
@@ -21798,12 +21957,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
21798
21957
  function readWorktreeFile(worktreePath, relativePath, opts) {
21799
21958
  assertSafeRelativePath(relativePath);
21800
21959
  const maxBytes = opts?.maxBytes ?? 2e5;
21801
- const abs = (0, import_node_path49.join)(worktreePath, relativePath);
21802
- const st = (0, import_node_fs50.statSync)(abs);
21960
+ const abs = (0, import_node_path50.join)(worktreePath, relativePath);
21961
+ const st = (0, import_node_fs52.statSync)(abs);
21803
21962
  if (!st.isFile()) {
21804
21963
  throw new Error(`Not a file: ${relativePath}`);
21805
21964
  }
21806
- const buf = (0, import_node_fs50.readFileSync)(abs);
21965
+ const buf = (0, import_node_fs52.readFileSync)(abs);
21807
21966
  if (isImageRelativePath(relativePath)) {
21808
21967
  const maxImageBytes = Math.max(maxBytes, 15e6);
21809
21968
  const truncated2 = buf.length > maxImageBytes;
@@ -21846,9 +22005,9 @@ function assertSafeRelativePath(relativePath) {
21846
22005
  }
21847
22006
  function writeWorktreeFile(worktreePath, relativePath, content) {
21848
22007
  assertSafeRelativePath(relativePath);
21849
- const abs = (0, import_node_path49.join)(worktreePath, relativePath);
21850
- (0, import_node_fs50.mkdirSync)((0, import_node_path49.dirname)(abs), { recursive: true });
21851
- (0, import_node_fs50.writeFileSync)(abs, content, "utf8");
22008
+ const abs = (0, import_node_path50.join)(worktreePath, relativePath);
22009
+ (0, import_node_fs52.mkdirSync)((0, import_node_path50.dirname)(abs), { recursive: true });
22010
+ (0, import_node_fs52.writeFileSync)(abs, content, "utf8");
21852
22011
  return { path: relativePath };
21853
22012
  }
21854
22013
  async function getWorktreeDirtyStat(worktreePath) {
@@ -21888,12 +22047,12 @@ async function getDiffSummary(worktreePath, repoPath, opts) {
21888
22047
  truncated: full.files.length > maxFiles
21889
22048
  };
21890
22049
  }
21891
- var import_node_fs50, import_node_path49, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS2, DEFAULT_UPLOAD_MAX_BYTES;
22050
+ var import_node_fs52, import_node_path50, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS2, DEFAULT_UPLOAD_MAX_BYTES;
21892
22051
  var init_diff = __esm({
21893
22052
  "src/diff/diff.ts"() {
21894
22053
  "use strict";
21895
- import_node_fs50 = require("fs");
21896
- import_node_path49 = require("path");
22054
+ import_node_fs52 = require("fs");
22055
+ import_node_path50 = require("path");
21897
22056
  init_run();
21898
22057
  init_worktree();
21899
22058
  mergeBaseCache = /* @__PURE__ */ new Map();
@@ -22250,7 +22409,7 @@ function parseFrontmatter(content) {
22250
22409
  }
22251
22410
  function readSkill(skillMd, source) {
22252
22411
  try {
22253
- const content = (0, import_node_fs51.readFileSync)(skillMd, "utf8");
22412
+ const content = (0, import_node_fs53.readFileSync)(skillMd, "utf8");
22254
22413
  const { name: fmName, description } = parseFrontmatter(content);
22255
22414
  const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
22256
22415
  const name = fmName || dirName;
@@ -22269,19 +22428,19 @@ function readSkill(skillMd, source) {
22269
22428
  }
22270
22429
  }
22271
22430
  function scanSkillsDir(dir, source, out) {
22272
- if (!(0, import_node_fs51.existsSync)(dir)) return;
22431
+ if (!(0, import_node_fs53.existsSync)(dir)) return;
22273
22432
  let entries;
22274
22433
  try {
22275
- entries = (0, import_node_fs51.readdirSync)(dir);
22434
+ entries = (0, import_node_fs53.readdirSync)(dir);
22276
22435
  } catch {
22277
22436
  return;
22278
22437
  }
22279
22438
  for (const entry of entries) {
22280
22439
  if (entry.startsWith(".")) continue;
22281
- const skillMd = (0, import_node_path50.join)(dir, entry, "SKILL.md");
22282
- if (!(0, import_node_fs51.existsSync)(skillMd)) continue;
22440
+ const skillMd = (0, import_node_path51.join)(dir, entry, "SKILL.md");
22441
+ if (!(0, import_node_fs53.existsSync)(skillMd)) continue;
22283
22442
  try {
22284
- if (!(0, import_node_fs51.statSync)(skillMd).isFile()) continue;
22443
+ if (!(0, import_node_fs53.statSync)(skillMd).isFile()) continue;
22285
22444
  } catch {
22286
22445
  continue;
22287
22446
  }
@@ -22290,24 +22449,24 @@ function scanSkillsDir(dir, source, out) {
22290
22449
  }
22291
22450
  }
22292
22451
  function scanClaudePluginSkills(pluginsRoot, out) {
22293
- if (!(0, import_node_fs51.existsSync)(pluginsRoot)) return;
22452
+ if (!(0, import_node_fs53.existsSync)(pluginsRoot)) return;
22294
22453
  const walk = (dir, depth, lookingForSkillsDir) => {
22295
22454
  if (depth > 7) return;
22296
22455
  let entries;
22297
22456
  try {
22298
- entries = (0, import_node_fs51.readdirSync)(dir);
22457
+ entries = (0, import_node_fs53.readdirSync)(dir);
22299
22458
  } catch {
22300
22459
  return;
22301
22460
  }
22302
22461
  if (lookingForSkillsDir && entries.includes("SKILL.md")) {
22303
- const skill = readSkill((0, import_node_path50.join)(dir, "SKILL.md"), "cli");
22462
+ const skill = readSkill((0, import_node_path51.join)(dir, "SKILL.md"), "cli");
22304
22463
  if (skill) out.push(skill);
22305
22464
  }
22306
22465
  for (const entry of entries) {
22307
22466
  if (entry === "node_modules" || entry === ".git") continue;
22308
- const full = (0, import_node_path50.join)(dir, entry);
22467
+ const full = (0, import_node_path51.join)(dir, entry);
22309
22468
  try {
22310
- if (!(0, import_node_fs51.statSync)(full).isDirectory()) continue;
22469
+ if (!(0, import_node_fs53.statSync)(full).isDirectory()) continue;
22311
22470
  } catch {
22312
22471
  continue;
22313
22472
  }
@@ -22325,17 +22484,17 @@ function discoverSkills(worktreePath) {
22325
22484
  const home = (0, import_node_os15.homedir)();
22326
22485
  const collected = [];
22327
22486
  for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
22328
- scanSkillsDir((0, import_node_path50.join)(worktreePath, rel), "workspace", collected);
22487
+ scanSkillsDir((0, import_node_path51.join)(worktreePath, rel), "workspace", collected);
22329
22488
  }
22330
22489
  for (const abs of [
22331
- (0, import_node_path50.join)(home, ".claude/skills"),
22332
- (0, import_node_path50.join)(home, ".cursor/skills"),
22333
- (0, import_node_path50.join)(home, ".sideboard/skills"),
22334
- (0, import_node_path50.join)(home, ".brightsy/skills")
22490
+ (0, import_node_path51.join)(home, ".claude/skills"),
22491
+ (0, import_node_path51.join)(home, ".cursor/skills"),
22492
+ (0, import_node_path51.join)(home, ".sideboard/skills"),
22493
+ (0, import_node_path51.join)(home, ".brightsy/skills")
22335
22494
  ]) {
22336
22495
  scanSkillsDir(abs, "user", collected);
22337
22496
  }
22338
- scanClaudePluginSkills((0, import_node_path50.join)(home, ".claude/plugins"), collected);
22497
+ scanClaudePluginSkills((0, import_node_path51.join)(home, ".claude/plugins"), collected);
22339
22498
  collected.push(...bundledSkills());
22340
22499
  const rank = {
22341
22500
  workspace: 0,
@@ -22361,7 +22520,7 @@ function readSkillBody(skillPath, maxChars = 12e3) {
22361
22520
  \u2026(truncated)` : body;
22362
22521
  }
22363
22522
  }
22364
- const raw = (0, import_node_fs51.readFileSync)(skillPath, "utf8");
22523
+ const raw = (0, import_node_fs53.readFileSync)(skillPath, "utf8");
22365
22524
  if (raw.startsWith("---")) {
22366
22525
  const end = raw.indexOf("\n---", 3);
22367
22526
  if (end >= 0) {
@@ -22375,13 +22534,13 @@ function readSkillBody(skillPath, maxChars = 12e3) {
22375
22534
 
22376
22535
  \u2026(truncated)` : raw;
22377
22536
  }
22378
- var import_node_fs51, import_node_os15, import_node_path50, BUNDLED_SKILL_PREFIX;
22537
+ var import_node_fs53, import_node_os15, import_node_path51, BUNDLED_SKILL_PREFIX;
22379
22538
  var init_discover = __esm({
22380
22539
  "src/skills/discover.ts"() {
22381
22540
  "use strict";
22382
- import_node_fs51 = require("fs");
22541
+ import_node_fs53 = require("fs");
22383
22542
  import_node_os15 = require("os");
22384
- import_node_path50 = require("path");
22543
+ import_node_path51 = require("path");
22385
22544
  init_long_running();
22386
22545
  BUNDLED_SKILL_PREFIX = "bundled:";
22387
22546
  }
@@ -22534,9 +22693,9 @@ function compiledModuleDir() {
22534
22693
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
22535
22694
  if (cjsDir) return cjsDir;
22536
22695
  try {
22537
- const url = import_meta3.url;
22696
+ const url = import_meta4.url;
22538
22697
  if (typeof url === "string" && url.length > 0) {
22539
- return (0, import_node_path51.dirname)((0, import_node_url3.fileURLToPath)(url));
22698
+ return (0, import_node_path52.dirname)((0, import_node_url4.fileURLToPath)(url));
22540
22699
  }
22541
22700
  } catch {
22542
22701
  }
@@ -22544,8 +22703,8 @@ function compiledModuleDir() {
22544
22703
  }
22545
22704
  function detachedJobScriptIn(dir) {
22546
22705
  for (const name of DETACHED_JOB_FILENAMES) {
22547
- const script = (0, import_node_path51.join)(dir, "scripts", name);
22548
- if ((0, import_node_fs52.existsSync)(script)) return script;
22706
+ const script = (0, import_node_path52.join)(dir, "scripts", name);
22707
+ if ((0, import_node_fs54.existsSync)(script)) return script;
22549
22708
  }
22550
22709
  return null;
22551
22710
  }
@@ -22562,7 +22721,7 @@ function resolveDetachedJobScript() {
22562
22721
  for (let i = 0; i < 8; i++) {
22563
22722
  const candidate = detachedJobScriptIn(dir);
22564
22723
  if (candidate) return candidate;
22565
- const parent = (0, import_node_path51.dirname)(dir);
22724
+ const parent = (0, import_node_path52.dirname)(dir);
22566
22725
  if (parent === dir) break;
22567
22726
  dir = parent;
22568
22727
  }
@@ -22573,15 +22732,15 @@ function formatDetachedJobInvoke(scriptPath) {
22573
22732
  if (resolved) return `node ${JSON.stringify(resolved)}`;
22574
22733
  return "node scripts/detached-job.cjs";
22575
22734
  }
22576
- var import_node_fs52, import_node_path51, import_node_url3, import_meta3, DETACHED_JOB_FILENAMES;
22735
+ var import_node_fs54, import_node_path52, import_node_url4, import_meta4, DETACHED_JOB_FILENAMES;
22577
22736
  var init_detached_job_path = __esm({
22578
22737
  "src/skills/detached-job-path.ts"() {
22579
22738
  "use strict";
22580
- import_node_fs52 = require("fs");
22581
- import_node_path51 = require("path");
22582
- import_node_url3 = require("url");
22739
+ import_node_fs54 = require("fs");
22740
+ import_node_path52 = require("path");
22741
+ import_node_url4 = require("url");
22583
22742
  init_packaged_runtime();
22584
- import_meta3 = {};
22743
+ import_meta4 = {};
22585
22744
  DETACHED_JOB_FILENAMES = ["detached-job.cjs", "detached-job.js"];
22586
22745
  }
22587
22746
  });
@@ -22760,9 +22919,9 @@ function formatPrGateDirective() {
22760
22919
  }
22761
22920
  function formatProcessGuideDirective(opts) {
22762
22921
  const worktree = opts?.worktreePath?.trim();
22763
- const hasGraphSkill = !!worktree && (0, import_node_fs53.existsSync)((0, import_node_path52.join)(worktree, ".claude/skills/graph-engineering/SKILL.md"));
22764
- const hasReviewSkill = !!worktree && (0, import_node_fs53.existsSync)((0, import_node_path52.join)(worktree, ".claude/skills/review/SKILL.md"));
22765
- const hasInstallSkill = !!worktree && (0, import_node_fs53.existsSync)((0, import_node_path52.join)(worktree, ".claude/skills/worktree-install/SKILL.md"));
22922
+ const hasGraphSkill = !!worktree && (0, import_node_fs55.existsSync)((0, import_node_path53.join)(worktree, ".claude/skills/graph-engineering/SKILL.md"));
22923
+ const hasReviewSkill = !!worktree && (0, import_node_fs55.existsSync)((0, import_node_path53.join)(worktree, ".claude/skills/review/SKILL.md"));
22924
+ const hasInstallSkill = !!worktree && (0, import_node_fs55.existsSync)((0, import_node_path53.join)(worktree, ".claude/skills/worktree-install/SKILL.md"));
22766
22925
  return [
22767
22926
  "Process guides (recurring work only):",
22768
22927
  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,
@@ -22801,12 +22960,12 @@ function formatArtifactDirective() {
22801
22960
  function formatUiReminder() {
22802
22961
  return "Sideboard UI: markdown table is enough to read data; present_schema if they ask to edit/filter (even after markdown); present_files for the file manager. html fence or present_artifact, not both for the same document. type=log appends (same artifact_id, new lines only). ask_user only for a real multiple-choice (not hellos, \u201Cwhat next?\u201D, or after a review) \u2014 reply in chat. Do not say artifacts/CMS UI are unavailable. Dev / preview: run_dev_script (same as the Dev button); stop_dev_script to stop.";
22803
22962
  }
22804
- var import_node_fs53, import_node_path52, PR_GOAL_RE, GITHUB_TICKET_REF, KEYED_TICKET_REF;
22963
+ var import_node_fs55, import_node_path53, PR_GOAL_RE, GITHUB_TICKET_REF, KEYED_TICKET_REF;
22805
22964
  var init_instructions = __esm({
22806
22965
  "src/agents/instructions.ts"() {
22807
22966
  "use strict";
22808
- import_node_fs53 = require("fs");
22809
- import_node_path52 = require("path");
22967
+ import_node_fs55 = require("fs");
22968
+ import_node_path53 = require("path");
22810
22969
  init_git_auth_mode();
22811
22970
  init_branch_prefix();
22812
22971
  init_worktree_labels();
@@ -23192,40 +23351,40 @@ __export(plan_file_exports, {
23192
23351
  writePlanFile: () => writePlanFile
23193
23352
  });
23194
23353
  function ensureAttachmentsGitignore(worktreePath) {
23195
- const gitignoreAbs = (0, import_node_path53.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
23196
- if ((0, import_node_fs54.existsSync)(gitignoreAbs)) return;
23197
- (0, import_node_fs54.mkdirSync)((0, import_node_path53.dirname)(gitignoreAbs), { recursive: true });
23198
- (0, import_node_fs54.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
23354
+ const gitignoreAbs = (0, import_node_path54.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
23355
+ if ((0, import_node_fs56.existsSync)(gitignoreAbs)) return;
23356
+ (0, import_node_fs56.mkdirSync)((0, import_node_path54.dirname)(gitignoreAbs), { recursive: true });
23357
+ (0, import_node_fs56.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
23199
23358
  }
23200
23359
  function planFileAbs(worktreePath) {
23201
- return (0, import_node_path53.join)(worktreePath, PLAN_FILE_REL);
23360
+ return (0, import_node_path54.join)(worktreePath, PLAN_FILE_REL);
23202
23361
  }
23203
23362
  function readTextIfPresent2(abs) {
23204
- if (!(0, import_node_fs54.existsSync)(abs)) return null;
23363
+ if (!(0, import_node_fs56.existsSync)(abs)) return null;
23205
23364
  try {
23206
- const content = (0, import_node_fs54.readFileSync)(abs, "utf8");
23365
+ const content = (0, import_node_fs56.readFileSync)(abs, "utf8");
23207
23366
  return content.trim() ? content : null;
23208
23367
  } catch {
23209
23368
  return null;
23210
23369
  }
23211
23370
  }
23212
23371
  function readPlanFile(worktreePath) {
23213
- return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path53.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path53.join)(worktreePath, LEGACY_PLAN_FILE_REL));
23372
+ return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path54.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path54.join)(worktreePath, LEGACY_PLAN_FILE_REL));
23214
23373
  }
23215
23374
  function writePlanFile(worktreePath, content) {
23216
23375
  ensureAttachmentsGitignore(worktreePath);
23217
23376
  const abs = planFileAbs(worktreePath);
23218
- (0, import_node_fs54.mkdirSync)((0, import_node_path53.dirname)(abs), { recursive: true });
23377
+ (0, import_node_fs56.mkdirSync)((0, import_node_path54.dirname)(abs), { recursive: true });
23219
23378
  const body = content.trimEnd() + (content.endsWith("\n") ? "" : "\n");
23220
- (0, import_node_fs54.writeFileSync)(abs, body, "utf8");
23379
+ (0, import_node_fs56.writeFileSync)(abs, body, "utf8");
23221
23380
  return PLAN_FILE_REL;
23222
23381
  }
23223
- var import_node_fs54, import_node_path53;
23382
+ var import_node_fs56, import_node_path54;
23224
23383
  var init_plan_file = __esm({
23225
23384
  "src/plan/plan-file.ts"() {
23226
23385
  "use strict";
23227
- import_node_fs54 = require("fs");
23228
- import_node_path53 = require("path");
23386
+ import_node_fs56 = require("fs");
23387
+ import_node_path54 = require("path");
23229
23388
  init_workspace_scratch();
23230
23389
  init_plan_present();
23231
23390
  init_plan_present();
@@ -23287,9 +23446,9 @@ function recoverFinishedCursorRun(opts) {
23287
23446
  return best;
23288
23447
  }
23289
23448
  function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
23290
- if (!(0, import_node_fs55.existsSync)(runsPath)) return null;
23449
+ if (!(0, import_node_fs57.existsSync)(runsPath)) return null;
23291
23450
  try {
23292
- const lines = (0, import_node_fs55.readFileSync)(runsPath, "utf8").split("\n");
23451
+ const lines = (0, import_node_fs57.readFileSync)(runsPath, "utf8").split("\n");
23293
23452
  let best = null;
23294
23453
  for (const line of lines) {
23295
23454
  const trimmed = line.trim();
@@ -23315,11 +23474,11 @@ function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
23315
23474
  return null;
23316
23475
  }
23317
23476
  }
23318
- var import_node_fs55;
23477
+ var import_node_fs57;
23319
23478
  var init_cursor_recover = __esm({
23320
23479
  "src/agents/cursor-recover.ts"() {
23321
23480
  "use strict";
23322
- import_node_fs55 = require("fs");
23481
+ import_node_fs57 = require("fs");
23323
23482
  init_cursor_store();
23324
23483
  }
23325
23484
  });
@@ -23473,14 +23632,14 @@ async function startOrchestration(opts) {
23473
23632
  }
23474
23633
  return updated;
23475
23634
  }
23476
- var import_node_events, import_node_crypto12, import_node_fs56, LIVE_TURN_SPAWN_GRACE_MS, RUN_SCRIPT_DESKTOP_ADOPT_MS, STALE_AGENT_PID_WAIT_MS, LIGHT_RECONCILE_THROTTLE_MS, Orchestrator, singleton;
23635
+ var import_node_events, import_node_crypto12, import_node_fs58, LIVE_TURN_SPAWN_GRACE_MS, RUN_SCRIPT_DESKTOP_ADOPT_MS, STALE_AGENT_PID_WAIT_MS, LIGHT_RECONCILE_THROTTLE_MS, Orchestrator, singleton;
23477
23636
  var init_orchestrator = __esm({
23478
23637
  "src/orchestrator/orchestrator.ts"() {
23479
23638
  "use strict";
23480
23639
  import_node_events = require("events");
23481
23640
  init_outbound_watch();
23482
23641
  import_node_crypto12 = require("crypto");
23483
- import_node_fs56 = require("fs");
23642
+ import_node_fs58 = require("fs");
23484
23643
  init_error_detail();
23485
23644
  init_run();
23486
23645
  init_stale_lock();
@@ -23582,6 +23741,8 @@ var init_orchestrator = __esm({
23582
23741
  jobContinueNudged = /* @__PURE__ */ new Set();
23583
23742
  /** In-flight startDev per worktree run key — agent MCP + UI Start must not double-spawn. */
23584
23743
  startingDev = /* @__PURE__ */ new Map();
23744
+ /** Serialize desktop apply of `runScriptRequest` per thread (start then stop). */
23745
+ applyingRunScriptThreads = /* @__PURE__ */ new Set();
23585
23746
  /**
23586
23747
  * MCP/CLI poll budget while Electron main adopts `runScriptRequest`.
23587
23748
  * Tests shorten this so a missing desktop does not wait 20s.
@@ -23655,7 +23816,7 @@ var init_orchestrator = __esm({
23655
23816
  this.lightReconcileAt.set(repoPath, Date.now());
23656
23817
  for (const thread of listThreads()) {
23657
23818
  if (isGlobalThread(thread) || thread.repoPath !== repoPath) continue;
23658
- if (!(0, import_node_fs56.existsSync)(thread.worktreePath)) {
23819
+ if (!(0, import_node_fs58.existsSync)(thread.worktreePath)) {
23659
23820
  setStatus(thread.id, "broken", "Worktree missing on disk");
23660
23821
  this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
23661
23822
  }
@@ -23684,7 +23845,7 @@ var init_orchestrator = __esm({
23684
23845
  }
23685
23846
  continue;
23686
23847
  }
23687
- if (!(0, import_node_fs56.existsSync)(thread.worktreePath)) {
23848
+ if (!(0, import_node_fs58.existsSync)(thread.worktreePath)) {
23688
23849
  setStatus(thread.id, "broken", "Worktree missing on disk");
23689
23850
  this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
23690
23851
  continue;
@@ -23768,11 +23929,19 @@ var init_orchestrator = __esm({
23768
23929
  for (const thread of listThreads()) {
23769
23930
  if (thread.status === "archived") continue;
23770
23931
  const req = thread.runScriptRequest;
23771
- if (!isUnclaimedRunScriptRequest(req) || !req) continue;
23772
- const claimedAt = (/* @__PURE__ */ new Date()).toISOString();
23932
+ if (!isAdoptableRunScriptRequest(req) || !req) continue;
23933
+ if (this.applyingRunScriptThreads.has(thread.id)) continue;
23934
+ const claimedAt = req.claimedAt ?? (/* @__PURE__ */ new Date()).toISOString();
23773
23935
  const claimed = { ...req, claimedAt };
23936
+ this.applyingRunScriptThreads.add(thread.id);
23774
23937
  updateThread(thread.id, { runScriptRequest: claimed });
23775
- void this.applyRunScriptRequest(thread.id, claimed);
23938
+ void this.applyRunScriptRequest(thread.id, claimed).finally(() => {
23939
+ this.applyingRunScriptThreads.delete(thread.id);
23940
+ const latest = readThread(thread.id)?.runScriptRequest;
23941
+ if (latest && latest.requestId !== req.requestId && isAdoptableRunScriptRequest(latest)) {
23942
+ this.adoptPersistedRunScripts();
23943
+ }
23944
+ });
23776
23945
  }
23777
23946
  }
23778
23947
  async applyRunScriptRequest(threadId, req) {
@@ -25028,9 +25197,8 @@ var init_orchestrator = __esm({
25028
25197
  if (fulfilled && !run2) {
25029
25198
  throw new Error("Desktop reported the run script started, but it is not active.");
25030
25199
  }
25031
- } else {
25032
- const gone = scriptName ? !run2 : shared.activeRuns.length === 0;
25033
- if (fulfilled || gone) return null;
25200
+ } else if (fulfilled) {
25201
+ return null;
25034
25202
  }
25035
25203
  await new Promise((r) => setTimeout(r, 40));
25036
25204
  }
@@ -25038,12 +25206,26 @@ var init_orchestrator = __esm({
25038
25206
  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."
25039
25207
  );
25040
25208
  }
25209
+ async awaitStartingDev(worktreePath, scriptName) {
25210
+ const keys = scriptName ? [worktreeRunProcessKey(worktreePath, scriptName)] : [...this.startingDev.keys()].filter((k) => isWorktreeRunProcessKey(k, worktreePath));
25211
+ await Promise.all(
25212
+ keys.map(async (key) => {
25213
+ const pending = this.startingDev.get(key);
25214
+ if (!pending) return;
25215
+ try {
25216
+ await pending;
25217
+ } catch {
25218
+ }
25219
+ })
25220
+ );
25221
+ }
25041
25222
  async stopDev(threadRef, scriptName) {
25042
25223
  const thread = this.requireThread(threadRef);
25043
25224
  if (!this.shouldOwnRunScripts()) {
25044
25225
  await this.requestDesktopRunScript(thread, "stop", scriptName);
25045
25226
  return;
25046
25227
  }
25228
+ await this.awaitStartingDev(thread.worktreePath, scriptName);
25047
25229
  const siblings = threadsSharingWorktree(thread.worktreePath);
25048
25230
  const shared = mergeWorktreeActiveRuns(siblings);
25049
25231
  if (scriptName) {
@@ -25954,7 +26136,7 @@ var init_orchestrator = __esm({
25954
26136
  this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
25955
26137
  return restored2;
25956
26138
  }
25957
- if (!(0, import_node_fs56.existsSync)(thread.worktreePath)) {
26139
+ if (!(0, import_node_fs58.existsSync)(thread.worktreePath)) {
25958
26140
  if (isCowboyThread(thread) || isPrimaryCheckoutThread(thread)) {
25959
26141
  throw new Error(
25960
26142
  `Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
@@ -26199,6 +26381,7 @@ __export(index_exports, {
26199
26381
  CONTEXT_REVIEW_PATH: () => CONTEXT_REVIEW_PATH,
26200
26382
  CONVENTION_SETUP_RELPATHS: () => CONVENTION_SETUP_RELPATHS,
26201
26383
  COORDINATOR_TOOL_PLAYBOOK: () => COORDINATOR_TOOL_PLAYBOOK,
26384
+ CURSOR_SDK_INSTALL_HINT: () => CURSOR_SDK_INSTALL_HINT,
26202
26385
  DEFAULT_ABLETIME_HOST: () => DEFAULT_ABLETIME_HOST,
26203
26386
  DEFAULT_WORKTREE_SORT: () => DEFAULT_WORKTREE_SORT,
26204
26387
  DETACHED_JOBS_DIR: () => DETACHED_JOBS_DIR,
@@ -26630,6 +26813,7 @@ __export(index_exports, {
26630
26813
  isAbleTimeConnected: () => isAbleTimeConnected,
26631
26814
  isAbleTimeOAuthCancelled: () => isAbleTimeOAuthCancelled,
26632
26815
  isAbleTimeRejectedCredential: () => isAbleTimeRejectedCredential,
26816
+ isAdoptableRunScriptRequest: () => isAdoptableRunScriptRequest,
26633
26817
  isAgentDoneSound: () => isAgentDoneSound,
26634
26818
  isAskUserToolName: () => isAskUserToolName,
26635
26819
  isBrightsyConnected: () => isBrightsyConnected,
@@ -26639,6 +26823,7 @@ __export(index_exports, {
26639
26823
  isCowboyThread: () => isCowboyThread,
26640
26824
  isCursorApiKeyConfigured: () => isCursorApiKeyConfigured,
26641
26825
  isCursorAutoModel: () => isCursorAutoModel,
26826
+ isCursorSdkInstalled: () => isCursorSdkInstalled,
26642
26827
  isDefaultishSourceRef: () => isDefaultishSourceRef,
26643
26828
  isDesktopHostAlive: () => isDesktopHostAlive,
26644
26829
  isDirty: () => isDirty,
@@ -26689,6 +26874,7 @@ __export(index_exports, {
26689
26874
  issueSourceLabel: () => issueSourceLabel,
26690
26875
  issueTicketFromThread: () => issueTicketFromThread,
26691
26876
  killListenersOnPorts: () => killListenersOnPorts,
26877
+ killableListenerPids: () => killableListenerPids,
26692
26878
  lastAssistantMessageText: () => lastAssistantMessageText,
26693
26879
  lastRequestOccupancy: () => lastRequestOccupancy,
26694
26880
  latestPendingPlanQuestions: () => latestPendingPlanQuestions,
@@ -26777,6 +26963,8 @@ __export(index_exports, {
26777
26963
  normalizeThread: () => normalizeThread,
26778
26964
  normalizeTurnInput: () => normalizeTurnInput,
26779
26965
  normalizeWorktreePath: () => normalizeWorktreePath,
26966
+ npmGlobalNodeModules: () => npmGlobalNodeModules,
26967
+ npmGlobalPrefix: () => npmGlobalPrefix,
26780
26968
  openInSystemTerminal: () => openInSystemTerminal,
26781
26969
  openPrStackLayers: () => openPrStackLayers,
26782
26970
  openStackLayer: () => openStackLayer,
@@ -26865,6 +27053,7 @@ __export(index_exports, {
26865
27053
  resolveConductorCursorAgentId: () => resolveConductorCursorAgentId,
26866
27054
  resolveCreateFirstPrompt: () => resolveCreateFirstPrompt,
26867
27055
  resolveCursorModelId: () => resolveCursorModelId,
27056
+ resolveCursorSdkRoot: () => resolveCursorSdkRoot,
26868
27057
  resolveDefaultBranch: () => resolveDefaultBranch,
26869
27058
  resolveDetachedJobScript: () => resolveDetachedJobScript,
26870
27059
  resolveDiffBaseRef: () => resolveDiffBaseRef,
@@ -29204,6 +29393,15 @@ async function installOptionalServiceCli(id) {
29204
29393
  message: `${spec.label} has no CLI to install. Use the HTTP API with the stored token.`
29205
29394
  };
29206
29395
  }
29396
+ enrichPathWithNpmGlobalBin();
29397
+ const existing = await whichOnPath(spec.cli);
29398
+ if (existing) {
29399
+ return {
29400
+ ok: true,
29401
+ command: existing,
29402
+ message: `Already on PATH: ${existing}`
29403
+ };
29404
+ }
29207
29405
  return installNpmGlobalPackage({
29208
29406
  npmPackage: spec.npmPackage,
29209
29407
  installCommand: `npm install -g ${spec.npmPackage}`,
@@ -29562,7 +29760,7 @@ var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
29562
29760
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
29563
29761
  var import_zod9 = require("zod");
29564
29762
  var import_node_crypto16 = require("crypto");
29565
- var import_node_path56 = require("path");
29763
+ var import_node_path57 = require("path");
29566
29764
  init_orchestrator();
29567
29765
  init_worktree();
29568
29766
  init_global_workspace();
@@ -31299,27 +31497,27 @@ init_gh_errors();
31299
31497
  init_git_auth_mode();
31300
31498
 
31301
31499
  // src/board/load-home-board.ts
31302
- var import_node_fs58 = require("fs");
31303
- var import_node_path55 = require("path");
31500
+ var import_node_fs60 = require("fs");
31501
+ var import_node_path56 = require("path");
31304
31502
  init_worktree();
31305
31503
  init_paths();
31306
31504
 
31307
31505
  // src/board/board-pins.ts
31308
31506
  var import_node_crypto15 = require("crypto");
31309
- var import_node_fs57 = require("fs");
31310
- var import_node_path54 = require("path");
31507
+ var import_node_fs59 = require("fs");
31508
+ var import_node_path55 = require("path");
31311
31509
  init_paths();
31312
31510
  init_home_board();
31313
31511
  var FILE = "home-board-pins.json";
31314
31512
  var VERSION = 1;
31315
31513
  function pinsFile() {
31316
- return (0, import_node_path54.join)(appDataDir(), FILE);
31514
+ return (0, import_node_path55.join)(appDataDir(), FILE);
31317
31515
  }
31318
31516
  function readDisk() {
31319
31517
  const path2 = pinsFile();
31320
- if (!(0, import_node_fs57.existsSync)(path2)) return [];
31518
+ if (!(0, import_node_fs59.existsSync)(path2)) return [];
31321
31519
  try {
31322
- const raw = JSON.parse((0, import_node_fs57.readFileSync)(path2, "utf8"));
31520
+ const raw = JSON.parse((0, import_node_fs59.readFileSync)(path2, "utf8"));
31323
31521
  if (raw?.version !== VERSION || !Array.isArray(raw.items)) return [];
31324
31522
  return raw.items.filter((item) => item?.id && item.kind && item.ref);
31325
31523
  } catch {
@@ -31327,8 +31525,8 @@ function readDisk() {
31327
31525
  }
31328
31526
  }
31329
31527
  function writeDisk(items) {
31330
- (0, import_node_fs57.mkdirSync)(appDataDir(), { recursive: true });
31331
- (0, import_node_fs57.writeFileSync)(pinsFile(), JSON.stringify({ version: VERSION, items }, null, 2), "utf8");
31528
+ (0, import_node_fs59.mkdirSync)(appDataDir(), { recursive: true });
31529
+ (0, import_node_fs59.writeFileSync)(pinsFile(), JSON.stringify({ version: VERSION, items }, null, 2), "utf8");
31332
31530
  }
31333
31531
  function listBoardPins() {
31334
31532
  return readDisk();
@@ -31380,7 +31578,7 @@ function replaceBoardPins(items) {
31380
31578
  }
31381
31579
  function clearBoardPins() {
31382
31580
  try {
31383
- (0, import_node_fs57.unlinkSync)(pinsFile());
31581
+ (0, import_node_fs59.unlinkSync)(pinsFile());
31384
31582
  } catch {
31385
31583
  }
31386
31584
  }
@@ -31397,7 +31595,7 @@ function homeBoardWorkspaceKey(workspaces) {
31397
31595
  return workspaces.map((w) => w.path).filter(Boolean).sort().join("\n");
31398
31596
  }
31399
31597
  function cacheFile() {
31400
- return (0, import_node_path55.join)(appDataDir(), "home-board-cache.json");
31598
+ return (0, import_node_path56.join)(appDataDir(), "home-board-cache.json");
31401
31599
  }
31402
31600
  function emptyInputs() {
31403
31601
  return {
@@ -31423,9 +31621,9 @@ function shouldCacheHomeBoardInputs(inputs) {
31423
31621
  }
31424
31622
  function readDiskCache() {
31425
31623
  const path2 = cacheFile();
31426
- if (!(0, import_node_fs58.existsSync)(path2)) return null;
31624
+ if (!(0, import_node_fs60.existsSync)(path2)) return null;
31427
31625
  try {
31428
- const raw = JSON.parse((0, import_node_fs58.readFileSync)(path2, "utf8"));
31626
+ const raw = JSON.parse((0, import_node_fs60.readFileSync)(path2, "utf8"));
31429
31627
  if (raw?.version !== CACHE_VERSION || typeof raw.fetchedAt !== "number") {
31430
31628
  return null;
31431
31629
  }
@@ -31439,14 +31637,14 @@ function readDiskCache() {
31439
31637
  }
31440
31638
  function writeDiskCache(entry) {
31441
31639
  try {
31442
- (0, import_node_fs58.mkdirSync)(appDataDir(), { recursive: true });
31443
- (0, import_node_fs58.writeFileSync)(cacheFile(), JSON.stringify(entry), "utf8");
31640
+ (0, import_node_fs60.mkdirSync)(appDataDir(), { recursive: true });
31641
+ (0, import_node_fs60.writeFileSync)(cacheFile(), JSON.stringify(entry), "utf8");
31444
31642
  } catch {
31445
31643
  }
31446
31644
  }
31447
31645
  function deleteDiskCache() {
31448
31646
  try {
31449
- (0, import_node_fs58.unlinkSync)(cacheFile());
31647
+ (0, import_node_fs60.unlinkSync)(cacheFile());
31450
31648
  } catch {
31451
31649
  }
31452
31650
  }
@@ -31796,7 +31994,7 @@ async function startMcpServer() {
31796
31994
  async () => {
31797
31995
  const threads = orch.getThreads(true);
31798
31996
  const lines = threads.map((t) => {
31799
- const repo = t.repoPath === GLOBAL_WORKSPACE_ID2 ? "Orchestration" : (0, import_node_path56.basename)(t.repoPath) || t.repoPath;
31997
+ const repo = t.repoPath === GLOBAL_WORKSPACE_ID2 ? "Orchestration" : (0, import_node_path57.basename)(t.repoPath) || t.repoPath;
31800
31998
  const live = orch.threadLooksLive(t) ? readTurnLive(t.id) : null;
31801
31999
  const parent = t.parentThreadId ? ` parent:${t.parentThreadId.slice(0, 8)}` : "";
31802
32000
  const preview = lastMessagePreview(t.messages, 80);
@@ -34797,9 +34995,9 @@ var import_node_http4 = require("http");
34797
34995
  var import_ws3 = require("ws");
34798
34996
 
34799
34997
  // src/slack/relay-static.ts
34800
- var import_node_fs59 = require("fs");
34998
+ var import_node_fs61 = require("fs");
34801
34999
  var import_promises = require("fs/promises");
34802
- var import_node_path57 = __toESM(require("path"), 1);
35000
+ var import_node_path58 = __toESM(require("path"), 1);
34803
35001
  var TYPES = {
34804
35002
  ".css": "text/css; charset=utf-8",
34805
35003
  ".html": "text/html; charset=utf-8",
@@ -34830,9 +35028,9 @@ function resolveStaticPath(root, requestUrl) {
34830
35028
  return null;
34831
35029
  }
34832
35030
  if (!pathname.startsWith("/") || pathname.includes("\0")) return null;
34833
- const rootResolved = import_node_path57.default.resolve(root);
34834
- const candidate = import_node_path57.default.resolve(rootResolved, `.${pathname}`);
34835
- if (candidate !== rootResolved && !candidate.startsWith(rootResolved + import_node_path57.default.sep)) {
35031
+ const rootResolved = import_node_path58.default.resolve(root);
35032
+ const candidate = import_node_path58.default.resolve(rootResolved, `.${pathname}`);
35033
+ if (candidate !== rootResolved && !candidate.startsWith(rootResolved + import_node_path58.default.sep)) {
34836
35034
  return null;
34837
35035
  }
34838
35036
  return candidate;
@@ -34846,7 +35044,7 @@ async function fileSize(file) {
34846
35044
  }
34847
35045
  }
34848
35046
  function sendFile(req, res, file, size) {
34849
- const ext = import_node_path57.default.extname(file).toLowerCase();
35047
+ const ext = import_node_path58.default.extname(file).toLowerCase();
34850
35048
  res.writeHead(200, {
34851
35049
  "Content-Type": TYPES[ext] ?? "application/octet-stream",
34852
35050
  "Content-Length": size,
@@ -34856,7 +35054,7 @@ function sendFile(req, res, file, size) {
34856
35054
  res.end();
34857
35055
  return true;
34858
35056
  }
34859
- (0, import_node_fs59.createReadStream)(file).pipe(res);
35057
+ (0, import_node_fs61.createReadStream)(file).pipe(res);
34860
35058
  return true;
34861
35059
  }
34862
35060
  async function tryServeStatic(req, res, root) {
@@ -34865,7 +35063,7 @@ async function tryServeStatic(req, res, root) {
34865
35063
  if (!candidate) return false;
34866
35064
  const direct = await fileSize(candidate);
34867
35065
  if (direct != null) return sendFile(req, res, candidate, direct);
34868
- const asIndex = import_node_path57.default.join(candidate, "index.html");
35066
+ const asIndex = import_node_path58.default.join(candidate, "index.html");
34869
35067
  const indexSize = await fileSize(asIndex);
34870
35068
  if (indexSize != null) return sendFile(req, res, asIndex, indexSize);
34871
35069
  return false;
@@ -35153,6 +35351,7 @@ init_outbound_watch();
35153
35351
  CONTEXT_REVIEW_PATH,
35154
35352
  CONVENTION_SETUP_RELPATHS,
35155
35353
  COORDINATOR_TOOL_PLAYBOOK,
35354
+ CURSOR_SDK_INSTALL_HINT,
35156
35355
  DEFAULT_ABLETIME_HOST,
35157
35356
  DEFAULT_WORKTREE_SORT,
35158
35357
  DETACHED_JOBS_DIR,
@@ -35584,6 +35783,7 @@ init_outbound_watch();
35584
35783
  isAbleTimeConnected,
35585
35784
  isAbleTimeOAuthCancelled,
35586
35785
  isAbleTimeRejectedCredential,
35786
+ isAdoptableRunScriptRequest,
35587
35787
  isAgentDoneSound,
35588
35788
  isAskUserToolName,
35589
35789
  isBrightsyConnected,
@@ -35593,6 +35793,7 @@ init_outbound_watch();
35593
35793
  isCowboyThread,
35594
35794
  isCursorApiKeyConfigured,
35595
35795
  isCursorAutoModel,
35796
+ isCursorSdkInstalled,
35596
35797
  isDefaultishSourceRef,
35597
35798
  isDesktopHostAlive,
35598
35799
  isDirty,
@@ -35643,6 +35844,7 @@ init_outbound_watch();
35643
35844
  issueSourceLabel,
35644
35845
  issueTicketFromThread,
35645
35846
  killListenersOnPorts,
35847
+ killableListenerPids,
35646
35848
  lastAssistantMessageText,
35647
35849
  lastRequestOccupancy,
35648
35850
  latestPendingPlanQuestions,
@@ -35731,6 +35933,8 @@ init_outbound_watch();
35731
35933
  normalizeThread,
35732
35934
  normalizeTurnInput,
35733
35935
  normalizeWorktreePath,
35936
+ npmGlobalNodeModules,
35937
+ npmGlobalPrefix,
35734
35938
  openInSystemTerminal,
35735
35939
  openPrStackLayers,
35736
35940
  openStackLayer,
@@ -35819,6 +36023,7 @@ init_outbound_watch();
35819
36023
  resolveConductorCursorAgentId,
35820
36024
  resolveCreateFirstPrompt,
35821
36025
  resolveCursorModelId,
36026
+ resolveCursorSdkRoot,
35822
36027
  resolveDefaultBranch,
35823
36028
  resolveDetachedJobScript,
35824
36029
  resolveDiffBaseRef,