@sideboard-ai/core 0.1.97 → 0.1.99

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.
@@ -5167,6 +5167,7 @@ __export(global_workspace_exports, {
5167
5167
  createGlobalChat: () => createGlobalChat,
5168
5168
  ensureCloudCoordinator: () => ensureCloudCoordinator,
5169
5169
  ensureSlackCoordinator: () => ensureSlackCoordinator,
5170
+ findSlackCoordinator: () => findSlackCoordinator,
5170
5171
  globalAgentCwd: () => globalAgentCwd,
5171
5172
  healOrchestrationSoccerTitles: () => healOrchestrationSoccerTitles,
5172
5173
  isCloudCoordinatorThread: () => isCloudCoordinatorThread,
@@ -5313,42 +5314,40 @@ function findSlackCoordinator(teamId, userId) {
5313
5314
  (t) => t.status !== "archived" && t.sourceRef === ref && isSlackCoordinatorThread(t)
5314
5315
  );
5315
5316
  }
5316
- function ensureSlackCoordinator(teamId, userId, agent) {
5317
+ function ensureSlackCoordinator(teamId, userId, agent, opts) {
5317
5318
  const defaults = resolveThreadDefaults();
5318
5319
  const desired = assertOrchestratorCapableAgent(agent);
5319
5320
  const ref = slackCoordinatorSourceRef(teamId, userId);
5320
- const existing = findSlackCoordinator(teamId, userId);
5321
- if (existing) {
5322
- const patch = {};
5323
- if (existing.repoPath !== GLOBAL_WORKSPACE_ID) {
5324
- patch.repoPath = GLOBAL_WORKSPACE_ID;
5325
- patch.worktreePath = globalAgentCwd();
5326
- patch.branchName = "global";
5327
- }
5328
- const hasAgentTurns = existing.messages.some((m) => m.role === "agent");
5329
- const canRetarget = !existing.sessionId && !hasAgentTurns && existing.status !== "running" && existing.status !== "queued";
5330
- if (canRetarget) {
5331
- if (existing.agent !== desired) patch.agent = desired;
5332
- if (existing.model !== defaults.model) patch.model = defaults.model;
5333
- if (existing.effort !== defaults.effort) patch.effort = defaults.effort;
5334
- if (existing.fast !== defaults.fast) patch.fast = defaults.fast;
5335
- }
5336
- if (Object.keys(patch).length > 0) {
5337
- return updateThread(existing.id, patch);
5321
+ if (!opts?.forceNew) {
5322
+ const existing = findSlackCoordinator(teamId, userId);
5323
+ if (existing) {
5324
+ const patch = {};
5325
+ if (existing.repoPath !== GLOBAL_WORKSPACE_ID) {
5326
+ patch.repoPath = GLOBAL_WORKSPACE_ID;
5327
+ patch.worktreePath = globalAgentCwd();
5328
+ patch.branchName = "global";
5329
+ }
5330
+ const hasAgentTurns = existing.messages.some((m) => m.role === "agent");
5331
+ const canRetarget = !existing.sessionId && !hasAgentTurns && existing.status !== "running" && existing.status !== "queued";
5332
+ if (canRetarget) {
5333
+ if (existing.agent !== desired) patch.agent = desired;
5334
+ if (existing.model !== defaults.model) patch.model = defaults.model;
5335
+ if (existing.effort !== defaults.effort) patch.effort = defaults.effort;
5336
+ if (existing.fast !== defaults.fast) patch.fast = defaults.fast;
5337
+ }
5338
+ if (Object.keys(patch).length > 0) {
5339
+ return updateThread(existing.id, patch);
5340
+ }
5341
+ return existing;
5338
5342
  }
5339
- return existing;
5340
5343
  }
5341
- const created = createGlobalChat({
5344
+ return createGlobalChat({
5342
5345
  sourceRef: ref,
5343
5346
  agent: desired,
5344
5347
  model: defaults.model,
5345
5348
  effort: defaults.effort,
5346
5349
  fast: defaults.fast
5347
5350
  });
5348
- const all = listThreads({ includeArchived: true }).filter(
5349
- (t) => t.status !== "archived" && t.sourceRef === ref && isSlackCoordinatorThread(t)
5350
- ).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
5351
- return all[0] ?? created;
5352
5351
  }
5353
5352
  function ensureCloudCoordinator(agent) {
5354
5353
  const defaults = resolveThreadDefaults();
@@ -8645,40 +8644,40 @@ __export(plan_file_exports, {
8645
8644
  writePlanFile: () => writePlanFile
8646
8645
  });
8647
8646
  function ensureAttachmentsGitignore2(worktreePath) {
8648
- const gitignoreAbs = (0, import_node_path35.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
8649
- if ((0, import_node_fs38.existsSync)(gitignoreAbs)) return;
8650
- (0, import_node_fs38.mkdirSync)((0, import_node_path35.dirname)(gitignoreAbs), { recursive: true });
8651
- (0, import_node_fs38.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
8647
+ const gitignoreAbs = (0, import_node_path36.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
8648
+ if ((0, import_node_fs39.existsSync)(gitignoreAbs)) return;
8649
+ (0, import_node_fs39.mkdirSync)((0, import_node_path36.dirname)(gitignoreAbs), { recursive: true });
8650
+ (0, import_node_fs39.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
8652
8651
  }
8653
8652
  function planFileAbs(worktreePath) {
8654
- return (0, import_node_path35.join)(worktreePath, PLAN_FILE_REL);
8653
+ return (0, import_node_path36.join)(worktreePath, PLAN_FILE_REL);
8655
8654
  }
8656
8655
  function readTextIfPresent2(abs) {
8657
- if (!(0, import_node_fs38.existsSync)(abs)) return null;
8656
+ if (!(0, import_node_fs39.existsSync)(abs)) return null;
8658
8657
  try {
8659
- const content = (0, import_node_fs38.readFileSync)(abs, "utf8");
8658
+ const content = (0, import_node_fs39.readFileSync)(abs, "utf8");
8660
8659
  return content.trim() ? content : null;
8661
8660
  } catch {
8662
8661
  return null;
8663
8662
  }
8664
8663
  }
8665
8664
  function readPlanFile(worktreePath) {
8666
- return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path35.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path35.join)(worktreePath, LEGACY_PLAN_FILE_REL));
8665
+ return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path36.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path36.join)(worktreePath, LEGACY_PLAN_FILE_REL));
8667
8666
  }
8668
8667
  function writePlanFile(worktreePath, content) {
8669
8668
  ensureAttachmentsGitignore2(worktreePath);
8670
8669
  const abs = planFileAbs(worktreePath);
8671
- (0, import_node_fs38.mkdirSync)((0, import_node_path35.dirname)(abs), { recursive: true });
8670
+ (0, import_node_fs39.mkdirSync)((0, import_node_path36.dirname)(abs), { recursive: true });
8672
8671
  const body = content.trimEnd() + (content.endsWith("\n") ? "" : "\n");
8673
- (0, import_node_fs38.writeFileSync)(abs, body, "utf8");
8672
+ (0, import_node_fs39.writeFileSync)(abs, body, "utf8");
8674
8673
  return PLAN_FILE_REL;
8675
8674
  }
8676
- var import_node_fs38, import_node_path35;
8675
+ var import_node_fs39, import_node_path36;
8677
8676
  var init_plan_file = __esm({
8678
8677
  "src/plan/plan-file.ts"() {
8679
8678
  "use strict";
8680
- import_node_fs38 = require("fs");
8681
- import_node_path35 = require("path");
8679
+ import_node_fs39 = require("fs");
8680
+ import_node_path36 = require("path");
8682
8681
  init_workspace_scratch();
8683
8682
  init_plan_present();
8684
8683
  init_plan_present();
@@ -8699,7 +8698,7 @@ function setCaffeinateHoldHooks(next) {
8699
8698
  hooks = next;
8700
8699
  }
8701
8700
  function caffeinateHoldPath() {
8702
- return (0, import_node_path36.join)(appDataDir(), "caffeinate-hold.json");
8701
+ return (0, import_node_path37.join)(appDataDir(), "caffeinate-hold.json");
8703
8702
  }
8704
8703
  function processAlive(pid) {
8705
8704
  if (hooks.processAlive) return hooks.processAlive(pid);
@@ -8733,9 +8732,9 @@ function uniqueIds(ids) {
8733
8732
  }
8734
8733
  function readHold() {
8735
8734
  const path = caffeinateHoldPath();
8736
- if (!(0, import_node_fs39.existsSync)(path)) return null;
8735
+ if (!(0, import_node_fs40.existsSync)(path)) return null;
8737
8736
  try {
8738
- const parsed = JSON.parse((0, import_node_fs39.readFileSync)(path, "utf8"));
8737
+ const parsed = JSON.parse((0, import_node_fs40.readFileSync)(path, "utf8"));
8739
8738
  if (typeof parsed?.pid === "number" && parsed.pid > 0) {
8740
8739
  return {
8741
8740
  pid: parsed.pid,
@@ -8757,7 +8756,7 @@ function writeHold(pid, threadIds) {
8757
8756
  }
8758
8757
  function clearHold() {
8759
8758
  try {
8760
- (0, import_node_fs39.unlinkSync)(caffeinateHoldPath());
8759
+ (0, import_node_fs40.unlinkSync)(caffeinateHoldPath());
8761
8760
  } catch {
8762
8761
  }
8763
8762
  }
@@ -8842,13 +8841,13 @@ function releaseCaffeinateHoldForThread(threadId) {
8842
8841
  }
8843
8842
  return setCaffeinateHold(false, { threadId: id });
8844
8843
  }
8845
- var import_node_child_process4, import_node_fs39, import_node_path36, hooks;
8844
+ var import_node_child_process4, import_node_fs40, import_node_path37, hooks;
8846
8845
  var init_caffeinate_hold = __esm({
8847
8846
  "src/store/caffeinate-hold.ts"() {
8848
8847
  "use strict";
8849
8848
  import_node_child_process4 = require("child_process");
8850
- import_node_fs39 = require("fs");
8851
- import_node_path36 = require("path");
8849
+ import_node_fs40 = require("fs");
8850
+ import_node_path37 = require("path");
8852
8851
  init_paths();
8853
8852
  init_private_file();
8854
8853
  hooks = {};
@@ -8863,10 +8862,10 @@ __export(cursor_recover_exports, {
8863
8862
  function recoverFinishedCursorRun(opts) {
8864
8863
  const agentId = opts.agentId.trim();
8865
8864
  if (!agentId) return null;
8866
- const runsPath = (0, import_node_path37.join)(appDataDir(), "cursor-sdk-store", "runs.ndjson");
8867
- if (!(0, import_node_fs40.existsSync)(runsPath)) return null;
8865
+ const runsPath = (0, import_node_path38.join)(appDataDir(), "cursor-sdk-store", "runs.ndjson");
8866
+ if (!(0, import_node_fs41.existsSync)(runsPath)) return null;
8868
8867
  try {
8869
- const lines = (0, import_node_fs40.readFileSync)(runsPath, "utf8").split("\n");
8868
+ const lines = (0, import_node_fs41.readFileSync)(runsPath, "utf8").split("\n");
8870
8869
  let best = null;
8871
8870
  for (const line of lines) {
8872
8871
  const trimmed = line.trim();
@@ -8892,12 +8891,12 @@ function recoverFinishedCursorRun(opts) {
8892
8891
  return null;
8893
8892
  }
8894
8893
  }
8895
- var import_node_fs40, import_node_path37;
8894
+ var import_node_fs41, import_node_path38;
8896
8895
  var init_cursor_recover = __esm({
8897
8896
  "src/agents/cursor-recover.ts"() {
8898
8897
  "use strict";
8899
- import_node_fs40 = require("fs");
8900
- import_node_path37 = require("path");
8898
+ import_node_fs41 = require("fs");
8899
+ import_node_path38 = require("path");
8901
8900
  init_paths();
8902
8901
  }
8903
8902
  });
@@ -8909,7 +8908,7 @@ init_nested_electron_env();
8909
8908
  var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
8910
8909
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
8911
8910
  var import_zod3 = require("zod");
8912
- var import_node_path38 = require("path");
8911
+ var import_node_path39 = require("path");
8913
8912
 
8914
8913
  // src/orchestrator/orchestrator.ts
8915
8914
  var import_node_events = require("events");
@@ -9420,7 +9419,7 @@ async function refreshSlackReplyBadges(opts) {
9420
9419
  }
9421
9420
 
9422
9421
  // src/orchestrator/orchestrator.ts
9423
- var import_node_fs41 = require("fs");
9422
+ var import_node_fs42 = require("fs");
9424
9423
  init_error_detail();
9425
9424
 
9426
9425
  // src/agents/spawn.ts
@@ -10537,8 +10536,44 @@ async function cloneRepoIntoSideboard(opts) {
10537
10536
  // src/orchestrator/orchestrator.ts
10538
10537
  init_thread_store();
10539
10538
 
10540
- // src/threads/create.ts
10539
+ // src/store/desktop-host.ts
10541
10540
  var import_node_fs30 = require("fs");
10541
+ var import_node_path29 = require("path");
10542
+ init_paths();
10543
+ function desktopHostPidPath() {
10544
+ return (0, import_node_path29.join)(appDataDir(), "desktop-host.pid");
10545
+ }
10546
+ function readDesktopHostPid() {
10547
+ try {
10548
+ const pid = Number.parseInt((0, import_node_fs30.readFileSync)(desktopHostPidPath(), "utf8").trim(), 10);
10549
+ if (!Number.isFinite(pid) || pid <= 0) return null;
10550
+ return pid;
10551
+ } catch {
10552
+ return null;
10553
+ }
10554
+ }
10555
+ function pidAlive(pid) {
10556
+ try {
10557
+ process.kill(pid, 0);
10558
+ return true;
10559
+ } catch {
10560
+ return false;
10561
+ }
10562
+ }
10563
+ function isDesktopHostAlive() {
10564
+ const pid = readDesktopHostPid();
10565
+ return pid != null && pidAlive(pid);
10566
+ }
10567
+ function isThisProcessDesktopHost() {
10568
+ return readDesktopHostPid() === process.pid && pidAlive(process.pid);
10569
+ }
10570
+ function thisProcessShouldDrainAgentQueues() {
10571
+ if (isThisProcessDesktopHost()) return true;
10572
+ return !isDesktopHostAlive();
10573
+ }
10574
+
10575
+ // src/threads/create.ts
10576
+ var import_node_fs31 = require("fs");
10542
10577
 
10543
10578
  // src/detect/detect.ts
10544
10579
  init_agents();
@@ -10583,7 +10618,7 @@ async function createThread(input, _onSetupLine) {
10583
10618
  });
10584
10619
  await requireAgent(resolved.agent);
10585
10620
  const repoPath = await resolveRepoRoot(input.repoPath);
10586
- if (!(0, import_node_fs30.existsSync)(repoPath)) {
10621
+ if (!(0, import_node_fs31.existsSync)(repoPath)) {
10587
10622
  throw new Error(`Repo not found: ${repoPath}`);
10588
10623
  }
10589
10624
  let sourceRef = input.sourceRef;
@@ -11014,6 +11049,7 @@ function createChatTab(input) {
11014
11049
  if (isOrchestratorThread(from) || binding.sourceType === "orchestration") {
11015
11050
  assertOrchestratorCapableAgent(nextAgent);
11016
11051
  }
11052
+ const singletonInbox = isSlackCoordinatorThread(from) || isCloudCoordinatorThread(from);
11017
11053
  const thread = createEmptyThread({
11018
11054
  title,
11019
11055
  // Chat-tab nicknames (soccer team or explicit) must stick. Post-turn
@@ -11021,6 +11057,10 @@ function createChatTab(input) {
11021
11057
  // shared worktree folder name (e.g. fork "Arsenal" → "Monaco").
11022
11058
  userSetTitle: true,
11023
11059
  ...binding,
11060
+ // Slack / Brightsy cloud identity stays on the original chat. A + tab
11061
+ // that copies `slack:team:user` would steal inbound DMs after you close
11062
+ // the connected chat.
11063
+ sourceRef: singletonInbox ? title : binding.sourceRef,
11024
11064
  agent: nextAgent,
11025
11065
  model: input.model !== void 0 ? input.model : input.agent && input.agent !== from.agent ? null : from.model,
11026
11066
  effort: input.effort !== void 0 ? input.effort : from.effort,
@@ -11054,8 +11094,8 @@ function forkChatTab(input) {
11054
11094
 
11055
11095
  // src/review/request-review.ts
11056
11096
  var import_node_crypto5 = require("crypto");
11057
- var import_node_fs31 = require("fs");
11058
- var import_node_path29 = require("path");
11097
+ var import_node_fs32 = require("fs");
11098
+ var import_node_path30 = require("path");
11059
11099
  init_global_workspace();
11060
11100
  init_thread_store();
11061
11101
 
@@ -11203,22 +11243,22 @@ function shouldRefreshReviewRequestTemplate(content) {
11203
11243
  return LEGACY_REVIEW_TEMPLATE_MARKERS.every((m) => trimmed.includes(m));
11204
11244
  }
11205
11245
  function readTextIfPresent(abs) {
11206
- if (!(0, import_node_fs31.existsSync)(abs)) return null;
11246
+ if (!(0, import_node_fs32.existsSync)(abs)) return null;
11207
11247
  try {
11208
- const content = (0, import_node_fs31.readFileSync)(abs, "utf8");
11248
+ const content = (0, import_node_fs32.readFileSync)(abs, "utf8");
11209
11249
  return content.trim() ? content : null;
11210
11250
  } catch {
11211
11251
  return null;
11212
11252
  }
11213
11253
  }
11214
11254
  function ensureAttachmentsGitignore(worktreePath) {
11215
- const gitignoreAbs = (0, import_node_path29.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
11216
- if ((0, import_node_fs31.existsSync)(gitignoreAbs)) return;
11217
- (0, import_node_fs31.mkdirSync)((0, import_node_path29.dirname)(gitignoreAbs), { recursive: true });
11218
- (0, import_node_fs31.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
11255
+ const gitignoreAbs = (0, import_node_path30.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
11256
+ if ((0, import_node_fs32.existsSync)(gitignoreAbs)) return;
11257
+ (0, import_node_fs32.mkdirSync)((0, import_node_path30.dirname)(gitignoreAbs), { recursive: true });
11258
+ (0, import_node_fs32.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
11219
11259
  }
11220
11260
  function resolveReviewGuidelines(worktreePath) {
11221
- const repoAbs = (0, import_node_path29.join)(worktreePath, REPO_REVIEW_PATH);
11261
+ const repoAbs = (0, import_node_path30.join)(worktreePath, REPO_REVIEW_PATH);
11222
11262
  const repoContent = readTextIfPresent(repoAbs);
11223
11263
  if (repoContent) {
11224
11264
  return {
@@ -11228,7 +11268,7 @@ function resolveReviewGuidelines(worktreePath) {
11228
11268
  source: "repo"
11229
11269
  };
11230
11270
  }
11231
- const localAbs = (0, import_node_path29.join)(worktreePath, REVIEW_REQUEST_PATH);
11271
+ const localAbs = (0, import_node_path30.join)(worktreePath, REVIEW_REQUEST_PATH);
11232
11272
  const localContent = readTextIfPresent(localAbs);
11233
11273
  if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
11234
11274
  return {
@@ -11238,7 +11278,7 @@ function resolveReviewGuidelines(worktreePath) {
11238
11278
  source: "local"
11239
11279
  };
11240
11280
  }
11241
- const legacyAbs = (0, import_node_path29.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
11281
+ const legacyAbs = (0, import_node_path30.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
11242
11282
  const legacyContent = readTextIfPresent(legacyAbs);
11243
11283
  if (legacyContent && !shouldRefreshReviewRequestTemplate(legacyContent)) {
11244
11284
  return {
@@ -11249,8 +11289,8 @@ function resolveReviewGuidelines(worktreePath) {
11249
11289
  };
11250
11290
  }
11251
11291
  ensureAttachmentsGitignore(worktreePath);
11252
- (0, import_node_fs31.mkdirSync)((0, import_node_path29.dirname)(localAbs), { recursive: true });
11253
- (0, import_node_fs31.writeFileSync)(localAbs, REVIEW_REQUEST_TEMPLATE, "utf8");
11292
+ (0, import_node_fs32.mkdirSync)((0, import_node_path30.dirname)(localAbs), { recursive: true });
11293
+ (0, import_node_fs32.writeFileSync)(localAbs, REVIEW_REQUEST_TEMPLATE, "utf8");
11254
11294
  return {
11255
11295
  path: REVIEW_REQUEST_PATH,
11256
11296
  name: REVIEW_REQUEST_NAME,
@@ -11450,21 +11490,21 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText) {
11450
11490
 
11451
11491
  // src/threads/adopt.ts
11452
11492
  var import_node_child_process3 = require("child_process");
11453
- var import_node_fs32 = require("fs");
11493
+ var import_node_fs33 = require("fs");
11454
11494
  var import_node_os10 = require("os");
11455
- var import_node_path30 = require("path");
11495
+ var import_node_path31 = require("path");
11456
11496
  var import_node_module4 = require("module");
11457
11497
  init_worktree();
11458
11498
  init_thread_store();
11459
11499
  var import_meta4 = {};
11460
- var CONDUCTOR_APP_SUPPORT = (0, import_node_path30.join)(
11500
+ var CONDUCTOR_APP_SUPPORT = (0, import_node_path31.join)(
11461
11501
  process.env.HOME ?? "",
11462
11502
  "Library",
11463
11503
  "Application Support",
11464
11504
  "com.conductor.app"
11465
11505
  );
11466
- var CONDUCTOR_DB = (0, import_node_path30.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
11467
- var CURSOR_SDK_STORE = (0, import_node_path30.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
11506
+ var CONDUCTOR_DB = (0, import_node_path31.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
11507
+ var CURSOR_SDK_STORE = (0, import_node_path31.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
11468
11508
  function openReadonlySqlite(file) {
11469
11509
  const req = (0, import_node_module4.createRequire)(import_meta4.url);
11470
11510
  const Database = req("better-sqlite3");
@@ -11481,21 +11521,21 @@ function mapAgentType(raw) {
11481
11521
  return null;
11482
11522
  }
11483
11523
  function resolveConductorCursorAgentId(workspacePath) {
11484
- if (!workspacePath || !(0, import_node_fs32.existsSync)(CURSOR_SDK_STORE)) return null;
11524
+ if (!workspacePath || !(0, import_node_fs33.existsSync)(CURSOR_SDK_STORE)) return null;
11485
11525
  const normalized = workspacePath.replace(/\/$/, "");
11486
11526
  let best = null;
11487
11527
  let hashes;
11488
11528
  try {
11489
- hashes = (0, import_node_fs32.readdirSync)(CURSOR_SDK_STORE);
11529
+ hashes = (0, import_node_fs33.readdirSync)(CURSOR_SDK_STORE);
11490
11530
  } catch {
11491
11531
  return null;
11492
11532
  }
11493
11533
  for (const hash of hashes) {
11494
- const agentsFile = (0, import_node_path30.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
11495
- if (!(0, import_node_fs32.existsSync)(agentsFile)) continue;
11534
+ const agentsFile = (0, import_node_path31.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
11535
+ if (!(0, import_node_fs33.existsSync)(agentsFile)) continue;
11496
11536
  let text3;
11497
11537
  try {
11498
- text3 = (0, import_node_fs32.readFileSync)(agentsFile, "utf8");
11538
+ text3 = (0, import_node_fs33.readFileSync)(agentsFile, "utf8");
11499
11539
  } catch {
11500
11540
  continue;
11501
11541
  }
@@ -11519,7 +11559,7 @@ function resolveConductorCursorAgentId(workspacePath) {
11519
11559
  return best?.agentId ?? null;
11520
11560
  }
11521
11561
  async function adoptThread(input) {
11522
- if (!(0, import_node_fs32.existsSync)(input.worktreePath)) {
11562
+ if (!(0, import_node_fs33.existsSync)(input.worktreePath)) {
11523
11563
  throw new Error(`Worktree not found: ${input.worktreePath}`);
11524
11564
  }
11525
11565
  const repoPath = await resolveRepoRoot(input.worktreePath);
@@ -11543,18 +11583,18 @@ async function adoptThread(input) {
11543
11583
  return thread;
11544
11584
  }
11545
11585
  function listConductorWorkspaces() {
11546
- if (!(0, import_node_fs32.existsSync)(CONDUCTOR_DB)) {
11586
+ if (!(0, import_node_fs33.existsSync)(CONDUCTOR_DB)) {
11547
11587
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
11548
11588
  }
11549
- const tmp = (0, import_node_fs32.mkdtempSync)((0, import_node_path30.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
11550
- const snapshot = (0, import_node_path30.join)(tmp, "conductor.db");
11589
+ const tmp = (0, import_node_fs33.mkdtempSync)((0, import_node_path31.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
11590
+ const snapshot = (0, import_node_path31.join)(tmp, "conductor.db");
11551
11591
  try {
11552
- (0, import_node_fs32.copyFileSync)(CONDUCTOR_DB, snapshot);
11592
+ (0, import_node_fs33.copyFileSync)(CONDUCTOR_DB, snapshot);
11553
11593
  for (const suffix of ["-wal", "-shm"]) {
11554
11594
  const src = `${CONDUCTOR_DB}${suffix}`;
11555
- if ((0, import_node_fs32.existsSync)(src)) {
11595
+ if ((0, import_node_fs33.existsSync)(src)) {
11556
11596
  try {
11557
- (0, import_node_fs32.copyFileSync)(src, `${snapshot}${suffix}`);
11597
+ (0, import_node_fs33.copyFileSync)(src, `${snapshot}${suffix}`);
11558
11598
  } catch {
11559
11599
  }
11560
11600
  }
@@ -11630,22 +11670,22 @@ function listConductorWorkspaces() {
11630
11670
  db.close();
11631
11671
  }
11632
11672
  } finally {
11633
- (0, import_node_fs32.rmSync)(tmp, { recursive: true, force: true });
11673
+ (0, import_node_fs33.rmSync)(tmp, { recursive: true, force: true });
11634
11674
  }
11635
11675
  }
11636
11676
  function importConductorWorkspace(workspaceId) {
11637
- if (!(0, import_node_fs32.existsSync)(CONDUCTOR_DB)) {
11677
+ if (!(0, import_node_fs33.existsSync)(CONDUCTOR_DB)) {
11638
11678
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
11639
11679
  }
11640
- const tmp = (0, import_node_fs32.mkdtempSync)((0, import_node_path30.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
11641
- const snapshot = (0, import_node_path30.join)(tmp, "conductor.db");
11680
+ const tmp = (0, import_node_fs33.mkdtempSync)((0, import_node_path31.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
11681
+ const snapshot = (0, import_node_path31.join)(tmp, "conductor.db");
11642
11682
  try {
11643
- (0, import_node_fs32.copyFileSync)(CONDUCTOR_DB, snapshot);
11683
+ (0, import_node_fs33.copyFileSync)(CONDUCTOR_DB, snapshot);
11644
11684
  for (const suffix of ["-wal", "-shm"]) {
11645
11685
  const src = `${CONDUCTOR_DB}${suffix}`;
11646
- if ((0, import_node_fs32.existsSync)(src)) {
11686
+ if ((0, import_node_fs33.existsSync)(src)) {
11647
11687
  try {
11648
- (0, import_node_fs32.copyFileSync)(src, `${snapshot}${suffix}`);
11688
+ (0, import_node_fs33.copyFileSync)(src, `${snapshot}${suffix}`);
11649
11689
  } catch {
11650
11690
  }
11651
11691
  }
@@ -11663,7 +11703,7 @@ function importConductorWorkspace(workspaceId) {
11663
11703
  ).get(workspaceId);
11664
11704
  if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
11665
11705
  const worktreePath = String(row.workspacePath);
11666
- if (!(0, import_node_fs32.existsSync)(worktreePath)) {
11706
+ if (!(0, import_node_fs33.existsSync)(worktreePath)) {
11667
11707
  throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
11668
11708
  }
11669
11709
  let sessionId = null;
@@ -11726,7 +11766,7 @@ function importConductorWorkspace(workspaceId) {
11726
11766
  db.close();
11727
11767
  }
11728
11768
  } finally {
11729
- (0, import_node_fs32.rmSync)(tmp, { recursive: true, force: true });
11769
+ (0, import_node_fs33.rmSync)(tmp, { recursive: true, force: true });
11730
11770
  }
11731
11771
  }
11732
11772
  async function importConductorWorkspaceAsync(workspaceId) {
@@ -11734,7 +11774,7 @@ async function importConductorWorkspaceAsync(workspaceId) {
11734
11774
  }
11735
11775
 
11736
11776
  // src/threads/stack-layers.ts
11737
- var import_node_fs33 = require("fs");
11777
+ var import_node_fs34 = require("fs");
11738
11778
  init_run();
11739
11779
  init_stack();
11740
11780
  init_worktree();
@@ -11802,7 +11842,7 @@ async function openStackLayer(input, _onSetupLine) {
11802
11842
  let createdWorktree = false;
11803
11843
  const trees = await listWorktrees(repoPath);
11804
11844
  const checkedOut = trees.find((w) => w.branch === branchName);
11805
- if (checkedOut?.path && (0, import_node_fs33.existsSync)(checkedOut.path)) {
11845
+ if (checkedOut?.path && (0, import_node_fs34.existsSync)(checkedOut.path)) {
11806
11846
  if (input.reuseExistingWorktree !== false) {
11807
11847
  worktreePath = checkedOut.path;
11808
11848
  } else {
@@ -11944,7 +11984,7 @@ async function initStackFromThread(input, onSetupLine) {
11944
11984
  async function createPrStack(input, onSetupLine) {
11945
11985
  await requireAgent(input.agent);
11946
11986
  const repoPath = await resolveRepoRoot(input.repoPath);
11947
- if (!(0, import_node_fs33.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
11987
+ if (!(0, import_node_fs34.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
11948
11988
  if (!input.branches.length) throw new Error("At least one branch name required");
11949
11989
  const status = await detectGhStack(repoPath);
11950
11990
  if (!status.available) throw new Error(status.reason);
@@ -12011,7 +12051,7 @@ async function createPrStack(input, onSetupLine) {
12011
12051
  }
12012
12052
  }
12013
12053
  const claimed = new Set(threads.map((t) => t.worktreePath));
12014
- if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs33.existsSync)(bootstrap.worktreePath)) {
12054
+ if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs34.existsSync)(bootstrap.worktreePath)) {
12015
12055
  try {
12016
12056
  await removeWorktree(repoPath, bootstrap.worktreePath, {
12017
12057
  deleteBranch: bootstrap.branchName
@@ -12026,12 +12066,12 @@ async function createPrStack(input, onSetupLine) {
12026
12066
  init_worktree();
12027
12067
 
12028
12068
  // src/diff/diff.ts
12029
- var import_node_fs34 = require("fs");
12030
- var import_node_path31 = require("path");
12069
+ var import_node_fs35 = require("fs");
12070
+ var import_node_path32 = require("path");
12031
12071
  init_run();
12032
12072
  init_worktree();
12033
12073
  async function inspectGitWorktree(worktreePath) {
12034
- if (!worktreePath || !(0, import_node_fs34.existsSync)(worktreePath)) return "missing_worktree";
12074
+ if (!worktreePath || !(0, import_node_fs35.existsSync)(worktreePath)) return "missing_worktree";
12035
12075
  const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
12036
12076
  reject: false
12037
12077
  });
@@ -12039,7 +12079,7 @@ async function inspectGitWorktree(worktreePath) {
12039
12079
  return "ok";
12040
12080
  }
12041
12081
  async function initializeGitRepository(worktreePath) {
12042
- if (!worktreePath || !(0, import_node_fs34.existsSync)(worktreePath)) {
12082
+ if (!worktreePath || !(0, import_node_fs35.existsSync)(worktreePath)) {
12043
12083
  throw new Error("Worktree not found");
12044
12084
  }
12045
12085
  const status = await inspectGitWorktree(worktreePath);
@@ -12175,11 +12215,11 @@ new file mode 100644
12175
12215
  };
12176
12216
  }
12177
12217
  async function untrackedPatch(worktreePath, path, maxHunk) {
12178
- const abs = (0, import_node_path31.join)(worktreePath, path);
12218
+ const abs = (0, import_node_path32.join)(worktreePath, path);
12179
12219
  try {
12180
- const st = (0, import_node_fs34.statSync)(abs);
12220
+ const st = (0, import_node_fs35.statSync)(abs);
12181
12221
  if (st.isFile() && st.size > maxHunk) {
12182
- const buf = (0, import_node_fs34.readFileSync)(abs).subarray(0, maxHunk);
12222
+ const buf = (0, import_node_fs35.readFileSync)(abs).subarray(0, maxHunk);
12183
12223
  return syntheticAddPatch(path, buf.toString("utf8"), maxHunk);
12184
12224
  }
12185
12225
  } catch {
@@ -12680,8 +12720,8 @@ var DEFAULT_UPLOAD_MAX_BYTES = 5e7;
12680
12720
  function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
12681
12721
  assertSafeRelativePath(relativePath);
12682
12722
  const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
12683
- const abs = (0, import_node_path31.join)(worktreePath, relativePath);
12684
- const st = (0, import_node_fs34.statSync)(abs);
12723
+ const abs = (0, import_node_path32.join)(worktreePath, relativePath);
12724
+ const st = (0, import_node_fs35.statSync)(abs);
12685
12725
  if (!st.isFile()) {
12686
12726
  throw new Error(`Not a file: ${relativePath}`);
12687
12727
  }
@@ -12690,7 +12730,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
12690
12730
  `File too large to upload (${st.size} bytes; max ${maxBytes})`
12691
12731
  );
12692
12732
  }
12693
- const buf = (0, import_node_fs34.readFileSync)(abs);
12733
+ const buf = (0, import_node_fs35.readFileSync)(abs);
12694
12734
  return {
12695
12735
  path: relativePath,
12696
12736
  contentBase64: buf.toString("base64"),
@@ -12700,12 +12740,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
12700
12740
  function readWorktreeFile(worktreePath, relativePath, opts) {
12701
12741
  assertSafeRelativePath(relativePath);
12702
12742
  const maxBytes = opts?.maxBytes ?? 2e5;
12703
- const abs = (0, import_node_path31.join)(worktreePath, relativePath);
12704
- const st = (0, import_node_fs34.statSync)(abs);
12743
+ const abs = (0, import_node_path32.join)(worktreePath, relativePath);
12744
+ const st = (0, import_node_fs35.statSync)(abs);
12705
12745
  if (!st.isFile()) {
12706
12746
  throw new Error(`Not a file: ${relativePath}`);
12707
12747
  }
12708
- const buf = (0, import_node_fs34.readFileSync)(abs);
12748
+ const buf = (0, import_node_fs35.readFileSync)(abs);
12709
12749
  if (isImageRelativePath(relativePath)) {
12710
12750
  const maxImageBytes = Math.max(maxBytes, 15e6);
12711
12751
  const truncated2 = buf.length > maxImageBytes;
@@ -12748,9 +12788,9 @@ function assertSafeRelativePath(relativePath) {
12748
12788
  }
12749
12789
  function writeWorktreeFile(worktreePath, relativePath, content) {
12750
12790
  assertSafeRelativePath(relativePath);
12751
- const abs = (0, import_node_path31.join)(worktreePath, relativePath);
12752
- (0, import_node_fs34.mkdirSync)((0, import_node_path31.dirname)(abs), { recursive: true });
12753
- (0, import_node_fs34.writeFileSync)(abs, content, "utf8");
12791
+ const abs = (0, import_node_path32.join)(worktreePath, relativePath);
12792
+ (0, import_node_fs35.mkdirSync)((0, import_node_path32.dirname)(abs), { recursive: true });
12793
+ (0, import_node_fs35.writeFileSync)(abs, content, "utf8");
12754
12794
  return { path: relativePath };
12755
12795
  }
12756
12796
  async function getDiffSummary(worktreePath, repoPath, opts) {
@@ -12854,9 +12894,9 @@ async function confirmLand(thread, opts) {
12854
12894
  }
12855
12895
 
12856
12896
  // src/skills/discover.ts
12857
- var import_node_fs35 = require("fs");
12897
+ var import_node_fs36 = require("fs");
12858
12898
  var import_node_os11 = require("os");
12859
- var import_node_path32 = require("path");
12899
+ var import_node_path33 = require("path");
12860
12900
  function toCommand(name) {
12861
12901
  return name.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
12862
12902
  }
@@ -12888,7 +12928,7 @@ function parseFrontmatter(content) {
12888
12928
  }
12889
12929
  function readSkill(skillMd, source) {
12890
12930
  try {
12891
- const content = (0, import_node_fs35.readFileSync)(skillMd, "utf8");
12931
+ const content = (0, import_node_fs36.readFileSync)(skillMd, "utf8");
12892
12932
  const { name: fmName, description } = parseFrontmatter(content);
12893
12933
  const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
12894
12934
  const name = fmName || dirName;
@@ -12907,19 +12947,19 @@ function readSkill(skillMd, source) {
12907
12947
  }
12908
12948
  }
12909
12949
  function scanSkillsDir(dir, source, out) {
12910
- if (!(0, import_node_fs35.existsSync)(dir)) return;
12950
+ if (!(0, import_node_fs36.existsSync)(dir)) return;
12911
12951
  let entries;
12912
12952
  try {
12913
- entries = (0, import_node_fs35.readdirSync)(dir);
12953
+ entries = (0, import_node_fs36.readdirSync)(dir);
12914
12954
  } catch {
12915
12955
  return;
12916
12956
  }
12917
12957
  for (const entry of entries) {
12918
12958
  if (entry.startsWith(".")) continue;
12919
- const skillMd = (0, import_node_path32.join)(dir, entry, "SKILL.md");
12920
- if (!(0, import_node_fs35.existsSync)(skillMd)) continue;
12959
+ const skillMd = (0, import_node_path33.join)(dir, entry, "SKILL.md");
12960
+ if (!(0, import_node_fs36.existsSync)(skillMd)) continue;
12921
12961
  try {
12922
- if (!(0, import_node_fs35.statSync)(skillMd).isFile()) continue;
12962
+ if (!(0, import_node_fs36.statSync)(skillMd).isFile()) continue;
12923
12963
  } catch {
12924
12964
  continue;
12925
12965
  }
@@ -12928,24 +12968,24 @@ function scanSkillsDir(dir, source, out) {
12928
12968
  }
12929
12969
  }
12930
12970
  function scanClaudePluginSkills(pluginsRoot, out) {
12931
- if (!(0, import_node_fs35.existsSync)(pluginsRoot)) return;
12971
+ if (!(0, import_node_fs36.existsSync)(pluginsRoot)) return;
12932
12972
  const walk = (dir, depth, lookingForSkillsDir) => {
12933
12973
  if (depth > 7) return;
12934
12974
  let entries;
12935
12975
  try {
12936
- entries = (0, import_node_fs35.readdirSync)(dir);
12976
+ entries = (0, import_node_fs36.readdirSync)(dir);
12937
12977
  } catch {
12938
12978
  return;
12939
12979
  }
12940
12980
  if (lookingForSkillsDir && entries.includes("SKILL.md")) {
12941
- const skill = readSkill((0, import_node_path32.join)(dir, "SKILL.md"), "cli");
12981
+ const skill = readSkill((0, import_node_path33.join)(dir, "SKILL.md"), "cli");
12942
12982
  if (skill) out.push(skill);
12943
12983
  }
12944
12984
  for (const entry of entries) {
12945
12985
  if (entry === "node_modules" || entry === ".git") continue;
12946
- const full = (0, import_node_path32.join)(dir, entry);
12986
+ const full = (0, import_node_path33.join)(dir, entry);
12947
12987
  try {
12948
- if (!(0, import_node_fs35.statSync)(full).isDirectory()) continue;
12988
+ if (!(0, import_node_fs36.statSync)(full).isDirectory()) continue;
12949
12989
  } catch {
12950
12990
  continue;
12951
12991
  }
@@ -12963,17 +13003,17 @@ function discoverSkills(worktreePath) {
12963
13003
  const home = (0, import_node_os11.homedir)();
12964
13004
  const collected = [];
12965
13005
  for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
12966
- scanSkillsDir((0, import_node_path32.join)(worktreePath, rel), "workspace", collected);
13006
+ scanSkillsDir((0, import_node_path33.join)(worktreePath, rel), "workspace", collected);
12967
13007
  }
12968
13008
  for (const abs of [
12969
- (0, import_node_path32.join)(home, ".claude/skills"),
12970
- (0, import_node_path32.join)(home, ".cursor/skills"),
12971
- (0, import_node_path32.join)(home, ".sideboard/skills"),
12972
- (0, import_node_path32.join)(home, ".brightsy/skills")
13009
+ (0, import_node_path33.join)(home, ".claude/skills"),
13010
+ (0, import_node_path33.join)(home, ".cursor/skills"),
13011
+ (0, import_node_path33.join)(home, ".sideboard/skills"),
13012
+ (0, import_node_path33.join)(home, ".brightsy/skills")
12973
13013
  ]) {
12974
13014
  scanSkillsDir(abs, "user", collected);
12975
13015
  }
12976
- scanClaudePluginSkills((0, import_node_path32.join)(home, ".claude/plugins"), collected);
13016
+ scanClaudePluginSkills((0, import_node_path33.join)(home, ".claude/plugins"), collected);
12977
13017
  const rank = { workspace: 0, user: 1, cli: 2 };
12978
13018
  const byCommand = /* @__PURE__ */ new Map();
12979
13019
  for (const skill of collected) {
@@ -12985,7 +13025,7 @@ function discoverSkills(worktreePath) {
12985
13025
  return [...byCommand.values()].sort((a, b) => a.command.localeCompare(b.command));
12986
13026
  }
12987
13027
  function readSkillBody(skillPath, maxChars = 12e3) {
12988
- const raw = (0, import_node_fs35.readFileSync)(skillPath, "utf8");
13028
+ const raw = (0, import_node_fs36.readFileSync)(skillPath, "utf8");
12989
13029
  if (raw.startsWith("---")) {
12990
13030
  const end = raw.indexOf("\n---", 3);
12991
13031
  if (end >= 0) {
@@ -13078,8 +13118,8 @@ function expandComposerPrompt(worktreePath, prompt, opts) {
13078
13118
  }
13079
13119
 
13080
13120
  // src/composer/stage-files.ts
13081
- var import_node_fs36 = require("fs");
13082
- var import_node_path33 = require("path");
13121
+ var import_node_fs37 = require("fs");
13122
+ var import_node_path34 = require("path");
13083
13123
  var import_node_crypto7 = require("crypto");
13084
13124
  init_workspace_scratch();
13085
13125
  var IMAGE_EXTENSIONS2 = /* @__PURE__ */ new Set([
@@ -13105,7 +13145,7 @@ var IMAGE_MIME_BY_EXT = {
13105
13145
  var MAX_INLINE_BYTES = 4e5;
13106
13146
  var MAX_PREVIEW_BYTES = 5e6;
13107
13147
  function fileExtension(filePath) {
13108
- const base = (0, import_node_path33.basename)(filePath).toLowerCase();
13148
+ const base = (0, import_node_path34.basename)(filePath).toLowerCase();
13109
13149
  return base.includes(".") ? base.split(".").pop() || "" : "";
13110
13150
  }
13111
13151
  function isImageFilePath(filePath) {
@@ -13115,22 +13155,22 @@ function imageMimeType(filePath) {
13115
13155
  return IMAGE_MIME_BY_EXT[fileExtension(filePath)] || "image/png";
13116
13156
  }
13117
13157
  function ensureAttachmentsDir(worktreePath) {
13118
- const dir = (0, import_node_path33.join)(worktreePath, ATTACHMENTS_DIR);
13119
- (0, import_node_fs36.mkdirSync)(dir, { recursive: true });
13120
- const gi = (0, import_node_path33.join)(dir, ".gitignore");
13121
- if (!(0, import_node_fs36.existsSync)(gi)) {
13122
- (0, import_node_fs36.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
13158
+ const dir = (0, import_node_path34.join)(worktreePath, ATTACHMENTS_DIR);
13159
+ (0, import_node_fs37.mkdirSync)(dir, { recursive: true });
13160
+ const gi = (0, import_node_path34.join)(dir, ".gitignore");
13161
+ if (!(0, import_node_fs37.existsSync)(gi)) {
13162
+ (0, import_node_fs37.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
13123
13163
  }
13124
13164
  return dir;
13125
13165
  }
13126
13166
  function uniqueAttachmentName(dir, originalName) {
13127
13167
  const safe = originalName.replace(/[/\\]/g, "_") || "file";
13128
- if (!(0, import_node_fs36.existsSync)((0, import_node_path33.join)(dir, safe))) return safe;
13129
- const ext = (0, import_node_path33.extname)(safe);
13168
+ if (!(0, import_node_fs37.existsSync)((0, import_node_path34.join)(dir, safe))) return safe;
13169
+ const ext = (0, import_node_path34.extname)(safe);
13130
13170
  const stem = ext ? safe.slice(0, -ext.length) : safe;
13131
13171
  for (let i = 1; i < 1e4; i++) {
13132
13172
  const candidate = `${stem}-${i}${ext}`;
13133
- if (!(0, import_node_fs36.existsSync)((0, import_node_path33.join)(dir, candidate))) return candidate;
13173
+ if (!(0, import_node_fs37.existsSync)((0, import_node_path34.join)(dir, candidate))) return candidate;
13134
13174
  }
13135
13175
  return `${stem}-${(0, import_node_crypto7.randomUUID)()}${ext}`;
13136
13176
  }
@@ -13186,15 +13226,15 @@ function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
13186
13226
  const dir = ensureAttachmentsDir(worktreePath);
13187
13227
  const out = [];
13188
13228
  for (const abs of absolutePaths) {
13189
- const originalName = (0, import_node_path33.basename)(abs);
13229
+ const originalName = (0, import_node_path34.basename)(abs);
13190
13230
  try {
13191
- const st = (0, import_node_fs36.statSync)(abs);
13231
+ const st = (0, import_node_fs37.statSync)(abs);
13192
13232
  if (!st.isFile()) continue;
13193
13233
  const name = uniqueAttachmentName(dir, originalName);
13194
- const destAbs = (0, import_node_path33.join)(dir, name);
13195
- (0, import_node_fs36.copyFileSync)(abs, destAbs);
13234
+ const destAbs = (0, import_node_path34.join)(dir, name);
13235
+ (0, import_node_fs37.copyFileSync)(abs, destAbs);
13196
13236
  const rel = `${ATTACHMENTS_DIR}/${name}`;
13197
- const buf = (0, import_node_fs36.readFileSync)(destAbs);
13237
+ const buf = (0, import_node_fs37.readFileSync)(destAbs);
13198
13238
  out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
13199
13239
  } catch (err) {
13200
13240
  out.push({
@@ -13216,8 +13256,8 @@ function stageBuffersAsAttachments(worktreePath, buffers) {
13216
13256
  try {
13217
13257
  const buf = Buffer.from(item.dataBase64, "base64");
13218
13258
  const name = uniqueAttachmentName(dir, originalName);
13219
- const destAbs = (0, import_node_path33.join)(dir, name);
13220
- (0, import_node_fs36.writeFileSync)(destAbs, buf);
13259
+ const destAbs = (0, import_node_path34.join)(dir, name);
13260
+ (0, import_node_fs37.writeFileSync)(destAbs, buf);
13221
13261
  const rel = `${ATTACHMENTS_DIR}/${name}`;
13222
13262
  out.push(attachmentFromBuffer(name, buf, { path: rel }));
13223
13263
  } catch (err) {
@@ -13237,18 +13277,18 @@ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
13237
13277
  if (!rel || rel.includes("..") || rel.startsWith("/")) {
13238
13278
  out.push({
13239
13279
  id: (0, import_node_crypto7.randomUUID)(),
13240
- name: (0, import_node_path33.basename)(rel) || "file",
13280
+ name: (0, import_node_path34.basename)(rel) || "file",
13241
13281
  kind: "file",
13242
13282
  content: `(invalid path: ${rel})`
13243
13283
  });
13244
13284
  continue;
13245
13285
  }
13246
- const name = (0, import_node_path33.basename)(rel);
13286
+ const name = (0, import_node_path34.basename)(rel);
13247
13287
  try {
13248
- const abs = (0, import_node_path33.join)(worktreePath, rel);
13249
- const st = (0, import_node_fs36.statSync)(abs);
13288
+ const abs = (0, import_node_path34.join)(worktreePath, rel);
13289
+ const st = (0, import_node_fs37.statSync)(abs);
13250
13290
  if (!st.isFile()) continue;
13251
- const buf = (0, import_node_fs36.readFileSync)(abs);
13291
+ const buf = (0, import_node_fs37.readFileSync)(abs);
13252
13292
  out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
13253
13293
  } catch (err) {
13254
13294
  out.push({
@@ -13263,8 +13303,8 @@ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
13263
13303
  }
13264
13304
 
13265
13305
  // src/agents/instructions.ts
13266
- var import_node_fs37 = require("fs");
13267
- var import_node_path34 = require("path");
13306
+ var import_node_fs38 = require("fs");
13307
+ var import_node_path35 = require("path");
13268
13308
  init_git_auth_mode();
13269
13309
  init_worktree_labels();
13270
13310
  function normPath3(p) {
@@ -13544,7 +13584,7 @@ var Orchestrator = class {
13544
13584
  }
13545
13585
  continue;
13546
13586
  }
13547
- if (!(0, import_node_fs41.existsSync)(thread.worktreePath)) {
13587
+ if (!(0, import_node_fs42.existsSync)(thread.worktreePath)) {
13548
13588
  setStatus(thread.id, "broken", "Worktree missing on disk");
13549
13589
  this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
13550
13590
  continue;
@@ -13782,6 +13822,9 @@ var Orchestrator = class {
13782
13822
  }
13783
13823
  return withThreadLock(thread.id, async () => {
13784
13824
  const current = this.requireThread(thread.id);
13825
+ if (current.status === "archived") {
13826
+ throw new Error(`Thread is archived: ${thread.id}`);
13827
+ }
13785
13828
  const queue = [...current.queue, prompt];
13786
13829
  this.haltDrain.delete(thread.id);
13787
13830
  const patch = { queue, status: "queued" };
@@ -13792,7 +13835,9 @@ var Orchestrator = class {
13792
13835
  updateThread(thread.id, patch);
13793
13836
  this.emit({ type: "queue_changed", threadId: thread.id, queue });
13794
13837
  this.emit({ type: "status_changed", threadId: thread.id, status: "queued" });
13795
- void this.drainQueue(thread.id);
13838
+ if (thisProcessShouldDrainAgentQueues()) {
13839
+ void this.drainQueue(thread.id);
13840
+ }
13796
13841
  return this.requireThread(thread.id);
13797
13842
  });
13798
13843
  }
@@ -13845,10 +13890,10 @@ var Orchestrator = class {
13845
13890
  async sendQueuedMessageNow(threadRef, index) {
13846
13891
  const thread = this.requireThread(threadRef);
13847
13892
  const promoted = await withThreadLock(thread.id, async () => {
13848
- const current = this.requireThread(thread.id);
13849
- if (index < 0 || index >= current.queue.length) return false;
13850
- const item = current.queue[index];
13851
- const rest = current.queue.filter((_, i) => i !== index);
13893
+ const current2 = this.requireThread(thread.id);
13894
+ if (index < 0 || index >= current2.queue.length) return false;
13895
+ const item = current2.queue[index];
13896
+ const rest = current2.queue.filter((_, i) => i !== index);
13852
13897
  const queue = [item, ...rest];
13853
13898
  this.haltDrain.delete(thread.id);
13854
13899
  updateThread(thread.id, { queue });
@@ -13856,10 +13901,16 @@ var Orchestrator = class {
13856
13901
  return true;
13857
13902
  });
13858
13903
  if (!promoted) return this.requireThread(thread.id);
13904
+ const current = this.requireThread(thread.id);
13859
13905
  const inFlight = this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id);
13906
+ const livePid = current.agentPid;
13907
+ const foreignLive = !inFlight && typeof livePid === "number" && livePid > 0 && isPidAlive(livePid);
13860
13908
  if (inFlight) {
13861
13909
  this.stop(thread.id, { clearQueue: false, continueQueue: true });
13862
13910
  } else {
13911
+ if (foreignLive) {
13912
+ this.stop(thread.id, { clearQueue: false, continueQueue: true });
13913
+ }
13863
13914
  void this.drainQueue(thread.id);
13864
13915
  }
13865
13916
  return this.requireThread(thread.id);
@@ -14294,6 +14345,13 @@ var Orchestrator = class {
14294
14345
  if (handle) handle.kill();
14295
14346
  const proc = this.processes.get(`${thread.id}:agent`);
14296
14347
  if (proc) proc.kill();
14348
+ const pid = thread.agentPid;
14349
+ if (typeof pid === "number" && pid > 0 && isPidAlive(pid)) {
14350
+ try {
14351
+ process.kill(pid, "SIGTERM");
14352
+ } catch {
14353
+ }
14354
+ }
14297
14355
  const stopped = writeLiveStatus(thread.id, "stopped") ?? readThread(thread.id) ?? thread;
14298
14356
  if (stopped.status === "stopped") {
14299
14357
  this.emit({ type: "status_changed", threadId: thread.id, status: "stopped" });
@@ -15074,7 +15132,7 @@ var Orchestrator = class {
15074
15132
  this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
15075
15133
  return restored2;
15076
15134
  }
15077
- if (!(0, import_node_fs41.existsSync)(thread.worktreePath)) {
15135
+ if (!(0, import_node_fs42.existsSync)(thread.worktreePath)) {
15078
15136
  const { createThreadWorktree: createThreadWorktree2 } = await Promise.resolve().then(() => (init_worktree(), worktree_exports));
15079
15137
  const { execa: execa7 } = await import("execa");
15080
15138
  const slug = thread.worktreePath.split("/").pop();
@@ -16314,7 +16372,7 @@ async function startMcpServer() {
16314
16372
  async () => {
16315
16373
  const threads = orch.getThreads(true);
16316
16374
  const lines = threads.map((t) => {
16317
- const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path38.basename)(t.repoPath) || t.repoPath;
16375
+ const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path39.basename)(t.repoPath) || t.repoPath;
16318
16376
  return `${t.id.slice(0, 8)} ${t.status.padEnd(9)} ${t.agent.padEnd(8)} ${repo} ${t.sourceType}:${t.sourceRef} ${t.title} sideboard://thread/${t.id}${t.devPort ? ` http://localhost:${t.devPort}` : ""}`;
16319
16377
  });
16320
16378
  return {