@sideboard-ai/core 0.1.135 → 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 (27) hide show
  1. package/dist/{agents-O3AJMI2Y.js → agents-ELWR7A2T.js} +3 -3
  2. package/dist/{agents-RTQFF7PY.js → agents-QNTTLMG2.js} +3 -3
  3. package/dist/{chunk-RDULVW3E.js → chunk-4XKUHP6G.js} +1 -1
  4. package/dist/{chunk-N62K3KXX.js → chunk-CYM5DCHI.js} +38 -4
  5. package/dist/{chunk-XUEI4GCF.js → chunk-GSKRGF7B.js} +284 -3
  6. package/dist/{chunk-57GIFU3X.js → chunk-IFZ4MOTN.js} +2 -2
  7. package/dist/{chunk-KBBXNS2V.js → chunk-JPBRMUM6.js} +8 -4
  8. package/dist/{chunk-2ESCEK2Q.js → chunk-K5YT5GX2.js} +242 -3
  9. package/dist/{chunk-LOKXPQ4U.js → chunk-MDCKV2NF.js} +1 -1
  10. package/dist/{chunk-XIKEUCNC.js → chunk-TIGKDMIA.js} +139 -266
  11. package/dist/{chunk-K7EX47QG.js → chunk-TQ4S5AGJ.js} +2 -2
  12. package/dist/{chunk-Z5LYMW7M.js → chunk-WS5LFFU3.js} +135 -217
  13. package/dist/{coordinator-prompt-Y737IIFR.js → coordinator-prompt-2OWSUAUR.js} +1 -1
  14. package/dist/{coordinator-prompt-FYMWE33S.js → coordinator-prompt-IPL4Z6SL.js} +1 -1
  15. package/dist/{global-workspace-6KH6BSKL.js → global-workspace-JDUCUL7S.js} +2 -2
  16. package/dist/{global-workspace-ZFKNLBZA.js → global-workspace-NIKZAKOO.js} +2 -2
  17. package/dist/index.cjs +828 -615
  18. package/dist/index.d.cts +24 -1
  19. package/dist/index.d.ts +24 -1
  20. package/dist/index.js +38 -17
  21. package/dist/mcp/run-stdio.cjs +657 -485
  22. package/dist/mcp/run-stdio.js +20 -9
  23. package/dist/{orchestrator-3YDPPZHZ.js → orchestrator-6I47JMU2.js} +5 -5
  24. package/dist/{orchestrator-2BRAPJ47.js → orchestrator-KK3CUW37.js} +5 -5
  25. package/dist/{workspaces-3RRF3LVF.js → workspaces-5EWNNALF.js} +3 -3
  26. package/dist/{workspaces-AYI5DHK4.js → workspaces-KZA3TCEE.js} +3 -3
  27. package/package.json +1 -1
@@ -5825,6 +5825,240 @@ var init_cloud_connect_constants = __esm({
5825
5825
  }
5826
5826
  });
5827
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
+
5828
6062
  // src/agents/orchestrator-capable.ts
