@sideboard-ai/core 0.1.133 → 0.1.136

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 (35) hide show
  1. package/dist/{agents-NHS6P25H.js → agents-ELWR7A2T.js} +5 -5
  2. package/dist/{agents-SOU5GPWI.js → agents-QNTTLMG2.js} +5 -5
  3. package/dist/{chunk-Y645NFYN.js → chunk-4XKUHP6G.js} +2 -2
  4. package/dist/{chunk-4YAVXWFR.js → chunk-CYM5DCHI.js} +39 -5
  5. package/dist/{chunk-LTP7GHIF.js → chunk-GSKRGF7B.js} +286 -5
  6. package/dist/{chunk-WEU5M7BW.js → chunk-HQQNLDVC.js} +1 -1
  7. package/dist/{chunk-IM36S4HZ.js → chunk-IFZ4MOTN.js} +3 -3
  8. package/dist/{chunk-G6X6UFJO.js → chunk-J5IBSVB3.js} +42 -12
  9. package/dist/{chunk-AK7SWE2U.js → chunk-JPBRMUM6.js} +9 -5
  10. package/dist/{chunk-YEIH7P7D.js → chunk-K5YT5GX2.js} +244 -5
  11. package/dist/{chunk-3UVVWNHF.js → chunk-MDCKV2NF.js} +2 -2
  12. package/dist/{chunk-HLJUNJBF.js → chunk-PM3C2J6K.js} +42 -12
  13. package/dist/{chunk-Q6XQXCOM.js → chunk-QAV3HGVS.js} +1 -1
  14. package/dist/{chunk-TG7YU2KG.js → chunk-TIGKDMIA.js} +144 -271
  15. package/dist/{chunk-6CRKPD4C.js → chunk-TQ4S5AGJ.js} +3 -3
  16. package/dist/{chunk-VSON7EJ6.js → chunk-WS5LFFU3.js} +140 -222
  17. package/dist/{coordinator-prompt-DXHEDRRN.js → coordinator-prompt-2OWSUAUR.js} +3 -3
  18. package/dist/{coordinator-prompt-XF7LVOUN.js → coordinator-prompt-IPL4Z6SL.js} +3 -3
  19. package/dist/{global-workspace-2LO5ATOH.js → global-workspace-JDUCUL7S.js} +4 -4
  20. package/dist/{global-workspace-MLQNULOU.js → global-workspace-NIKZAKOO.js} +4 -4
  21. package/dist/index.cjs +873 -628
  22. package/dist/index.d.cts +26 -1
  23. package/dist/index.d.ts +26 -1
  24. package/dist/index.js +42 -19
  25. package/dist/mcp/run-stdio.cjs +700 -498
  26. package/dist/mcp/run-stdio.js +22 -11
  27. package/dist/{orchestrator-P2SYHVLS.js → orchestrator-6I47JMU2.js} +7 -7
  28. package/dist/{orchestrator-KR5RA5B7.js → orchestrator-KK3CUW37.js} +7 -7
  29. package/dist/{thread-store-5MLYY35S.js → thread-store-CRLQJ2HM.js} +3 -1
  30. package/dist/{thread-store-F6BCARQG.js → thread-store-FADXSMEJ.js} +3 -1
  31. package/dist/{workspaces-MINB764G.js → workspaces-5EWNNALF.js} +5 -5
  32. package/dist/{workspaces-ARWPZG6F.js → workspaces-KZA3TCEE.js} +5 -5
  33. package/dist/{worktree-EBZMUUAL.js → worktree-BC6XDMQK.js} +2 -2
  34. package/dist/{worktree-S7MKMYAT.js → worktree-MX7XBX6Z.js} +2 -2
  35. package/package.json +1 -1