5829
6063
  function isOrchestratorCapableAgent(agent) {
5830
6064
  return Boolean(
@@ -5907,13 +6141,13 @@ function coordinatorTurnReminder(opts) {
5907
6141
  `- YOUR orchestration thread id is ${opts.parentId} \u2014 pass parentThreadId="${opts.parentId}" on create_thread, or omit it.`,
5908
6142
  goal ? `- Goal / title: ${goal}` : null,
5909
6143
  accountDefaultsPlaybookLine(),
5910
- "- 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."
5911
6145
  ].filter(Boolean).join("\n");
5912
6146
  }
5913
6147
  function ensureGlobalCoordinatorCwd(opts) {
5914
6148
  const dir = globalAgentCwd();
5915
6149
  try {
5916
- (0, import_node_fs15.mkdirSync)(dir, { recursive: true });
6150
+ (0, import_node_fs16.mkdirSync)(dir, { recursive: true });
5917
6151
  } catch {
5918
6152
  return dir;
5919
6153
  }
@@ -5921,7 +6155,7 @@ function ensureGlobalCoordinatorCwd(opts) {
5921
6155
  let orchId = opts?.orchestratorThreadId?.trim() || "";
5922
6156
  if (!orchId) {
5923
6157
  try {
5924
- 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");
5925
6159
  const m = existing.match(
5926
6160
  /YOUR orchestration thread id is `([0-9a-f-]{36})`/i
5927
6161
  );
@@ -5964,9 +6198,9 @@ function ensureGlobalCoordinatorCwd(opts) {
5964
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."
5965
6199
  ].join("\n");
5966
6200
  try {
5967
- (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}
5968
6202
  `, "utf8");
5969
- (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}
5970
6204
  `, "utf8");
5971
6205
  } catch {
5972
6206
  }
@@ -5998,12 +6232,12 @@ function coordinatorSystemPrompt(opts) {
5998
6232
  formatWorkspaceInventory(opts.workspaces)
5999
6233
  ].join("\n");
6000
6234
  }
6001
- 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;
6002
6236
  var init_coordinator_prompt = __esm({
6003
6237
  "src/orchestrator/coordinator-prompt.ts"() {
6004
6238
  "use strict";
6005
- import_node_fs15 = require("fs");
6006
- import_node_path18 = require("path");
6239
+ import_node_fs16 = require("fs");
6240
+ import_node_path19 = require("path");
6007
6241
  init_worktree();
6008
6242
  init_app_settings();
6009
6243
  init_paths();
@@ -6032,7 +6266,7 @@ var init_coordinator_prompt = __esm({
6032
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.",
6033
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.",
6034
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",
6035
- "- 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.",
6036
6270
  "- stop_thread \u2014 force-stop: kill in-flight turn AND clear queued prompts (do not leave stale queue after an interrupt)",
6037
6271
  "- archive_thread / restore_thread \u2014 archive (tears down worktree when last tab) or restore",
6038
6272
  "Setup / run:",
@@ -6152,6 +6386,7 @@ function createGlobalChat(opts) {
6152
6386
  fast: opts.fast
6153
6387
  });
6154
6388
  const agent = assertOrchestratorCapableAgent(resolved.agent);
6389
+ const worktreePath = globalAgentCwd();
6155
6390
  const thread = createEmptyThread({
6156
6391
  title,
6157
6392
  // Stick nicknames the same way chat tabs do (avoid later sync overwrites).
@@ -6159,7 +6394,7 @@ function createGlobalChat(opts) {
6159
6394
  sourceType: "orchestration",
6160
6395
  sourceRef,
6161
6396
  branchName: "global",
6162
- worktreePath: globalAgentCwd(),
6397
+ worktreePath,
6163
6398
  repoPath: GLOBAL_WORKSPACE_ID,
6164
6399
  agent,
6165
6400
  autonomy: opts.autonomy ?? "default",
@@ -6167,7 +6402,10 @@ function createGlobalChat(opts) {
6167
6402
  effort: resolved.effort,
6168
6403
  fast: resolved.fast,
6169
6404
  planMode: Boolean(opts.planMode),
6170
- attachments: opts.attachments ?? [],
6405
+ attachments: persistPendingFileAttachments(
6406
+ worktreePath,
6407
+ opts.attachments ?? []
6408
+ ),
6171
6409
  parentThreadId: opts.parentThreadId ?? null,
6172
6410
  status: "idle"
6173
6411
  });
@@ -6292,6 +6530,7 @@ var init_global_workspace = __esm({
6292
6530
  "src/store/global-workspace.ts"() {
6293
6531
  "use strict";
6294
6532
  init_cloud_connect_constants();
6533
+ init_stage_files();
6295
6534
  init_orchestrator_capable();
6296
6535
  init_teams();
6297
6536
  init_coordinator_prompt();
@@ -6306,32 +6545,32 @@ var init_global_workspace = __esm({
6306
6545
  function brightsyConfigPath() {
6307
6546
  const override = process.env.BRIGHTSY_CONFIG?.trim();
6308
6547
  if (override) return override;
6309
- 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");
6310
6549
  }
6311
6550
  function loadBrightsyConfig() {
6312
6551
  const path = brightsyConfigPath();
6313
- if (!(0, import_node_fs16.existsSync)(path)) {
6552
+ if (!(0, import_node_fs17.existsSync)(path)) {
6314
6553
  throw new Error("Brightsy not logged in \u2014 run `brightsy login` first");
6315
6554
  }
6316
- const raw = JSON.parse((0, import_node_fs16.readFileSync)(path, "utf8"));
6555
+ const raw = JSON.parse((0, import_node_fs17.readFileSync)(path, "utf8"));
6317
6556
  if (!raw.access_token || !raw.account_id) {
6318
6557
  throw new Error("Brightsy config incomplete \u2014 run `brightsy login`");
6319
6558
  }
6320
6559
  return raw;
6321
6560
  }
6322
6561
  function saveBrightsyConfig(cfg) {
6323
- (0, import_node_fs16.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
6562
+ (0, import_node_fs17.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
6324
6563
  `, {
6325
6564
  mode: 384
6326
6565
  });
6327
6566
  }
6328
- var import_node_fs16, import_node_os6, import_node_path19;
6567
+ var import_node_fs17, import_node_os6, import_node_path20;
6329
6568
  var init_config = __esm({
6330
6569
  "src/brightsy/config.ts"() {
6331
6570
  "use strict";
6332
- import_node_fs16 = require("fs");
6571
+ import_node_fs17 = require("fs");
6333
6572
  import_node_os6 = require("os");
6334
- import_node_path19 = require("path");
6573
+ import_node_path20 = require("path");
6335
6574
  }
6336
6575
  });
6337
6576
 
@@ -6448,22 +6687,22 @@ var init_oauth = __esm({
6448
6687
 
6449
6688
  // src/brightsy/connected-teams.ts
6450
6689
  function storePath4() {
6451
- return (0, import_node_path20.join)(appDataDir(), "brightsy-teams.json");
6690
+ return (0, import_node_path21.join)(appDataDir(), "brightsy-teams.json");
6452
6691
  }
6453
6692
  function readStore4() {
6454
6693
  const path = storePath4();
6455
- if (!(0, import_node_fs17.existsSync)(path)) return [];
6694
+ if (!(0, import_node_fs18.existsSync)(path)) return [];
6456
6695
  try {
6457
- const parsed = JSON.parse((0, import_node_fs17.readFileSync)(path, "utf8"));
6696
+ const parsed = JSON.parse((0, import_node_fs18.readFileSync)(path, "utf8"));
6458
6697
  return Array.isArray(parsed.teams) ? parsed.teams : [];
6459
6698
  } catch {
6460
6699
  return [];
6461
6700
  }
6462
6701
  }
6463
6702
  function writeStore2(teams) {
6464
- (0, import_node_fs17.mkdirSync)(appDataDir(), { recursive: true });
6703
+ (0, import_node_fs18.mkdirSync)(appDataDir(), { recursive: true });
6465
6704
  const path = storePath4();
6466
- (0, import_node_fs17.writeFileSync)(path, `${JSON.stringify({ teams }, null, 2)}
6705
+ (0, import_node_fs18.writeFileSync)(path, `${JSON.stringify({ teams }, null, 2)}
6467
6706
  `, {
6468
6707
  mode: 384
6469
6708
  });
@@ -6569,12 +6808,12 @@ function brightsyMcpServerName(slug) {
6569
6808
  const cleaned = slug.replace(/[^A-Za-z0-9_-]/g, "_").replace(/^_+|_+$/g, "");
6570
6809
  return `brightsy_${cleaned || "team"}`;
6571
6810
  }
6572
- var import_node_fs17, import_node_path20;
6811
+ var import_node_fs18, import_node_path21;
6573
6812
  var init_connected_teams = __esm({
6574
6813
  "src/brightsy/connected-teams.ts"() {
6575
6814
  "use strict";
6576
- import_node_fs17 = require("fs");
6577
- import_node_path20 = require("path");
6815
+ import_node_fs18 = require("fs");
6816
+ import_node_path21 = require("path");
6578
6817
  init_paths();
6579
6818
  init_accounts();
6580
6819
  init_config();
@@ -6946,11 +7185,11 @@ async function syncCliForTarget(accountId) {
6946
7185
  }
6947
7186
  applyConnectedTeamToCli(team);
6948
7187
  }
6949
- var import_node_fs18, brightsyAdapter;
7188
+ var import_node_fs19, brightsyAdapter;
6950
7189
  var init_brightsy = __esm({
6951
7190
  "src/agents/brightsy.ts"() {
6952
7191
  "use strict";
6953
- import_node_fs18 = require("fs");
7192
+ import_node_fs19 = require("fs");
6954
7193
  init_run();
6955
7194
  init_connected_teams();
6956
7195
  init_config();
@@ -6965,7 +7204,7 @@ var init_brightsy = __esm({
6965
7204
  async detect() {
6966
7205
  const brightsy = resolveAgentExecutable("brightsy");
6967
7206
  if (brightsy !== "brightsy") {
6968
- if (!(0, import_node_fs18.existsSync)(brightsy)) {
7207
+ if (!(0, import_node_fs19.existsSync)(brightsy)) {
6969
7208
  return {
6970
7209
  agent: "brightsy",
6971
7210
  installed: false,
@@ -7093,10 +7332,14 @@ function toolDetail(name, input) {
7093
7332
  if (!input) return void 0;
7094
7333
  const command = str2(input.command) ?? str2(input.cmd);
7095
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
+ }
7096
7340
  const path = str2(input.file_path) ?? str2(input.path) ?? str2(input.filePath) ?? str2(input.filename);
7097
7341
  if (path) return path;
7098
- const pattern = str2(input.pattern) ?? str2(input.glob) ?? str2(input.glob_pattern);
7099
- if (pattern) return pattern;
7342
+ if (pattern) return pattern.length > 80 ? `${pattern.slice(0, 77)}\u2026` : pattern;
7100
7343
  const query = str2(input.query) ?? str2(input.prompt);
7101
7344
  if (query) return query.length > 80 ? `${query.slice(0, 77)}\u2026` : query;
7102
7345
  try {
@@ -7536,43 +7779,43 @@ function electronResourcesPath() {
7536
7779
  function packagedCursorRuntimeDir() {
7537
7780
  const resources = electronResourcesPath();
7538
7781
  if (!resources) return null;
7539
- const dir = (0, import_node_path21.join)(resources, "cursor-runtime");
7540
- 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;
7541
7784
  return dir;
7542
7785
  }
7543
7786
  function packagedCursorRunnerPath() {
7544
7787
  const dir = packagedCursorRuntimeDir();
7545
- 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;
7546
7789
  }
7547
7790
  function packagedMcpDir() {
7548
7791
  const resources = electronResourcesPath();
7549
7792
  if (!resources) return null;
7550
- const dir = (0, import_node_path21.join)(resources, "sideboard-mcp");
7551
- 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;
7552
7795
  return dir;
7553
7796
  }
7554
7797
  function packagedMcpStdioPath() {
7555
7798
  const dir = packagedMcpDir();
7556
- 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;
7557
7800
  }
7558
7801
  function packagedBundledNodePath() {
7559
7802
  const resources = electronResourcesPath();
7560
7803
  if (!resources) return null;
7561
- const bin = (0, import_node_path21.join)(resources, "node", "bin", "node");
7562
- 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;
7563
7806
  return bin;
7564
7807
  }
7565
7808
  function packagedCursorRipgrepCandidate(platformPkg, binName) {
7566
7809
  const dir = packagedCursorRuntimeDir();
7567
7810
  if (!dir) return null;
7568
- 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);
7569
7812
  }
7570
- var import_node_fs19, import_node_path21;
7813
+ var import_node_fs20, import_node_path22;
7571
7814
  var init_packaged_runtime = __esm({
7572
7815
  "src/agents/packaged-runtime.ts"() {
7573
7816
  "use strict";
7574
- import_node_fs19 = require("fs");
7575
- import_node_path21 = require("path");
7817
+ import_node_fs20 = require("fs");
7818
+ import_node_path22 = require("path");
7576
7819
  }
7577
7820
  });
7578
7821
 
@@ -7606,7 +7849,7 @@ function unpackedAsarPath(filePath) {
7606
7849
  if (!isAsarPath(filePath)) return null;
7607
7850
  const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
7608
7851
  if (unpacked === filePath) return null;
7609
- return (0, import_node_fs20.existsSync)(unpacked) ? unpacked : null;
7852
+ return (0, import_node_fs21.existsSync)(unpacked) ? unpacked : null;
7610
7853
  }
7611
7854
  function nodeReadableScriptPath(scriptPath) {
7612
7855
  return unpackedAsarPath(scriptPath) ?? scriptPath;
@@ -7646,37 +7889,37 @@ function pickPreferredNode(candidates) {
7646
7889
  return best;
7647
7890
  }
7648
7891
  function versionDirNodeBins(root, toBin) {
7649
- if (!(0, import_node_fs20.existsSync)(root)) return [];
7892
+ if (!(0, import_node_fs21.existsSync)(root)) return [];
7650
7893
  try {
7651
- return (0, import_node_fs20.readdirSync)(root).map(toBin);
7894
+ return (0, import_node_fs21.readdirSync)(root).map(toBin);
7652
7895
  } catch {
7653
7896
  return [];
7654
7897
  }
7655
7898
  }
7656
7899
  function defaultNodeBinCandidates(home = (0, import_node_os7.homedir)()) {
7657
7900
  const kegs = ["/opt/homebrew", "/usr/local"].flatMap(
7658
- (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"))
7659
7902
  );
7660
7903
  return [
7661
7904
  ...kegs,
7662
7905
  "/opt/homebrew/bin/node",
7663
7906
  "/usr/local/bin/node",
7664
- (0, import_node_path22.join)(home, ".local/share/fnm/aliases/default/bin/node"),
7665
- (0, import_node_path22.join)(home, ".nvm/current/bin/node"),
7666
- (0, import_node_path22.join)(home, ".volta/bin/node"),
7667
- (0, import_node_path22.join)(home, ".asdf/shims/node"),
7668
- (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"),
7669
7912
  ...versionDirNodeBins(
7670
- (0, import_node_path22.join)(home, ".nvm", "versions", "node"),
7671
- (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")
7672
7915
  ),
7673
7916
  ...versionDirNodeBins(
7674
- (0, import_node_path22.join)(home, ".local/share/fnm", "node-versions"),
7675
- (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")
7676
7919
  ),
7677
7920
  ...versionDirNodeBins(
7678
- (0, import_node_path22.join)(home, ".volta", "tools", "image", "node"),
7679
- (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")
7680
7923
  )
7681
7924
  ];
7682
7925
  }
@@ -7685,10 +7928,10 @@ function uniqueExistingNodeBins(paths) {
7685
7928
  const out = [];
7686
7929
  for (const raw of paths) {
7687
7930
  const p = raw.trim();
7688
- if (!p || !(0, import_node_fs20.existsSync)(p) || isElectronLikeCommand(p)) continue;
7931
+ if (!p || !(0, import_node_fs21.existsSync)(p) || isElectronLikeCommand(p)) continue;
7689
7932
  let key = p;
7690
7933
  try {
7691
- key = (0, import_node_fs20.realpathSync)(p);
7934
+ key = (0, import_node_fs21.realpathSync)(p);
7692
7935
  } catch {
7693
7936
  continue;
7694
7937
  }
@@ -7768,13 +8011,13 @@ async function resolveNodeLaunch(scriptPath) {
7768
8011
  env: { ELECTRON_RUN_AS_NODE: "1" }
7769
8012
  };
7770
8013
  }
7771
- 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;
7772
8015
  var init_node_launch = __esm({
7773
8016
  "src/agents/node-launch.ts"() {
7774
8017
  "use strict";
7775
- import_node_fs20 = require("fs");
8018
+ import_node_fs21 = require("fs");
7776
8019
  import_node_os7 = require("os");
7777
- import_node_path22 = require("path");
8020
+ import_node_path23 = require("path");
7778
8021
  init_nested_electron_env();
7779
8022
  init_run();
7780
8023
  init_packaged_runtime();
@@ -7868,37 +8111,37 @@ function corePackageDir() {
7868
8111
  try {
7869
8112
  const url = import_meta.url;
7870
8113
  if (typeof url === "string" && url.length > 0) {
7871
- 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));
7872
8115
  }
7873
8116
  } catch {
7874
8117
  }
7875
8118
  try {
7876
- const req = (0, import_node_module.createRequire)((0, import_node_path23.join)(process.cwd(), "package.json"));
7877
- 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"));
7878
8121
  } catch {
7879
8122
  return process.cwd();
7880
8123
  }
7881
8124
  }
7882
8125
  function findSideboardMcpJsEntry() {
7883
8126
  const override = process.env.SIDEBOARD_MCP_ENTRY?.trim() || process.env.SIDEBOARD_CLI?.trim();
7884
- if (override && (0, import_node_fs21.existsSync)(override)) return override;
8127
+ if (override && (0, import_node_fs22.existsSync)(override)) return override;
7885
8128
  const packaged = packagedMcpStdioPath();
7886
8129
  if (packaged) return packaged;
7887
8130
  let dir = corePackageDir();
7888
8131
  for (let i = 0; i < 10; i++) {
7889
8132
  const candidates = [
7890
- (0, import_node_path23.join)(dir, "mcp/run-stdio.js"),
7891
- (0, import_node_path23.join)(dir, "mcp/run-stdio.cjs"),
7892
- (0, import_node_path23.join)(dir, "dist/mcp/run-stdio.js"),
7893
- (0, import_node_path23.join)(dir, "dist/mcp/run-stdio.cjs"),
7894
- (0, import_node_path23.join)(dir, "packages/core/dist/mcp/run-stdio.js"),
7895
- (0, import_node_path23.join)(dir, "packages/cli/dist/index.js"),
7896
- (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")
7897
8140
  ];
7898
8141
  for (const p of candidates) {
7899
- if ((0, import_node_fs21.existsSync)(p) && !isAsarPath(p)) return p;
8142
+ if ((0, import_node_fs22.existsSync)(p) && !isAsarPath(p)) return p;
7900
8143
  }
7901
- const parent = (0, import_node_path23.dirname)(dir);
8144
+ const parent = (0, import_node_path24.dirname)(dir);
7902
8145
  if (parent === dir) break;
7903
8146
  dir = parent;
7904
8147
  }
@@ -8040,19 +8283,19 @@ function writeMcpServersConfig(servers) {
8040
8283
  ...env ? { env } : {}
8041
8284
  };
8042
8285
  }
8043
- const dir = (0, import_node_fs21.mkdtempSync)((0, import_node_path23.join)((0, import_node_os8.tmpdir)(), "sideboard-mcp-"));
8044
- const cfgPath = (0, import_node_path23.join)(dir, "mcp.json");
8045
- (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));
8046
8289
  return cfgPath;
8047
8290
  }
8048
- 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;
8049
8292
  var init_injected_mcp = __esm({
8050
8293
  "src/agents/injected-mcp.ts"() {
8051
8294
  "use strict";
8052
- import_node_fs21 = require("fs");
8295
+ import_node_fs22 = require("fs");
8053
8296
  import_node_module = require("module");
8054
8297
  import_node_os8 = require("os");
8055
- import_node_path23 = require("path");
8298
+ import_node_path24 = require("path");
8056
8299
  import_node_url = require("url");
8057
8300
  init_run();
8058
8301
  init_config();
@@ -8352,11 +8595,11 @@ function parseIssuesJson(raw) {
8352
8595
  }
8353
8596
  return [];
8354
8597
  }
8355
- 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;
8356
8599
  var init_claude = __esm({
8357
8600
  "src/agents/claude.ts"() {
8358
8601
  "use strict";
8359
- import_node_fs22 = require("fs");
8602
+ import_node_fs23 = require("fs");
8360
8603
  init_run();
8361
8604
  init_app_settings();
8362
8605
  init_claude_mcp();
@@ -8396,7 +8639,7 @@ var init_claude = __esm({
8396
8639
  async detect() {
8397
8640
  const claude = resolveClaudeExecutable();
8398
8641
  if (claude !== "claude") {
8399
- if (!(0, import_node_fs22.existsSync)(claude)) {
8642
+ if (!(0, import_node_fs23.existsSync)(claude)) {
8400
8643
  return {
8401
8644
  agent: "claude",
8402
8645
  installed: false,
@@ -8651,7 +8894,7 @@ async function listCodexModels() {
8651
8894
  if (codex === "codex") {
8652
8895
  const which = await run("which", ["codex"], { reject: false });
8653
8896
  if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
8654
- } else if (!(0, import_node_fs23.existsSync)(codex)) {
8897
+ } else if (!(0, import_node_fs24.existsSync)(codex)) {
8655
8898
  return FALLBACK_CODEX_MODELS;
8656
8899
  }
8657
8900
  const listed = await run(codex, ["debug", "models"], { reject: false });
@@ -8686,12 +8929,12 @@ function usageFromCodex(usage) {
8686
8929
  }
8687
8930
  function codexConfigHasNetworkAccess() {
8688
8931
  const candidates = [
8689
- (0, import_node_path24.join)((0, import_node_os9.homedir)(), ".codex", "config.toml"),
8690
- (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")
8691
8934
  ];
8692
8935
  for (const path of candidates) {
8693
- if (!(0, import_node_fs23.existsSync)(path)) continue;
8694
- 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");
8695
8938
  if (/network_access\s*=\s*true/.test(text5)) return true;
8696
8939
  }
8697
8940
  return false;
@@ -8723,21 +8966,21 @@ function asRecord2(value) {
8723
8966
  return void 0;
8724
8967
  }
8725
8968
  function codexLooksAuthenticated() {
8726
- const authPath = (0, import_node_path24.join)((0, import_node_os9.homedir)(), ".codex", "auth.json");
8727
- 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;
8728
8971
  try {
8729
- return (0, import_node_fs23.statSync)(authPath).size > 2;
8972
+ return (0, import_node_fs24.statSync)(authPath).size > 2;
8730
8973
  } catch {
8731
8974
  return false;
8732
8975
  }
8733
8976
  }
8734
- 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;
8735
8978
  var init_codex = __esm({
8736
8979
  "src/agents/codex.ts"() {
8737
8980
  "use strict";
8738
- import_node_fs23 = require("fs");
8981
+ import_node_fs24 = require("fs");
8739
8982
  import_node_os9 = require("os");
8740
- import_node_path24 = require("path");
8983
+ import_node_path25 = require("path");
8741
8984
  init_run();
8742
8985
  init_app_settings();
8743
8986
  init_global_workspace();
@@ -8762,7 +9005,7 @@ var init_codex = __esm({
8762
9005
  async detect() {
8763
9006
  const codex = resolveAgentExecutable("codex");
8764
9007
  if (codex !== "codex") {
8765
- if (!(0, import_node_fs23.existsSync)(codex)) {
9008
+ if (!(0, import_node_fs24.existsSync)(codex)) {
8766
9009
  return {
8767
9010
  agent: "codex",
8768
9011
  installed: false,
@@ -9249,21 +9492,21 @@ function platformRipgrepPackage() {
9249
9492
  }
9250
9493
  function usableRipgrepPath(candidate) {
9251
9494
  const raw = candidate?.trim();
9252
- if (!raw || !(0, import_node_path25.isAbsolute)(raw)) return null;
9495
+ if (!raw || !(0, import_node_path26.isAbsolute)(raw)) return null;
9253
9496
  const readable = nodeReadableScriptPath(raw);
9254
- if (!(0, import_node_fs24.existsSync)(readable) || isAsarPath(readable)) return null;
9497
+ if (!(0, import_node_fs25.existsSync)(readable) || isAsarPath(readable)) return null;
9255
9498
  return readable;
9256
9499
  }
9257
9500
  function walkForBundledRipgrep(startFile) {
9258
9501
  if (!startFile) return null;
9259
9502
  const pkg = platformRipgrepPackage();
9260
9503
  const name = rgBinaryName();
9261
- let dir = (0, import_node_path25.dirname)((0, import_node_path25.resolve)(startFile));
9262
- 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;
9263
9506
  while (dir !== root) {
9264
- 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));
9265
9508
  if (hit) return hit;
9266
- const next = (0, import_node_path25.dirname)(dir);
9509
+ const next = (0, import_node_path26.dirname)(dir);
9267
9510
  if (next === dir) break;
9268
9511
  dir = next;
9269
9512
  }
@@ -9273,7 +9516,7 @@ function requireResolveBundledRipgrep(fromFile) {
9273
9516
  try {
9274
9517
  const req = (0, import_node_module2.createRequire)(fromFile);
9275
9518
  const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
9276
- 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()));
9277
9520
  } catch {
9278
9521
  return null;
9279
9522
  }
@@ -9295,13 +9538,13 @@ function cursorRipgrepEnv(opts) {
9295
9538
  const path = resolveCursorRipgrepPath(opts);
9296
9539
  return path ? { [RIPGREP_ENV]: path } : {};
9297
9540
  }
9298
- 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;
9299
9542
  var init_cursor_ripgrep = __esm({
9300
9543
  "src/agents/cursor-ripgrep.ts"() {
9301
9544
  "use strict";
9302
- import_node_fs24 = require("fs");
9545
+ import_node_fs25 = require("fs");
9303
9546
  import_node_module2 = require("module");
9304
- import_node_path25 = require("path");
9547
+ import_node_path26 = require("path");
9305
9548
  init_node_launch();
9306
9549
  init_packaged_runtime();
9307
9550
  RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
@@ -9347,11 +9590,11 @@ function entryDir() {
9347
9590
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
9348
9591
  if (cjsDir) return cjsDir;
9349
9592
  try {
9350
- 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));
9351
9594
  } catch {
9352
9595
  try {
9353
9596
  const req = (0, import_node_module3.createRequire)(process.cwd() + "/");
9354
- return (0, import_node_path26.dirname)(req.resolve("@sideboard-ai/core"));
9597
+ return (0, import_node_path27.dirname)(req.resolve("@sideboard-ai/core"));
9355
9598
  } catch {
9356
9599
  return process.cwd();
9357
9600
  }
@@ -9362,27 +9605,27 @@ function cursorRunnerPath() {
9362
9605
  if (packaged) return packaged;
9363
9606
  const root = entryDir();
9364
9607
  const candidates = [
9365
- (0, import_node_path26.join)(root, "agents", "cursor-runner.js"),
9366
- (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"),
9367
9610
  // If somehow resolved from package root instead of dist/
9368
- (0, import_node_path26.join)(root, "dist", "agents", "cursor-runner.js"),
9369
- (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"),
9370
9613
  // Source tree (dev): packages/core/src/agents/cursor-runner.ts
9371
- (0, import_node_path26.join)(root, "cursor-runner.ts"),
9372
- (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")
9373
9616
  ];
9374
9617
  for (const candidate of candidates) {
9375
- if ((0, import_node_fs25.existsSync)(candidate)) return candidate;
9618
+ if ((0, import_node_fs26.existsSync)(candidate)) return candidate;
9376
9619
  }
9377
9620
  return candidates[0];
9378
9621
  }
9379
- 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;
9380
9623
  var init_cursor = __esm({
9381
9624
  "src/agents/cursor.ts"() {
9382
9625
  "use strict";
9383
- import_node_fs25 = require("fs");
9626
+ import_node_fs26 = require("fs");
9384
9627
  import_node_module3 = require("module");
9385
- import_node_path26 = require("path");
9628
+ import_node_path27 = require("path");
9386
9629
  import_node_url2 = require("url");
9387
9630
  import_sdk = require("@cursor/sdk");
9388
9631
  init_run();
@@ -9533,7 +9776,7 @@ async function listOpencodeModels() {
9533
9776
  if (opencode === "opencode") {
9534
9777
  const which = await run("which", ["opencode"], { reject: false });
9535
9778
  if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
9536
- } else if (!(0, import_node_fs26.existsSync)(opencode)) {
9779
+ } else if (!(0, import_node_fs27.existsSync)(opencode)) {
9537
9780
  return FALLBACK_OPENCODE_MODELS;
9538
9781
  }
9539
9782
  const listed = await run(opencode, ["models"], { reject: false });
@@ -9563,11 +9806,11 @@ function usageFromOpencode(tokens) {
9563
9806
  cacheWriteTokens: tokens.cache?.write ? Number(tokens.cache.write) : void 0
9564
9807
  };
9565
9808
  }
9566
- 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;
9567
9810
  var init_opencode = __esm({
9568
9811
  "src/agents/opencode.ts"() {
9569
9812
  "use strict";
9570
- import_node_fs26 = require("fs");
9813
+ import_node_fs27 = require("fs");
9571
9814
  init_run();
9572
9815
  init_app_settings();
9573
9816
  init_global_workspace();
@@ -9594,7 +9837,7 @@ var init_opencode = __esm({
9594
9837
  async detect() {
9595
9838
  const opencode = resolveAgentExecutable("opencode");
9596
9839
  if (opencode !== "opencode") {
9597
- if (!(0, import_node_fs26.existsSync)(opencode)) {
9840
+ if (!(0, import_node_fs27.existsSync)(opencode)) {
9598
9841
  return {
9599
9842
  agent: "opencode",
9600
9843
  installed: false,
@@ -11097,7 +11340,7 @@ function forkMessageSlice(from, throughIndex) {
11097
11340
  function buildForkTranscriptAttachment(baseTitle, messages) {
11098
11341
  const title = baseTitle || "Chat";
11099
11342
  return {
11100
- id: (0, import_node_crypto4.randomUUID)(),
11343
+ id: (0, import_node_crypto5.randomUUID)(),
11101
11344
  name: `Transcript of ${title}.md`,
11102
11345
  kind: "transcript",
11103
11346
  content: formatTranscriptMarkdown(title, messages)
@@ -11154,11 +11397,11 @@ function forkChatTab(input) {
11154
11397
  }
11155
11398
  return tab;
11156
11399
  }
11157
- var import_node_crypto4;
11400
+ var import_node_crypto5;
11158
11401
  var init_chat_tabs = __esm({
11159
11402
  "src/threads/chat-tabs.ts"() {
11160
11403
  "use strict";
11161
- import_node_crypto4 = require("crypto");
11404
+ import_node_crypto5 = require("crypto");
11162
11405
  init_context_compact();
11163
11406
  init_teams();
11164
11407
  init_worktree_labels();
@@ -11328,21 +11571,21 @@ function shouldRefreshReviewRequestTemplate(content) {
11328
11571
  return LEGACY_REVIEW_TEMPLATE_MARKERS.every((m) => trimmed.includes(m));
11329
11572
  }
11330
11573
  function readTextIfPresent(abs) {
11331
- if (!(0, import_node_fs27.existsSync)(abs)) return null;
11574
+ if (!(0, import_node_fs28.existsSync)(abs)) return null;
11332
11575
  try {
11333
- const content = (0, import_node_fs27.readFileSync)(abs, "utf8");
11576
+ const content = (0, import_node_fs28.readFileSync)(abs, "utf8");
11334
11577
  return content.trim() ? content : null;
11335
11578
  } catch {
11336
11579
  return null;
11337
11580
  }
11338
11581
  }
11339
11582
  function readLocalGuidelines(worktreePath) {
11340
- const localAbs = (0, import_node_path27.join)(worktreePath, REVIEW_REQUEST_PATH);
11583
+ const localAbs = (0, import_node_path28.join)(worktreePath, REVIEW_REQUEST_PATH);
11341
11584
  const localContent = readTextIfPresent(localAbs);
11342
11585
  if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
11343
11586
  return { path: REVIEW_REQUEST_PATH, content: localContent };
11344
11587
  }
11345
- 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);
11346
11589
  const legacyContent = readTextIfPresent(legacyAbs);
11347
11590
  if (legacyContent && !shouldRefreshReviewRequestTemplate(legacyContent)) {
11348
11591
  return { path: LEGACY_REVIEW_REQUEST_PATH, content: legacyContent };
@@ -11358,20 +11601,20 @@ function skillGuidelines(content, source) {
11358
11601
  };
11359
11602
  }
11360
11603
  function ensureReviewSkillFile(worktreePath) {
11361
- const abs = (0, import_node_path27.join)(worktreePath, REVIEW_SKILL_PATH);
11604
+ const abs = (0, import_node_path28.join)(worktreePath, REVIEW_SKILL_PATH);
11362
11605
  const existing = readTextIfPresent(abs);
11363
11606
  if (existing) {
11364
11607
  return { path: REVIEW_SKILL_PATH, content: existing, wrote: false };
11365
11608
  }
11366
- 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));
11367
11610
  const fromLocal = readLocalGuidelines(worktreePath)?.content ?? null;
11368
11611
  const content = wrapReviewSkillMarkdown(fromRepo ?? fromLocal ?? REVIEW_REQUEST_TEMPLATE);
11369
- (0, import_node_fs27.mkdirSync)((0, import_node_path27.dirname)(abs), { recursive: true });
11370
- (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");
11371
11614
  return { path: REVIEW_SKILL_PATH, content, wrote: true };
11372
11615
  }
11373
11616
  function resolveReviewGuidelines(worktreePath) {
11374
- 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));
11375
11618
  if (skillContent) return skillGuidelines(skillContent, "skill");
11376
11619
  const local = readLocalGuidelines(worktreePath);
11377
11620
  if (local) {
@@ -11389,7 +11632,7 @@ function buildReviewRequestAttachment(content, opts) {
11389
11632
  const path = opts?.path ?? REVIEW_SKILL_PATH;
11390
11633
  const name = opts?.name ?? (path === REVIEW_SKILL_PATH ? REVIEW_SKILL_NAME : path === REPO_REVIEW_PATH ? REPO_REVIEW_NAME : REVIEW_REQUEST_NAME);
11391
11634
  return {
11392
- id: (0, import_node_crypto5.randomUUID)(),
11635
+ id: (0, import_node_crypto6.randomUUID)(),
11393
11636
  name,
11394
11637
  kind: "file",
11395
11638
  path,
@@ -11421,13 +11664,13 @@ async function requestReview(threadRef, send) {
11421
11664
  const started = await send(tab.id, REVIEW_REQUEST_PREFILL);
11422
11665
  return { tab: started, from };
11423
11666
  }
11424
- 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;
11425
11668
  var init_request_review = __esm({
11426
11669
  "src/review/request-review.ts"() {
11427
11670
  "use strict";
11428
- import_node_crypto5 = require("crypto");
11429
- import_node_fs27 = require("fs");
11430
- import_node_path27 = require("path");
11671
+ import_node_crypto6 = require("crypto");
11672
+ import_node_fs28 = require("fs");
11673
+ import_node_path28 = require("path");
11431
11674
  init_global_workspace();
11432
11675
  init_chat_tabs();
11433
11676
  init_thread_store();
@@ -11452,9 +11695,9 @@ function matchSimpleGlob(pattern, name) {
11452
11695
  return new RegExp(`^${escaped}$`).test(name);
11453
11696
  }
11454
11697
  function readWorktreeInclude(repoPath) {
11455
- const path = (0, import_node_path28.join)(repoPath, ".worktreeinclude");
11456
- if (!(0, import_node_fs28.existsSync)(path)) return [];
11457
- 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("#"));
11458
11701
  }
11459
11702
  function resolveFilesToCopy(repoPath) {
11460
11703
  const fromInclude = readWorktreeInclude(repoPath);
@@ -11464,10 +11707,10 @@ function resolveFilesToCopy(repoPath) {
11464
11707
  if (settings?.fileIncludeGlobs?.length) {
11465
11708
  const matched = [];
11466
11709
  try {
11467
- 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 })) {
11468
11711
  if (!entry.isFile()) continue;
11469
11712
  for (const glob of settings.fileIncludeGlobs) {
11470
- 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)) {
11471
11714
  matched.push(entry.name);
11472
11715
  break;
11473
11716
  }
@@ -11479,7 +11722,7 @@ function resolveFilesToCopy(repoPath) {
11479
11722
  }
11480
11723
  const defaults = [];
11481
11724
  try {
11482
- 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 })) {
11483
11726
  if (entry.isFile() && entry.name.startsWith(".env")) {
11484
11727
  defaults.push(entry.name);
11485
11728
  }
@@ -11493,11 +11736,11 @@ function copyConfiguredFiles(repoPath, worktreePath) {
11493
11736
  const patterns = resolveFilesToCopy(repoPath);
11494
11737
  const copied = [];
11495
11738
  for (const rel of patterns) {
11496
- const src = (0, import_node_path28.join)(repoPath, rel);
11497
- if (!(0, import_node_fs28.existsSync)(src)) continue;
11498
- const dest = (0, import_node_path28.join)(worktreePath, rel);
11499
- (0, import_node_fs28.mkdirSync)((0, import_node_path28.dirname)(dest), { recursive: true });
11500
- (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);
11501
11744
  copied.push(rel);
11502
11745
  }
11503
11746
  return copied;
@@ -11532,7 +11775,7 @@ function buildWorkspaceScriptEnv(opts, baseEnv) {
11532
11775
  const env = stripNestedElectronEnv({
11533
11776
  ...baseEnv ?? process.env
11534
11777
  });
11535
- const name = opts.workspaceName ?? (0, import_node_path28.basename)(opts.worktreePath);
11778
+ const name = opts.workspaceName ?? (0, import_node_path29.basename)(opts.worktreePath);
11536
11779
  const ports = opts.ports ?? [];
11537
11780
  const primary = ports[0];
11538
11781
  env.SIDEBOARD_WORKSPACE_NAME = name;
@@ -11793,13 +12036,13 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
11793
12036
  done: handle.done
11794
12037
  };
11795
12038
  }
11796
- 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;
11797
12040
  var init_conductor = __esm({
11798
12041
  "src/hook/conductor.ts"() {
11799
12042
  "use strict";
11800
- import_node_fs28 = require("fs");
12043
+ import_node_fs29 = require("fs");
11801
12044
  import_node_net = require("net");
11802
- import_node_path28 = require("path");
12045
+ import_node_path29 = require("path");
11803
12046
  import_execa4 = require("execa");
11804
12047
  import_node_readline3 = require("readline");
11805
12048
  init_settings();
@@ -11825,9 +12068,9 @@ async function findOrphanWorktrees(repoPaths) {
11825
12068
  repoPaths?.length ? repoPaths : threads.map((t) => t.repoPath).filter(Boolean)
11826
12069
  );
11827
12070
  const homeRoot = sideboardWorkspacesDir();
11828
- if ((0, import_node_fs29.existsSync)(homeRoot)) {
12071
+ if ((0, import_node_fs30.existsSync)(homeRoot)) {
11829
12072
  try {
11830
- 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 })) {
11831
12074
  if (!entry.isDirectory()) continue;
11832
12075
  void entry;
11833
12076
  }
@@ -11837,7 +12080,7 @@ async function findOrphanWorktrees(repoPaths) {
11837
12080
  const orphans = [];
11838
12081
  const seen = /* @__PURE__ */ new Set();
11839
12082
  for (const repoPath of repos) {
11840
- if (!repoPath || !(0, import_node_fs29.existsSync)(repoPath)) continue;
12083
+ if (!repoPath || !(0, import_node_fs30.existsSync)(repoPath)) continue;
11841
12084
  try {
11842
12085
  const wts = await listWorktrees(repoPath);
11843
12086
  for (const wt of wts) {
@@ -11848,7 +12091,7 @@ async function findOrphanWorktrees(repoPaths) {
11848
12091
  seen.add(path);
11849
12092
  let mtimeMs = 0;
11850
12093
  try {
11851
- mtimeMs = (0, import_node_fs29.statSync)(path).mtimeMs;
12094
+ mtimeMs = (0, import_node_fs30.statSync)(path).mtimeMs;
11852
12095
  } catch {
11853
12096
  mtimeMs = 0;
11854
12097
  }
@@ -11858,16 +12101,16 @@ async function findOrphanWorktrees(repoPaths) {
11858
12101
  }
11859
12102
  try {
11860
12103
  const root = worktreesRoot(repoPath);
11861
- if ((0, import_node_fs29.existsSync)(root)) {
11862
- 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 })) {
11863
12106
  if (!entry.isDirectory()) continue;
11864
- const path = (0, import_node_path29.join)(root, entry.name).replace(/\/$/, "");
12107
+ const path = (0, import_node_path30.join)(root, entry.name).replace(/\/$/, "");
11865
12108
  if (known.has(path) || seen.has(path)) continue;
11866
- 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;
11867
12110
  seen.add(path);
11868
12111
  let mtimeMs = 0;
11869
12112
  try {
11870
- mtimeMs = (0, import_node_fs29.statSync)(path).mtimeMs;
12113
+ mtimeMs = (0, import_node_fs30.statSync)(path).mtimeMs;
11871
12114
  } catch {
11872
12115
  mtimeMs = Date.now();
11873
12116
  }
@@ -11919,12 +12162,12 @@ function shouldRunWorktreeCleanup(settings = loadAppSettings()) {
11919
12162
  const elapsed = Date.now() - Date.parse(last);
11920
12163
  return elapsed >= intervalHours * 36e5;
11921
12164
  }
11922
- var import_node_fs29, import_node_path29;
12165
+ var import_node_fs30, import_node_path30;
11923
12166
  var init_orphan_cleanup = __esm({
11924
12167
  "src/git/orphan-cleanup.ts"() {
11925
12168
  "use strict";
11926
- import_node_fs29 = require("fs");
11927
- import_node_path29 = require("path");
12169
+ import_node_fs30 = require("fs");
12170
+ import_node_path30 = require("path");
11928
12171
  init_worktree();
11929
12172
  init_thread_store();
11930
12173
  init_paths();
@@ -12031,38 +12274,38 @@ __export(workspaces_exports, {
12031
12274
  syncWorkspacesFromThreads: () => syncWorkspacesFromThreads
12032
12275
  });
12033
12276
  function workspacesFile() {
12034
- return (0, import_node_path30.join)(appDataDir(), "workspaces.json");
12277
+ return (0, import_node_path31.join)(appDataDir(), "workspaces.json");
12035
12278
  }
12036
12279
  function removedWorkspacesFile() {
12037
- return (0, import_node_path30.join)(appDataDir(), "removed-workspaces.json");
12280
+ return (0, import_node_path31.join)(appDataDir(), "removed-workspaces.json");
12038
12281
  }
12039
12282
  function readAll() {
12040
12283
  const path = workspacesFile();
12041
- if (!(0, import_node_fs30.existsSync)(path)) return [];
12284
+ if (!(0, import_node_fs31.existsSync)(path)) return [];
12042
12285
  try {
12043
- const raw = JSON.parse((0, import_node_fs30.readFileSync)(path, "utf8"));
12286
+ const raw = JSON.parse((0, import_node_fs31.readFileSync)(path, "utf8"));
12044
12287
  return Array.isArray(raw) ? raw : [];
12045
12288
  } catch {
12046
12289
  return [];
12047
12290
  }
12048
12291
  }
12049
12292
  function writeAll(list) {
12050
- (0, import_node_fs30.mkdirSync)(appDataDir(), { recursive: true });
12051
- (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");
12052
12295
  }
12053
12296
  function readRemoved() {
12054
12297
  const path = removedWorkspacesFile();
12055
- if (!(0, import_node_fs30.existsSync)(path)) return /* @__PURE__ */ new Set();
12298
+ if (!(0, import_node_fs31.existsSync)(path)) return /* @__PURE__ */ new Set();
12056
12299
  try {
12057
- const raw = JSON.parse((0, import_node_fs30.readFileSync)(path, "utf8"));
12300
+ const raw = JSON.parse((0, import_node_fs31.readFileSync)(path, "utf8"));
12058
12301
  return new Set(Array.isArray(raw) ? raw.filter((p) => typeof p === "string") : []);
12059
12302
  } catch {
12060
12303
  return /* @__PURE__ */ new Set();
12061
12304
  }
12062
12305
  }
12063
12306
  function writeRemoved(paths) {
12064
- (0, import_node_fs30.mkdirSync)(appDataDir(), { recursive: true });
12065
- (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");
12066
12309
  }
12067
12310
  function rememberRemoved(repoPath) {
12068
12311
  const next = readRemoved();
@@ -12085,7 +12328,7 @@ function listWorkspaces() {
12085
12328
  async function addWorkspace(repoPath) {
12086
12329
  const root = await resolveRepoRoot(repoPath);
12087
12330
  if (!root || root === "/") throw new Error(`Invalid repo path: ${repoPath}`);
12088
- 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}`);
12089
12332
  forgetRemoved(root);
12090
12333
  await ensureGhPreferOrigin(root);
12091
12334
  const current = readAll();
@@ -12093,7 +12336,7 @@ async function addWorkspace(repoPath) {
12093
12336
  if (existing) return existing;
12094
12337
  const next = {
12095
12338
  path: root,
12096
- name: (0, import_node_path30.basename)(root),
12339
+ name: (0, import_node_path31.basename)(root),
12097
12340
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
12098
12341
  };
12099
12342
  writeAll([...current, next]);
@@ -12115,10 +12358,10 @@ function syncWorkspacesFromThreads(repoPaths) {
12115
12358
  if (!path || path === "/" || isGlobalRepoPath(path) || byPath.has(path) || removed.has(path)) {
12116
12359
  continue;
12117
12360
  }
12118
- if (!(0, import_node_fs30.existsSync)(path)) continue;
12361
+ if (!(0, import_node_fs31.existsSync)(path)) continue;
12119
12362
  const ws = {
12120
12363
  path,
12121
- name: (0, import_node_path30.basename)(path),
12364
+ name: (0, import_node_path31.basename)(path),
12122
12365
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
12123
12366
  };
12124
12367
  byPath.set(path, ws);
@@ -12128,12 +12371,12 @@ function syncWorkspacesFromThreads(repoPaths) {
12128
12371
  if (dirty) writeAll(next);
12129
12372
  return next.sort((a, b) => a.name.localeCompare(b.name));
12130
12373
  }
12131
- var import_node_fs30, import_node_path30;
12374
+ var import_node_fs31, import_node_path31;
12132
12375
  var init_workspaces2 = __esm({
12133
12376
  "src/store/workspaces.ts"() {
12134
12377
  "use strict";
12135
- import_node_fs30 = require("fs");
12136
- import_node_path30 = require("path");
12378
+ import_node_fs31 = require("fs");
12379
+ import_node_path31 = require("path");
12137
12380
  init_paths();
12138
12381
  init_global_workspace();
12139
12382
  init_worktree();
@@ -12146,12 +12389,12 @@ async function cloneRepoIntoSideboard(opts) {
12146
12389
  if (!url) throw new Error("Clone URL is required");
12147
12390
  let name = opts.name?.trim();
12148
12391
  if (!name) {
12149
- const leaf = (0, import_node_path31.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
12392
+ const leaf = (0, import_node_path32.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
12150
12393
  name = leaf || "repo";
12151
12394
  }
12152
12395
  name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
12153
- const dest = (0, import_node_path31.join)(sideboardReposDir(), name);
12154
- 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)) {
12155
12398
  const repoPath2 = await resolveRepoRoot(dest);
12156
12399
  const workspace2 = await ensureWorkspace(repoPath2);
12157
12400
  return { repoPath: repoPath2, workspace: workspace2 };
@@ -12166,12 +12409,12 @@ async function cloneRepoIntoSideboard(opts) {
12166
12409
  const workspace = await ensureWorkspace(repoPath);
12167
12410
  return { repoPath, workspace };
12168
12411
  }
12169
- var import_node_fs31, import_node_path31, import_execa6;
12412
+ var import_node_fs32, import_node_path32, import_execa6;
12170
12413
  var init_clone_repo = __esm({
12171
12414
  "src/git/clone-repo.ts"() {
12172
12415
  "use strict";
12173
- import_node_fs31 = require("fs");
12174
- import_node_path31 = require("path");
12416
+ import_node_fs32 = require("fs");
12417
+ import_node_path32 = require("path");
12175
12418
  import_execa6 = require("execa");
12176
12419
  init_paths();
12177
12420
  init_workspaces2();
@@ -12181,11 +12424,11 @@ var init_clone_repo = __esm({
12181
12424
 
12182
12425
  // src/store/desktop-host.ts
12183
12426
  function desktopHostPidPath() {
12184
- return (0, import_node_path32.join)(appDataDir(), "desktop-host.pid");
12427
+ return (0, import_node_path33.join)(appDataDir(), "desktop-host.pid");
12185
12428
  }
12186
12429
  function readDesktopHostPid() {
12187
12430
  try {
12188
- 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);
12189
12432
  if (!Number.isFinite(pid) || pid <= 0) return null;
12190
12433
  return pid;
12191
12434
  } catch {
@@ -12211,16 +12454,63 @@ function thisProcessShouldDrainAgentQueues() {
12211
12454
  if (isThisProcessDesktopHost()) return true;
12212
12455
  return !isDesktopHostAlive();
12213
12456
  }
12214
- var import_node_fs32, import_node_path32;
12457
+ var import_node_fs33, import_node_path33;
12215
12458
  var init_desktop_host = __esm({
12216
12459
  "src/store/desktop-host.ts"() {
12217
12460
  "use strict";
12218
- import_node_fs32 = require("fs");
12219
- import_node_path32 = require("path");
12461
+ import_node_fs33 = require("fs");
12462
+ import_node_path33 = require("path");
12220
12463
  init_paths();
12221
12464
  }
12222
12465
  });
12223
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
+
12224
12514
  // src/detect/detect.ts
12225
12515
  async function requireAgent(agent, opts) {
12226
12516
  ensureAgentPath();
@@ -13166,9 +13456,12 @@ var init_abletime = __esm({
13166
13456
  });
13167
13457
 
13168
13458
  // src/threads/create.ts
13459
+ function persistCreateAttachments(worktreePath, attachments) {
13460
+ return persistPendingFileAttachments(worktreePath, attachments ?? []);
13461
+ }
13169
13462
  async function createThread(input, _onSetupLine) {
13170
13463
  const repoPath = await resolveRepoRoot(input.repoPath);
13171
- if (!(0, import_node_fs33.existsSync)(repoPath)) {
13464
+ if (!(0, import_node_fs34.existsSync)(repoPath)) {
13172
13465
  throw new Error(`Repo not found: ${repoPath}`);
13173
13466
  }
13174
13467
  if (input.reuseExisting !== false) {
@@ -13185,7 +13478,16 @@ async function createThread(input, _onSetupLine) {
13185
13478
  repoPath: canonicalizeRepoPath(t.repoPath)
13186
13479
  }))
13187
13480
  );
13188
- 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
+ }
13189
13491
  }
13190
13492
  const resolved = resolveNewThreadOptions({
13191
13493
  agent: input.agent,
@@ -13233,7 +13535,7 @@ async function createThread(input, _onSetupLine) {
13233
13535
  effort: resolved.effort,
13234
13536
  fast: resolved.fast,
13235
13537
  planMode: Boolean(input.planMode),
13236
- attachments: input.attachments ?? [],
13538
+ attachments: persistCreateAttachments(repoPath, input.attachments),
13237
13539
  sourceIsFork: false,
13238
13540
  parentThreadId: input.parentThreadId ?? null,
13239
13541
  status: "idle",
@@ -13312,7 +13614,7 @@ async function createThread(input, _onSetupLine) {
13312
13614
  effort: resolved.effort,
13313
13615
  fast: resolved.fast,
13314
13616
  planMode: Boolean(input.planMode),
13315
- attachments,
13617
+ attachments: persistCreateAttachments(worktreePath, attachments),
13316
13618
  sourceIsFork,
13317
13619
  parentThreadId: input.parentThreadId ?? null,
13318
13620
  status: "idle",
@@ -13332,16 +13634,17 @@ async function listLinearIssues(agent, repoPath) {
13332
13634
  }
13333
13635
  return adapter.listLinearIssues(repoPath);
13334
13636
  }
13335
- var import_node_fs33;
13637
+ var import_node_fs34;
13336
13638
  var init_create = __esm({
13337
13639
  "src/threads/create.ts"() {
13338
13640
  "use strict";
13339
- import_node_fs33 = require("fs");
13641
+ import_node_fs34 = require("fs");
13340
13642
  init_detect();
13341
13643
  init_worktree();
13342
13644
  init_home_board();
13343
13645
  init_conductor();
13344
13646
  init_app_settings();
13647
+ init_stage_files();
13345
13648
  init_thread_store();
13346
13649
  init_workspaces2();
13347
13650
  }
@@ -13438,20 +13741,20 @@ function writeTurnLive(threadId, progress) {
13438
13741
  const path = threadLivePath(threadId);
13439
13742
  const tmp = `${path}.${process.pid}.tmp`;
13440
13743
  try {
13441
- (0, import_node_fs34.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
13442
- (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);
13443
13746
  } catch {
13444
13747
  try {
13445
- (0, import_node_fs34.unlinkSync)(tmp);
13748
+ (0, import_node_fs35.unlinkSync)(tmp);
13446
13749
  } catch {
13447
13750
  }
13448
13751
  }
13449
13752
  }
13450
13753
  function readTurnLive(threadId) {
13451
13754
  const path = threadLivePath(threadId);
13452
- if (!(0, import_node_fs34.existsSync)(path)) return null;
13755
+ if (!(0, import_node_fs35.existsSync)(path)) return null;
13453
13756
  try {
13454
- const raw = JSON.parse((0, import_node_fs34.readFileSync)(path, "utf8"));
13757
+ const raw = JSON.parse((0, import_node_fs35.readFileSync)(path, "utf8"));
13455
13758
  if (!raw || typeof raw.summary !== "string") return null;
13456
13759
  return raw;
13457
13760
  } catch {
@@ -13463,17 +13766,17 @@ function clearTurnLive(threadId) {
13463
13766
  if (buf?.timer) clearTimeout(buf.timer);
13464
13767
  buffers.delete(threadId);
13465
13768
  const path = threadLivePath(threadId);
13466
- if (!(0, import_node_fs34.existsSync)(path)) return;
13769
+ if (!(0, import_node_fs35.existsSync)(path)) return;
13467
13770
  try {
13468
- (0, import_node_fs34.unlinkSync)(path);
13771
+ (0, import_node_fs35.unlinkSync)(path);
13469
13772
  } catch {
13470
13773
  }
13471
13774
  }
13472
- var import_node_fs34, buffers, FLUSH_MS, MAX_PARTS;
13775
+ var import_node_fs35, buffers, FLUSH_MS, MAX_PARTS;
13473
13776
  var init_turn_live = __esm({
13474
13777
  "src/store/turn-live.ts"() {
13475
13778
  "use strict";
13476
- import_node_fs34 = require("fs");
13779
+ import_node_fs35 = require("fs");
13477
13780
  init_message_parts();
13478
13781
  init_paths();
13479
13782
  buffers = /* @__PURE__ */ new Map();
@@ -13632,7 +13935,7 @@ function buildQuotaHandoffAttachment(from, limitText, fallbackAgent) {
13632
13935
  `- Do not wait on the limited ${from.agent} account; keep going on ${fallbackAgent}.`
13633
13936
  ].join("\n");
13634
13937
  return {
13635
- id: (0, import_node_crypto6.randomUUID)(),
13938
+ id: (0, import_node_crypto7.randomUUID)(),
13636
13939
  name: "Orchestration quota handoff.md",
13637
13940
  kind: "transcript",
13638
13941
  content: body
@@ -13653,11 +13956,11 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText) {
13653
13956
  sourceType: "orchestration"
13654
13957
  });
13655
13958
  }
13656
- var import_node_crypto6, QUOTA_CONTINUE_PROMPT, QUOTA_RESUME_PROMPT;
13959
+ var import_node_crypto7, QUOTA_CONTINUE_PROMPT, QUOTA_RESUME_PROMPT;
13657
13960
  var init_quota_failover = __esm({
13658
13961
  "src/orchestrator/quota-failover.ts"() {
13659
13962
  "use strict";
13660
- import_node_crypto6 = require("crypto");
13963
+ import_node_crypto7 = require("crypto");
13661
13964
  init_session_quota();
13662
13965
  init_app_settings();
13663
13966
  init_global_workspace();
@@ -13674,7 +13977,7 @@ var init_quota_failover = __esm({
13674
13977
  // src/threads/adopt.ts
13675
13978
  function thisModuleFile() {
13676
13979
  const cjsFile = typeof __filename !== "undefined" ? __filename : "";
13677
- 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");
13678
13981
  }
13679
13982
  function openReadonlySqlite(file) {
13680
13983
  const req = (0, import_node_module4.createRequire)(thisModuleFile());
@@ -13692,21 +13995,21 @@ function mapAgentType(raw) {
13692
13995
  return null;
13693
13996
  }
13694
13997
  function resolveConductorCursorAgentId(workspacePath) {
13695
- 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;
13696
13999
  const normalized = workspacePath.replace(/\/$/, "");
13697
14000
  let best = null;
13698
14001
  let hashes;
13699
14002
  try {
13700
- hashes = (0, import_node_fs35.readdirSync)(CURSOR_SDK_STORE);
14003
+ hashes = (0, import_node_fs36.readdirSync)(CURSOR_SDK_STORE);
13701
14004
  } catch {
13702
14005
  return null;
13703
14006
  }
13704
14007
  for (const hash of hashes) {
13705
- const agentsFile = (0, import_node_path33.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
13706
- 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;
13707
14010
  let text5;
13708
14011
  try {
13709
- text5 = (0, import_node_fs35.readFileSync)(agentsFile, "utf8");
14012
+ text5 = (0, import_node_fs36.readFileSync)(agentsFile, "utf8");
13710
14013
  } catch {
13711
14014
  continue;
13712
14015
  }
@@ -13730,7 +14033,7 @@ function resolveConductorCursorAgentId(workspacePath) {
13730
14033
  return best?.agentId ?? null;
13731
14034
  }
13732
14035
  async function adoptThread(input) {
13733
- if (!(0, import_node_fs35.existsSync)(input.worktreePath)) {
14036
+ if (!(0, import_node_fs36.existsSync)(input.worktreePath)) {
13734
14037
  throw new Error(`Worktree not found: ${input.worktreePath}`);
13735
14038
  }
13736
14039
  const repoPath = await resolveRepoRoot(input.worktreePath);
@@ -13754,18 +14057,18 @@ async function adoptThread(input) {
13754
14057
  return thread;
13755
14058
  }
13756
14059
  function listConductorWorkspaces() {
13757
- if (!(0, import_node_fs35.existsSync)(CONDUCTOR_DB)) {
14060
+ if (!(0, import_node_fs36.existsSync)(CONDUCTOR_DB)) {
13758
14061
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
13759
14062
  }
13760
- const tmp = (0, import_node_fs35.mkdtempSync)((0, import_node_path33.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
13761
- 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");
13762
14065
  try {
13763
- (0, import_node_fs35.copyFileSync)(CONDUCTOR_DB, snapshot);
14066
+ (0, import_node_fs36.copyFileSync)(CONDUCTOR_DB, snapshot);
13764
14067
  for (const suffix of ["-wal", "-shm"]) {
13765
14068
  const src = `${CONDUCTOR_DB}${suffix}`;
13766
- if ((0, import_node_fs35.existsSync)(src)) {
14069
+ if ((0, import_node_fs36.existsSync)(src)) {
13767
14070
  try {
13768
- (0, import_node_fs35.copyFileSync)(src, `${snapshot}${suffix}`);
14071
+ (0, import_node_fs36.copyFileSync)(src, `${snapshot}${suffix}`);
13769
14072
  } catch {
13770
14073
  }
13771
14074
  }
@@ -13841,22 +14144,22 @@ function listConductorWorkspaces() {
13841
14144
  db.close();
13842
14145
  }
13843
14146
  } finally {
13844
- (0, import_node_fs35.rmSync)(tmp, { recursive: true, force: true });
14147
+ (0, import_node_fs36.rmSync)(tmp, { recursive: true, force: true });
13845
14148
  }
13846
14149
  }
13847
14150
  function importConductorWorkspace(workspaceId) {
13848
- if (!(0, import_node_fs35.existsSync)(CONDUCTOR_DB)) {
14151
+ if (!(0, import_node_fs36.existsSync)(CONDUCTOR_DB)) {
13849
14152
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
13850
14153
  }
13851
- const tmp = (0, import_node_fs35.mkdtempSync)((0, import_node_path33.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
13852
- 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");
13853
14156
  try {
13854
- (0, import_node_fs35.copyFileSync)(CONDUCTOR_DB, snapshot);
14157
+ (0, import_node_fs36.copyFileSync)(CONDUCTOR_DB, snapshot);
13855
14158
  for (const suffix of ["-wal", "-shm"]) {
13856
14159
  const src = `${CONDUCTOR_DB}${suffix}`;
13857
- if ((0, import_node_fs35.existsSync)(src)) {
14160
+ if ((0, import_node_fs36.existsSync)(src)) {
13858
14161
  try {
13859
- (0, import_node_fs35.copyFileSync)(src, `${snapshot}${suffix}`);
14162
+ (0, import_node_fs36.copyFileSync)(src, `${snapshot}${suffix}`);
13860
14163
  } catch {
13861
14164
  }
13862
14165
  }
@@ -13874,7 +14177,7 @@ function importConductorWorkspace(workspaceId) {
13874
14177
  ).get(workspaceId);
13875
14178
  if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
13876
14179
  const worktreePath = String(row.workspacePath);
13877
- if (!(0, import_node_fs35.existsSync)(worktreePath)) {
14180
+ if (!(0, import_node_fs36.existsSync)(worktreePath)) {
13878
14181
  throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
13879
14182
  }
13880
14183
  let sessionId = null;
@@ -13937,31 +14240,31 @@ function importConductorWorkspace(workspaceId) {
13937
14240
  db.close();
13938
14241
  }
13939
14242
  } finally {
13940
- (0, import_node_fs35.rmSync)(tmp, { recursive: true, force: true });
14243
+ (0, import_node_fs36.rmSync)(tmp, { recursive: true, force: true });
13941
14244
  }
13942
14245
  }
13943
14246
  async function importConductorWorkspaceAsync(workspaceId) {
13944
14247
  return importConductorWorkspace(workspaceId);
13945
14248
  }
13946
- 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;
13947
14250
  var init_adopt = __esm({
13948
14251
  "src/threads/adopt.ts"() {
13949
14252
  "use strict";
13950
14253
  import_node_child_process3 = require("child_process");
13951
- import_node_fs35 = require("fs");
14254
+ import_node_fs36 = require("fs");
13952
14255
  import_node_os10 = require("os");
13953
- import_node_path33 = require("path");
14256
+ import_node_path34 = require("path");
13954
14257
  import_node_module4 = require("module");
13955
14258
  init_worktree();
13956
14259
  init_thread_store();
13957
- CONDUCTOR_APP_SUPPORT = (0, import_node_path33.join)(
14260
+ CONDUCTOR_APP_SUPPORT = (0, import_node_path34.join)(
13958
14261
  process.env.HOME ?? "",
13959
14262
  "Library",
13960
14263
  "Application Support",
13961
14264
  "com.conductor.app"
13962
14265
  );
13963
- CONDUCTOR_DB = (0, import_node_path33.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
13964
- 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");
13965
14268
  }
13966
14269
  });
13967
14270
 
@@ -14028,7 +14331,7 @@ async function openStackLayer(input, _onSetupLine) {
14028
14331
  let createdWorktree = false;
14029
14332
  const trees = await listWorktrees(repoPath);
14030
14333
  const checkedOut = trees.find((w) => w.branch === branchName);
14031
- if (checkedOut?.path && (0, import_node_fs36.existsSync)(checkedOut.path)) {
14334
+ if (checkedOut?.path && (0, import_node_fs37.existsSync)(checkedOut.path)) {
14032
14335
  if (input.reuseExistingWorktree !== false) {
14033
14336
  worktreePath = checkedOut.path;
14034
14337
  } else {
@@ -14170,7 +14473,7 @@ async function initStackFromThread(input, onSetupLine) {
14170
14473
  async function createPrStack(input, onSetupLine) {
14171
14474
  await requireAgent(input.agent);
14172
14475
  const repoPath = await resolveRepoRoot(input.repoPath);
14173
- 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}`);
14174
14477
  if (!input.branches.length) throw new Error("At least one branch name required");
14175
14478
  const status = await detectGhStack(repoPath);
14176
14479
  if (!status.available) throw new Error(status.reason);
@@ -14237,7 +14540,7 @@ async function createPrStack(input, onSetupLine) {
14237
14540
  }
14238
14541
  }
14239
14542
  const claimed = new Set(threads.map((t) => t.worktreePath));
14240
- 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)) {
14241
14544
  try {
14242
14545
  await removeWorktree(repoPath, bootstrap.worktreePath, {
14243
14546
  deleteBranch: bootstrap.branchName
@@ -14247,11 +14550,11 @@ async function createPrStack(input, onSetupLine) {
14247
14550
  }
14248
14551
  return { stack, threads, createdThreadIds };
14249
14552
  }
14250
- var import_node_fs36;
14553
+ var import_node_fs37;
14251
14554
  var init_stack_layers = __esm({
14252
14555
  "src/threads/stack-layers.ts"() {
14253
14556
  "use strict";
14254
- import_node_fs36 = require("fs");
14557
+ import_node_fs37 = require("fs");
14255
14558
  init_detect();
14256
14559
  init_run();
14257
14560
  init_stack();
@@ -14264,7 +14567,7 @@ var init_stack_layers = __esm({
14264
14567
 
14265
14568
  // src/diff/diff.ts
14266
14569
  async function inspectGitWorktree(worktreePath) {
14267
- if (!worktreePath || !(0, import_node_fs37.existsSync)(worktreePath)) return "missing_worktree";
14570
+ if (!worktreePath || !(0, import_node_fs38.existsSync)(worktreePath)) return "missing_worktree";
14268
14571
  const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
14269
14572
  reject: false
14270
14573
  });
@@ -14272,7 +14575,7 @@ async function inspectGitWorktree(worktreePath) {
14272
14575
  return "ok";
14273
14576
  }
14274
14577
  async function initializeGitRepository(worktreePath) {
14275
- if (!worktreePath || !(0, import_node_fs37.existsSync)(worktreePath)) {
14578
+ if (!worktreePath || !(0, import_node_fs38.existsSync)(worktreePath)) {
14276
14579
  throw new Error("Worktree not found");
14277
14580
  }
14278
14581
  const status = await inspectGitWorktree(worktreePath);
@@ -14406,11 +14709,11 @@ new file mode 100644
14406
14709
  };
14407
14710
  }
14408
14711
  async function untrackedPatch(worktreePath, path, maxHunk) {
14409
- const abs = (0, import_node_path34.join)(worktreePath, path);
14712
+ const abs = (0, import_node_path35.join)(worktreePath, path);
14410
14713
  try {
14411
- const st = (0, import_node_fs37.statSync)(abs);
14714
+ const st = (0, import_node_fs38.statSync)(abs);
14412
14715
  if (st.isFile() && st.size > maxHunk) {
14413
- const buf = (0, import_node_fs37.readFileSync)(abs).subarray(0, maxHunk);
14716
+ const buf = (0, import_node_fs38.readFileSync)(abs).subarray(0, maxHunk);
14414
14717
  return syntheticAddPatch(path, buf.toString("utf8"), maxHunk);
14415
14718
  }
14416
14719
  } catch {
@@ -14894,13 +15197,13 @@ async function listWorktreeFiles(worktreePath, opts) {
14894
15197
  function isImageRelativePath(relativePath) {
14895
15198
  const base = relativePath.split("/").pop()?.toLowerCase() || "";
14896
15199
  const ext = base.includes(".") ? base.split(".").pop() || "" : "";
14897
- return IMAGE_EXTENSIONS.has(ext);
15200
+ return IMAGE_EXTENSIONS2.has(ext);
14898
15201
  }
14899
15202
  function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
14900
15203
  assertSafeRelativePath(relativePath);
14901
15204
  const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
14902
- const abs = (0, import_node_path34.join)(worktreePath, relativePath);
14903
- 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);
14904
15207
  if (!st.isFile()) {
14905
15208
  throw new Error(`Not a file: ${relativePath}`);
14906
15209
  }
@@ -14909,7 +15212,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
14909
15212
  `File too large to upload (${st.size} bytes; max ${maxBytes})`
14910
15213
  );
14911
15214
  }
14912
- const buf = (0, import_node_fs37.readFileSync)(abs);
15215
+ const buf = (0, import_node_fs38.readFileSync)(abs);
14913
15216
  return {
14914
15217
  path: relativePath,
14915
15218
  contentBase64: buf.toString("base64"),
@@ -14919,12 +15222,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
14919
15222
  function readWorktreeFile(worktreePath, relativePath, opts) {
14920
15223
  assertSafeRelativePath(relativePath);
14921
15224
  const maxBytes = opts?.maxBytes ?? 2e5;
14922
- const abs = (0, import_node_path34.join)(worktreePath, relativePath);
14923
- 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);
14924
15227
  if (!st.isFile()) {
14925
15228
  throw new Error(`Not a file: ${relativePath}`);
14926
15229
  }
14927
- const buf = (0, import_node_fs37.readFileSync)(abs);
15230
+ const buf = (0, import_node_fs38.readFileSync)(abs);
14928
15231
  if (isImageRelativePath(relativePath)) {
14929
15232
  const maxImageBytes = Math.max(maxBytes, 15e6);
14930
15233
  const truncated2 = buf.length > maxImageBytes;
@@ -14967,9 +15270,9 @@ function assertSafeRelativePath(relativePath) {
14967
15270
  }
14968
15271
  function writeWorktreeFile(worktreePath, relativePath, content) {
14969
15272
  assertSafeRelativePath(relativePath);
14970
- const abs = (0, import_node_path34.join)(worktreePath, relativePath);
14971
- (0, import_node_fs37.mkdirSync)((0, import_node_path34.dirname)(abs), { recursive: true });
14972
- (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");
14973
15276
  return { path: relativePath };
14974
15277
  }
14975
15278
  async function getDiffSummary(worktreePath, repoPath, opts) {
@@ -14986,18 +15289,18 @@ async function getDiffSummary(worktreePath, repoPath, opts) {
14986
15289
  truncated: full.files.length > maxFiles
14987
15290
  };
14988
15291
  }
14989
- 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;
14990
15293
  var init_diff = __esm({
14991
15294
  "src/diff/diff.ts"() {
14992
15295
  "use strict";
14993
- import_node_fs37 = require("fs");
14994
- import_node_path34 = require("path");
15296
+ import_node_fs38 = require("fs");
15297
+ import_node_path35 = require("path");
14995
15298
  init_run();
14996
15299
  init_worktree();
14997
15300
  mergeBaseCache = /* @__PURE__ */ new Map();
14998
15301
  MERGE_BASE_TTL_MS = 45e3;
14999
15302
  SHA_RE = /^[0-9a-f]{7,40}$/i;
15000
- IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
15303
+ IMAGE_EXTENSIONS2 = /* @__PURE__ */ new Set([
15001
15304
  "png",
15002
15305
  "jpg",
15003
15306
  "jpeg",
@@ -15159,7 +15462,7 @@ function parseFrontmatter(content) {
15159
15462
  }
15160
15463
  function readSkill(skillMd, source) {
15161
15464
  try {
15162
- const content = (0, import_node_fs38.readFileSync)(skillMd, "utf8");
15465
+ const content = (0, import_node_fs39.readFileSync)(skillMd, "utf8");
15163
15466
  const { name: fmName, description } = parseFrontmatter(content);
15164
15467
  const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
15165
15468
  const name = fmName || dirName;
@@ -15178,19 +15481,19 @@ function readSkill(skillMd, source) {
15178
15481
  }
15179
15482
  }
15180
15483
  function scanSkillsDir(dir, source, out) {
15181
- if (!(0, import_node_fs38.existsSync)(dir)) return;
15484
+ if (!(0, import_node_fs39.existsSync)(dir)) return;
15182
15485
  let entries;
15183
15486
  try {
15184
- entries = (0, import_node_fs38.readdirSync)(dir);
15487
+ entries = (0, import_node_fs39.readdirSync)(dir);
15185
15488
  } catch {
15186
15489
  return;
15187
15490
  }
15188
15491
  for (const entry of entries) {
15189
15492
  if (entry.startsWith(".")) continue;
15190
- const skillMd = (0, import_node_path35.join)(dir, entry, "SKILL.md");
15191
- 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;
15192
15495
  try {
15193
- if (!(0, import_node_fs38.statSync)(skillMd).isFile()) continue;
15496
+ if (!(0, import_node_fs39.statSync)(skillMd).isFile()) continue;
15194
15497
  } catch {
15195
15498
  continue;
15196
15499
  }
@@ -15199,24 +15502,24 @@ function scanSkillsDir(dir, source, out) {
15199
15502
  }
15200
15503
  }
15201
15504
  function scanClaudePluginSkills(pluginsRoot, out) {
15202
- if (!(0, import_node_fs38.existsSync)(pluginsRoot)) return;
15505
+ if (!(0, import_node_fs39.existsSync)(pluginsRoot)) return;
15203
15506
  const walk = (dir, depth, lookingForSkillsDir) => {
15204
15507
  if (depth > 7) return;
15205
15508
  let entries;
15206
15509
  try {
15207
- entries = (0, import_node_fs38.readdirSync)(dir);
15510
+ entries = (0, import_node_fs39.readdirSync)(dir);
15208
15511
  } catch {
15209
15512
  return;
15210
15513
  }
15211
15514
  if (lookingForSkillsDir && entries.includes("SKILL.md")) {
15212
- 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");
15213
15516
  if (skill) out.push(skill);
15214
15517
  }
15215
15518
  for (const entry of entries) {
15216
15519
  if (entry === "node_modules" || entry === ".git") continue;
15217
- const full = (0, import_node_path35.join)(dir, entry);
15520
+ const full = (0, import_node_path36.join)(dir, entry);
15218
15521
  try {
15219
- if (!(0, import_node_fs38.statSync)(full).isDirectory()) continue;
15522
+ if (!(0, import_node_fs39.statSync)(full).isDirectory()) continue;
15220
15523
  } catch {
15221
15524
  continue;
15222
15525
  }
@@ -15234,17 +15537,17 @@ function discoverSkills(worktreePath) {
15234
15537
  const home = (0, import_node_os11.homedir)();
15235
15538
  const collected = [];
15236
15539
  for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
15237
- scanSkillsDir((0, import_node_path35.join)(worktreePath, rel), "workspace", collected);
15540
+ scanSkillsDir((0, import_node_path36.join)(worktreePath, rel), "workspace", collected);
15238
15541
  }
15239
15542
  for (const abs of [
15240
- (0, import_node_path35.join)(home, ".claude/skills"),
15241
- (0, import_node_path35.join)(home, ".cursor/skills"),
15242
- (0, import_node_path35.join)(home, ".sideboard/skills"),
15243
- (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")
15244
15547
  ]) {
15245
15548
  scanSkillsDir(abs, "user", collected);
15246
15549
  }
15247
- scanClaudePluginSkills((0, import_node_path35.join)(home, ".claude/plugins"), collected);
15550
+ scanClaudePluginSkills((0, import_node_path36.join)(home, ".claude/plugins"), collected);
15248
15551
  const rank = { workspace: 0, user: 1, cli: 2 };
15249
15552
  const byCommand = /* @__PURE__ */ new Map();
15250
15553
  for (const skill of collected) {
@@ -15256,7 +15559,7 @@ function discoverSkills(worktreePath) {
15256
15559
  return [...byCommand.values()].sort((a, b) => a.command.localeCompare(b.command));
15257
15560
  }
15258
15561
  function readSkillBody(skillPath, maxChars = 12e3) {
15259
- const raw = (0, import_node_fs38.readFileSync)(skillPath, "utf8");
15562
+ const raw = (0, import_node_fs39.readFileSync)(skillPath, "utf8");
15260
15563
  if (raw.startsWith("---")) {
15261
15564
  const end = raw.indexOf("\n---", 3);
15262
15565
  if (end >= 0) {
@@ -15270,13 +15573,13 @@ function readSkillBody(skillPath, maxChars = 12e3) {
15270
15573
 
15271
15574
  \u2026(truncated)` : raw;
15272
15575
  }
15273
- var import_node_fs38, import_node_os11, import_node_path35;
15576
+ var import_node_fs39, import_node_os11, import_node_path36;
15274
15577
  var init_discover = __esm({
15275
15578
  "src/skills/discover.ts"() {
15276
15579
  "use strict";
15277
- import_node_fs38 = require("fs");
15580
+ import_node_fs39 = require("fs");
15278
15581
  import_node_os11 = require("os");
15279
- import_node_path35 = require("path");
15582
+ import_node_path36 = require("path");
15280
15583
  }
15281
15584
  });
15282
15585
 
@@ -15365,197 +15668,6 @@ var init_expand = __esm({
15365
15668
  }
15366
15669
  });
15367
15670
 
15368
- // src/composer/stage-files.ts
15369
- function fileExtension(filePath) {
15370
- const base = (0, import_node_path36.basename)(filePath).toLowerCase();
15371
- return base.includes(".") ? base.split(".").pop() || "" : "";
15372
- }
15373
- function isImageFilePath(filePath) {
15374
- return IMAGE_EXTENSIONS2.has(fileExtension(filePath));
15375
- }
15376
- function imageMimeType(filePath) {
15377
- return IMAGE_MIME_BY_EXT[fileExtension(filePath)] || "image/png";
15378
- }
15379
- function ensureAttachmentsDir(worktreePath) {
15380
- const dir = (0, import_node_path36.join)(worktreePath, ATTACHMENTS_DIR);
15381
- (0, import_node_fs39.mkdirSync)(dir, { recursive: true });
15382
- const gi = (0, import_node_path36.join)(dir, ".gitignore");
15383
- if (!(0, import_node_fs39.existsSync)(gi)) {
15384
- (0, import_node_fs39.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
15385
- }
15386
- return dir;
15387
- }
15388
- function uniqueAttachmentName(dir, originalName) {
15389
- const safe = originalName.replace(/[/\\]/g, "_") || "file";
15390
- if (!(0, import_node_fs39.existsSync)((0, import_node_path36.join)(dir, safe))) return safe;
15391
- const ext = (0, import_node_path36.extname)(safe);
15392
- const stem = ext ? safe.slice(0, -ext.length) : safe;
15393
- for (let i = 1; i < 1e4; i++) {
15394
- const candidate = `${stem}-${i}${ext}`;
15395
- if (!(0, import_node_fs39.existsSync)((0, import_node_path36.join)(dir, candidate))) return candidate;
15396
- }
15397
- return `${stem}-${(0, import_node_crypto7.randomUUID)()}${ext}`;
15398
- }
15399
- function previewDataUrlFromBuf(filePath, buf) {
15400
- if (!isImageFilePath(filePath)) return void 0;
15401
- if (buf.length > MAX_PREVIEW_BYTES) return void 0;
15402
- return `data:${imageMimeType(filePath)};base64,${buf.toString("base64")}`;
15403
- }
15404
- function attachmentFromBuffer(name, buf, opts) {
15405
- const previewDataUrl = previewDataUrlFromBuf(name, buf);
15406
- if (isImageFilePath(name)) {
15407
- const pathHint = opts.path ? `\`${opts.path}\`` : opts.sourceLabel || name;
15408
- return {
15409
- id: (0, import_node_crypto7.randomUUID)(),
15410
- name,
15411
- kind: "file",
15412
- path: opts.path,
15413
- previewDataUrl,
15414
- content: [
15415
- `Image attached: ${pathHint}`,
15416
- 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."
15417
- ].join("\n")
15418
- };
15419
- }
15420
- if (buf.length > MAX_INLINE_BYTES) {
15421
- return {
15422
- id: (0, import_node_crypto7.randomUUID)(),
15423
- name,
15424
- kind: "file",
15425
- path: opts.path,
15426
- 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)`
15427
- };
15428
- }
15429
- if (buf.includes(0)) {
15430
- return {
15431
- id: (0, import_node_crypto7.randomUUID)(),
15432
- name,
15433
- kind: "file",
15434
- path: opts.path,
15435
- content: opts.path ? `(binary file at \`${opts.path}\` \u2014 use tools to inspect)` : `(binary file attached by path only: ${opts.sourceLabel || name})`
15436
- };
15437
- }
15438
- return {
15439
- id: (0, import_node_crypto7.randomUUID)(),
15440
- name,
15441
- kind: "file",
15442
- path: opts.path,
15443
- content: buf.toString("utf8")
15444
- };
15445
- }
15446
- function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
15447
- if (absolutePaths.length === 0) return [];
15448
- const dir = ensureAttachmentsDir(worktreePath);
15449
- const out = [];
15450
- for (const abs of absolutePaths) {
15451
- const originalName = (0, import_node_path36.basename)(abs);
15452
- try {
15453
- const st = (0, import_node_fs39.statSync)(abs);
15454
- if (!st.isFile()) continue;
15455
- const name = uniqueAttachmentName(dir, originalName);
15456
- const destAbs = (0, import_node_path36.join)(dir, name);
15457
- (0, import_node_fs39.copyFileSync)(abs, destAbs);
15458
- const rel = `${ATTACHMENTS_DIR}/${name}`;
15459
- const buf = (0, import_node_fs39.readFileSync)(destAbs);
15460
- out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
15461
- } catch (err) {
15462
- out.push({
15463
- id: (0, import_node_crypto7.randomUUID)(),
15464
- name: originalName,
15465
- kind: "file",
15466
- content: `(could not attach ${abs}: ${err instanceof Error ? err.message : String(err)})`
15467
- });
15468
- }
15469
- }
15470
- return out;
15471
- }
15472
- function stageBuffersAsAttachments(worktreePath, buffers2) {
15473
- if (buffers2.length === 0) return [];
15474
- const dir = ensureAttachmentsDir(worktreePath);
15475
- const out = [];
15476
- for (const item of buffers2) {
15477
- const originalName = (item.name || "file").replace(/[/\\]/g, "_") || "file";
15478
- try {
15479
- const buf = Buffer.from(item.dataBase64, "base64");
15480
- const name = uniqueAttachmentName(dir, originalName);
15481
- const destAbs = (0, import_node_path36.join)(dir, name);
15482
- (0, import_node_fs39.writeFileSync)(destAbs, buf);
15483
- const rel = `${ATTACHMENTS_DIR}/${name}`;
15484
- out.push(attachmentFromBuffer(name, buf, { path: rel }));
15485
- } catch (err) {
15486
- out.push({
15487
- id: (0, import_node_crypto7.randomUUID)(),
15488
- name: originalName,
15489
- kind: "file",
15490
- content: `(could not attach ${originalName}: ${err instanceof Error ? err.message : String(err)})`
15491
- });
15492
- }
15493
- }
15494
- return out;
15495
- }
15496
- function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
15497
- const out = [];
15498
- for (const rel of relativePaths) {
15499
- if (!rel || rel.includes("..") || rel.startsWith("/")) {
15500
- out.push({
15501
- id: (0, import_node_crypto7.randomUUID)(),
15502
- name: (0, import_node_path36.basename)(rel) || "file",
15503
- kind: "file",
15504
- content: `(invalid path: ${rel})`
15505
- });
15506
- continue;
15507
- }
15508
- const name = (0, import_node_path36.basename)(rel);
15509
- try {
15510
- const abs = (0, import_node_path36.join)(worktreePath, rel);
15511
- const st = (0, import_node_fs39.statSync)(abs);
15512
- if (!st.isFile()) continue;
15513
- const buf = (0, import_node_fs39.readFileSync)(abs);
15514
- out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
15515
- } catch (err) {
15516
- out.push({
15517
- id: (0, import_node_crypto7.randomUUID)(),
15518
- name,
15519
- kind: "file",
15520
- content: `(could not read ${rel}: ${err instanceof Error ? err.message : String(err)})`
15521
- });
15522
- }
15523
- }
15524
- return out;
15525
- }
15526
- var import_node_fs39, import_node_path36, import_node_crypto7, IMAGE_EXTENSIONS2, IMAGE_MIME_BY_EXT, MAX_INLINE_BYTES, MAX_PREVIEW_BYTES;
15527
- var init_stage_files = __esm({
15528
- "src/composer/stage-files.ts"() {
15529
- "use strict";
15530
- import_node_fs39 = require("fs");
15531
- import_node_path36 = require("path");
15532
- import_node_crypto7 = require("crypto");
15533
- init_workspace_scratch();
15534
- IMAGE_EXTENSIONS2 = /* @__PURE__ */ new Set([
15535
- "png",
15536
- "jpg",
15537
- "jpeg",
15538
- "gif",
15539
- "webp",
15540
- "svg",
15541
- "bmp",
15542
- "ico"
15543
- ]);
15544
- IMAGE_MIME_BY_EXT = {
15545
- png: "image/png",
15546
- jpg: "image/jpeg",
15547
- jpeg: "image/jpeg",
15548
- gif: "image/gif",
15549
- webp: "image/webp",
15550
- svg: "image/svg+xml",
15551
- bmp: "image/bmp",
15552
- ico: "image/x-icon"
15553
- };
15554
- MAX_INLINE_BYTES = 4e5;
15555
- MAX_PREVIEW_BYTES = 5e6;
15556
- }
15557
- });
15558
-
15559
15671
  // src/agents/instructions.ts
15560
15672
  function normPath3(p) {
15561
15673
  return p.replace(/\/+$/, "");
@@ -16625,6 +16737,7 @@ var init_orchestrator = __esm({
16625
16737
  init_usage();
16626
16738
  init_thread_store();
16627
16739
  init_desktop_host();
16740
+ init_child_halt();
16628
16741
  init_create();
16629
16742
  init_cowboy();
16630
16743
  init_orchestrator_capable();
@@ -16772,6 +16885,9 @@ var init_orchestrator = __esm({
16772
16885
  * MCP-created review threads don't stay `queued` after the MCP child exits.
16773
16886
  */
16774
16887
  adoptPersistedQueues() {
16888
+ if (thisProcessShouldDrainAgentQueues()) {
16889
+ this.healStaleRunningTurns();
16890
+ }
16775
16891
  for (const thread of listThreads()) {
16776
16892
  if (thread.status === "stopped" || thread.status === "archived") continue;
16777
16893
  const pid = thread.agentPid;
@@ -16792,6 +16908,32 @@ var init_orchestrator = __esm({
16792
16908
  }
16793
16909
  }
16794
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
+ }
16795
16937
  clearQuotaResumeTimer(threadId) {
16796
16938
  const timer = this.quotaResumeTimers.get(threadId);
16797
16939
  if (timer) clearTimeout(timer);
@@ -17509,6 +17651,12 @@ var init_orchestrator = __esm({
17509
17651
  assistantText: chatText,
17510
17652
  partsCount: parts.length
17511
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
+ }
17512
17660
  }
17513
17661
  }
17514
17662
  } catch (err) {
@@ -17533,6 +17681,12 @@ var init_orchestrator = __esm({
17533
17681
  assistantText: "",
17534
17682
  partsCount: 0
17535
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
+ }
17536
17690
  }
17537
17691
  } finally {
17538
17692
  this.startingTurns.delete(threadId);
@@ -17588,6 +17742,9 @@ var init_orchestrator = __esm({
17588
17742
  const stopped = writeLiveStatus(thread.id, "stopped") ?? readThread(thread.id) ?? thread;
17589
17743
  if (stopped.status === "stopped") {
17590
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
+ }
17591
17748
  }
17592
17749
  return stopped;
17593
17750
  }
@@ -17832,21 +17989,25 @@ var init_orchestrator = __esm({
17832
17989
  fn();
17833
17990
  };
17834
17991
  const off = this.on((event) => {
17835
- 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") {
17836
17994
  const latest = readThread(thread.id);
17837
17995
  if (!latest) {
17838
17996
  finish(() => reject(new Error(`Thread not found: ${thread.id}`)));
17839
17997
  return;
17840
17998
  }
17841
17999
  finish(() => resolve(latest));
18000
+ return;
17842
18001
  }
17843
- if (event.type === "error" && event.threadId === thread.id) {
18002
+ if (event.type === "status_changed") {
17844
18003
  const latest = readThread(thread.id);
17845
18004
  if (!latest) {
17846
18005
  finish(() => reject(new Error(`Thread not found: ${thread.id}`)));
17847
18006
  return;
17848
18007
  }
17849
- finish(() => resolve(latest));
18008
+ if (!["running", "queued"].includes(latest.status)) {
18009
+ finish(() => resolve(latest));
18010
+ }
17850
18011
  }
17851
18012
  });
17852
18013
  timer = setInterval(() => {
@@ -17881,7 +18042,7 @@ var init_orchestrator = __esm({
17881
18042
  const thread = this.requireThread(threadRef);
17882
18043
  const lastAgent = [...thread.messages].reverse().find((m) => m.role === "agent");
17883
18044
  const lastError = thread.lastError ?? null;
17884
- 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 ?? "" : "");
17885
18046
  const stillRunning = thread.status === "running" || thread.status === "queued";
17886
18047
  const live = stillRunning ? readTurnLive(thread.id) : null;
17887
18048
  const queuedHint = thread.status === "queued" && !live?.summary ? "Queued \u2014 waiting for a concurrency slot" : null;
@@ -19079,6 +19240,15 @@ var MCP_WAIT_QUEUED_HINT = "Child is queued waiting for a concurrency slot \u201
19079
19240
  function mcpWaitStillRunningHint(status) {
19080
19241
  return status === "queued" ? MCP_WAIT_QUEUED_HINT : MCP_WAIT_STILL_RUNNING_HINT;
19081
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
+ }
19082
19252
 
19083
19253
  // src/mcp/server.ts
19084
19254
  init_turn_live();
@@ -20795,7 +20965,7 @@ async function startMcpServer() {
20795
20965
  );
20796
20966
  server.tool(
20797
20967
  "wait_for_turn",
20798
- "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).",
20799
20969
  {
20800
20970
  ref: import_zod5.z.string(),
20801
20971
  timeoutMs: import_zod5.z.number().optional()
@@ -20817,7 +20987,8 @@ async function startMcpServer() {
20817
20987
  stillRunning: result.stillRunning,
20818
20988
  progress: result.progress,
20819
20989
  lastActivityAt: result.lastActivityAt,
20820
- 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))
20821
20992
  })
20822
20993
  }
20823
20994
  ]
@@ -20836,7 +21007,8 @@ async function startMcpServer() {
20836
21007
  type: "text",
20837
21008
  text: JSON.stringify({
20838
21009
  ...result,
20839
- 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))
20840
21012
  })
20841
21013
  }
20842
21014
  ]
@@ -20860,7 +21032,7 @@ async function startMcpServer() {
20860
21032
  }
20861
21033
  const clearQueue = force !== false;
20862
21034
  const hadQueued = t.queue.length > 0;
20863
- const stopped = orch.stop(ref, { clearQueue });
21035
+ const stopped = orch.stop(ref, { clearQueue, notifyParent: false });
20864
21036
  return {
20865
21037
  content: [
20866
21038
  {