@@ -670,6 +670,7 @@ __export(thread_store_exports, {
670
670
  createEmptyThread: () => createEmptyThread,
671
671
  deleteThreadRecord: () => deleteThreadRecord,
672
672
  findThreadByRef: () => findThreadByRef,
673
+ invalidateThreadListCache: () => invalidateThreadListCache,
673
674
  isThreadRecordFile: () => isThreadRecordFile,
674
675
  listThreads: () => listThreads,
675
676
  normalizeThread: () => normalizeThread,
@@ -767,11 +768,28 @@ async function withThreadLock(id, fn) {
767
768
  if (release) await release();
768
769
  }
769
770
  }
771
+ function cacheForDir() {
772
+ const dir = threadsDir();
773
+ if (!listCache || listCache.dir !== dir) {
774
+ listCache = { dir, byId: /* @__PURE__ */ new Map(), listed: false };
775
+ }
776
+ return listCache;
777
+ }
778
+ function invalidateThreadListCache() {
779
+ listCache = null;
780
+ }
781
+ function rememberThread(thread) {
782
+ cacheForDir().byId.set(thread.id, thread);
783
+ }
770
784
  function readThread(id) {
785
+ const cached = cacheForDir().byId.get(id);
786
+ if (cached) return cached;
771
787
  const path = threadFilePath(id);
772
788
  if (!(0, import_node_fs7.existsSync)(path)) return null;
773
789
  const raw = (0, import_node_fs7.readFileSync)(path, "utf8");
774
- return normalizeThread(JSON.parse(raw));
790
+ const thread = normalizeThread(JSON.parse(raw));
791
+ rememberThread(thread);
792
+ return thread;
775
793
  }
776
794
  function writeThread(thread) {
777
795
  const path = threadFilePath(idPath(thread.id));
@@ -779,6 +797,7 @@ function writeThread(thread) {
779
797
  const next = { ...thread, updatedAt: nowIso() };
780
798
  (0, import_node_fs7.writeFileSync)(tmp, JSON.stringify(next, null, 2), "utf8");
781
799
  (0, import_node_fs7.renameSync)(tmp, path);
800
+ rememberThread(next);
782
801
  }
783
802
  function idPath(id) {
784
803
  return id;
@@ -788,22 +807,32 @@ function isThreadRecordFile(nameOrPath) {
788
807
  return name.endsWith(".json") && !name.endsWith(".live.json");
789
808
  }
790
809
  function listThreads(opts) {
791
- const files = (0, import_node_fs7.readdirSync)(threadsDir()).filter(isThreadRecordFile);
792
- const threads = files.map((f) => {
793
- try {
794
- return normalizeThread(
795
- JSON.parse((0, import_node_fs7.readFileSync)(threadFilePath(f.replace(/\.json$/, "")), "utf8"))
796
- );
797
- } catch {
798
- return null;
810
+ const cache = cacheForDir();
811
+ if (!cache.listed) {
812
+ const files = (0, import_node_fs7.readdirSync)(threadsDir()).filter(isThreadRecordFile);
813
+ const byId = /* @__PURE__ */ new Map();
814
+ for (const f of files) {
815
+ try {
816
+ const thread = normalizeThread(
817
+ JSON.parse((0, import_node_fs7.readFileSync)(threadFilePath(f.replace(/\.json$/, "")), "utf8"))
818
+ );
819
+ if (typeof thread.id === "string" && thread.id.length > 0) {
820
+ byId.set(thread.id, thread);
821
+ }
822
+ } catch {
823
+ }
799
824
  }
800
- }).filter(
801
- (t) => t !== null && typeof t.id === "string" && t.id.length > 0
802
- ).sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
825
+ cache.byId = byId;
826
+ cache.listed = true;
827
+ }
828
+ const threads = [...cache.byId.values()].sort(
829
+ (a, b) => b.updatedAt.localeCompare(a.updatedAt)
830
+ );
803
831
  if (opts?.includeArchived) return threads;
804
832
  return threads.filter((t) => t.status !== "archived");
805
833
  }
806
834
  function deleteThreadRecord(id) {
835
+ cacheForDir().byId.delete(id);
807
836
  const path = threadFilePath(id);
808
837
  if ((0, import_node_fs7.existsSync)(path)) (0, import_node_fs7.unlinkSync)(path);
809
838
  const lock = threadLockPath(id);
@@ -835,7 +864,7 @@ function findThreadByRef(ref) {
835
864
  (t) => t.id === ref || t.id.startsWith(ref) || t.branchName === ref || t.title === ref
836
865
  ) ?? null;
837
866
  }
838
- var import_node_crypto2, import_node_fs7, import_node_path7, import_proper_lockfile;
867
+ var import_node_crypto2, import_node_fs7, import_node_path7, import_proper_lockfile, listCache;
839
868
  var init_thread_store = __esm({
840
869
  "src/store/thread-store.ts"() {
841
870
  "use strict";
@@ -845,6 +874,7 @@ var init_thread_store = __esm({
845
874
  import_proper_lockfile = __toESM(require("proper-lockfile"), 1);
846
875
  init_thinking_effort();
847
876
  init_paths();
877
+ listCache = null;
848
878
  }
849
879
  });
850
880
 
@@ -5795,6 +5825,240 @@ var init_cloud_connect_constants = __esm({
5795
5825
  }
5796
5826
  });
5797
5827
 
5828
+ // src/composer/stage-files.ts
5829
+ function fileExtension(filePath) {
5830
+ const base = (0, import_node_path18.basename)(filePath).toLowerCase();
5831
+ return base.includes(".") ? base.split(".").pop() || "" : "";
5832
+ }
5833
+ function isImageFilePath(filePath) {
5834
+ return IMAGE_EXTENSIONS.has(fileExtension(filePath));
5835
+ }
5836
+ function imageMimeType(filePath) {
5837
+ return IMAGE_MIME_BY_EXT[fileExtension(filePath)] || "image/png";
5838
+ }
5839
+ function ensureAttachmentsDir(worktreePath) {
5840
+ const dir = (0, import_node_path18.join)(worktreePath, ATTACHMENTS_DIR);
5841
+ (0, import_node_fs15.mkdirSync)(dir, { recursive: true });
5842
+ const gi = (0, import_node_path18.join)(dir, ".gitignore");
5843
+ if (!(0, import_node_fs15.existsSync)(gi)) {
5844
+ (0, import_node_fs15.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
5845
+ }
5846
+ return dir;
5847
+ }
5848
+ function uniqueAttachmentName(dir, originalName) {
5849
+ const safe = originalName.replace(/[/\\]/g, "_") || "file";
5850
+ if (!(0, import_node_fs15.existsSync)((0, import_node_path18.join)(dir, safe))) return safe;
5851
+ const ext = (0, import_node_path18.extname)(safe);
5852
+ const stem = ext ? safe.slice(0, -ext.length) : safe;
5853
+ for (let i = 1; i < 1e4; i++) {
5854
+ const candidate = `${stem}-${i}${ext}`;
5855
+ if (!(0, import_node_fs15.existsSync)((0, import_node_path18.join)(dir, candidate))) return candidate;
5856
+ }
5857
+ return `${stem}-${(0, import_node_crypto4.randomUUID)()}${ext}`;
5858
+ }
5859
+ function previewDataUrlFromBuf(filePath, buf) {
5860
+ if (!isImageFilePath(filePath)) return void 0;
5861
+ if (buf.length > MAX_PREVIEW_BYTES) return void 0;
5862
+ return `data:${imageMimeType(filePath)};base64,${buf.toString("base64")}`;
5863
+ }
5864
+ function attachmentFromBuffer(name, buf, opts) {
5865
+ const previewDataUrl = previewDataUrlFromBuf(name, buf);
5866
+ if (isImageFilePath(name)) {
5867
+ const pathHint = opts.path ? `\`${opts.path}\`` : opts.sourceLabel || name;
5868
+ return {
5869
+ id: (0, import_node_crypto4.randomUUID)(),
5870
+ name,
5871
+ kind: "file",
5872
+ path: opts.path,
5873
+ previewDataUrl,
5874
+ content: [
5875
+ `Image attached: ${pathHint}`,
5876
+ opts.path ? `Use the Read tool on \`${opts.path}\` to view this image.` : "The image is shown in the composer; copy it into the worktree if you need to inspect pixels."
5877
+ ].join("\n")
5878
+ };
5879
+ }
5880
+ if (buf.length > MAX_INLINE_BYTES) {
5881
+ return {
5882
+ id: (0, import_node_crypto4.randomUUID)(),
5883
+ name,
5884
+ kind: "file",
5885
+ path: opts.path,
5886
+ content: opts.path ? `(file too large to attach inline: \`${opts.path}\`, ${buf.length} bytes \u2014 use the Read tool)` : `(file too large to attach inline: ${opts.sourceLabel || name}, ${buf.length} bytes)`
5887
+ };
5888
+ }
5889
+ if (buf.includes(0)) {
5890
+ return {
5891
+ id: (0, import_node_crypto4.randomUUID)(),
5892
+ name,
5893
+ kind: "file",
5894
+ path: opts.path,
5895
+ content: opts.path ? `(binary file at \`${opts.path}\` \u2014 use tools to inspect)` : `(binary file attached by path only: ${opts.sourceLabel || name})`
5896
+ };
5897
+ }
5898
+ return {
5899
+ id: (0, import_node_crypto4.randomUUID)(),
5900
+ name,
5901
+ kind: "file",
5902
+ path: opts.path,
5903
+ content: buf.toString("utf8")
5904
+ };
5905
+ }
5906
+ function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
5907
+ if (absolutePaths.length === 0) return [];
5908
+ const dir = ensureAttachmentsDir(worktreePath);
5909
+ const out = [];
5910
+ for (const abs of absolutePaths) {
5911
+ const originalName = (0, import_node_path18.basename)(abs);
5912
+ try {
5913
+ const st = (0, import_node_fs15.statSync)(abs);
5914
+ if (!st.isFile()) continue;
5915
+ const name = uniqueAttachmentName(dir, originalName);
5916
+ const destAbs = (0, import_node_path18.join)(dir, name);
5917
+ (0, import_node_fs15.copyFileSync)(abs, destAbs);
5918
+ const rel = `${ATTACHMENTS_DIR}/${name}`;
5919
+ const buf = (0, import_node_fs15.readFileSync)(destAbs);
5920
+ out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
5921
+ } catch (err) {
5922
+ out.push({
5923
+ id: (0, import_node_crypto4.randomUUID)(),
5924
+ name: originalName,
5925
+ kind: "file",
5926
+ content: `(could not attach ${abs}: ${err instanceof Error ? err.message : String(err)})`
5927
+ });
5928
+ }
5929
+ }
5930
+ return out;
5931
+ }
5932
+ function stageBuffersAsAttachments(worktreePath, buffers2) {
5933
+ if (buffers2.length === 0) return [];
5934
+ const dir = ensureAttachmentsDir(worktreePath);
5935
+ const out = [];
5936
+ for (const item of buffers2) {
5937
+ const originalName = (item.name || "file").replace(/[/\\]/g, "_") || "file";
5938
+ try {
5939
+ const buf = Buffer.from(item.dataBase64, "base64");
5940
+ const name = uniqueAttachmentName(dir, originalName);
5941
+ const destAbs = (0, import_node_path18.join)(dir, name);
5942
+ (0, import_node_fs15.writeFileSync)(destAbs, buf);
5943
+ const rel = `${ATTACHMENTS_DIR}/${name}`;
5944
+ out.push(attachmentFromBuffer(name, buf, { path: rel }));
5945
+ } catch (err) {
5946
+ out.push({
5947
+ id: (0, import_node_crypto4.randomUUID)(),
5948
+ name: originalName,
5949
+ kind: "file",
5950
+ content: `(could not attach ${originalName}: ${err instanceof Error ? err.message : String(err)})`
5951
+ });
5952
+ }
5953
+ }
5954
+ return out;
5955
+ }
5956
+ function isWorktreeRelativePath(p) {
5957
+ if (!p || p.includes("..")) return false;
5958
+ if (p.startsWith("/")) return false;
5959
+ if (/^[A-Za-z]:[\\/]/.test(p)) return false;
5960
+ return true;
5961
+ }
5962
+ function dataUrlToBase64(url) {
5963
+ if (!url) return null;
5964
+ const m = /^data:[^;]+;base64,(.+)$/s.exec(url);
5965
+ return m?.[1] ?? null;
5966
+ }
5967
+ function persistPendingFileAttachments(worktreePath, attachments) {
5968
+ if (attachments.length === 0) return attachments;
5969
+ const keep = [];
5970
+ const buffers2 = [];
5971
+ for (const att of attachments) {
5972
+ if (att.kind !== "file") {
5973
+ keep.push(att);
5974
+ continue;
5975
+ }
5976
+ if (att.path && isWorktreeRelativePath(att.path)) {
5977
+ keep.push(att);
5978
+ continue;
5979
+ }
5980
+ const fromPreview = dataUrlToBase64(att.previewDataUrl);
5981
+ if (fromPreview) {
5982
+ buffers2.push({ name: att.name, dataBase64: fromPreview });
5983
+ continue;
5984
+ }
5985
+ if (att.content && !IMAGE_HINT_RE.test(att.content) && !PLACEHOLDER_CONTENT_RE.test(att.content)) {
5986
+ buffers2.push({
5987
+ name: att.name,
5988
+ dataBase64: Buffer.from(att.content, "utf8").toString("base64")
5989
+ });
5990
+ continue;
5991
+ }
5992
+ keep.push(att);
5993
+ }
5994
+ if (buffers2.length === 0) return attachments;
5995
+ return [...keep, ...stageBuffersAsAttachments(worktreePath, buffers2)];
5996
+ }
5997
+ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
5998
+ const out = [];
5999
+ for (const rel of relativePaths) {
6000
+ if (!rel || rel.includes("..") || rel.startsWith("/")) {
6001
+ out.push({
6002
+ id: (0, import_node_crypto4.randomUUID)(),
6003
+ name: (0, import_node_path18.basename)(rel) || "file",
6004
+ kind: "file",
6005
+ content: `(invalid path: ${rel})`
6006
+ });
6007
+ continue;
6008
+ }
6009
+ const name = (0, import_node_path18.basename)(rel);
6010
+ try {
6011
+ const abs = (0, import_node_path18.join)(worktreePath, rel);
6012
+ const st = (0, import_node_fs15.statSync)(abs);
6013
+ if (!st.isFile()) continue;
6014
+ const buf = (0, import_node_fs15.readFileSync)(abs);
6015
+ out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
6016
+ } catch (err) {
6017
+ out.push({
6018
+ id: (0, import_node_crypto4.randomUUID)(),
6019
+ name,
6020
+ kind: "file",
6021
+ content: `(could not read ${rel}: ${err instanceof Error ? err.message : String(err)})`
6022
+ });
6023
+ }
6024
+ }
6025
+ return out;
6026
+ }
6027
+ var import_node_fs15, import_node_path18, import_node_crypto4, IMAGE_EXTENSIONS, IMAGE_MIME_BY_EXT, MAX_INLINE_BYTES, MAX_PREVIEW_BYTES, IMAGE_HINT_RE, PLACEHOLDER_CONTENT_RE;
6028
+ var init_stage_files = __esm({
6029
+ "src/composer/stage-files.ts"() {
6030
+ "use strict";
6031
+ import_node_fs15 = require("fs");
6032
+ import_node_path18 = require("path");
6033
+ import_node_crypto4 = require("crypto");
6034
+ init_workspace_scratch();
6035
+ IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
6036
+ "png",
6037
+ "jpg",
6038
+ "jpeg",
6039
+ "gif",
6040
+ "webp",
6041
+ "svg",
6042
+ "bmp",
6043
+ "ico"
6044
+ ]);
6045
+ IMAGE_MIME_BY_EXT = {
6046
+ png: "image/png",
6047
+ jpg: "image/jpeg",
6048
+ jpeg: "image/jpeg",
6049
+ gif: "image/gif",
6050
+ webp: "image/webp",
6051
+ svg: "image/svg+xml",
6052
+ bmp: "image/bmp",
6053
+ ico: "image/x-icon"
6054
+ };
6055
+ MAX_INLINE_BYTES = 4e5;
6056
+ MAX_PREVIEW_BYTES = 5e6;
6057
+ IMAGE_HINT_RE = /^Image attached:/;
6058
+ PLACEHOLDER_CONTENT_RE = /^\((could not |file too large|binary file|not a file|invalid path)/;
6059
+ }
6060
+ });
6061
+
5798
6062
  // src/agents/orchestrator-capable.ts
5799
6063
  function isOrchestratorCapableAgent(agent) {
5800
6064
  return Boolean(
@@ -5877,13 +6141,13 @@ function coordinatorTurnReminder(opts) {
5877
6141
  `- YOUR orchestration thread id is ${opts.parentId} \u2014 pass parentThreadId="${opts.parentId}" on create_thread, or omit it.`,
5878
6142
  goal ? `- Goal / title: ${goal}` : null,
5879
6143
  accountDefaultsPlaybookLine(),
5880
- "- Status: list_board (worktree Kanban: New \u2192 Draft \u2192 Review \u2192 Merged) or list_threads. Link chats as `[Title](sideboard://thread/<id>)`. Merge only if the user asked."
6144
+ "- Status: list_board (worktree Kanban: New \u2192 Draft \u2192 Review \u2192 Merged) or list_threads. Link chats as `[Title](sideboard://thread/<id>)`. Merge only if the user asked. If a child is stopped/error/broken, it did not finish \u2014 resume or tell the user."
5881
6145
  ].filter(Boolean).join("\n");
5882
6146
  }
5883
6147
  function ensureGlobalCoordinatorCwd(opts) {
5884
6148
  const dir = globalAgentCwd();
5885
6149
  try {
5886
- (0, import_node_fs15.mkdirSync)(dir, { recursive: true });
6150
+ (0, import_node_fs16.mkdirSync)(dir, { recursive: true });
5887
6151
  } catch {
5888
6152
  return dir;
5889
6153
  }
@@ -5891,7 +6155,7 @@ function ensureGlobalCoordinatorCwd(opts) {
5891
6155
  let orchId = opts?.orchestratorThreadId?.trim() || "";
5892
6156
  if (!orchId) {
5893
6157
  try {
5894
- const existing = (0, import_node_fs15.readFileSync)((0, import_node_path18.join)(dir, "AGENTS.md"), "utf8");
6158
+ const existing = (0, import_node_fs16.readFileSync)((0, import_node_path19.join)(dir, "AGENTS.md"), "utf8");
5895
6159
  const m = existing.match(
5896
6160
  /YOUR orchestration thread id is `([0-9a-f-]{36})`/i
5897
6161
  );
@@ -5934,9 +6198,9 @@ function ensureGlobalCoordinatorCwd(opts) {
5934
6198
  "Always ask worktree agents to commit, push, and open draft PRs (`ask_git` / `send_to_thread`). Tell them to merge only when the user explicitly asked. The worktree agent runs git/gh; never merge from this orchestration cwd."
5935
6199
  ].join("\n");
5936
6200
  try {
5937
- (0, import_node_fs15.writeFileSync)((0, import_node_path18.join)(dir, "CLAUDE.md"), `${body}
6201
+ (0, import_node_fs16.writeFileSync)((0, import_node_path19.join)(dir, "CLAUDE.md"), `${body}
5938
6202
  `, "utf8");
5939
- (0, import_node_fs15.writeFileSync)((0, import_node_path18.join)(dir, "AGENTS.md"), `${body}
6203
+ (0, import_node_fs16.writeFileSync)((0, import_node_path19.join)(dir, "AGENTS.md"), `${body}
5940
6204
  `, "utf8");
5941
6205
  } catch {
5942
6206
  }
@@ -5968,12 +6232,12 @@ function coordinatorSystemPrompt(opts) {
5968
6232
  formatWorkspaceInventory(opts.workspaces)
5969
6233
  ].join("\n");
5970
6234
  }
5971
- var import_node_fs15, import_node_path18, COORDINATOR_TOOL_PLAYBOOK, SLACK_REPLY_FORMATTING;
6235
+ var import_node_fs16, import_node_path19, COORDINATOR_TOOL_PLAYBOOK, SLACK_REPLY_FORMATTING;
5972
6236
  var init_coordinator_prompt = __esm({
5973
6237
  "src/orchestrator/coordinator-prompt.ts"() {
5974
6238
  "use strict";
5975
- import_node_fs15 = require("fs");
5976
- import_node_path18 = require("path");
6239
+ import_node_fs16 = require("fs");
6240
+ import_node_path19 = require("path");
5977
6241
  init_worktree();
5978
6242
  init_app_settings();
5979
6243
  init_paths();
@@ -6002,7 +6266,7 @@ var init_coordinator_prompt = __esm({
6002
6266
  "- fork_worktree \u2014 fork a worktree chat into a NEW git worktree + chat (transcript attached); optional agent; leave model unset (Auto) unless you have a reason. Not for orchestration chats.",
6003
6267
  "- fork_chat \u2014 fork a worktree chat (same worktree tab) OR a Global orchestration chat (new orchestration tab); optional agent; leave model unset (Auto) unless you have a reason. Remote coordinators: use this to continue another orchestration chat on a different agent after session limits.",
6004
6268
  "- send_to_thread \u2014 queue a prompt (start/continue a chat turn); pass force_stop: true to interrupt mid-turn / clear stale queued prompts before replacing with a new request",
6005
- "- wait_for_turn / get_turn_result \u2014 wait for and read the agent reply (includes last-turn usage / costUsd when the child agent reported it). wait_for_turn returns within ~45s even if the child is still working (MCP clients kill longer tool calls). If stillRunning is true, progress is a live snapshot of tools/thinking \u2014 call wait_for_turn again. status=queued with no lastActivityAt means the child has not started yet (concurrency cap) \u2014 keep waiting; do not force_stop or send a check-in. Do not send \u201Care you stuck?\u201D or assume a hang while lastActivityAt is recent. On status error, lastError (and text) is the failure \u2014 switch agent, tell the user, or retry; do not treat empty text as success.",
6269
+ "- wait_for_turn / get_turn_result \u2014 wait for and read the agent reply (includes last-turn usage / costUsd when the child agent reported it). wait_for_turn returns within ~45s even if the child is still working (MCP clients kill longer tool calls). If stillRunning is true, progress is a live snapshot of tools/thinking \u2014 call wait_for_turn again. status=queued with no lastActivityAt means the child has not started yet (concurrency cap) \u2014 keep waiting; do not force_stop or send a check-in. Do not send \u201Care you stuck?\u201D or assume a hang while lastActivityAt is recent. On status error, lastError (and text) is the failure \u2014 switch agent, tell the user, or retry; do not treat empty text as success. On status stopped or broken (or incomplete=true), the child was interrupted or died \u2014 resume with send_to_thread or tell the user; never treat stopped as a finished turn. Sideboard also injects a notice into this chat when a child stops unexpectedly.",
6006
6270
  "- stop_thread \u2014 force-stop: kill in-flight turn AND clear queued prompts (do not leave stale queue after an interrupt)",
6007
6271
  "- archive_thread / restore_thread \u2014 archive (tears down worktree when last tab) or restore",
6008
6272
  "Setup / run:",
@@ -6122,6 +6386,7 @@ function createGlobalChat(opts) {
6122
6386
  fast: opts.fast
6123
6387
  });
6124
6388
  const agent = assertOrchestratorCapableAgent(resolved.agent);
6389
+ const worktreePath = globalAgentCwd();
6125
6390
  const thread = createEmptyThread({
6126
6391
  title,
6127
6392
  // Stick nicknames the same way chat tabs do (avoid later sync overwrites).
@@ -6129,7 +6394,7 @@ function createGlobalChat(opts) {
6129
6394
  sourceType: "orchestration",
6130
6395
  sourceRef,
6131
6396
  branchName: "global",
6132
- worktreePath: globalAgentCwd(),
6397
+ worktreePath,
6133
6398
  repoPath: GLOBAL_WORKSPACE_ID,
6134
6399
  agent,
6135
6400
  autonomy: opts.autonomy ?? "default",
@@ -6137,7 +6402,10 @@ function createGlobalChat(opts) {
6137
6402
  effort: resolved.effort,
6138
6403
  fast: resolved.fast,
6139
6404
  planMode: Boolean(opts.planMode),
6140
- attachments: opts.attachments ?? [],
6405
+ attachments: persistPendingFileAttachments(
6406
+ worktreePath,
6407
+ opts.attachments ?? []
6408
+ ),
6141
6409
  parentThreadId: opts.parentThreadId ?? null,
6142
6410
  status: "idle"
6143
6411
  });
@@ -6262,6 +6530,7 @@ var init_global_workspace = __esm({
6262
6530
  "src/store/global-workspace.ts"() {
6263
6531
  "use strict";
6264
6532
  init_cloud_connect_constants();
6533
+ init_stage_files();
6265
6534
  init_orchestrator_capable();
6266
6535
  init_teams();
6267
6536
  init_coordinator_prompt();
@@ -6276,32 +6545,32 @@ var init_global_workspace = __esm({
6276
6545
  function brightsyConfigPath() {
6277
6546
  const override = process.env.BRIGHTSY_CONFIG?.trim();
6278
6547
  if (override) return override;
6279
- return (0, import_node_path19.join)((0, import_node_os6.homedir)(), ".brightsy", "config.json");
6548
+ return (0, import_node_path20.join)((0, import_node_os6.homedir)(), ".brightsy", "config.json");
6280
6549
  }
6281
6550
  function loadBrightsyConfig() {
6282
6551
  const path = brightsyConfigPath();
6283
- if (!(0, import_node_fs16.existsSync)(path)) {
6552
+ if (!(0, import_node_fs17.existsSync)(path)) {
6284
6553
  throw new Error("Brightsy not logged in \u2014 run `brightsy login` first");
6285
6554
  }
6286
- const raw = JSON.parse((0, import_node_fs16.readFileSync)(path, "utf8"));
6555
+ const raw = JSON.parse((0, import_node_fs17.readFileSync)(path, "utf8"));
6287
6556
  if (!raw.access_token || !raw.account_id) {
6288
6557
  throw new Error("Brightsy config incomplete \u2014 run `brightsy login`");
6289
6558
  }
6290
6559
  return raw;
6291
6560
  }
6292
6561
  function saveBrightsyConfig(cfg) {
6293
- (0, import_node_fs16.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
6562
+ (0, import_node_fs17.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
6294
6563
  `, {
6295
6564
  mode: 384
6296
6565
  });
6297
6566
  }
6298
- var import_node_fs16, import_node_os6, import_node_path19;
6567
+ var import_node_fs17, import_node_os6, import_node_path20;
6299
6568
  var init_config = __esm({
6300
6569
  "src/brightsy/config.ts"() {
6301
6570
  "use strict";
6302
- import_node_fs16 = require("fs");
6571
+ import_node_fs17 = require("fs");
6303
6572
  import_node_os6 = require("os");
6304
- import_node_path19 = require("path");
6573
+ import_node_path20 = require("path");
6305
6574
  }
6306
6575
  });
6307
6576
 
@@ -6418,22 +6687,22 @@ var init_oauth = __esm({
6418
6687
 
6419
6688
  // src/brightsy/connected-teams.ts
6420
6689
  function storePath4() {
6421
- return (0, import_node_path20.join)(appDataDir(), "brightsy-teams.json");
6690
+ return (0, import_node_path21.join)(appDataDir(), "brightsy-teams.json");
6422
6691
  }
6423
6692
  function readStore4() {
6424
6693
  const path = storePath4();
6425
- if (!(0, import_node_fs17.existsSync)(path)) return [];
6694
+ if (!(0, import_node_fs18.existsSync)(path)) return [];
6426
6695
  try {
6427
- const parsed = JSON.parse((0, import_node_fs17.readFileSync)(path, "utf8"));
6696
+ const parsed = JSON.parse((0, import_node_fs18.readFileSync)(path, "utf8"));
6428
6697
  return Array.isArray(parsed.teams) ? parsed.teams : [];
6429
6698
  } catch {
6430
6699
  return [];
6431
6700
  }
6432
6701
  }
6433
6702
  function writeStore2(teams) {
6434
- (0, import_node_fs17.mkdirSync)(appDataDir(), { recursive: true });
6703
+ (0, import_node_fs18.mkdirSync)(appDataDir(), { recursive: true });
6435
6704
  const path = storePath4();
6436
- (0, import_node_fs17.writeFileSync)(path, `${JSON.stringify({ teams }, null, 2)}
6705
+ (0, import_node_fs18.writeFileSync)(path, `${JSON.stringify({ teams }, null, 2)}
6437
6706
  `, {
6438
6707
  mode: 384
6439
6708
  });
@@ -6539,12 +6808,12 @@ function brightsyMcpServerName(slug) {
6539
6808
  const cleaned = slug.replace(/[^A-Za-z0-9_-]/g, "_").replace(/^_+|_+$/g, "");
6540
6809
  return `brightsy_${cleaned || "team"}`;
6541
6810
  }
6542
- var import_node_fs17, import_node_path20;
6811
+ var import_node_fs18, import_node_path21;
6543
6812
  var init_connected_teams = __esm({
6544
6813
  "src/brightsy/connected-teams.ts"() {
6545
6814
  "use strict";
6546
- import_node_fs17 = require("fs");
6547
- import_node_path20 = require("path");
6815
+ import_node_fs18 = require("fs");
6816
+ import_node_path21 = require("path");
6548
6817
  init_paths();
6549
6818
  init_accounts();
6550
6819
  init_config();
@@ -6916,11 +7185,11 @@ async function syncCliForTarget(accountId) {
6916
7185
  }
6917
7186
  applyConnectedTeamToCli(team);
6918
7187
  }
6919
- var import_node_fs18, brightsyAdapter;
7188
+ var import_node_fs19, brightsyAdapter;
6920
7189
  var init_brightsy = __esm({
6921
7190
  "src/agents/brightsy.ts"() {
6922
7191
  "use strict";
6923
- import_node_fs18 = require("fs");
7192
+ import_node_fs19 = require("fs");
6924
7193
  init_run();
6925
7194
  init_connected_teams();
6926
7195
  init_config();
@@ -6935,7 +7204,7 @@ var init_brightsy = __esm({
6935
7204
  async detect() {
6936
7205
  const brightsy = resolveAgentExecutable("brightsy");
6937
7206
  if (brightsy !== "brightsy") {
6938
- if (!(0, import_node_fs18.existsSync)(brightsy)) {
7207
+ if (!(0, import_node_fs19.existsSync)(brightsy)) {
6939
7208
  return {
6940
7209
  agent: "brightsy",
6941
7210
  installed: false,
@@ -7063,10 +7332,14 @@ function toolDetail(name, input) {
7063
7332
  if (!input) return void 0;
7064
7333
  const command = str2(input.command) ?? str2(input.cmd);
7065
7334
  if (command) return command;
7335
+ const pattern = str2(input.pattern) ?? str2(input.glob) ?? str2(input.glob_pattern);
7336
+ const isSearch = /grep|glob|search|ripgrep|findfiles|semsearch/i.test(name);
7337
+ if (isSearch && pattern) {
7338
+ return pattern.length > 80 ? `${pattern.slice(0, 77)}\u2026` : pattern;
7339
+ }
7066
7340
  const path = str2(input.file_path) ?? str2(input.path) ?? str2(input.filePath) ?? str2(input.filename);
7067
7341
  if (path) return path;
7068
- const pattern = str2(input.pattern) ?? str2(input.glob) ?? str2(input.glob_pattern);
7069
- if (pattern) return pattern;
7342
+ if (pattern) return pattern.length > 80 ? `${pattern.slice(0, 77)}\u2026` : pattern;
7070
7343
  const query = str2(input.query) ?? str2(input.prompt);
7071
7344
  if (query) return query.length > 80 ? `${query.slice(0, 77)}\u2026` : query;
7072
7345
  try {
@@ -7506,43 +7779,43 @@ function electronResourcesPath() {
7506
7779
  function packagedCursorRuntimeDir() {
7507
7780
  const resources = electronResourcesPath();
7508
7781
  if (!resources) return null;
7509
- const dir = (0, import_node_path21.join)(resources, "cursor-runtime");
7510
- if (!(0, import_node_fs19.existsSync)((0, import_node_path21.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
7782
+ const dir = (0, import_node_path22.join)(resources, "cursor-runtime");
7783
+ if (!(0, import_node_fs20.existsSync)((0, import_node_path22.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
7511
7784
  return dir;
7512
7785
  }
7513
7786
  function packagedCursorRunnerPath() {
7514
7787
  const dir = packagedCursorRuntimeDir();
7515
- return dir ? (0, import_node_path21.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
7788
+ return dir ? (0, import_node_path22.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
7516
7789
  }
7517
7790
  function packagedMcpDir() {
7518
7791
  const resources = electronResourcesPath();
7519
7792
  if (!resources) return null;
7520
- const dir = (0, import_node_path21.join)(resources, "sideboard-mcp");
7521
- if (!(0, import_node_fs19.existsSync)((0, import_node_path21.join)(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
7793
+ const dir = (0, import_node_path22.join)(resources, "sideboard-mcp");
7794
+ if (!(0, import_node_fs20.existsSync)((0, import_node_path22.join)(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
7522
7795
  return dir;
7523
7796
  }
7524
7797
  function packagedMcpStdioPath() {
7525
7798
  const dir = packagedMcpDir();
7526
- return dir ? (0, import_node_path21.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
7799
+ return dir ? (0, import_node_path22.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
7527
7800
  }
7528
7801
  function packagedBundledNodePath() {
7529
7802
  const resources = electronResourcesPath();
7530
7803
  if (!resources) return null;
7531
- const bin = (0, import_node_path21.join)(resources, "node", "bin", "node");
7532
- if (!(0, import_node_fs19.existsSync)(bin)) return null;
7804
+ const bin = (0, import_node_path22.join)(resources, "node", "bin", "node");
7805
+ if (!(0, import_node_fs20.existsSync)(bin)) return null;
7533
7806
  return bin;
7534
7807
  }
7535
7808
  function packagedCursorRipgrepCandidate(platformPkg, binName) {
7536
7809
  const dir = packagedCursorRuntimeDir();
7537
7810
  if (!dir) return null;
7538
- return (0, import_node_path21.join)(dir, "node_modules", platformPkg, "bin", binName);
7811
+ return (0, import_node_path22.join)(dir, "node_modules", platformPkg, "bin", binName);
7539
7812
  }
7540
- var import_node_fs19, import_node_path21;
7813
+ var import_node_fs20, import_node_path22;
7541
7814
  var init_packaged_runtime = __esm({
7542
7815
  "src/agents/packaged-runtime.ts"() {
7543
7816
  "use strict";
7544
- import_node_fs19 = require("fs");
7545
- import_node_path21 = require("path");
7817
+ import_node_fs20 = require("fs");
7818
+ import_node_path22 = require("path");
7546
7819
  }
7547
7820
  });
7548
7821
 
@@ -7576,7 +7849,7 @@ function unpackedAsarPath(filePath) {
7576
7849
  if (!isAsarPath(filePath)) return null;
7577
7850
  const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
7578
7851
  if (unpacked === filePath) return null;
7579
- return (0, import_node_fs20.existsSync)(unpacked) ? unpacked : null;
7852
+ return (0, import_node_fs21.existsSync)(unpacked) ? unpacked : null;
7580
7853
  }
7581
7854
  function nodeReadableScriptPath(scriptPath) {
7582
7855
  return unpackedAsarPath(scriptPath) ?? scriptPath;
@@ -7616,37 +7889,37 @@ function pickPreferredNode(candidates) {
7616
7889
  return best;
7617
7890
  }
7618
7891
  function versionDirNodeBins(root, toBin) {
7619
- if (!(0, import_node_fs20.existsSync)(root)) return [];
7892
+ if (!(0, import_node_fs21.existsSync)(root)) return [];
7620
7893
  try {
7621
- return (0, import_node_fs20.readdirSync)(root).map(toBin);
7894
+ return (0, import_node_fs21.readdirSync)(root).map(toBin);
7622
7895
  } catch {
7623
7896
  return [];
7624
7897
  }
7625
7898
  }
7626
7899
  function defaultNodeBinCandidates(home = (0, import_node_os7.homedir)()) {
7627
7900
  const kegs = ["/opt/homebrew", "/usr/local"].flatMap(
7628
- (prefix) => PREFERRED_LTS_MAJORS.map((major) => (0, import_node_path22.join)(prefix, "opt", `node@${major}`, "bin", "node"))
7901
+ (prefix) => PREFERRED_LTS_MAJORS.map((major) => (0, import_node_path23.join)(prefix, "opt", `node@${major}`, "bin", "node"))
7629
7902
  );
7630
7903
  return [
7631
7904
  ...kegs,
7632
7905
  "/opt/homebrew/bin/node",
7633
7906
  "/usr/local/bin/node",
7634
- (0, import_node_path22.join)(home, ".local/share/fnm/aliases/default/bin/node"),
7635
- (0, import_node_path22.join)(home, ".nvm/current/bin/node"),
7636
- (0, import_node_path22.join)(home, ".volta/bin/node"),
7637
- (0, import_node_path22.join)(home, ".asdf/shims/node"),
7638
- (0, import_node_path22.join)(home, ".local/share/mise/shims/node"),
7907
+ (0, import_node_path23.join)(home, ".local/share/fnm/aliases/default/bin/node"),
7908
+ (0, import_node_path23.join)(home, ".nvm/current/bin/node"),
7909
+ (0, import_node_path23.join)(home, ".volta/bin/node"),
7910
+ (0, import_node_path23.join)(home, ".asdf/shims/node"),
7911
+ (0, import_node_path23.join)(home, ".local/share/mise/shims/node"),
7639
7912
  ...versionDirNodeBins(
7640
- (0, import_node_path22.join)(home, ".nvm", "versions", "node"),
7641
- (name) => (0, import_node_path22.join)(home, ".nvm", "versions", "node", name, "bin", "node")
7913
+ (0, import_node_path23.join)(home, ".nvm", "versions", "node"),
7914
+ (name) => (0, import_node_path23.join)(home, ".nvm", "versions", "node", name, "bin", "node")
7642
7915
  ),
7643
7916
  ...versionDirNodeBins(
7644
- (0, import_node_path22.join)(home, ".local/share/fnm", "node-versions"),
7645
- (name) => (0, import_node_path22.join)(home, ".local/share/fnm", "node-versions", name, "installation", "bin", "node")
7917
+ (0, import_node_path23.join)(home, ".local/share/fnm", "node-versions"),
7918
+ (name) => (0, import_node_path23.join)(home, ".local/share/fnm", "node-versions", name, "installation", "bin", "node")
7646
7919
  ),
7647
7920
  ...versionDirNodeBins(
7648
- (0, import_node_path22.join)(home, ".volta", "tools", "image", "node"),
7649
- (name) => (0, import_node_path22.join)(home, ".volta", "tools", "image", "node", name, "bin", "node")
7921
+ (0, import_node_path23.join)(home, ".volta", "tools", "image", "node"),
7922
+ (name) => (0, import_node_path23.join)(home, ".volta", "tools", "image", "node", name, "bin", "node")
7650
7923
  )
7651
7924
  ];
7652
7925
  }
@@ -7655,10 +7928,10 @@ function uniqueExistingNodeBins(paths) {
7655
7928
  const out = [];
7656
7929
  for (const raw of paths) {
7657
7930
  const p = raw.trim();
7658
- if (!p || !(0, import_node_fs20.existsSync)(p) || isElectronLikeCommand(p)) continue;
7931
+ if (!p || !(0, import_node_fs21.existsSync)(p) || isElectronLikeCommand(p)) continue;
7659
7932
  let key = p;
7660
7933
  try {
7661
- key = (0, import_node_fs20.realpathSync)(p);
7934
+ key = (0, import_node_fs21.realpathSync)(p);
7662
7935
  } catch {
7663
7936
  continue;
7664
7937
  }
@@ -7738,13 +8011,13 @@ async function resolveNodeLaunch(scriptPath) {
7738
8011
  env: { ELECTRON_RUN_AS_NODE: "1" }
7739
8012
  };
7740
8013
  }
7741
- var import_node_fs20, import_node_os7, import_node_path22, AGENT_RUNNER_MAX_OLD_SPACE_MB, MAX_OLD_SPACE_FLAG, PREFERRED_LTS_MAJORS;
8014
+ var import_node_fs21, import_node_os7, import_node_path23, AGENT_RUNNER_MAX_OLD_SPACE_MB, MAX_OLD_SPACE_FLAG, PREFERRED_LTS_MAJORS;
7742
8015
  var init_node_launch = __esm({
7743
8016
  "src/agents/node-launch.ts"() {
7744
8017
  "use strict";
7745
- import_node_fs20 = require("fs");
8018
+ import_node_fs21 = require("fs");
7746
8019
  import_node_os7 = require("os");
7747
- import_node_path22 = require("path");
8020
+ import_node_path23 = require("path");
7748
8021
  init_nested_electron_env();
7749
8022
  init_run();
7750
8023
  init_packaged_runtime();
@@ -7838,37 +8111,37 @@ function corePackageDir() {
7838
8111
  try {
7839
8112
  const url = import_meta.url;
7840
8113
  if (typeof url === "string" && url.length > 0) {
7841
- return (0, import_node_path23.dirname)((0, import_node_url.fileURLToPath)(url));
8114
+ return (0, import_node_path24.dirname)((0, import_node_url.fileURLToPath)(url));
7842
8115
  }
7843
8116
  } catch {
7844
8117
  }
7845
8118
  try {
7846
- const req = (0, import_node_module.createRequire)((0, import_node_path23.join)(process.cwd(), "package.json"));
7847
- return (0, import_node_path23.dirname)(req.resolve("@sideboard-ai/core"));
8119
+ const req = (0, import_node_module.createRequire)((0, import_node_path24.join)(process.cwd(), "package.json"));
8120
+ return (0, import_node_path24.dirname)(req.resolve("@sideboard-ai/core"));
7848
8121
  } catch {
7849
8122
  return process.cwd();
7850
8123
  }
7851
8124
  }
7852
8125
  function findSideboardMcpJsEntry() {
7853
8126
  const override = process.env.SIDEBOARD_MCP_ENTRY?.trim() || process.env.SIDEBOARD_CLI?.trim();
7854
- if (override && (0, import_node_fs21.existsSync)(override)) return override;
8127
+ if (override && (0, import_node_fs22.existsSync)(override)) return override;
7855
8128
  const packaged = packagedMcpStdioPath();
7856
8129
  if (packaged) return packaged;
7857
8130
  let dir = corePackageDir();
7858
8131
  for (let i = 0; i < 10; i++) {
7859
8132
  const candidates = [
7860
- (0, import_node_path23.join)(dir, "mcp/run-stdio.js"),
7861
- (0, import_node_path23.join)(dir, "mcp/run-stdio.cjs"),
7862
- (0, import_node_path23.join)(dir, "dist/mcp/run-stdio.js"),
7863
- (0, import_node_path23.join)(dir, "dist/mcp/run-stdio.cjs"),
7864
- (0, import_node_path23.join)(dir, "packages/core/dist/mcp/run-stdio.js"),
7865
- (0, import_node_path23.join)(dir, "packages/cli/dist/index.js"),
7866
- (0, import_node_path23.join)(dir, "cli/dist/index.js")
8133
+ (0, import_node_path24.join)(dir, "mcp/run-stdio.js"),
8134
+ (0, import_node_path24.join)(dir, "mcp/run-stdio.cjs"),
8135
+ (0, import_node_path24.join)(dir, "dist/mcp/run-stdio.js"),
8136
+ (0, import_node_path24.join)(dir, "dist/mcp/run-stdio.cjs"),
8137
+ (0, import_node_path24.join)(dir, "packages/core/dist/mcp/run-stdio.js"),
8138
+ (0, import_node_path24.join)(dir, "packages/cli/dist/index.js"),
8139
+ (0, import_node_path24.join)(dir, "cli/dist/index.js")
7867
8140
  ];
7868
8141
  for (const p of candidates) {
7869
- if ((0, import_node_fs21.existsSync)(p) && !isAsarPath(p)) return p;
8142
+ if ((0, import_node_fs22.existsSync)(p) && !isAsarPath(p)) return p;
7870
8143
  }
7871
- const parent = (0, import_node_path23.dirname)(dir);
8144
+ const parent = (0, import_node_path24.dirname)(dir);
7872
8145
  if (parent === dir) break;
7873
8146
  dir = parent;
7874
8147
  }
@@ -8010,19 +8283,19 @@ function writeMcpServersConfig(servers) {
8010
8283
  ...env ? { env } : {}
8011
8284
  };
8012
8285
  }
8013
- const dir = (0, import_node_fs21.mkdtempSync)((0, import_node_path23.join)((0, import_node_os8.tmpdir)(), "sideboard-mcp-"));
8014
- const cfgPath = (0, import_node_path23.join)(dir, "mcp.json");
8015
- (0, import_node_fs21.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
8286
+ const dir = (0, import_node_fs22.mkdtempSync)((0, import_node_path24.join)((0, import_node_os8.tmpdir)(), "sideboard-mcp-"));
8287
+ const cfgPath = (0, import_node_path24.join)(dir, "mcp.json");
8288
+ (0, import_node_fs22.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
8016
8289
  return cfgPath;
8017
8290
  }
8018
- var import_node_fs21, import_node_module, import_node_os8, import_node_path23, import_node_url, import_meta, SIDEBOARD_MCP_ALLOWED_TOOLS, SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS, brightsyMcpCommandCache, BRIGHTSY_WORD;
8291
+ var import_node_fs22, import_node_module, import_node_os8, import_node_path24, import_node_url, import_meta, SIDEBOARD_MCP_ALLOWED_TOOLS, SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS, brightsyMcpCommandCache, BRIGHTSY_WORD;
8019
8292
  var init_injected_mcp = __esm({
8020
8293
  "src/agents/injected-mcp.ts"() {
8021
8294
  "use strict";
8022
- import_node_fs21 = require("fs");
8295
+ import_node_fs22 = require("fs");
8023
8296
  import_node_module = require("module");
8024
8297
  import_node_os8 = require("os");
8025
- import_node_path23 = require("path");
8298
+ import_node_path24 = require("path");
8026
8299
  import_node_url = require("url");
8027
8300
  init_run();
8028
8301
  init_config();
@@ -8322,11 +8595,11 @@ function parseIssuesJson(raw) {
8322
8595
  }
8323
8596
  return [];
8324
8597
  }
8325
- var import_node_fs22, BASE_ALLOWED_TOOLS, CLAUDE_PRINT_BG_WAIT_CEILING_MS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, mcpListCache, claudeAdapter;
8598
+ var import_node_fs23, BASE_ALLOWED_TOOLS, CLAUDE_PRINT_BG_WAIT_CEILING_MS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, mcpListCache, claudeAdapter;
8326
8599
  var init_claude = __esm({
8327
8600
  "src/agents/claude.ts"() {
8328
8601
  "use strict";
8329
- import_node_fs22 = require("fs");
8602
+ import_node_fs23 = require("fs");
8330
8603
  init_run();
8331
8604
  init_app_settings();
8332
8605
  init_claude_mcp();
@@ -8366,7 +8639,7 @@ var init_claude = __esm({
8366
8639
  async detect() {
8367
8640
  const claude = resolveClaudeExecutable();
8368
8641
  if (claude !== "claude") {
8369
- if (!(0, import_node_fs22.existsSync)(claude)) {
8642
+ if (!(0, import_node_fs23.existsSync)(claude)) {
8370
8643
  return {
8371
8644
  agent: "claude",
8372
8645
  installed: false,
@@ -8621,7 +8894,7 @@ async function listCodexModels() {
8621
8894
  if (codex === "codex") {
8622
8895
  const which = await run("which", ["codex"], { reject: false });
8623
8896
  if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
8624
- } else if (!(0, import_node_fs23.existsSync)(codex)) {
8897
+ } else if (!(0, import_node_fs24.existsSync)(codex)) {
8625
8898
  return FALLBACK_CODEX_MODELS;
8626
8899
  }
8627
8900
  const listed = await run(codex, ["debug", "models"], { reject: false });
@@ -8656,12 +8929,12 @@ function usageFromCodex(usage) {
8656
8929
  }
8657
8930
  function codexConfigHasNetworkAccess() {
8658
8931
  const candidates = [
8659
- (0, import_node_path24.join)((0, import_node_os9.homedir)(), ".codex", "config.toml"),
8660
- (0, import_node_path24.join)((0, import_node_os9.homedir)(), ".config", "codex", "config.toml")
8932
+ (0, import_node_path25.join)((0, import_node_os9.homedir)(), ".codex", "config.toml"),
8933
+ (0, import_node_path25.join)((0, import_node_os9.homedir)(), ".config", "codex", "config.toml")
8661
8934
  ];
8662
8935
  for (const path of candidates) {
8663
- if (!(0, import_node_fs23.existsSync)(path)) continue;
8664
- const text5 = (0, import_node_fs23.readFileSync)(path, "utf8");
8936
+ if (!(0, import_node_fs24.existsSync)(path)) continue;
8937
+ const text5 = (0, import_node_fs24.readFileSync)(path, "utf8");
8665
8938
  if (/network_access\s*=\s*true/.test(text5)) return true;
8666
8939
  }
8667
8940
  return false;
@@ -8693,21 +8966,21 @@ function asRecord2(value) {
8693
8966
  return void 0;
8694
8967
  }
8695
8968
  function codexLooksAuthenticated() {
8696
- const authPath = (0, import_node_path24.join)((0, import_node_os9.homedir)(), ".codex", "auth.json");
8697
- if (!(0, import_node_fs23.existsSync)(authPath)) return false;
8969
+ const authPath = (0, import_node_path25.join)((0, import_node_os9.homedir)(), ".codex", "auth.json");
8970
+ if (!(0, import_node_fs24.existsSync)(authPath)) return false;
8698
8971
  try {
8699
- return (0, import_node_fs23.statSync)(authPath).size > 2;
8972
+ return (0, import_node_fs24.statSync)(authPath).size > 2;
8700
8973
  } catch {
8701
8974
  return false;
8702
8975
  }
8703
8976
  }
8704
- var import_node_fs23, import_node_os9, import_node_path24, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
8977
+ var import_node_fs24, import_node_os9, import_node_path25, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
8705
8978
  var init_codex = __esm({
8706
8979
  "src/agents/codex.ts"() {
8707
8980
  "use strict";
8708
- import_node_fs23 = require("fs");
8981
+ import_node_fs24 = require("fs");
8709
8982
  import_node_os9 = require("os");
8710
- import_node_path24 = require("path");
8983
+ import_node_path25 = require("path");
8711
8984
  init_run();
8712
8985
  init_app_settings();
8713
8986
  init_global_workspace();
@@ -8732,7 +9005,7 @@ var init_codex = __esm({
8732
9005
  async detect() {
8733
9006
  const codex = resolveAgentExecutable("codex");
8734
9007
  if (codex !== "codex") {
8735
- if (!(0, import_node_fs23.existsSync)(codex)) {
9008
+ if (!(0, import_node_fs24.existsSync)(codex)) {
8736
9009
  return {
8737
9010
  agent: "codex",
8738
9011
  installed: false,
@@ -9219,21 +9492,21 @@ function platformRipgrepPackage() {
9219
9492
  }
9220
9493
  function usableRipgrepPath(candidate) {
9221
9494
  const raw = candidate?.trim();
9222
- if (!raw || !(0, import_node_path25.isAbsolute)(raw)) return null;
9495
+ if (!raw || !(0, import_node_path26.isAbsolute)(raw)) return null;
9223
9496
  const readable = nodeReadableScriptPath(raw);
9224
- if (!(0, import_node_fs24.existsSync)(readable) || isAsarPath(readable)) return null;
9497
+ if (!(0, import_node_fs25.existsSync)(readable) || isAsarPath(readable)) return null;
9225
9498
  return readable;
9226
9499
  }
9227
9500
  function walkForBundledRipgrep(startFile) {
9228
9501
  if (!startFile) return null;
9229
9502
  const pkg = platformRipgrepPackage();
9230
9503
  const name = rgBinaryName();
9231
- let dir = (0, import_node_path25.dirname)((0, import_node_path25.resolve)(startFile));
9232
- const root = (0, import_node_path25.parse)(dir).root;
9504
+ let dir = (0, import_node_path26.dirname)((0, import_node_path26.resolve)(startFile));
9505
+ const root = (0, import_node_path26.parse)(dir).root;
9233
9506
  while (dir !== root) {
9234
- const hit = usableRipgrepPath((0, import_node_path25.join)(dir, "node_modules", pkg, "bin", name));
9507
+ const hit = usableRipgrepPath((0, import_node_path26.join)(dir, "node_modules", pkg, "bin", name));
9235
9508
  if (hit) return hit;
9236
- const next = (0, import_node_path25.dirname)(dir);
9509
+ const next = (0, import_node_path26.dirname)(dir);
9237
9510
  if (next === dir) break;
9238
9511
  dir = next;
9239
9512
  }
@@ -9243,7 +9516,7 @@ function requireResolveBundledRipgrep(fromFile) {
9243
9516
  try {
9244
9517
  const req = (0, import_node_module2.createRequire)(fromFile);
9245
9518
  const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
9246
- return usableRipgrepPath((0, import_node_path25.join)((0, import_node_path25.dirname)(pkgJson), "bin", rgBinaryName()));
9519
+ return usableRipgrepPath((0, import_node_path26.join)((0, import_node_path26.dirname)(pkgJson), "bin", rgBinaryName()));
9247
9520
  } catch {
9248
9521
  return null;
9249
9522
  }
@@ -9265,13 +9538,13 @@ function cursorRipgrepEnv(opts) {
9265
9538
  const path = resolveCursorRipgrepPath(opts);
9266
9539
  return path ? { [RIPGREP_ENV]: path } : {};
9267
9540
  }
9268
- var import_node_fs24, import_node_module2, import_node_path25, RIPGREP_ENV;
9541
+ var import_node_fs25, import_node_module2, import_node_path26, RIPGREP_ENV;
9269
9542
  var init_cursor_ripgrep = __esm({
9270
9543
  "src/agents/cursor-ripgrep.ts"() {
9271
9544
  "use strict";
9272
- import_node_fs24 = require("fs");
9545
+ import_node_fs25 = require("fs");
9273
9546
  import_node_module2 = require("module");
9274
- import_node_path25 = require("path");
9547
+ import_node_path26 = require("path");
9275
9548
  init_node_launch();
9276
9549
  init_packaged_runtime();
9277
9550
  RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
@@ -9317,11 +9590,11 @@ function entryDir() {
9317
9590
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
9318
9591
  if (cjsDir) return cjsDir;
9319
9592
  try {
9320
- return (0, import_node_path26.dirname)((0, import_node_url2.fileURLToPath)(import_meta2.url));
9593
+ return (0, import_node_path27.dirname)((0, import_node_url2.fileURLToPath)(import_meta2.url));
9321
9594
  } catch {
9322
9595
  try {
9323
9596
  const req = (0, import_node_module3.createRequire)(process.cwd() + "/");
9324
- return (0, import_node_path26.dirname)(req.resolve("@sideboard-ai/core"));
9597
+ return (0, import_node_path27.dirname)(req.resolve("@sideboard-ai/core"));
9325
9598
  } catch {
9326
9599
  return process.cwd();
9327
9600
  }
@@ -9332,27 +9605,27 @@ function cursorRunnerPath() {
9332
9605
  if (packaged) return packaged;
9333
9606
  const root = entryDir();
9334
9607
  const candidates = [
9335
- (0, import_node_path26.join)(root, "agents", "cursor-runner.js"),
9336
- (0, import_node_path26.join)(root, "agents", "cursor-runner.cjs"),
9608
+ (0, import_node_path27.join)(root, "agents", "cursor-runner.js"),
9609
+ (0, import_node_path27.join)(root, "agents", "cursor-runner.cjs"),
9337
9610
  // If somehow resolved from package root instead of dist/
9338
- (0, import_node_path26.join)(root, "dist", "agents", "cursor-runner.js"),
9339
- (0, import_node_path26.join)(root, "dist", "agents", "cursor-runner.cjs"),
9611
+ (0, import_node_path27.join)(root, "dist", "agents", "cursor-runner.js"),
9612
+ (0, import_node_path27.join)(root, "dist", "agents", "cursor-runner.cjs"),
9340
9613
  // Source tree (dev): packages/core/src/agents/cursor-runner.ts
9341
- (0, import_node_path26.join)(root, "cursor-runner.ts"),
9342
- (0, import_node_path26.join)(root, "src", "agents", "cursor-runner.ts")
9614
+ (0, import_node_path27.join)(root, "cursor-runner.ts"),
9615
+ (0, import_node_path27.join)(root, "src", "agents", "cursor-runner.ts")
9343
9616
  ];
9344
9617
  for (const candidate of candidates) {
9345
- if ((0, import_node_fs25.existsSync)(candidate)) return candidate;
9618
+ if ((0, import_node_fs26.existsSync)(candidate)) return candidate;
9346
9619
  }
9347
9620
  return candidates[0];
9348
9621
  }
9349
- var import_node_fs25, import_node_module3, import_node_path26, import_node_url2, import_sdk, import_meta2, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
9622
+ var import_node_fs26, import_node_module3, import_node_path27, import_node_url2, import_sdk, import_meta2, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
9350
9623
  var init_cursor = __esm({
9351
9624
  "src/agents/cursor.ts"() {
9352
9625
  "use strict";
9353
- import_node_fs25 = require("fs");
9626
+ import_node_fs26 = require("fs");
9354
9627
  import_node_module3 = require("module");
9355
- import_node_path26 = require("path");
9628
+ import_node_path27 = require("path");
9356
9629
  import_node_url2 = require("url");
9357
9630
  import_sdk = require("@cursor/sdk");
9358
9631
  init_run();
@@ -9503,7 +9776,7 @@ async function listOpencodeModels() {
9503
9776
  if (opencode === "opencode") {
9504
9777
  const which = await run("which", ["opencode"], { reject: false });
9505
9778
  if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
9506
- } else if (!(0, import_node_fs26.existsSync)(opencode)) {
9779
+ } else if (!(0, import_node_fs27.existsSync)(opencode)) {
9507
9780
  return FALLBACK_OPENCODE_MODELS;
9508
9781
  }
9509
9782
  const listed = await run(opencode, ["models"], { reject: false });
@@ -9533,11 +9806,11 @@ function usageFromOpencode(tokens) {
9533
9806
  cacheWriteTokens: tokens.cache?.write ? Number(tokens.cache.write) : void 0
9534
9807
  };
9535
9808
  }
9536
- var import_node_fs26, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
9809
+ var import_node_fs27, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
9537
9810
  var init_opencode = __esm({
9538
9811
  "src/agents/opencode.ts"() {
9539
9812
  "use strict";
9540
- import_node_fs26 = require("fs");
9813
+ import_node_fs27 = require("fs");
9541
9814
  init_run();
9542
9815
  init_app_settings();
9543
9816
  init_global_workspace();
@@ -9564,7 +9837,7 @@ var init_opencode = __esm({
9564
9837
  async detect() {
9565
9838
  const opencode = resolveAgentExecutable("opencode");
9566
9839
  if (opencode !== "opencode") {
9567
- if (!(0, import_node_fs26.existsSync)(opencode)) {
9840
+ if (!(0, import_node_fs27.existsSync)(opencode)) {
9568
9841
  return {
9569
9842
  agent: "opencode",
9570
9843
  installed: false,
@@ -11067,7 +11340,7 @@ function forkMessageSlice(from, throughIndex) {
11067
11340
  function buildForkTranscriptAttachment(baseTitle, messages) {
11068
11341
  const title = baseTitle || "Chat";
11069
11342
  return {
11070
- id: (0, import_node_crypto4.randomUUID)(),
11343
+ id: (0, import_node_crypto5.randomUUID)(),
11071
11344
  name: `Transcript of ${title}.md`,
11072
11345
  kind: "transcript",
11073
11346
  content: formatTranscriptMarkdown(title, messages)
@@ -11124,11 +11397,11 @@ function forkChatTab(input) {
11124
11397
  }
11125
11398
  return tab;
11126
11399
  }
11127
- var import_node_crypto4;
11400
+ var import_node_crypto5;
11128
11401
  var init_chat_tabs = __esm({
11129
11402
  "src/threads/chat-tabs.ts"() {
11130
11403
  "use strict";
11131
- import_node_crypto4 = require("crypto");
11404
+ import_node_crypto5 = require("crypto");
11132
11405
  init_context_compact();
11133
11406
  init_teams();
11134
11407
  init_worktree_labels();
@@ -11298,21 +11571,21 @@ function shouldRefreshReviewRequestTemplate(content) {
11298
11571
  return LEGACY_REVIEW_TEMPLATE_MARKERS.every((m) => trimmed.includes(m));
11299
11572
  }
11300
11573
  function readTextIfPresent(abs) {
11301
- if (!(0, import_node_fs27.existsSync)(abs)) return null;
11574
+ if (!(0, import_node_fs28.existsSync)(abs)) return null;
11302
11575
  try {
11303
- const content = (0, import_node_fs27.readFileSync)(abs, "utf8");
11576
+ const content = (0, import_node_fs28.readFileSync)(abs, "utf8");
11304
11577
  return content.trim() ? content : null;
11305
11578
  } catch {
11306
11579
  return null;
11307
11580
  }
11308
11581
  }
11309
11582
  function readLocalGuidelines(worktreePath) {
11310
- const localAbs = (0, import_node_path27.join)(worktreePath, REVIEW_REQUEST_PATH);
11583
+ const localAbs = (0, import_node_path28.join)(worktreePath, REVIEW_REQUEST_PATH);
11311
11584
  const localContent = readTextIfPresent(localAbs);
11312
11585
  if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
11313
11586
  return { path: REVIEW_REQUEST_PATH, content: localContent };
11314
11587
  }
11315
- const legacyAbs = (0, import_node_path27.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
11588
+ const legacyAbs = (0, import_node_path28.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
11316
11589
  const legacyContent = readTextIfPresent(legacyAbs);
11317
11590
  if (legacyContent && !shouldRefreshReviewRequestTemplate(legacyContent)) {
11318
11591
  return { path: LEGACY_REVIEW_REQUEST_PATH, content: legacyContent };
@@ -11328,20 +11601,20 @@ function skillGuidelines(content, source) {
11328
11601
  };
11329
11602
  }
11330
11603
  function ensureReviewSkillFile(worktreePath) {
11331
- const abs = (0, import_node_path27.join)(worktreePath, REVIEW_SKILL_PATH);
11604
+ const abs = (0, import_node_path28.join)(worktreePath, REVIEW_SKILL_PATH);
11332
11605
  const existing = readTextIfPresent(abs);
11333
11606
  if (existing) {
11334
11607
  return { path: REVIEW_SKILL_PATH, content: existing, wrote: false };
11335
11608
  }
11336
- const fromRepo = readTextIfPresent((0, import_node_path27.join)(worktreePath, REPO_REVIEW_PATH));
11609
+ const fromRepo = readTextIfPresent((0, import_node_path28.join)(worktreePath, REPO_REVIEW_PATH));
11337
11610
  const fromLocal = readLocalGuidelines(worktreePath)?.content ?? null;
11338
11611
  const content = wrapReviewSkillMarkdown(fromRepo ?? fromLocal ?? REVIEW_REQUEST_TEMPLATE);
11339
- (0, import_node_fs27.mkdirSync)((0, import_node_path27.dirname)(abs), { recursive: true });
11340
- (0, import_node_fs27.writeFileSync)(abs, content, "utf8");
11612
+ (0, import_node_fs28.mkdirSync)((0, import_node_path28.dirname)(abs), { recursive: true });
11613
+ (0, import_node_fs28.writeFileSync)(abs, content, "utf8");
11341
11614
  return { path: REVIEW_SKILL_PATH, content, wrote: true };
11342
11615
  }
11343
11616
  function resolveReviewGuidelines(worktreePath) {
11344
- const skillContent = readTextIfPresent((0, import_node_path27.join)(worktreePath, REVIEW_SKILL_PATH));
11617
+ const skillContent = readTextIfPresent((0, import_node_path28.join)(worktreePath, REVIEW_SKILL_PATH));
11345
11618
  if (skillContent) return skillGuidelines(skillContent, "skill");
11346
11619
  const local = readLocalGuidelines(worktreePath);
11347
11620
  if (local) {
@@ -11359,7 +11632,7 @@ function buildReviewRequestAttachment(content, opts) {
11359
11632
  const path = opts?.path ?? REVIEW_SKILL_PATH;
11360
11633
  const name = opts?.name ?? (path === REVIEW_SKILL_PATH ? REVIEW_SKILL_NAME : path === REPO_REVIEW_PATH ? REPO_REVIEW_NAME : REVIEW_REQUEST_NAME);
11361
11634
  return {
11362
- id: (0, import_node_crypto5.randomUUID)(),
11635
+ id: (0, import_node_crypto6.randomUUID)(),
11363
11636
  name,
11364
11637
  kind: "file",
11365
11638
  path,
@@ -11391,13 +11664,13 @@ async function requestReview(threadRef, send) {
11391
11664
  const started = await send(tab.id, REVIEW_REQUEST_PREFILL);
11392
11665
  return { tab: started, from };
11393
11666
  }
11394
- var import_node_crypto5, import_node_fs27, import_node_path27, REPO_REVIEW_PATH, REPO_REVIEW_NAME, REVIEW_REQUEST_PATH, LEGACY_REVIEW_REQUEST_PATH, REVIEW_REQUEST_NAME, REVIEW_REQUEST_PREFILL, LEGACY_REVIEW_TEMPLATE_MARKERS;
11667
+ var import_node_crypto6, import_node_fs28, import_node_path28, REPO_REVIEW_PATH, REPO_REVIEW_NAME, REVIEW_REQUEST_PATH, LEGACY_REVIEW_REQUEST_PATH, REVIEW_REQUEST_NAME, REVIEW_REQUEST_PREFILL, LEGACY_REVIEW_TEMPLATE_MARKERS;
11395
11668
  var init_request_review = __esm({
11396
11669
  "src/review/request-review.ts"() {
11397
11670
  "use strict";
11398
- import_node_crypto5 = require("crypto");
11399
- import_node_fs27 = require("fs");
11400
- import_node_path27 = require("path");
11671
+ import_node_crypto6 = require("crypto");
11672
+ import_node_fs28 = require("fs");
11673
+ import_node_path28 = require("path");
11401
11674
  init_global_workspace();
11402
11675
  init_chat_tabs();
11403
11676
  init_thread_store();
@@ -11422,9 +11695,9 @@ function matchSimpleGlob(pattern, name) {
11422
11695
  return new RegExp(`^${escaped}$`).test(name);
11423
11696
  }
11424
11697
  function readWorktreeInclude(repoPath) {
11425
- const path = (0, import_node_path28.join)(repoPath, ".worktreeinclude");
11426
- if (!(0, import_node_fs28.existsSync)(path)) return [];
11427
- return (0, import_node_fs28.readFileSync)(path, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
11698
+ const path = (0, import_node_path29.join)(repoPath, ".worktreeinclude");
11699
+ if (!(0, import_node_fs29.existsSync)(path)) return [];
11700
+ return (0, import_node_fs29.readFileSync)(path, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
11428
11701
  }
11429
11702
  function resolveFilesToCopy(repoPath) {
11430
11703
  const fromInclude = readWorktreeInclude(repoPath);
@@ -11434,10 +11707,10 @@ function resolveFilesToCopy(repoPath) {
11434
11707
  if (settings?.fileIncludeGlobs?.length) {
11435
11708
  const matched = [];
11436
11709
  try {
11437
- for (const entry of (0, import_node_fs28.readdirSync)(repoPath, { withFileTypes: true })) {
11710
+ for (const entry of (0, import_node_fs29.readdirSync)(repoPath, { withFileTypes: true })) {
11438
11711
  if (!entry.isFile()) continue;
11439
11712
  for (const glob of settings.fileIncludeGlobs) {
11440
- if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path28.basename)(glob), entry.name)) {
11713
+ if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path29.basename)(glob), entry.name)) {
11441
11714
  matched.push(entry.name);
11442
11715
  break;
11443
11716
  }
@@ -11449,7 +11722,7 @@ function resolveFilesToCopy(repoPath) {
11449
11722
  }
11450
11723
  const defaults = [];
11451
11724
  try {
11452
- for (const entry of (0, import_node_fs28.readdirSync)(repoPath, { withFileTypes: true })) {
11725
+ for (const entry of (0, import_node_fs29.readdirSync)(repoPath, { withFileTypes: true })) {
11453
11726
  if (entry.isFile() && entry.name.startsWith(".env")) {
11454
11727
  defaults.push(entry.name);
11455
11728
  }
@@ -11463,11 +11736,11 @@ function copyConfiguredFiles(repoPath, worktreePath) {
11463
11736
  const patterns = resolveFilesToCopy(repoPath);
11464
11737
  const copied = [];
11465
11738
  for (const rel of patterns) {
11466
- const src = (0, import_node_path28.join)(repoPath, rel);
11467
- if (!(0, import_node_fs28.existsSync)(src)) continue;
11468
- const dest = (0, import_node_path28.join)(worktreePath, rel);
11469
- (0, import_node_fs28.mkdirSync)((0, import_node_path28.dirname)(dest), { recursive: true });
11470
- (0, import_node_fs28.copyFileSync)(src, dest);
11739
+ const src = (0, import_node_path29.join)(repoPath, rel);
11740
+ if (!(0, import_node_fs29.existsSync)(src)) continue;
11741
+ const dest = (0, import_node_path29.join)(worktreePath, rel);
11742
+ (0, import_node_fs29.mkdirSync)((0, import_node_path29.dirname)(dest), { recursive: true });
11743
+ (0, import_node_fs29.copyFileSync)(src, dest);
11471
11744
  copied.push(rel);
11472
11745
  }
11473
11746
  return copied;
@@ -11502,7 +11775,7 @@ function buildWorkspaceScriptEnv(opts, baseEnv) {
11502
11775
  const env = stripNestedElectronEnv({
11503
11776
  ...baseEnv ?? process.env
11504
11777
  });
11505
- const name = opts.workspaceName ?? (0, import_node_path28.basename)(opts.worktreePath);
11778
+ const name = opts.workspaceName ?? (0, import_node_path29.basename)(opts.worktreePath);
11506
11779
  const ports = opts.ports ?? [];
11507
11780
  const primary = ports[0];
11508
11781
  env.SIDEBOARD_WORKSPACE_NAME = name;
@@ -11763,13 +12036,13 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
11763
12036
  done: handle.done
11764
12037
  };
11765
12038
  }
11766
- var import_node_fs28, import_node_net, import_node_path28, import_execa4, import_node_readline3, PORT_RANGE_SIZE, cachedLoginEnv;
12039
+ var import_node_fs29, import_node_net, import_node_path29, import_execa4, import_node_readline3, PORT_RANGE_SIZE, cachedLoginEnv;
11767
12040
  var init_conductor = __esm({
11768
12041
  "src/hook/conductor.ts"() {
11769
12042
  "use strict";
11770
- import_node_fs28 = require("fs");
12043
+ import_node_fs29 = require("fs");
11771
12044
  import_node_net = require("net");
11772
- import_node_path28 = require("path");
12045
+ import_node_path29 = require("path");
11773
12046
  import_execa4 = require("execa");
11774
12047
  import_node_readline3 = require("readline");
11775
12048
  init_settings();
@@ -11795,9 +12068,9 @@ async function findOrphanWorktrees(repoPaths) {
11795
12068
  repoPaths?.length ? repoPaths : threads.map((t) => t.repoPath).filter(Boolean)
11796
12069
  );
11797
12070
  const homeRoot = sideboardWorkspacesDir();
11798
- if ((0, import_node_fs29.existsSync)(homeRoot)) {
12071
+ if ((0, import_node_fs30.existsSync)(homeRoot)) {
11799
12072
  try {
11800
- for (const entry of (0, import_node_fs29.readdirSync)(homeRoot, { withFileTypes: true })) {
12073
+ for (const entry of (0, import_node_fs30.readdirSync)(homeRoot, { withFileTypes: true })) {
11801
12074
  if (!entry.isDirectory()) continue;
11802
12075
  void entry;
11803
12076
  }
@@ -11807,7 +12080,7 @@ async function findOrphanWorktrees(repoPaths) {
11807
12080
  const orphans = [];
11808
12081
  const seen = /* @__PURE__ */ new Set();
11809
12082
  for (const repoPath of repos) {
11810
- if (!repoPath || !(0, import_node_fs29.existsSync)(repoPath)) continue;
12083
+ if (!repoPath || !(0, import_node_fs30.existsSync)(repoPath)) continue;
11811
12084
  try {
11812
12085
  const wts = await listWorktrees(repoPath);
11813
12086
  for (const wt of wts) {
@@ -11818,7 +12091,7 @@ async function findOrphanWorktrees(repoPaths) {
11818
12091
  seen.add(path);
11819
12092
  let mtimeMs = 0;
11820
12093
  try {
11821
- mtimeMs = (0, import_node_fs29.statSync)(path).mtimeMs;
12094
+ mtimeMs = (0, import_node_fs30.statSync)(path).mtimeMs;
11822
12095
  } catch {
11823
12096
  mtimeMs = 0;
11824
12097
  }
@@ -11828,16 +12101,16 @@ async function findOrphanWorktrees(repoPaths) {
11828
12101
  }
11829
12102
  try {
11830
12103
  const root = worktreesRoot(repoPath);
11831
- if ((0, import_node_fs29.existsSync)(root)) {
11832
- for (const entry of (0, import_node_fs29.readdirSync)(root, { withFileTypes: true })) {
12104
+ if ((0, import_node_fs30.existsSync)(root)) {
12105
+ for (const entry of (0, import_node_fs30.readdirSync)(root, { withFileTypes: true })) {
11833
12106
  if (!entry.isDirectory()) continue;
11834
- const path = (0, import_node_path29.join)(root, entry.name).replace(/\/$/, "");
12107
+ const path = (0, import_node_path30.join)(root, entry.name).replace(/\/$/, "");
11835
12108
  if (known.has(path) || seen.has(path)) continue;
11836
- if (!(0, import_node_fs29.existsSync)((0, import_node_path29.join)(path, ".git"))) continue;
12109
+ if (!(0, import_node_fs30.existsSync)((0, import_node_path30.join)(path, ".git"))) continue;
11837
12110
  seen.add(path);
11838
12111
  let mtimeMs = 0;
11839
12112
  try {
11840
- mtimeMs = (0, import_node_fs29.statSync)(path).mtimeMs;
12113
+ mtimeMs = (0, import_node_fs30.statSync)(path).mtimeMs;
11841
12114
  } catch {
11842
12115
  mtimeMs = Date.now();
11843
12116
  }
@@ -11889,12 +12162,12 @@ function shouldRunWorktreeCleanup(settings = loadAppSettings()) {
11889
12162
  const elapsed = Date.now() - Date.parse(last);
11890
12163
  return elapsed >= intervalHours * 36e5;
11891
12164
  }
11892
- var import_node_fs29, import_node_path29;
12165
+ var import_node_fs30, import_node_path30;
11893
12166
  var init_orphan_cleanup = __esm({
11894
12167
  "src/git/orphan-cleanup.ts"() {
11895
12168
  "use strict";
11896
- import_node_fs29 = require("fs");
11897
- import_node_path29 = require("path");
12169
+ import_node_fs30 = require("fs");
12170
+ import_node_path30 = require("path");
11898
12171
  init_worktree();
11899
12172
  init_thread_store();
11900
12173
  init_paths();
@@ -12001,38 +12274,38 @@ __export(workspaces_exports, {
12001
12274
  syncWorkspacesFromThreads: () => syncWorkspacesFromThreads
12002
12275
  });
12003
12276
  function workspacesFile() {
12004
- return (0, import_node_path30.join)(appDataDir(), "workspaces.json");
12277
+ return (0, import_node_path31.join)(appDataDir(), "workspaces.json");
12005
12278
  }
12006
12279
  function removedWorkspacesFile() {
12007
- return (0, import_node_path30.join)(appDataDir(), "removed-workspaces.json");
12280
+ return (0, import_node_path31.join)(appDataDir(), "removed-workspaces.json");
12008
12281
  }
12009
12282
  function readAll() {
12010
12283
  const path = workspacesFile();
12011
- if (!(0, import_node_fs30.existsSync)(path)) return [];
12284
+ if (!(0, import_node_fs31.existsSync)(path)) return [];
12012
12285
  try {
12013
- const raw = JSON.parse((0, import_node_fs30.readFileSync)(path, "utf8"));
12286
+ const raw = JSON.parse((0, import_node_fs31.readFileSync)(path, "utf8"));
12014
12287
  return Array.isArray(raw) ? raw : [];
12015
12288
  } catch {
12016
12289
  return [];
12017
12290
  }
12018
12291
  }
12019
12292
  function writeAll(list) {
12020
- (0, import_node_fs30.mkdirSync)(appDataDir(), { recursive: true });
12021
- (0, import_node_fs30.writeFileSync)(workspacesFile(), JSON.stringify(list, null, 2), "utf8");
12293
+ (0, import_node_fs31.mkdirSync)(appDataDir(), { recursive: true });
12294
+ (0, import_node_fs31.writeFileSync)(workspacesFile(), JSON.stringify(list, null, 2), "utf8");
12022
12295
  }
12023
12296
  function readRemoved() {
12024
12297
  const path = removedWorkspacesFile();
12025
- if (!(0, import_node_fs30.existsSync)(path)) return /* @__PURE__ */ new Set();
12298
+ if (!(0, import_node_fs31.existsSync)(path)) return /* @__PURE__ */ new Set();
12026
12299
  try {
12027
- const raw = JSON.parse((0, import_node_fs30.readFileSync)(path, "utf8"));
12300
+ const raw = JSON.parse((0, import_node_fs31.readFileSync)(path, "utf8"));
12028
12301
  return new Set(Array.isArray(raw) ? raw.filter((p) => typeof p === "string") : []);
12029
12302
  } catch {
12030
12303
  return /* @__PURE__ */ new Set();
12031
12304
  }
12032
12305
  }
12033
12306
  function writeRemoved(paths) {
12034
- (0, import_node_fs30.mkdirSync)(appDataDir(), { recursive: true });
12035
- (0, import_node_fs30.writeFileSync)(removedWorkspacesFile(), JSON.stringify([...paths].sort(), null, 2), "utf8");
12307
+ (0, import_node_fs31.mkdirSync)(appDataDir(), { recursive: true });
12308
+ (0, import_node_fs31.writeFileSync)(removedWorkspacesFile(), JSON.stringify([...paths].sort(), null, 2), "utf8");
12036
12309
  }
12037
12310
  function rememberRemoved(repoPath) {
12038
12311
  const next = readRemoved();
@@ -12055,7 +12328,7 @@ function listWorkspaces() {
12055
12328
  async function addWorkspace(repoPath) {
12056
12329
  const root = await resolveRepoRoot(repoPath);
12057
12330
  if (!root || root === "/") throw new Error(`Invalid repo path: ${repoPath}`);
12058
- if (!(0, import_node_fs30.existsSync)(root)) throw new Error(`Repo not found: ${root}`);
12331
+ if (!(0, import_node_fs31.existsSync)(root)) throw new Error(`Repo not found: ${root}`);
12059
12332
  forgetRemoved(root);
12060
12333
  await ensureGhPreferOrigin(root);
12061
12334
  const current = readAll();
@@ -12063,7 +12336,7 @@ async function addWorkspace(repoPath) {
12063
12336
  if (existing) return existing;
12064
12337
  const next = {
12065
12338
  path: root,
12066
- name: (0, import_node_path30.basename)(root),
12339
+ name: (0, import_node_path31.basename)(root),
12067
12340
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
12068
12341
  };
12069
12342
  writeAll([...current, next]);
@@ -12085,10 +12358,10 @@ function syncWorkspacesFromThreads(repoPaths) {
12085
12358
  if (!path || path === "/" || isGlobalRepoPath(path) || byPath.has(path) || removed.has(path)) {
12086
12359
  continue;
12087
12360
  }
12088
- if (!(0, import_node_fs30.existsSync)(path)) continue;
12361
+ if (!(0, import_node_fs31.existsSync)(path)) continue;
12089
12362
  const ws = {
12090
12363
  path,
12091
- name: (0, import_node_path30.basename)(path),
12364
+ name: (0, import_node_path31.basename)(path),
12092
12365
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
12093
12366
  };
12094
12367
  byPath.set(path, ws);
@@ -12098,12 +12371,12 @@ function syncWorkspacesFromThreads(repoPaths) {
12098
12371
  if (dirty) writeAll(next);
12099
12372
  return next.sort((a, b) => a.name.localeCompare(b.name));
12100
12373
  }
12101
- var import_node_fs30, import_node_path30;
12374
+ var import_node_fs31, import_node_path31;
12102
12375
  var init_workspaces2 = __esm({
12103
12376
  "src/store/workspaces.ts"() {
12104
12377
  "use strict";
12105
- import_node_fs30 = require("fs");
12106
- import_node_path30 = require("path");
12378
+ import_node_fs31 = require("fs");
12379
+ import_node_path31 = require("path");
12107
12380
  init_paths();
12108
12381
  init_global_workspace();
12109
12382
  init_worktree();
@@ -12116,12 +12389,12 @@ async function cloneRepoIntoSideboard(opts) {
12116
12389
  if (!url) throw new Error("Clone URL is required");
12117
12390
  let name = opts.name?.trim();
12118
12391
  if (!name) {
12119
- const leaf = (0, import_node_path31.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
12392
+ const leaf = (0, import_node_path32.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
12120
12393
  name = leaf || "repo";
12121
12394
  }
12122
12395
  name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
12123
- const dest = (0, import_node_path31.join)(sideboardReposDir(), name);
12124
- if ((0, import_node_fs31.existsSync)(dest)) {
12396
+ const dest = (0, import_node_path32.join)(sideboardReposDir(), name);
12397
+ if ((0, import_node_fs32.existsSync)(dest)) {
12125
12398
  const repoPath2 = await resolveRepoRoot(dest);
12126
12399
  const workspace2 = await ensureWorkspace(repoPath2);
12127
12400
  return { repoPath: repoPath2, workspace: workspace2 };
@@ -12136,12 +12409,12 @@ async function cloneRepoIntoSideboard(opts) {
12136
12409
  const workspace = await ensureWorkspace(repoPath);
12137
12410
  return { repoPath, workspace };
12138
12411
  }
12139
- var import_node_fs31, import_node_path31, import_execa6;
12412
+ var import_node_fs32, import_node_path32, import_execa6;
12140
12413
  var init_clone_repo = __esm({
12141
12414
  "src/git/clone-repo.ts"() {
12142
12415
  "use strict";
12143
- import_node_fs31 = require("fs");
12144
- import_node_path31 = require("path");
12416
+ import_node_fs32 = require("fs");
12417
+ import_node_path32 = require("path");
12145
12418
  import_execa6 = require("execa");
12146
12419
  init_paths();
12147
12420
  init_workspaces2();
@@ -12151,11 +12424,11 @@ var init_clone_repo = __esm({
12151
12424
 
12152
12425
  // src/store/desktop-host.ts
12153
12426
  function desktopHostPidPath() {
12154
- return (0, import_node_path32.join)(appDataDir(), "desktop-host.pid");
12427
+ return (0, import_node_path33.join)(appDataDir(), "desktop-host.pid");
12155
12428
  }
12156
12429
  function readDesktopHostPid() {
12157
12430
  try {
12158
- const pid = Number.parseInt((0, import_node_fs32.readFileSync)(desktopHostPidPath(), "utf8").trim(), 10);
12431
+ const pid = Number.parseInt((0, import_node_fs33.readFileSync)(desktopHostPidPath(), "utf8").trim(), 10);
12159
12432
  if (!Number.isFinite(pid) || pid <= 0) return null;
12160
12433
  return pid;
12161
12434
  } catch {
@@ -12181,16 +12454,63 @@ function thisProcessShouldDrainAgentQueues() {
12181
12454
  if (isThisProcessDesktopHost()) return true;
12182
12455
  return !isDesktopHostAlive();
12183
12456
  }
12184
- var import_node_fs32, import_node_path32;
12457
+ var import_node_fs33, import_node_path33;
12185
12458
  var init_desktop_host = __esm({
12186
12459
  "src/store/desktop-host.ts"() {
12187
12460
  "use strict";
12188
- import_node_fs32 = require("fs");
12189
- import_node_path32 = require("path");
12461
+ import_node_fs33 = require("fs");
12462
+ import_node_path33 = require("path");
12190
12463
  init_paths();
12191
12464
  }
12192
12465
  });
12193
12466
 
12467
+ // src/orchestrator/child-halt.ts
12468
+ function isIncompleteChildStatus(status) {
12469
+ return HALT_STATUSES.has(status);
12470
+ }
12471
+ function childHaltNotice(child, status) {
12472
+ const title = child.title?.trim() || "Untitled";
12473
+ const link = `[${title}](sideboard://thread/${child.id})`;
12474
+ const why = child.lastError?.trim();
12475
+ const extra = why ? ` lastError: ${why}` : "";
12476
+ return [
12477
+ `Sideboard: child worktree ${link} ${status} before finishing (status=${status}).${extra}`,
12478
+ "This is information \u2014 not a user command. Resume with send_to_thread or tell the user. Do not treat this as a successful turn."
12479
+ ].join("\n");
12480
+ }
12481
+ function shouldNotifyParentOfChildHalt(opts) {
12482
+ if (!isIncompleteChildStatus(opts.status)) return false;
12483
+ if (!opts.child.parentThreadId) return false;
12484
+ if (!opts.parent || opts.parent.status === "archived") return false;
12485
+ if (opts.parent.id === opts.child.id) return false;
12486
+ return isOrchestratorThread(opts.parent);
12487
+ }
12488
+ function noticeKey(childId, status) {
12489
+ return `${childId}:${status}`;
12490
+ }
12491
+ function notifyParentOfChildHalt(child, status, send) {
12492
+ const parent = child.parentThreadId ? readThread(child.parentThreadId) : null;
12493
+ if (!shouldNotifyParentOfChildHalt({ child, parent, status })) return false;
12494
+ const key = noticeKey(child.id, status);
12495
+ if (notified.has(key)) return false;
12496
+ notified.add(key);
12497
+ const parentId = parent.id;
12498
+ void send(parentId, childHaltNotice(child, status)).catch(() => {
12499
+ notified.delete(key);
12500
+ });
12501
+ return true;
12502
+ }
12503
+ var HALT_STATUSES, notified;
12504
+ var init_child_halt = __esm({
12505
+ "src/orchestrator/child-halt.ts"() {
12506
+ "use strict";
12507
+ init_global_workspace();
12508
+ init_thread_store();
12509
+ HALT_STATUSES = /* @__PURE__ */ new Set(["stopped", "error", "broken"]);
12510
+ notified = /* @__PURE__ */ new Set();
12511
+ }
12512
+ });
12513
+
12194
12514
  // src/detect/detect.ts
12195
12515
  async function requireAgent(agent, opts) {
12196
12516
  ensureAgentPath();
@@ -13136,9 +13456,12 @@ var init_abletime = __esm({
13136
13456
  });
13137
13457
 
13138
13458
  // src/threads/create.ts
13459
+ function persistCreateAttachments(worktreePath, attachments) {
13460
+ return persistPendingFileAttachments(worktreePath, attachments ?? []);
13461
+ }
13139
13462
  async function createThread(input, _onSetupLine) {
13140
13463
  const repoPath = await resolveRepoRoot(input.repoPath);
13141
- if (!(0, import_node_fs33.existsSync)(repoPath)) {
13464
+ if (!(0, import_node_fs34.existsSync)(repoPath)) {
13142
13465
  throw new Error(`Repo not found: ${repoPath}`);
13143
13466
  }
13144
13467
  if (input.reuseExisting !== false) {
@@ -13155,7 +13478,16 @@ async function createThread(input, _onSetupLine) {
13155
13478
  repoPath: canonicalizeRepoPath(t.repoPath)
13156
13479
  }))
13157
13480
  );
13158
- if (existing) return readThread(existing.id) ?? existing;
13481
+ if (existing) {
13482
+ const thread2 = readThread(existing.id) ?? existing;
13483
+ if (!input.attachments?.length) return thread2;
13484
+ return updateThread(thread2.id, {
13485
+ attachments: persistCreateAttachments(thread2.worktreePath, [
13486
+ ...thread2.attachments,
13487
+ ...input.attachments
13488
+ ])
13489
+ });
13490
+ }
13159
13491
  }
13160
13492
  const resolved = resolveNewThreadOptions({
13161
13493
  agent: input.agent,
@@ -13203,7 +13535,7 @@ async function createThread(input, _onSetupLine) {
13203
13535
  effort: resolved.effort,
13204
13536
  fast: resolved.fast,
13205
13537
  planMode: Boolean(input.planMode),
13206
- attachments: input.attachments ?? [],
13538
+ attachments: persistCreateAttachments(repoPath, input.attachments),
13207
13539
  sourceIsFork: false,
13208
13540
  parentThreadId: input.parentThreadId ?? null,
13209
13541
  status: "idle",
@@ -13282,7 +13614,7 @@ async function createThread(input, _onSetupLine) {
13282
13614
  effort: resolved.effort,
13283
13615
  fast: resolved.fast,
13284
13616
  planMode: Boolean(input.planMode),
13285
- attachments,
13617
+ attachments: persistCreateAttachments(worktreePath, attachments),
13286
13618
  sourceIsFork,
13287
13619
  parentThreadId: input.parentThreadId ?? null,
13288
13620
  status: "idle",
@@ -13302,16 +13634,17 @@ async function listLinearIssues(agent, repoPath) {
13302
13634
  }
13303
13635
  return adapter.listLinearIssues(repoPath);
13304
13636
  }
13305
- var import_node_fs33;
13637
+ var import_node_fs34;
13306
13638
  var init_create = __esm({
13307
13639
  "src/threads/create.ts"() {
13308
13640
  "use strict";
13309
- import_node_fs33 = require("fs");
13641
+ import_node_fs34 = require("fs");
13310
13642
  init_detect();
13311
13643
  init_worktree();
13312
13644
  init_home_board();
13313
13645
  init_conductor();
13314
13646
  init_app_settings();
13647
+ init_stage_files();
13315
13648
  init_thread_store();
13316
13649
  init_workspaces2();
13317
13650
  }
@@ -13408,20 +13741,20 @@ function writeTurnLive(threadId, progress) {
13408
13741
  const path = threadLivePath(threadId);
13409
13742
  const tmp = `${path}.${process.pid}.tmp`;
13410
13743
  try {
13411
- (0, import_node_fs34.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
13412
- (0, import_node_fs34.renameSync)(tmp, path);
13744
+ (0, import_node_fs35.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
13745
+ (0, import_node_fs35.renameSync)(tmp, path);
13413
13746
  } catch {
13414
13747
  try {
13415
- (0, import_node_fs34.unlinkSync)(tmp);
13748
+ (0, import_node_fs35.unlinkSync)(tmp);
13416
13749
  } catch {
13417
13750
  }
13418
13751
  }
13419
13752
  }
13420
13753
  function readTurnLive(threadId) {
13421
13754
  const path = threadLivePath(threadId);
13422
- if (!(0, import_node_fs34.existsSync)(path)) return null;
13755
+ if (!(0, import_node_fs35.existsSync)(path)) return null;
13423
13756
  try {
13424
- const raw = JSON.parse((0, import_node_fs34.readFileSync)(path, "utf8"));
13757
+ const raw = JSON.parse((0, import_node_fs35.readFileSync)(path, "utf8"));
13425
13758
  if (!raw || typeof raw.summary !== "string") return null;
13426
13759
  return raw;
13427
13760
  } catch {
@@ -13433,17 +13766,17 @@ function clearTurnLive(threadId) {
13433
13766
  if (buf?.timer) clearTimeout(buf.timer);
13434
13767
  buffers.delete(threadId);
13435
13768
  const path = threadLivePath(threadId);
13436
- if (!(0, import_node_fs34.existsSync)(path)) return;
13769
+ if (!(0, import_node_fs35.existsSync)(path)) return;
13437
13770
  try {
13438
- (0, import_node_fs34.unlinkSync)(path);
13771
+ (0, import_node_fs35.unlinkSync)(path);
13439
13772
  } catch {
13440
13773
  }
13441
13774
  }
13442
- var import_node_fs34, buffers, FLUSH_MS, MAX_PARTS;
13775
+ var import_node_fs35, buffers, FLUSH_MS, MAX_PARTS;
13443
13776
  var init_turn_live = __esm({
13444
13777
  "src/store/turn-live.ts"() {
13445
13778
  "use strict";
13446
- import_node_fs34 = require("fs");
13779
+ import_node_fs35 = require("fs");
13447
13780
  init_message_parts();
13448
13781
  init_paths();
13449
13782
  buffers = /* @__PURE__ */ new Map();
@@ -13602,7 +13935,7 @@ function buildQuotaHandoffAttachment(from, limitText, fallbackAgent) {
13602
13935
  `- Do not wait on the limited ${from.agent} account; keep going on ${fallbackAgent}.`
13603
13936
  ].join("\n");
13604
13937
  return {
13605
- id: (0, import_node_crypto6.randomUUID)(),
13938
+ id: (0, import_node_crypto7.randomUUID)(),
13606
13939
  name: "Orchestration quota handoff.md",
13607
13940
  kind: "transcript",
13608
13941
  content: body
@@ -13623,11 +13956,11 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText) {
13623
13956
  sourceType: "orchestration"
13624
13957
  });
13625
13958
  }
13626
- var import_node_crypto6, QUOTA_CONTINUE_PROMPT, QUOTA_RESUME_PROMPT;
13959
+ var import_node_crypto7, QUOTA_CONTINUE_PROMPT, QUOTA_RESUME_PROMPT;
13627
13960
  var init_quota_failover = __esm({
13628
13961
  "src/orchestrator/quota-failover.ts"() {
13629
13962
  "use strict";
13630
- import_node_crypto6 = require("crypto");
13963
+ import_node_crypto7 = require("crypto");
13631
13964
  init_session_quota();
13632
13965
  init_app_settings();
13633
13966
  init_global_workspace();
@@ -13644,7 +13977,7 @@ var init_quota_failover = __esm({
13644
13977
  // src/threads/adopt.ts
13645
13978
  function thisModuleFile() {
13646
13979
  const cjsFile = typeof __filename !== "undefined" ? __filename : "";
13647
- return cjsFile || process.argv[1] || (0, import_node_path33.join)(process.cwd(), "package.json");
13980
+ return cjsFile || process.argv[1] || (0, import_node_path34.join)(process.cwd(), "package.json");
13648
13981
  }
13649
13982
  function openReadonlySqlite(file) {
13650
13983
  const req = (0, import_node_module4.createRequire)(thisModuleFile());
@@ -13662,21 +13995,21 @@ function mapAgentType(raw) {
13662
13995
  return null;
13663
13996
  }
13664
13997
  function resolveConductorCursorAgentId(workspacePath) {
13665
- if (!workspacePath || !(0, import_node_fs35.existsSync)(CURSOR_SDK_STORE)) return null;
13998
+ if (!workspacePath || !(0, import_node_fs36.existsSync)(CURSOR_SDK_STORE)) return null;
13666
13999
  const normalized = workspacePath.replace(/\/$/, "");
13667
14000
  let best = null;
13668
14001
  let hashes;
13669
14002
  try {
13670
- hashes = (0, import_node_fs35.readdirSync)(CURSOR_SDK_STORE);
14003
+ hashes = (0, import_node_fs36.readdirSync)(CURSOR_SDK_STORE);
13671
14004
  } catch {
13672
14005
  return null;
13673
14006
  }
13674
14007
  for (const hash of hashes) {
13675
- const agentsFile = (0, import_node_path33.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
13676
- if (!(0, import_node_fs35.existsSync)(agentsFile)) continue;
14008
+ const agentsFile = (0, import_node_path34.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
14009
+ if (!(0, import_node_fs36.existsSync)(agentsFile)) continue;
13677
14010
  let text5;
13678
14011
  try {
13679
- text5 = (0, import_node_fs35.readFileSync)(agentsFile, "utf8");
14012
+ text5 = (0, import_node_fs36.readFileSync)(agentsFile, "utf8");
13680
14013
  } catch {
13681
14014
  continue;
13682
14015
  }
@@ -13700,7 +14033,7 @@ function resolveConductorCursorAgentId(workspacePath) {
13700
14033
  return best?.agentId ?? null;
13701
14034
  }
13702
14035
  async function adoptThread(input) {
13703
- if (!(0, import_node_fs35.existsSync)(input.worktreePath)) {
14036
+ if (!(0, import_node_fs36.existsSync)(input.worktreePath)) {
13704
14037
  throw new Error(`Worktree not found: ${input.worktreePath}`);
13705
14038
  }
13706
14039
  const repoPath = await resolveRepoRoot(input.worktreePath);
@@ -13724,18 +14057,18 @@ async function adoptThread(input) {
13724
14057
  return thread;
13725
14058
  }
13726
14059
  function listConductorWorkspaces() {
13727
- if (!(0, import_node_fs35.existsSync)(CONDUCTOR_DB)) {
14060
+ if (!(0, import_node_fs36.existsSync)(CONDUCTOR_DB)) {
13728
14061
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
13729
14062
  }
13730
- const tmp = (0, import_node_fs35.mkdtempSync)((0, import_node_path33.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
13731
- const snapshot = (0, import_node_path33.join)(tmp, "conductor.db");
14063
+ const tmp = (0, import_node_fs36.mkdtempSync)((0, import_node_path34.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
14064
+ const snapshot = (0, import_node_path34.join)(tmp, "conductor.db");
13732
14065
  try {
13733
- (0, import_node_fs35.copyFileSync)(CONDUCTOR_DB, snapshot);
14066
+ (0, import_node_fs36.copyFileSync)(CONDUCTOR_DB, snapshot);
13734
14067
  for (const suffix of ["-wal", "-shm"]) {
13735
14068
  const src = `${CONDUCTOR_DB}${suffix}`;
13736
- if ((0, import_node_fs35.existsSync)(src)) {
14069
+ if ((0, import_node_fs36.existsSync)(src)) {
13737
14070
  try {
13738
- (0, import_node_fs35.copyFileSync)(src, `${snapshot}${suffix}`);
14071
+ (0, import_node_fs36.copyFileSync)(src, `${snapshot}${suffix}`);
13739
14072
  } catch {
13740
14073
  }
13741
14074
  }
@@ -13811,22 +14144,22 @@ function listConductorWorkspaces() {
13811
14144
  db.close();
13812
14145
  }
13813
14146
  } finally {
13814
- (0, import_node_fs35.rmSync)(tmp, { recursive: true, force: true });
14147
+ (0, import_node_fs36.rmSync)(tmp, { recursive: true, force: true });
13815
14148
  }
13816
14149
  }
13817
14150
  function importConductorWorkspace(workspaceId) {
13818
- if (!(0, import_node_fs35.existsSync)(CONDUCTOR_DB)) {
14151
+ if (!(0, import_node_fs36.existsSync)(CONDUCTOR_DB)) {
13819
14152
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
13820
14153
  }
13821
- const tmp = (0, import_node_fs35.mkdtempSync)((0, import_node_path33.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
13822
- const snapshot = (0, import_node_path33.join)(tmp, "conductor.db");
14154
+ const tmp = (0, import_node_fs36.mkdtempSync)((0, import_node_path34.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
14155
+ const snapshot = (0, import_node_path34.join)(tmp, "conductor.db");
13823
14156
  try {
13824
- (0, import_node_fs35.copyFileSync)(CONDUCTOR_DB, snapshot);
14157
+ (0, import_node_fs36.copyFileSync)(CONDUCTOR_DB, snapshot);
13825
14158
  for (const suffix of ["-wal", "-shm"]) {
13826
14159
  const src = `${CONDUCTOR_DB}${suffix}`;
13827
- if ((0, import_node_fs35.existsSync)(src)) {
14160
+ if ((0, import_node_fs36.existsSync)(src)) {
13828
14161
  try {
13829
- (0, import_node_fs35.copyFileSync)(src, `${snapshot}${suffix}`);
14162
+ (0, import_node_fs36.copyFileSync)(src, `${snapshot}${suffix}`);
13830
14163
  } catch {
13831
14164
  }
13832
14165
  }
@@ -13844,7 +14177,7 @@ function importConductorWorkspace(workspaceId) {
13844
14177
  ).get(workspaceId);
13845
14178
  if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
13846
14179
  const worktreePath = String(row.workspacePath);
13847
- if (!(0, import_node_fs35.existsSync)(worktreePath)) {
14180
+ if (!(0, import_node_fs36.existsSync)(worktreePath)) {
13848
14181
  throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
13849
14182
  }
13850
14183
  let sessionId = null;
@@ -13907,31 +14240,31 @@ function importConductorWorkspace(workspaceId) {
13907
14240
  db.close();
13908
14241
  }
13909
14242
  } finally {
13910
- (0, import_node_fs35.rmSync)(tmp, { recursive: true, force: true });
14243
+ (0, import_node_fs36.rmSync)(tmp, { recursive: true, force: true });
13911
14244
  }
13912
14245
  }
13913
14246
  async function importConductorWorkspaceAsync(workspaceId) {
13914
14247
  return importConductorWorkspace(workspaceId);
13915
14248
  }
13916
- var import_node_child_process3, import_node_fs35, import_node_os10, import_node_path33, import_node_module4, CONDUCTOR_APP_SUPPORT, CONDUCTOR_DB, CURSOR_SDK_STORE;
14249
+ var import_node_child_process3, import_node_fs36, import_node_os10, import_node_path34, import_node_module4, CONDUCTOR_APP_SUPPORT, CONDUCTOR_DB, CURSOR_SDK_STORE;
13917
14250
  var init_adopt = __esm({
13918
14251
  "src/threads/adopt.ts"() {
13919
14252
  "use strict";
13920
14253
  import_node_child_process3 = require("child_process");
13921
- import_node_fs35 = require("fs");
14254
+ import_node_fs36 = require("fs");
13922
14255
  import_node_os10 = require("os");
13923
- import_node_path33 = require("path");
14256
+ import_node_path34 = require("path");
13924
14257
  import_node_module4 = require("module");
13925
14258
  init_worktree();
13926
14259
  init_thread_store();
13927
- CONDUCTOR_APP_SUPPORT = (0, import_node_path33.join)(
14260
+ CONDUCTOR_APP_SUPPORT = (0, import_node_path34.join)(
13928
14261
  process.env.HOME ?? "",
13929
14262
  "Library",
13930
14263
  "Application Support",
13931
14264
  "com.conductor.app"
13932
14265
  );
13933
- CONDUCTOR_DB = (0, import_node_path33.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
13934
- CURSOR_SDK_STORE = (0, import_node_path33.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
14266
+ CONDUCTOR_DB = (0, import_node_path34.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
14267
+ CURSOR_SDK_STORE = (0, import_node_path34.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
13935
14268
  }
13936
14269
  });
13937
14270
 
@@ -13998,7 +14331,7 @@ async function openStackLayer(input, _onSetupLine) {
13998
14331
  let createdWorktree = false;
13999
14332
  const trees = await listWorktrees(repoPath);
14000
14333
  const checkedOut = trees.find((w) => w.branch === branchName);
14001
- if (checkedOut?.path && (0, import_node_fs36.existsSync)(checkedOut.path)) {
14334
+ if (checkedOut?.path && (0, import_node_fs37.existsSync)(checkedOut.path)) {
14002
14335
  if (input.reuseExistingWorktree !== false) {
14003
14336
  worktreePath = checkedOut.path;
14004
14337
  } else {
@@ -14140,7 +14473,7 @@ async function initStackFromThread(input, onSetupLine) {
14140
14473
  async function createPrStack(input, onSetupLine) {
14141
14474
  await requireAgent(input.agent);
14142
14475
  const repoPath = await resolveRepoRoot(input.repoPath);
14143
- if (!(0, import_node_fs36.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
14476
+ if (!(0, import_node_fs37.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
14144
14477
  if (!input.branches.length) throw new Error("At least one branch name required");
14145
14478
  const status = await detectGhStack(repoPath);
14146
14479
  if (!status.available) throw new Error(status.reason);
@@ -14207,7 +14540,7 @@ async function createPrStack(input, onSetupLine) {
14207
14540
  }
14208
14541
  }
14209
14542
  const claimed = new Set(threads.map((t) => t.worktreePath));
14210
- if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs36.existsSync)(bootstrap.worktreePath)) {
14543
+ if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs37.existsSync)(bootstrap.worktreePath)) {
14211
14544
  try {
14212
14545
  await removeWorktree(repoPath, bootstrap.worktreePath, {
14213
14546
  deleteBranch: bootstrap.branchName
@@ -14217,11 +14550,11 @@ async function createPrStack(input, onSetupLine) {
14217
14550
  }
14218
14551
  return { stack, threads, createdThreadIds };
14219
14552
  }
14220
- var import_node_fs36;
14553
+ var import_node_fs37;
14221
14554
  var init_stack_layers = __esm({
14222
14555
  "src/threads/stack-layers.ts"() {
14223
14556
  "use strict";
14224
- import_node_fs36 = require("fs");
14557
+ import_node_fs37 = require("fs");
14225
14558
  init_detect();
14226
14559
  init_run();
14227
14560
  init_stack();
@@ -14234,7 +14567,7 @@ var init_stack_layers = __esm({
14234
14567
 
14235
14568
  // src/diff/diff.ts
14236
14569
  async function inspectGitWorktree(worktreePath) {
14237
- if (!worktreePath || !(0, import_node_fs37.existsSync)(worktreePath)) return "missing_worktree";
14570
+ if (!worktreePath || !(0, import_node_fs38.existsSync)(worktreePath)) return "missing_worktree";
14238
14571
  const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
14239
14572
  reject: false
14240
14573
  });
@@ -14242,7 +14575,7 @@ async function inspectGitWorktree(worktreePath) {
14242
14575
  return "ok";
14243
14576
  }
14244
14577
  async function initializeGitRepository(worktreePath) {
14245
- if (!worktreePath || !(0, import_node_fs37.existsSync)(worktreePath)) {
14578
+ if (!worktreePath || !(0, import_node_fs38.existsSync)(worktreePath)) {
14246
14579
  throw new Error("Worktree not found");
14247
14580
  }
14248
14581
  const status = await inspectGitWorktree(worktreePath);
@@ -14376,11 +14709,11 @@ new file mode 100644
14376
14709
  };
14377
14710
  }
14378
14711
  async function untrackedPatch(worktreePath, path, maxHunk) {
14379
- const abs = (0, import_node_path34.join)(worktreePath, path);
14712
+ const abs = (0, import_node_path35.join)(worktreePath, path);
14380
14713
  try {
14381
- const st = (0, import_node_fs37.statSync)(abs);
14714
+ const st = (0, import_node_fs38.statSync)(abs);
14382
14715
  if (st.isFile() && st.size > maxHunk) {
14383
- const buf = (0, import_node_fs37.readFileSync)(abs).subarray(0, maxHunk);
14716
+ const buf = (0, import_node_fs38.readFileSync)(abs).subarray(0, maxHunk);
14384
14717
  return syntheticAddPatch(path, buf.toString("utf8"), maxHunk);
14385
14718
  }
14386
14719
  } catch {
@@ -14864,13 +15197,13 @@ async function listWorktreeFiles(worktreePath, opts) {
14864
15197
  function isImageRelativePath(relativePath) {
14865
15198
  const base = relativePath.split("/").pop()?.toLowerCase() || "";
14866
15199
  const ext = base.includes(".") ? base.split(".").pop() || "" : "";
14867
- return IMAGE_EXTENSIONS.has(ext);
15200
+ return IMAGE_EXTENSIONS2.has(ext);
14868
15201
  }
14869
15202
  function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
14870
15203
  assertSafeRelativePath(relativePath);
14871
15204
  const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
14872
- const abs = (0, import_node_path34.join)(worktreePath, relativePath);
14873
- const st = (0, import_node_fs37.statSync)(abs);
15205
+ const abs = (0, import_node_path35.join)(worktreePath, relativePath);
15206
+ const st = (0, import_node_fs38.statSync)(abs);
14874
15207
  if (!st.isFile()) {
14875
15208
  throw new Error(`Not a file: ${relativePath}`);
14876
15209
  }
@@ -14879,7 +15212,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
14879
15212
  `File too large to upload (${st.size} bytes; max ${maxBytes})`
14880
15213
  );
14881
15214
  }
14882
- const buf = (0, import_node_fs37.readFileSync)(abs);
15215
+ const buf = (0, import_node_fs38.readFileSync)(abs);
14883
15216
  return {
14884
15217
  path: relativePath,
14885
15218
  contentBase64: buf.toString("base64"),
@@ -14889,12 +15222,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
14889
15222
  function readWorktreeFile(worktreePath, relativePath, opts) {
14890
15223
  assertSafeRelativePath(relativePath);
14891
15224
  const maxBytes = opts?.maxBytes ?? 2e5;
14892
- const abs = (0, import_node_path34.join)(worktreePath, relativePath);
14893
- const st = (0, import_node_fs37.statSync)(abs);
15225
+ const abs = (0, import_node_path35.join)(worktreePath, relativePath);
15226
+ const st = (0, import_node_fs38.statSync)(abs);
14894
15227
  if (!st.isFile()) {
14895
15228
  throw new Error(`Not a file: ${relativePath}`);
14896
15229
  }
14897
- const buf = (0, import_node_fs37.readFileSync)(abs);
15230
+ const buf = (0, import_node_fs38.readFileSync)(abs);
14898
15231
  if (isImageRelativePath(relativePath)) {
14899
15232
  const maxImageBytes = Math.max(maxBytes, 15e6);
14900
15233
  const truncated2 = buf.length > maxImageBytes;
@@ -14937,9 +15270,9 @@ function assertSafeRelativePath(relativePath) {
14937
15270
  }
14938
15271
  function writeWorktreeFile(worktreePath, relativePath, content) {
14939
15272
  assertSafeRelativePath(relativePath);
14940
- const abs = (0, import_node_path34.join)(worktreePath, relativePath);
14941
- (0, import_node_fs37.mkdirSync)((0, import_node_path34.dirname)(abs), { recursive: true });
14942
- (0, import_node_fs37.writeFileSync)(abs, content, "utf8");
15273
+ const abs = (0, import_node_path35.join)(worktreePath, relativePath);
15274
+ (0, import_node_fs38.mkdirSync)((0, import_node_path35.dirname)(abs), { recursive: true });
15275
+ (0, import_node_fs38.writeFileSync)(abs, content, "utf8");
14943
15276
  return { path: relativePath };
14944
15277
  }
14945
15278
  async function getDiffSummary(worktreePath, repoPath, opts) {
@@ -14956,18 +15289,18 @@ async function getDiffSummary(worktreePath, repoPath, opts) {
14956
15289
  truncated: full.files.length > maxFiles
14957
15290
  };
14958
15291
  }
14959
- var import_node_fs37, import_node_path34, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS, DEFAULT_UPLOAD_MAX_BYTES;
15292
+ var import_node_fs38, import_node_path35, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS2, DEFAULT_UPLOAD_MAX_BYTES;
14960
15293
  var init_diff = __esm({
14961
15294
  "src/diff/diff.ts"() {
14962
15295
  "use strict";
14963
- import_node_fs37 = require("fs");
14964
- import_node_path34 = require("path");
15296
+ import_node_fs38 = require("fs");
15297
+ import_node_path35 = require("path");
14965
15298
  init_run();
14966
15299
  init_worktree();
14967
15300
  mergeBaseCache = /* @__PURE__ */ new Map();
14968
15301
  MERGE_BASE_TTL_MS = 45e3;
14969
15302
  SHA_RE = /^[0-9a-f]{7,40}$/i;
14970
- IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
15303
+ IMAGE_EXTENSIONS2 = /* @__PURE__ */ new Set([
14971
15304
  "png",
14972
15305
  "jpg",
14973
15306
  "jpeg",
@@ -15129,7 +15462,7 @@ function parseFrontmatter(content) {
15129
15462
  }
15130
15463
  function readSkill(skillMd, source) {
15131
15464
  try {
15132
- const content = (0, import_node_fs38.readFileSync)(skillMd, "utf8");
15465
+ const content = (0, import_node_fs39.readFileSync)(skillMd, "utf8");
15133
15466
  const { name: fmName, description } = parseFrontmatter(content);
15134
15467
  const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
15135
15468
  const name = fmName || dirName;
@@ -15148,19 +15481,19 @@ function readSkill(skillMd, source) {
15148
15481
  }
15149
15482
  }
15150
15483
  function scanSkillsDir(dir, source, out) {
15151
- if (!(0, import_node_fs38.existsSync)(dir)) return;
15484
+ if (!(0, import_node_fs39.existsSync)(dir)) return;
15152
15485
  let entries;
15153
15486
  try {
15154
- entries = (0, import_node_fs38.readdirSync)(dir);
15487
+ entries = (0, import_node_fs39.readdirSync)(dir);
15155
15488
  } catch {
15156
15489
  return;
15157
15490
  }
15158
15491
  for (const entry of entries) {
15159
15492
  if (entry.startsWith(".")) continue;
15160
- const skillMd = (0, import_node_path35.join)(dir, entry, "SKILL.md");
15161
- if (!(0, import_node_fs38.existsSync)(skillMd)) continue;
15493
+ const skillMd = (0, import_node_path36.join)(dir, entry, "SKILL.md");
15494
+ if (!(0, import_node_fs39.existsSync)(skillMd)) continue;
15162
15495
  try {
15163
- if (!(0, import_node_fs38.statSync)(skillMd).isFile()) continue;
15496
+ if (!(0, import_node_fs39.statSync)(skillMd).isFile()) continue;
15164
15497
  } catch {
15165
15498
  continue;
15166
15499
  }
@@ -15169,24 +15502,24 @@ function scanSkillsDir(dir, source, out) {
15169
15502
  }
15170
15503
  }
15171
15504
  function scanClaudePluginSkills(pluginsRoot, out) {
15172
- if (!(0, import_node_fs38.existsSync)(pluginsRoot)) return;
15505
+ if (!(0, import_node_fs39.existsSync)(pluginsRoot)) return;
15173
15506
  const walk = (dir, depth, lookingForSkillsDir) => {
15174
15507
  if (depth > 7) return;
15175
15508
  let entries;
15176
15509
  try {
15177
- entries = (0, import_node_fs38.readdirSync)(dir);
15510
+ entries = (0, import_node_fs39.readdirSync)(dir);
15178
15511
  } catch {
15179
15512
  return;
15180
15513
  }
15181
15514
  if (lookingForSkillsDir && entries.includes("SKILL.md")) {
15182
- const skill = readSkill((0, import_node_path35.join)(dir, "SKILL.md"), "cli");
15515
+ const skill = readSkill((0, import_node_path36.join)(dir, "SKILL.md"), "cli");
15183
15516
  if (skill) out.push(skill);
15184
15517
  }
15185
15518
  for (const entry of entries) {
15186
15519
  if (entry === "node_modules" || entry === ".git") continue;
15187
- const full = (0, import_node_path35.join)(dir, entry);
15520
+ const full = (0, import_node_path36.join)(dir, entry);
15188
15521
  try {
15189
- if (!(0, import_node_fs38.statSync)(full).isDirectory()) continue;
15522
+ if (!(0, import_node_fs39.statSync)(full).isDirectory()) continue;
15190
15523
  } catch {
15191
15524
  continue;
15192
15525
  }
@@ -15204,17 +15537,17 @@ function discoverSkills(worktreePath) {
15204
15537
  const home = (0, import_node_os11.homedir)();
15205
15538
  const collected = [];
15206
15539
  for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
15207
- scanSkillsDir((0, import_node_path35.join)(worktreePath, rel), "workspace", collected);
15540
+ scanSkillsDir((0, import_node_path36.join)(worktreePath, rel), "workspace", collected);
15208
15541
  }
15209
15542
  for (const abs of [
15210
- (0, import_node_path35.join)(home, ".claude/skills"),
15211
- (0, import_node_path35.join)(home, ".cursor/skills"),
15212
- (0, import_node_path35.join)(home, ".sideboard/skills"),
15213
- (0, import_node_path35.join)(home, ".brightsy/skills")
15543
+ (0, import_node_path36.join)(home, ".claude/skills"),
15544
+ (0, import_node_path36.join)(home, ".cursor/skills"),
15545
+ (0, import_node_path36.join)(home, ".sideboard/skills"),
15546
+ (0, import_node_path36.join)(home, ".brightsy/skills")
15214
15547
  ]) {
15215
15548
  scanSkillsDir(abs, "user", collected);
15216
15549
  }
15217
- scanClaudePluginSkills((0, import_node_path35.join)(home, ".claude/plugins"), collected);
15550
+ scanClaudePluginSkills((0, import_node_path36.join)(home, ".claude/plugins"), collected);
15218
15551
  const rank = { workspace: 0, user: 1, cli: 2 };
15219
15552
  const byCommand = /* @__PURE__ */ new Map();
15220
15553
  for (const skill of collected) {
@@ -15226,7 +15559,7 @@ function discoverSkills(worktreePath) {
15226
15559
  return [...byCommand.values()].sort((a, b) => a.command.localeCompare(b.command));
15227
15560
  }
15228
15561
  function readSkillBody(skillPath, maxChars = 12e3) {
15229
- const raw = (0, import_node_fs38.readFileSync)(skillPath, "utf8");
15562
+ const raw = (0, import_node_fs39.readFileSync)(skillPath, "utf8");
15230
15563
  if (raw.startsWith("---")) {
15231
15564
  const end = raw.indexOf("\n---", 3);
15232
15565
  if (end >= 0) {
@@ -15240,13 +15573,13 @@ function readSkillBody(skillPath, maxChars = 12e3) {
15240
15573
 
15241
15574
  \u2026(truncated)` : raw;
15242
15575
  }
15243
- var import_node_fs38, import_node_os11, import_node_path35;
15576
+ var import_node_fs39, import_node_os11, import_node_path36;
15244
15577
  var init_discover = __esm({
15245
15578
  "src/skills/discover.ts"() {
15246
15579
  "use strict";
15247
- import_node_fs38 = require("fs");
15580
+ import_node_fs39 = require("fs");
15248
15581
  import_node_os11 = require("os");
15249
- import_node_path35 = require("path");
15582
+ import_node_path36 = require("path");
15250
15583
  }
15251
15584
  });
15252
15585
 
@@ -15335,197 +15668,6 @@ var init_expand = __esm({
15335
15668
  }
15336
15669
  });
15337
15670
 
15338
- // src/composer/stage-files.ts
15339
- function fileExtension(filePath) {
15340
- const base = (0, import_node_path36.basename)(filePath).toLowerCase();
15341
- return base.includes(".") ? base.split(".").pop() || "" : "";
15342
- }
15343
- function isImageFilePath(filePath) {
15344
- return IMAGE_EXTENSIONS2.has(fileExtension(filePath));
15345
- }
15346
- function imageMimeType(filePath) {
15347
- return IMAGE_MIME_BY_EXT[fileExtension(filePath)] || "image/png";
15348
- }
15349
- function ensureAttachmentsDir(worktreePath) {
15350
- const dir = (0, import_node_path36.join)(worktreePath, ATTACHMENTS_DIR);
15351
- (0, import_node_fs39.mkdirSync)(dir, { recursive: true });
15352
- const gi = (0, import_node_path36.join)(dir, ".gitignore");
15353
- if (!(0, import_node_fs39.existsSync)(gi)) {
15354
- (0, import_node_fs39.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
15355
- }
15356
- return dir;
15357
- }
15358
- function uniqueAttachmentName(dir, originalName) {
15359
- const safe = originalName.replace(/[/\\]/g, "_") || "file";
15360
- if (!(0, import_node_fs39.existsSync)((0, import_node_path36.join)(dir, safe))) return safe;
15361
- const ext = (0, import_node_path36.extname)(safe);
15362
- const stem = ext ? safe.slice(0, -ext.length) : safe;
15363
- for (let i = 1; i < 1e4; i++) {
15364
- const candidate = `${stem}-${i}${ext}`;
15365
- if (!(0, import_node_fs39.existsSync)((0, import_node_path36.join)(dir, candidate))) return candidate;
15366
- }
15367
- return `${stem}-${(0, import_node_crypto7.randomUUID)()}${ext}`;
15368
- }
15369
- function previewDataUrlFromBuf(filePath, buf) {
15370
- if (!isImageFilePath(filePath)) return void 0;
15371
- if (buf.length > MAX_PREVIEW_BYTES) return void 0;
15372
- return `data:${imageMimeType(filePath)};base64,${buf.toString("base64")}`;
15373
- }
15374
- function attachmentFromBuffer(name, buf, opts) {
15375
- const previewDataUrl = previewDataUrlFromBuf(name, buf);
15376
- if (isImageFilePath(name)) {
15377
- const pathHint = opts.path ? `\`${opts.path}\`` : opts.sourceLabel || name;
15378
- return {
15379
- id: (0, import_node_crypto7.randomUUID)(),
15380
- name,
15381
- kind: "file",
15382
- path: opts.path,
15383
- previewDataUrl,
15384
- content: [
15385
- `Image attached: ${pathHint}`,
15386
- opts.path ? `Use the Read tool on \`${opts.path}\` to view this image.` : "The image is shown in the composer; copy it into the worktree if you need to inspect pixels."
15387
- ].join("\n")
15388
- };
15389
- }
15390
- if (buf.length > MAX_INLINE_BYTES) {
15391
- return {
15392
- id: (0, import_node_crypto7.randomUUID)(),
15393
- name,
15394
- kind: "file",
15395
- path: opts.path,
15396
- content: opts.path ? `(file too large to attach inline: \`${opts.path}\`, ${buf.length} bytes \u2014 use the Read tool)` : `(file too large to attach inline: ${opts.sourceLabel || name}, ${buf.length} bytes)`
15397
- };
15398
- }
15399
- if (buf.includes(0)) {
15400
- return {
15401
- id: (0, import_node_crypto7.randomUUID)(),
15402
- name,
15403
- kind: "file",
15404
- path: opts.path,
15405
- content: opts.path ? `(binary file at \`${opts.path}\` \u2014 use tools to inspect)` : `(binary file attached by path only: ${opts.sourceLabel || name})`
15406
- };
15407
- }
15408
- return {
15409
- id: (0, import_node_crypto7.randomUUID)(),
15410
- name,
15411
- kind: "file",
15412
- path: opts.path,
15413
- content: buf.toString("utf8")
15414
- };
15415
- }
15416
- function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
15417
- if (absolutePaths.length === 0) return [];
15418
- const dir = ensureAttachmentsDir(worktreePath);
15419
- const out = [];
15420
- for (const abs of absolutePaths) {
15421
- const originalName = (0, import_node_path36.basename)(abs);
15422
- try {
15423
- const st = (0, import_node_fs39.statSync)(abs);
15424
- if (!st.isFile()) continue;
15425
- const name = uniqueAttachmentName(dir, originalName);
15426
- const destAbs = (0, import_node_path36.join)(dir, name);
15427
- (0, import_node_fs39.copyFileSync)(abs, destAbs);
15428
- const rel = `${ATTACHMENTS_DIR}/${name}`;
15429
- const buf = (0, import_node_fs39.readFileSync)(destAbs);
15430
- out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
15431
- } catch (err) {
15432
- out.push({
15433
- id: (0, import_node_crypto7.randomUUID)(),
15434
- name: originalName,
15435
- kind: "file",
15436
- content: `(could not attach ${abs}: ${err instanceof Error ? err.message : String(err)})`
15437
- });
15438
- }
15439
- }
15440
- return out;
15441
- }
15442
- function stageBuffersAsAttachments(worktreePath, buffers2) {
15443
- if (buffers2.length === 0) return [];
15444
- const dir = ensureAttachmentsDir(worktreePath);
15445
- const out = [];
15446
- for (const item of buffers2) {
15447
- const originalName = (item.name || "file").replace(/[/\\]/g, "_") || "file";
15448
- try {
15449
- const buf = Buffer.from(item.dataBase64, "base64");
15450
- const name = uniqueAttachmentName(dir, originalName);
15451
- const destAbs = (0, import_node_path36.join)(dir, name);
15452
- (0, import_node_fs39.writeFileSync)(destAbs, buf);
15453
- const rel = `${ATTACHMENTS_DIR}/${name}`;
15454
- out.push(attachmentFromBuffer(name, buf, { path: rel }));
15455
- } catch (err) {
15456
- out.push({
15457
- id: (0, import_node_crypto7.randomUUID)(),
15458
- name: originalName,
15459
- kind: "file",
15460
- content: `(could not attach ${originalName}: ${err instanceof Error ? err.message : String(err)})`
15461
- });
15462
- }
15463
- }
15464
- return out;
15465
- }
15466
- function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
15467
- const out = [];
15468
- for (const rel of relativePaths) {
15469
- if (!rel || rel.includes("..") || rel.startsWith("/")) {
15470
- out.push({
15471
- id: (0, import_node_crypto7.randomUUID)(),
15472
- name: (0, import_node_path36.basename)(rel) || "file",
15473
- kind: "file",
15474
- content: `(invalid path: ${rel})`
15475
- });
15476
- continue;
15477
- }
15478
- const name = (0, import_node_path36.basename)(rel);
15479
- try {
15480
- const abs = (0, import_node_path36.join)(worktreePath, rel);
15481
- const st = (0, import_node_fs39.statSync)(abs);
15482
- if (!st.isFile()) continue;
15483
- const buf = (0, import_node_fs39.readFileSync)(abs);
15484
- out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
15485
- } catch (err) {
15486
- out.push({
15487
- id: (0, import_node_crypto7.randomUUID)(),
15488
- name,
15489
- kind: "file",
15490
- content: `(could not read ${rel}: ${err instanceof Error ? err.message : String(err)})`
15491
- });
15492
- }
15493
- }
15494
- return out;
15495
- }
15496
- var import_node_fs39, import_node_path36, import_node_crypto7, IMAGE_EXTENSIONS2, IMAGE_MIME_BY_EXT, MAX_INLINE_BYTES, MAX_PREVIEW_BYTES;
15497
- var init_stage_files = __esm({
15498
- "src/composer/stage-files.ts"() {
15499
- "use strict";
15500
- import_node_fs39 = require("fs");
15501
- import_node_path36 = require("path");
15502
- import_node_crypto7 = require("crypto");
15503
- init_workspace_scratch();
15504
- IMAGE_EXTENSIONS2 = /* @__PURE__ */ new Set([
15505
- "png",
15506
- "jpg",
15507
- "jpeg",
15508
- "gif",
15509
- "webp",
15510
- "svg",
15511
- "bmp",
15512
- "ico"
15513
- ]);
15514
- IMAGE_MIME_BY_EXT = {
15515
- png: "image/png",
15516
- jpg: "image/jpeg",
15517
- jpeg: "image/jpeg",
15518
- gif: "image/gif",
15519
- webp: "image/webp",
15520
- svg: "image/svg+xml",
15521
- bmp: "image/bmp",
15522
- ico: "image/x-icon"
15523
- };
15524
- MAX_INLINE_BYTES = 4e5;
15525
- MAX_PREVIEW_BYTES = 5e6;
15526
- }
15527
- });
15528
-
15529
15671
  // src/agents/instructions.ts
15530
15672
  function normPath3(p) {
15531
15673
  return p.replace(/\/+$/, "");
@@ -16595,6 +16737,7 @@ var init_orchestrator = __esm({
16595
16737
  init_usage();
16596
16738
  init_thread_store();
16597
16739
  init_desktop_host();
16740
+ init_child_halt();
16598
16741
  init_create();
16599
16742
  init_cowboy();
16600
16743
  init_orchestrator_capable();
@@ -16742,6 +16885,9 @@ var init_orchestrator = __esm({
16742
16885
  * MCP-created review threads don't stay `queued` after the MCP child exits.
16743
16886
  */
16744
16887
  adoptPersistedQueues() {
16888
+ if (thisProcessShouldDrainAgentQueues()) {
16889
+ this.healStaleRunningTurns();
16890
+ }
16745
16891
  for (const thread of listThreads()) {
16746
16892
  if (thread.status === "stopped" || thread.status === "archived") continue;
16747
16893
  const pid = thread.agentPid;
@@ -16762,6 +16908,32 @@ var init_orchestrator = __esm({
16762
16908
  }
16763
16909
  }
16764
16910
  }
16911
+ /**
16912
+ * Mid-session: a worktree can sit at `running` after the agent process dies
16913
+ * (Cursor/CLI crash, OOM) while wait_for_turn still reports stillRunning.
16914
+ * Reclaim those and wake the parent orchestration chat.
16915
+ */
16916
+ healStaleRunningTurns() {
16917
+ for (const thread of listThreads()) {
16918
+ if (thread.status === "archived") continue;
16919
+ const handle = this.activeTurns.get(thread.id);
16920
+ if (handle) {
16921
+ const pid = thread.agentPid;
16922
+ if (typeof pid === "number" && pid > 0 && !isPidAlive(pid)) {
16923
+ handle.kill();
16924
+ }
16925
+ continue;
16926
+ }
16927
+ if (!this.shouldReclaimRunningThread(thread)) continue;
16928
+ setStatus(thread.id, "stopped", "Process died (agent exited)");
16929
+ this.emit({ type: "status_changed", threadId: thread.id, status: "stopped" });
16930
+ this.emit({ type: "turn_finished", threadId: thread.id, exitCode: 1 });
16931
+ const latest = readThread(thread.id);
16932
+ if (latest) {
16933
+ notifyParentOfChildHalt(latest, "stopped", (id, prompt) => this.send(id, prompt));
16934
+ }
16935
+ }
16936
+ }
16765
16937
  clearQuotaResumeTimer(threadId) {
16766
16938
  const timer = this.quotaResumeTimers.get(threadId);
16767
16939
  if (timer) clearTimeout(timer);
@@ -17479,6 +17651,12 @@ var init_orchestrator = __esm({
17479
17651
  assistantText: chatText,
17480
17652
  partsCount: parts.length
17481
17653
  });
17654
+ if (!this.crashContinued.has(threadId)) {
17655
+ const failed = readThread(threadId);
17656
+ if (failed) {
17657
+ notifyParentOfChildHalt(failed, "error", (id, prompt2) => this.send(id, prompt2));
17658
+ }
17659
+ }
17482
17660
  }
17483
17661
  }
17484
17662
  } catch (err) {
@@ -17503,6 +17681,12 @@ var init_orchestrator = __esm({
17503
17681
  assistantText: "",
17504
17682
  partsCount: 0
17505
17683
  });
17684
+ if (!this.crashContinued.has(threadId)) {
17685
+ const failed = readThread(threadId);
17686
+ if (failed) {
17687
+ notifyParentOfChildHalt(failed, "error", (id, prompt2) => this.send(id, prompt2));
17688
+ }
17689
+ }
17506
17690
  }
17507
17691
  } finally {
17508
17692
  this.startingTurns.delete(threadId);
@@ -17558,6 +17742,9 @@ var init_orchestrator = __esm({
17558
17742
  const stopped = writeLiveStatus(thread.id, "stopped") ?? readThread(thread.id) ?? thread;
17559
17743
  if (stopped.status === "stopped") {
17560
17744
  this.emit({ type: "status_changed", threadId: thread.id, status: "stopped" });
17745
+ if (opts?.notifyParent !== false) {
17746
+ notifyParentOfChildHalt(stopped, "stopped", (id, prompt) => this.send(id, prompt));
17747
+ }
17561
17748
  }
17562
17749
  return stopped;
17563
17750
  }
@@ -17802,21 +17989,25 @@ var init_orchestrator = __esm({
17802
17989
  fn();
17803
17990
  };
17804
17991
  const off = this.on((event) => {
17805
- if (event.type === "turn_finished" && event.threadId === thread.id) {
17992
+ if (!("threadId" in event) || event.threadId !== thread.id) return;
17993
+ if (event.type === "turn_finished" || event.type === "error") {
17806
17994
  const latest = readThread(thread.id);
17807
17995
  if (!latest) {
17808
17996
  finish(() => reject(new Error(`Thread not found: ${thread.id}`)));
17809
17997
  return;
17810
17998
  }
17811
17999
  finish(() => resolve(latest));
18000
+ return;
17812
18001
  }
17813
- if (event.type === "error" && event.threadId === thread.id) {
18002
+ if (event.type === "status_changed") {
17814
18003
  const latest = readThread(thread.id);
17815
18004
  if (!latest) {
17816
18005
  finish(() => reject(new Error(`Thread not found: ${thread.id}`)));
17817
18006
  return;
17818
18007
  }
17819
- finish(() => resolve(latest));
18008
+ if (!["running", "queued"].includes(latest.status)) {
18009
+ finish(() => resolve(latest));
18010
+ }
17820
18011
  }
17821
18012
  });
17822
18013
  timer = setInterval(() => {
@@ -17851,7 +18042,7 @@ var init_orchestrator = __esm({
17851
18042
  const thread = this.requireThread(threadRef);
17852
18043
  const lastAgent = [...thread.messages].reverse().find((m) => m.role === "agent");
17853
18044
  const lastError = thread.lastError ?? null;
17854
- const text5 = (lastAgent?.text ?? "").trim() || (thread.status === "error" ? lastError ?? "" : "");
18045
+ const text5 = (lastAgent?.text ?? "").trim() || (thread.status === "error" || thread.status === "stopped" || thread.status === "broken" ? lastError ?? "" : "");
17855
18046
  const stillRunning = thread.status === "running" || thread.status === "queued";
17856
18047
  const live = stillRunning ? readTurnLive(thread.id) : null;
17857
18048
  const queuedHint = thread.status === "queued" && !live?.summary ? "Queued \u2014 waiting for a concurrency slot" : null;
@@ -19049,6 +19240,15 @@ var MCP_WAIT_QUEUED_HINT = "Child is queued waiting for a concurrency slot \u201
19049
19240
  function mcpWaitStillRunningHint(status) {
19050
19241
  return status === "queued" ? MCP_WAIT_QUEUED_HINT : MCP_WAIT_STILL_RUNNING_HINT;
19051
19242
  }
19243
+ var MCP_WAIT_STOPPED_HINT = "Child was stopped before the turn finished. Do not treat this as success. send_to_thread to resume, or tell the user.";
19244
+ var MCP_WAIT_BROKEN_HINT = "Child worktree is broken (missing on disk). Tell the user \u2014 do not treat this as success.";
19245
+ var MCP_WAIT_ERROR_HINT = "Child turn failed. lastError/text is the failure \u2014 switch agent, tell the user, or retry. Do not treat empty text as success.";
19246
+ function mcpWaitFinishedHint(status) {
19247
+ if (status === "stopped") return MCP_WAIT_STOPPED_HINT;
19248
+ if (status === "broken") return MCP_WAIT_BROKEN_HINT;
19249
+ if (status === "error") return MCP_WAIT_ERROR_HINT;
19250
+ return void 0;
19251
+ }
19052
19252
 
19053
19253
  // src/mcp/server.ts
19054
19254
  init_turn_live();
@@ -20765,7 +20965,7 @@ async function startMcpServer() {
20765
20965
  );
20766
20966
  server.tool(
20767
20967
  "wait_for_turn",
20768
- "Wait until the thread finishes its current/queued turn, or return early with a live progress snapshot. MCP clients often kill tools around 60s, so this returns within 45s even while the child is still working. If stillRunning is true, progress is tools/thinking (or \u201Cqueued, waiting for a concurrency slot\u201D if it has not started). Call wait_for_turn again. Do not send a check-in prompt, force_stop, or assume a hang. On status error, lastError/text is the failure. When finished, usage is the last agent turn\u2019s tokens + costUsd (when the provider reported cost).",
20968
+ "Wait until the thread finishes its current/queued turn, or return early with a live progress snapshot. MCP clients often kill tools around 60s, so this returns within 45s even while the child is still working. If stillRunning is true, progress is tools/thinking (or \u201Cqueued, waiting for a concurrency slot\u201D if it has not started). Call wait_for_turn again. Do not send a check-in prompt, force_stop, or assume a hang. On status error, lastError/text is the failure. On status stopped or broken, the child did not finish \u2014 resume with send_to_thread or tell the user; do not treat that as success. When finished, usage is the last agent turn\u2019s tokens + costUsd (when the provider reported cost).",
20769
20969
  {
20770
20970
  ref: import_zod5.z.string(),
20771
20971
  timeoutMs: import_zod5.z.number().optional()
@@ -20787,7 +20987,8 @@ async function startMcpServer() {
20787
20987
  stillRunning: result.stillRunning,
20788
20988
  progress: result.progress,
20789
20989
  lastActivityAt: result.lastActivityAt,
20790
- hint: result.stillRunning ? mcpWaitStillRunningHint(result.status) : void 0
20990
+ hint: result.stillRunning ? mcpWaitStillRunningHint(result.status) : mcpWaitFinishedHint(result.status),
20991
+ incomplete: !result.stillRunning && Boolean(mcpWaitFinishedHint(result.status))
20791
20992
  })
20792
20993
  }
20793
20994
  ]
@@ -20806,7 +21007,8 @@ async function startMcpServer() {
20806
21007
  type: "text",
20807
21008
  text: JSON.stringify({
20808
21009
  ...result,
20809
- hint: result.stillRunning ? mcpWaitStillRunningHint(result.status) : void 0
21010
+ hint: result.stillRunning ? mcpWaitStillRunningHint(result.status) : mcpWaitFinishedHint(result.status),
21011
+ incomplete: !result.stillRunning && Boolean(mcpWaitFinishedHint(result.status))
20810
21012
  })
20811
21013
  }
20812
21014
  ]
@@ -20830,7 +21032,7 @@ async function startMcpServer() {
20830
21032
  }
20831
21033
  const clearQueue = force !== false;
20832
21034
  const hadQueued = t.queue.length > 0;
20833
- const stopped = orch.stop(ref, { clearQueue });
21035
+ const stopped = orch.stop(ref, { clearQueue, notifyParent: false });
20834
21036
  return {
20835
21037
  content: [
20836
21038
  {