agent-workbench 0.5.0 → 0.5.1

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.
package/dist/server.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // packages/server/src/index.ts
4
4
  import { existsSync as existsSync4 } from "node:fs";
5
5
  import { createServer } from "node:http";
6
- import path49 from "node:path";
6
+ import path51 from "node:path";
7
7
  import { fileURLToPath as fileURLToPath2 } from "node:url";
8
8
  import express from "express";
9
9
 
@@ -153,7 +153,8 @@ function parseSessionSummary(value) {
153
153
  var CONVERSATION_ROLES = ["user", "assistant"];
154
154
  var CONVERSATION_IMAGE_SOURCES = [
155
155
  "content",
156
- "attachment"
156
+ "attachment",
157
+ "pasted"
157
158
  ];
158
159
  var CONVERSATION_NOTICES = [
159
160
  "compacted",
@@ -277,7 +278,7 @@ function parseConversationPart(value) {
277
278
  const index = asFiniteNumber(record["index"]);
278
279
  const mediaType = asString(record["mediaType"]);
279
280
  if (index === null || mediaType === null) return null;
280
- const source = record["source"] === "attachment" ? "attachment" : "content";
281
+ const source = asLiteral(record["source"], CONVERSATION_IMAGE_SOURCES) ?? "content";
281
282
  return { kind: "image", index, mediaType, source };
282
283
  }
283
284
  case "notice": {
@@ -4219,7 +4220,7 @@ function createAntigravityAdapter(options = {}) {
4219
4220
 
4220
4221
  // packages/server/src/agents/claude-code/index.ts
4221
4222
  import { homedir as homedir5 } from "node:os";
4222
- import path19 from "node:path";
4223
+ import path21 from "node:path";
4223
4224
 
4224
4225
  // packages/server/src/agents/claude-code/agent-defaults.ts
4225
4226
  import { readFile as readFile6 } from "node:fs/promises";
@@ -4555,8 +4556,8 @@ function claudeCodeEnvironment(base) {
4555
4556
  }
4556
4557
 
4557
4558
  // packages/server/src/agents/claude-code/history.ts
4558
- import { readdir as readdir7, stat as stat11 } from "node:fs/promises";
4559
- import path18 from "node:path";
4559
+ import { readdir as readdir7, stat as stat12 } from "node:fs/promises";
4560
+ import path20 from "node:path";
4560
4561
 
4561
4562
  // packages/server/src/agents/claude-code/plans-store.ts
4562
4563
  import { readFile as readFile8, stat as stat9 } from "node:fs/promises";
@@ -4730,10 +4731,30 @@ async function readPlan(target, ref) {
4730
4731
  }
4731
4732
 
4732
4733
  // packages/server/src/agents/claude-code/session-follower.ts
4733
- import path17 from "node:path";
4734
+ import path19 from "node:path";
4734
4735
 
4735
4736
  // packages/server/src/agents/claude-code/jsonl-events.ts
4737
+ import path17 from "node:path";
4738
+
4739
+ // packages/server/src/paste-paths.ts
4740
+ import { tmpdir as tmpdir3 } from "node:os";
4736
4741
  import path16 from "node:path";
4742
+ function pasteRoot() {
4743
+ return path16.join(tmpdir3(), "agent-workbench", "pasted");
4744
+ }
4745
+ var PASTED_IMAGE = /(?:^|[\\/])agent-workbench[\\/]pasted[\\/][A-Za-z0-9_-]+[\\/]pegada-\d+-[0-9a-f]{8}\.(png|jpg|gif|webp)$/i;
4746
+ var MEDIA_TYPES = {
4747
+ png: "image/png",
4748
+ jpg: "image/jpeg",
4749
+ gif: "image/gif",
4750
+ webp: "image/webp"
4751
+ };
4752
+ function pastedImageMediaType(filePath) {
4753
+ const extension = PASTED_IMAGE.exec(filePath)?.[1];
4754
+ return extension === void 0 ? null : MEDIA_TYPES[extension.toLowerCase()] ?? null;
4755
+ }
4756
+
4757
+ // packages/server/src/agents/claude-code/jsonl-events.ts
4737
4758
  var HARNESS_TAGS = [
4738
4759
  "system-reminder",
4739
4760
  "task-notification",
@@ -4916,9 +4937,18 @@ function toQueuedUserEvent(record, lineNumber, limits) {
4916
4937
  if (!isHumanOrigin(attachmentRecord["origin"])) return null;
4917
4938
  const prompt = attachmentRecord["prompt"];
4918
4939
  if (typeof prompt !== "string") return null;
4919
- const cleaned = cleanUserText(prompt);
4920
- if (cleaned.length === 0) return null;
4921
- const { text, truncated } = cut(cleaned, limits.textMaxChars);
4940
+ const { text: cleaned, images } = takePastedImages(cleanUserText(prompt));
4941
+ const parts = images.map((image, index) => ({
4942
+ kind: "image",
4943
+ index,
4944
+ mediaType: image.mediaType,
4945
+ source: "pasted"
4946
+ }));
4947
+ if (cleaned.length > 0) {
4948
+ const { text, truncated } = cut(cleaned, limits.textMaxChars);
4949
+ parts.push({ kind: "text", text, truncated });
4950
+ }
4951
+ if (parts.length === 0) return null;
4922
4952
  const uuid = record["uuid"];
4923
4953
  return {
4924
4954
  eventId: typeof uuid === "string" && uuid.length > 0 ? uuid : `line-${lineNumber}`,
@@ -4926,7 +4956,7 @@ function toQueuedUserEvent(record, lineNumber, limits) {
4926
4956
  // El `timestamp` de la linea es el de cuando se escribio, no el de cuando
4927
4957
  // se absorbio. Es el que corresponde: es cuando el usuario lo mando.
4928
4958
  at: readTimestamp(record["timestamp"] ?? attachmentRecord["timestamp"]),
4929
- parts: [{ kind: "text", text, truncated }],
4959
+ parts,
4930
4960
  model: null,
4931
4961
  usage: null,
4932
4962
  effort: null,
@@ -4992,6 +5022,30 @@ function stripFileReference(text, filename) {
4992
5022
  }
4993
5023
  return text;
4994
5024
  }
5025
+ function sameFilePath(a, b) {
5026
+ return normalizePath(a) === normalizePath(b);
5027
+ }
5028
+ function takePastedImages(text) {
5029
+ const images = [];
5030
+ const tokens = /(^|\s)@(?:"([^"]*)"|(\S+))/g;
5031
+ let match = tokens.exec(text);
5032
+ while (match !== null) {
5033
+ const raw = match[2] ?? match[3] ?? "";
5034
+ const mediaType = pastedImageMediaType(raw);
5035
+ if (mediaType !== null) images.push({ path: raw, mediaType });
5036
+ match = tokens.exec(text);
5037
+ }
5038
+ let rest = text;
5039
+ for (const image of images) rest = stripFileReference(rest, image.path);
5040
+ return { text: rest, images };
5041
+ }
5042
+ function queuedPastedImages(record) {
5043
+ const attachment = recordOf(record["attachment"]);
5044
+ if (attachment === null || attachment["type"] !== "queued_command") return [];
5045
+ const prompt = attachment["prompt"];
5046
+ if (typeof prompt !== "string") return [];
5047
+ return takePastedImages(cleanUserText(prompt)).images.map((image) => image.path);
5048
+ }
4995
5049
  function toConversationEvent(record, lineNumber, limits = TRANSPORT_LIMITS) {
4996
5050
  const type = record["type"];
4997
5051
  if (record["isMeta"] === true) return null;
@@ -5069,7 +5123,7 @@ function documentRefOf(value, target) {
5069
5123
  if (!value.toLowerCase().endsWith(".md")) return null;
5070
5124
  if (value.includes("\0")) return null;
5071
5125
  if (target.cwd.length === 0) return null;
5072
- const absolute = path16.isAbsolute(value) ? value : path16.resolve(target.cwd, value);
5126
+ const absolute = path17.isAbsolute(value) ? value : path17.resolve(target.cwd, value);
5073
5127
  if (target.sessionId.length > 0) {
5074
5128
  const inScratch = relativeInside(scratchRoot(target.cwd, target.sessionId), absolute);
5075
5129
  if (inScratch !== null) return `tmp:${inScratch}`;
@@ -5078,15 +5132,15 @@ function documentRefOf(value, target) {
5078
5132
  return inProject === null ? null : `proj:${inProject}`;
5079
5133
  }
5080
5134
  function relativeInside(root, absolute) {
5081
- const relative = path16.relative(root, absolute);
5135
+ const relative = path17.relative(root, absolute);
5082
5136
  if (relative.length === 0) return null;
5083
- if (relative.startsWith("..") || path16.isAbsolute(relative)) {
5137
+ if (relative.startsWith("..") || path17.isAbsolute(relative)) {
5084
5138
  if (process.platform !== "win32") return null;
5085
- const lower = path16.relative(root.toLowerCase(), absolute.toLowerCase());
5086
- if (lower.length === 0 || lower.startsWith("..") || path16.isAbsolute(lower)) return null;
5087
- return lower.split(path16.sep).join("/");
5139
+ const lower = path17.relative(root.toLowerCase(), absolute.toLowerCase());
5140
+ if (lower.length === 0 || lower.startsWith("..") || path17.isAbsolute(lower)) return null;
5141
+ return lower.split(path17.sep).join("/");
5088
5142
  }
5089
- return relative.split(path16.sep).join("/");
5143
+ return relative.split(path17.sep).join("/");
5090
5144
  }
5091
5145
  function planFileNameOf(value) {
5092
5146
  if (typeof value !== "string" || value.length === 0) return null;
@@ -5636,13 +5690,50 @@ var ConversationFollower = class {
5636
5690
  };
5637
5691
 
5638
5692
  // packages/server/src/agents/claude-code/conversation-image.ts
5639
- import { open as open5 } from "node:fs/promises";
5693
+ import { open as open5, readFile as readFile9, stat as stat10 } from "node:fs/promises";
5694
+ import path18 from "node:path";
5695
+
5696
+ // packages/server/src/image-signature.ts
5697
+ var FORMATS = [
5698
+ {
5699
+ format: { ext: "png", mediaType: "image/png" },
5700
+ test: (b) => b.length > 8 && b.subarray(0, 8).equals(Buffer.from("89504e470d0a1a0a", "hex"))
5701
+ },
5702
+ {
5703
+ format: { ext: "jpg", mediaType: "image/jpeg" },
5704
+ test: (b) => b.length > 3 && b[0] === 255 && b[1] === 216 && b[2] === 255
5705
+ },
5706
+ {
5707
+ format: { ext: "gif", mediaType: "image/gif" },
5708
+ test: (b) => b.length > 6 && b.subarray(0, 4).toString("ascii") === "GIF8"
5709
+ },
5710
+ {
5711
+ format: { ext: "webp", mediaType: "image/webp" },
5712
+ test: (b) => b.length > 12 && b.subarray(0, 4).toString("ascii") === "RIFF" && b.subarray(8, 12).toString("ascii") === "WEBP"
5713
+ }
5714
+ ];
5715
+ var IMAGE_MEDIA_TYPES = new Set(
5716
+ FORMATS.map((entry) => entry.format.mediaType)
5717
+ );
5718
+ function detectImageFormat(bytes) {
5719
+ return FORMATS.find((entry) => entry.test(bytes))?.format ?? null;
5720
+ }
5721
+
5722
+ // packages/server/src/agents/claude-code/conversation-image.ts
5640
5723
  var CHUNK_SIZE2 = 256 * 1024;
5641
5724
  var NEWLINE2 = 10;
5642
5725
  var MAX_IMAGE_BYTES = MAX_SUBMIT_IMAGE_BYTES;
5643
- async function loadConversationImage(filePath, eventId, index, source = "content") {
5726
+ async function loadConversationImage(filePath, eventId, index, source = "content", pastedDir = pasteRoot()) {
5644
5727
  const handle = await open5(filePath, "r").catch(() => null);
5645
5728
  if (handle === null) return null;
5729
+ try {
5730
+ if (source === "pasted") return await findPastedImage(linesOf(handle), eventId, index, pastedDir);
5731
+ return await findInLines(linesOf(handle), eventId, index, source);
5732
+ } finally {
5733
+ await handle.close();
5734
+ }
5735
+ }
5736
+ async function findInLines(lines, eventId, index, source) {
5646
5737
  let seen = 0;
5647
5738
  const chain = /* @__PURE__ */ new Set([eventId]);
5648
5739
  const consider = (line) => {
@@ -5665,56 +5756,126 @@ async function loadConversationImage(filePath, eventId, index, source = "content
5665
5756
  if (typeof ownId === "string" && ownId.length > 0) chain.add(ownId);
5666
5757
  return seen++ === index ? found : null;
5667
5758
  };
5668
- try {
5669
- const buffer = Buffer.allocUnsafe(CHUNK_SIZE2);
5670
- let pending = Buffer.alloc(0);
5671
- let offset = 0;
5672
- for (; ; ) {
5673
- const { bytesRead } = await handle.read(buffer, 0, CHUNK_SIZE2, offset);
5674
- if (bytesRead === 0) break;
5675
- offset += bytesRead;
5676
- const combined = Buffer.concat([pending, buffer.subarray(0, bytesRead)]);
5677
- let start = 0;
5678
- let newlineIndex = combined.indexOf(NEWLINE2, start);
5679
- while (newlineIndex !== -1) {
5680
- const line = combined.subarray(start, newlineIndex).toString("utf8");
5681
- start = newlineIndex + 1;
5682
- newlineIndex = combined.indexOf(NEWLINE2, start);
5683
- const found = consider(line);
5684
- if (found !== null) return found;
5685
- }
5686
- pending = Buffer.from(combined.subarray(start));
5759
+ for await (const line of lines) {
5760
+ const found = consider(line);
5761
+ if (found !== null) return found;
5762
+ }
5763
+ return null;
5764
+ }
5765
+ async function* linesOf(handle) {
5766
+ const buffer = Buffer.allocUnsafe(CHUNK_SIZE2);
5767
+ let pending = Buffer.alloc(0);
5768
+ let offset = 0;
5769
+ for (; ; ) {
5770
+ const { bytesRead } = await handle.read(buffer, 0, CHUNK_SIZE2, offset);
5771
+ if (bytesRead === 0) break;
5772
+ offset += bytesRead;
5773
+ const combined = Buffer.concat([pending, buffer.subarray(0, bytesRead)]);
5774
+ let start = 0;
5775
+ let newlineIndex = combined.indexOf(NEWLINE2, start);
5776
+ while (newlineIndex !== -1) {
5777
+ yield combined.subarray(start, newlineIndex).toString("utf8");
5778
+ start = newlineIndex + 1;
5779
+ newlineIndex = combined.indexOf(NEWLINE2, start);
5780
+ }
5781
+ pending = Buffer.from(combined.subarray(start));
5782
+ }
5783
+ if (pending.length > 0) yield pending.toString("utf8");
5784
+ }
5785
+ async function findPastedImage(lines, eventId, index, pastedDir) {
5786
+ let target = null;
5787
+ let readId = null;
5788
+ for await (const line of lines) {
5789
+ if (target === null) {
5790
+ if (!line.includes(eventId)) continue;
5791
+ const record = parseJsonlLine(line);
5792
+ if (record === null || record["uuid"] !== eventId) continue;
5793
+ target = queuedPastedImages(record)[index] ?? null;
5794
+ if (target === null) return null;
5795
+ const fromDisk = await readPastedFile(target, pastedDir);
5796
+ if (fromDisk !== null) return fromDisk;
5797
+ continue;
5687
5798
  }
5688
- if (pending.length > 0) return consider(pending.toString("utf8"));
5799
+ if (readId === null) {
5800
+ if (line.includes('"Read"')) readId = readToolUseOf(parseJsonlLine(line), target);
5801
+ continue;
5802
+ }
5803
+ if (!line.includes(readId)) continue;
5804
+ const result = toolResultOf(parseJsonlLine(line), readId);
5805
+ if (result === null) continue;
5806
+ const content = result["content"];
5807
+ const image = Array.isArray(content) ? firstImage(content) : null;
5808
+ if (image !== null) return image;
5809
+ readId = null;
5810
+ }
5811
+ return null;
5812
+ }
5813
+ async function readPastedFile(target, pastedDir) {
5814
+ try {
5815
+ const inside = await resolveInside(pastedDir, path18.relative(pastedDir, target), { mustExist: true });
5816
+ const info = await stat10(inside);
5817
+ if (!info.isFile() || info.size === 0 || info.size > MAX_IMAGE_BYTES) return null;
5818
+ const bytes = await readFile9(inside);
5819
+ const format = detectImageFormat(bytes);
5820
+ return format === null ? null : { mediaType: format.mediaType, data: bytes.toString("base64") };
5821
+ } catch {
5689
5822
  return null;
5690
- } finally {
5691
- await handle.close();
5692
5823
  }
5693
5824
  }
5825
+ function readToolUseOf(record, target) {
5826
+ if (record === null || record["type"] !== "assistant") return null;
5827
+ const content = recordOf(record["message"])?.["content"];
5828
+ if (!Array.isArray(content)) return null;
5829
+ for (const block of content) {
5830
+ const tool = recordOf(block);
5831
+ if (tool === null || tool["type"] !== "tool_use" || tool["name"] !== "Read") continue;
5832
+ const id = tool["id"];
5833
+ const filePath = recordOf(tool["input"])?.["file_path"];
5834
+ if (typeof id === "string" && id.length > 0 && typeof filePath === "string" && sameFilePath(filePath, target)) {
5835
+ return id;
5836
+ }
5837
+ }
5838
+ return null;
5839
+ }
5840
+ function toolResultOf(record, toolUseId) {
5841
+ if (record === null || record["type"] !== "user") return null;
5842
+ const content = recordOf(record["message"])?.["content"];
5843
+ if (!Array.isArray(content)) return null;
5844
+ for (const block of content) {
5845
+ const result = recordOf(block);
5846
+ if (result !== null && result["type"] === "tool_result" && result["tool_use_id"] === toolUseId) return result;
5847
+ }
5848
+ return null;
5849
+ }
5694
5850
  function tooBig(data) {
5695
5851
  return data.length > MAX_IMAGE_BYTES * 1.4;
5696
5852
  }
5697
- function imageFromContent(record, eventId, index) {
5698
- if (record["uuid"] !== eventId) return null;
5699
- const message = record["message"];
5700
- if (typeof message !== "object" || message === null) return null;
5701
- const content = message["content"];
5702
- if (!Array.isArray(content)) return null;
5703
- const block = content[index];
5704
- if (typeof block !== "object" || block === null) return null;
5705
- const blockRecord = block;
5706
- if (blockRecord["type"] !== "image") return null;
5707
- const source = blockRecord["source"];
5708
- if (typeof source !== "object" || source === null) return null;
5709
- const sourceRecord = source;
5710
- const data = sourceRecord["data"];
5711
- const mediaType = sourceRecord["media_type"];
5853
+ function imageFromBlock(value) {
5854
+ const block = recordOf(value);
5855
+ if (block === null || block["type"] !== "image") return null;
5856
+ const source = recordOf(block["source"]);
5857
+ if (source === null) return null;
5858
+ const data = source["data"];
5859
+ const mediaType = source["media_type"];
5712
5860
  if (typeof data !== "string" || data.length === 0 || tooBig(data)) return null;
5713
5861
  return {
5714
5862
  mediaType: typeof mediaType === "string" ? mediaType : "image/png",
5715
5863
  data
5716
5864
  };
5717
5865
  }
5866
+ function firstImage(blocks) {
5867
+ for (const block of blocks) {
5868
+ const image = imageFromBlock(block);
5869
+ if (image !== null) return image;
5870
+ }
5871
+ return null;
5872
+ }
5873
+ function imageFromContent(record, eventId, index) {
5874
+ if (record["uuid"] !== eventId) return null;
5875
+ const content = recordOf(record["message"])?.["content"];
5876
+ if (!Array.isArray(content)) return null;
5877
+ return imageFromBlock(content[index]);
5878
+ }
5718
5879
  function imageFromAttachment(record) {
5719
5880
  if (record["type"] !== "attachment") return null;
5720
5881
  const attachment = record["attachment"];
@@ -5786,7 +5947,7 @@ var ClaudeCodeSessionFollower = class {
5786
5947
  }
5787
5948
  noticeChange(filePath) {
5788
5949
  if (isSameFilePath(this.inner.filePath, filePath, process.platform)) return true;
5789
- if (this.inner.getState() === "waiting" && path17.basename(filePath).toLowerCase() === `${this.sessionId.toLowerCase()}.jsonl`) {
5950
+ if (this.inner.getState() === "waiting" && path19.basename(filePath).toLowerCase() === `${this.sessionId.toLowerCase()}.jsonl`) {
5790
5951
  console.warn(
5791
5952
  `[conversation] session ${this.sessionId.slice(0, 8)} wrote to ${filePath}, not to the computed path; moving there.`
5792
5953
  );
@@ -5833,7 +5994,7 @@ var ClaudeCodeSessionFollower = class {
5833
5994
  };
5834
5995
 
5835
5996
  // packages/server/src/agents/claude-code/session-scan.ts
5836
- import { stat as stat10 } from "node:fs/promises";
5997
+ import { stat as stat11 } from "node:fs/promises";
5837
5998
  var HEAD_MAX_LINES = 40;
5838
5999
  var HEAD_MAX_BYTES = 512 * 1024;
5839
6000
  var TAIL_MAX_BYTES = 64 * 1024;
@@ -5858,7 +6019,7 @@ function isRealUserMessage(record) {
5858
6019
  return true;
5859
6020
  }
5860
6021
  async function scanSessionFile(filePath, sessionId) {
5861
- const info = await stat10(filePath);
6022
+ const info = await stat11(filePath);
5862
6023
  const [headLines, tailLines] = await Promise.all([
5863
6024
  readHeadLines(filePath, { maxLines: HEAD_MAX_LINES, maxBytes: HEAD_MAX_BYTES }),
5864
6025
  readTailLines(filePath, { maxBytes: TAIL_MAX_BYTES })
@@ -5931,7 +6092,7 @@ async function scanSessionFile(filePath, sessionId) {
5931
6092
  var SESSION_EXTENSION = /\.jsonl$/i;
5932
6093
  async function pathExists(candidate) {
5933
6094
  try {
5934
- await stat11(candidate);
6095
+ await stat12(candidate);
5935
6096
  return true;
5936
6097
  } catch {
5937
6098
  return false;
@@ -5940,8 +6101,8 @@ async function pathExists(candidate) {
5940
6101
  function toItem(ref, info) {
5941
6102
  return {
5942
6103
  ref,
5943
- sessionId: path18.basename(ref).replace(SESSION_EXTENSION, ""),
5944
- group: path18.basename(path18.dirname(ref)),
6104
+ sessionId: path20.basename(ref).replace(SESSION_EXTENSION, ""),
6105
+ group: path20.basename(path20.dirname(ref)),
5945
6106
  mtimeMs: info.mtimeMs,
5946
6107
  sizeBytes: info.size
5947
6108
  };
@@ -5971,14 +6132,14 @@ function createClaudeCodeHistory(variants) {
5971
6132
  for (const slug of directories) {
5972
6133
  let files;
5973
6134
  try {
5974
- files = (await readdir7(path18.join(root, slug))).filter((name) => name.endsWith(".jsonl"));
6135
+ files = (await readdir7(path20.join(root, slug))).filter((name) => name.endsWith(".jsonl"));
5975
6136
  } catch {
5976
6137
  continue;
5977
6138
  }
5978
6139
  for (const file of files) {
5979
- const ref = path18.join(root, slug, file);
6140
+ const ref = path20.join(root, slug, file);
5980
6141
  try {
5981
- items.push(toItem(ref, await stat11(ref)));
6142
+ items.push(toItem(ref, await stat12(ref)));
5982
6143
  } catch {
5983
6144
  }
5984
6145
  }
@@ -5986,15 +6147,15 @@ function createClaudeCodeHistory(variants) {
5986
6147
  return items;
5987
6148
  },
5988
6149
  async changedRefs(filePath) {
5989
- const relative = path18.relative(sessionsRoot(), filePath);
5990
- const [slug] = relative.split(path18.sep);
6150
+ const relative = path20.relative(sessionsRoot(), filePath);
6151
+ const [slug] = relative.split(path20.sep);
5991
6152
  if (slug === void 0 || slug.length === 0 || slug.startsWith("..")) return null;
5992
6153
  if (!filePath.endsWith(".jsonl")) return null;
5993
6154
  return [filePath];
5994
6155
  },
5995
6156
  async item(ref) {
5996
6157
  try {
5997
- return toItem(ref, await stat11(ref));
6158
+ return toItem(ref, await stat12(ref));
5998
6159
  } catch {
5999
6160
  return null;
6000
6161
  }
@@ -6181,18 +6342,18 @@ function createClaudeCodeAdapter() {
6181
6342
  status,
6182
6343
  defaults: (cwd) => readAgentDefaults(cwd),
6183
6344
  /** La carpeta de la CLI. No se lista ni se entra: regla 2.1. */
6184
- protectedDirs: () => [path19.join(homedir5(), ".claude")],
6345
+ protectedDirs: () => [path21.join(homedir5(), ".claude")],
6185
6346
  dispose: () => status.dispose()
6186
6347
  };
6187
6348
  }
6188
6349
 
6189
6350
  // packages/server/src/agents/codex/index.ts
6190
6351
  import { homedir as homedir7 } from "node:os";
6191
- import path25 from "node:path";
6352
+ import path27 from "node:path";
6192
6353
 
6193
6354
  // packages/server/src/agents/codex/discovery.ts
6194
- import { stat as stat12 } from "node:fs/promises";
6195
- import path22 from "node:path";
6355
+ import { stat as stat13 } from "node:fs/promises";
6356
+ import path24 from "node:path";
6196
6357
 
6197
6358
  // packages/server/src/debug.ts
6198
6359
  var enabled = process.env["AGENT_WORKBENCH_DEBUG"] === "1";
@@ -6203,11 +6364,11 @@ function debugLog(scope, message) {
6203
6364
 
6204
6365
  // packages/server/src/agents/codex/find-rollout.ts
6205
6366
  import { readdir as readdir8 } from "node:fs/promises";
6206
- import path21 from "node:path";
6367
+ import path23 from "node:path";
6207
6368
 
6208
6369
  // packages/server/src/agents/codex/paths.ts
6209
6370
  import { homedir as homedir6 } from "node:os";
6210
- import path20 from "node:path";
6371
+ import path22 from "node:path";
6211
6372
  var INTERACTIVE_SOURCES = ["cli", "vscode"];
6212
6373
  var LISTED_HISTORY_MODES = ["legacy", "paginated"];
6213
6374
  var ROLLOUT_FILE_PATTERN = /^rollout-(\d{4})-(\d{2})-(\d{2})T(\d{2})-(\d{2})-(\d{2})-([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i;
@@ -6219,13 +6380,13 @@ function isUuid(value) {
6219
6380
  }
6220
6381
  var warnedHomes = /* @__PURE__ */ new Set();
6221
6382
  function isFullyQualified(candidate) {
6222
- if (!path20.isAbsolute(candidate)) return false;
6383
+ if (!path22.isAbsolute(candidate)) return false;
6223
6384
  return process.platform !== "win32" || /^([a-zA-Z]:[\\/]|[\\/]{2})/.test(candidate);
6224
6385
  }
6225
6386
  function codexHome() {
6226
6387
  const configured = process.env["CODEX_HOME"];
6227
6388
  if (configured === void 0 || configured.length === 0) {
6228
- return path20.join(homedir6(), ".codex");
6389
+ return path22.join(homedir6(), ".codex");
6229
6390
  }
6230
6391
  if (isFullyQualified(configured)) return configured;
6231
6392
  if (!warnedHomes.has(configured)) {
@@ -6238,11 +6399,11 @@ function codexHome() {
6238
6399
  }
6239
6400
  function codexSessionsRoot() {
6240
6401
  const home = codexHome();
6241
- return home === null ? null : path20.join(home, "sessions");
6402
+ return home === null ? null : path22.join(home, "sessions");
6242
6403
  }
6243
6404
  function codexArchivedRoot() {
6244
6405
  const home = codexHome();
6245
- return home === null ? null : path20.join(home, "archived_sessions");
6406
+ return home === null ? null : path22.join(home, "archived_sessions");
6246
6407
  }
6247
6408
  function parseRolloutFileName(name) {
6248
6409
  const match = ROLLOUT_FILE_PATTERN.exec(name);
@@ -6269,7 +6430,7 @@ function localDayFolder(root, epochMs) {
6269
6430
  const year = String(date.getFullYear()).padStart(4, "0");
6270
6431
  const month = String(date.getMonth() + 1).padStart(2, "0");
6271
6432
  const day = String(date.getDate()).padStart(2, "0");
6272
- return path20.join(root, year, month, day);
6433
+ return path22.join(root, year, month, day);
6273
6434
  }
6274
6435
  function localDayFolders(root, fromMs, toMs) {
6275
6436
  const folders = [];
@@ -6301,14 +6462,14 @@ async function numberedFolders(folder, pattern) {
6301
6462
  return (await entriesOf(folder)).filter((entry) => entry.isDirectory() && pattern.test(entry.name)).map((entry) => entry.name).sort();
6302
6463
  }
6303
6464
  async function rolloutFilesIn(folder) {
6304
- return (await entriesOf(folder)).filter((entry) => entry.isFile() && parseRolloutFileName(entry.name) !== null).map((entry) => entry.name).sort().map((name) => path21.join(folder, name));
6465
+ return (await entriesOf(folder)).filter((entry) => entry.isFile() && parseRolloutFileName(entry.name) !== null).map((entry) => entry.name).sort().map((name) => path23.join(folder, name));
6305
6466
  }
6306
6467
  async function walkSessionFiles(root, limit = Number.POSITIVE_INFINITY) {
6307
6468
  const files = [];
6308
6469
  for (const year of await numberedFolders(root, YEAR)) {
6309
- for (const month of await numberedFolders(path21.join(root, year), TWO_DIGITS)) {
6310
- for (const day of await numberedFolders(path21.join(root, year, month), TWO_DIGITS)) {
6311
- for (const file of await rolloutFilesIn(path21.join(root, year, month, day))) {
6470
+ for (const month of await numberedFolders(path23.join(root, year), TWO_DIGITS)) {
6471
+ for (const day of await numberedFolders(path23.join(root, year, month), TWO_DIGITS)) {
6472
+ for (const file of await rolloutFilesIn(path23.join(root, year, month, day))) {
6312
6473
  files.push(file);
6313
6474
  if (files.length >= limit) return files;
6314
6475
  }
@@ -6319,7 +6480,7 @@ async function walkSessionFiles(root, limit = Number.POSITIVE_INFINITY) {
6319
6480
  }
6320
6481
  function matching(files, sessionId) {
6321
6482
  for (const file of files) {
6322
- if (parseRolloutFileName(path21.basename(file))?.sessionId === sessionId) return file;
6483
+ if (parseRolloutFileName(path23.basename(file))?.sessionId === sessionId) return file;
6323
6484
  }
6324
6485
  return null;
6325
6486
  }
@@ -6687,7 +6848,7 @@ var CodexSessionDiscovery = class {
6687
6848
  if (this.seen.has(filePath)) continue;
6688
6849
  let info;
6689
6850
  try {
6690
- info = await stat12(filePath);
6851
+ info = await stat13(filePath);
6691
6852
  } catch {
6692
6853
  continue;
6693
6854
  }
@@ -6726,7 +6887,7 @@ var CodexSessionDiscovery = class {
6726
6887
  this.stopTimerIfIdle();
6727
6888
  }
6728
6889
  async readHead(filePath, size) {
6729
- const name = parseRolloutFileName(path22.basename(filePath));
6890
+ const name = parseRolloutFileName(path24.basename(filePath));
6730
6891
  if (name === null) return { kind: "rejected" };
6731
6892
  let lines;
6732
6893
  try {
@@ -6774,8 +6935,8 @@ var CodexSessionDiscovery = class {
6774
6935
  };
6775
6936
 
6776
6937
  // packages/server/src/agents/codex/history.ts
6777
- import { stat as stat13 } from "node:fs/promises";
6778
- import path24 from "node:path";
6938
+ import { stat as stat14 } from "node:fs/promises";
6939
+ import path26 from "node:path";
6779
6940
 
6780
6941
  // packages/server/src/agents/codex/rollout-scan.ts
6781
6942
  var TAIL_MAX_BYTES2 = 256 * 1024;
@@ -6849,7 +7010,7 @@ async function scanRollout(item) {
6849
7010
  }
6850
7011
 
6851
7012
  // packages/server/src/agents/codex/session-follower.ts
6852
- import path23 from "node:path";
7013
+ import path25 from "node:path";
6853
7014
 
6854
7015
  // packages/server/src/agents/codex/rollout-image.ts
6855
7016
  import { createReadStream } from "node:fs";
@@ -7217,7 +7378,7 @@ var CodexSessionFollower = class {
7217
7378
  return own === filePath || normalizeCwdKey(own, process.platform) === normalizeCwdKey(filePath, process.platform);
7218
7379
  }
7219
7380
  if (this.sessionId.length === 0) return false;
7220
- if (parseRolloutFileName(path23.basename(filePath))?.sessionId !== this.sessionId.toLowerCase()) return false;
7381
+ if (parseRolloutFileName(path25.basename(filePath))?.sessionId !== this.sessionId.toLowerCase()) return false;
7221
7382
  this.jsonl.setPath(filePath);
7222
7383
  return true;
7223
7384
  }
@@ -7255,26 +7416,26 @@ var CodexSessionFollower = class {
7255
7416
  // packages/server/src/agents/codex/history.ts
7256
7417
  async function pathExists2(candidate) {
7257
7418
  try {
7258
- await stat13(candidate);
7419
+ await stat14(candidate);
7259
7420
  return true;
7260
7421
  } catch {
7261
7422
  return false;
7262
7423
  }
7263
7424
  }
7264
- var accepts = (filePath) => ROLLOUT_FILE_PATTERN.test(path24.basename(filePath));
7425
+ var accepts = (filePath) => ROLLOUT_FILE_PATTERN.test(path26.basename(filePath));
7265
7426
  var CODEX_FOLLOW_POLL_MS = 1e3;
7266
7427
  function isInside2(root, filePath) {
7267
- const relative = path24.relative(root, filePath);
7268
- return relative.length > 0 && !relative.startsWith("..") && !path24.isAbsolute(relative);
7428
+ const relative = path26.relative(root, filePath);
7429
+ return relative.length > 0 && !relative.startsWith("..") && !path26.isAbsolute(relative);
7269
7430
  }
7270
7431
  function toItem2(ref, info) {
7271
- const name = parseRolloutFileName(path24.basename(ref));
7432
+ const name = parseRolloutFileName(path26.basename(ref));
7272
7433
  if (name === null) return null;
7273
7434
  return { ref, sessionId: name.sessionId, group: name.sessionId, mtimeMs: info.mtimeMs, sizeBytes: info.size };
7274
7435
  }
7275
7436
  async function itemOf(ref) {
7276
7437
  try {
7277
- return toItem2(ref, await stat13(ref));
7438
+ return toItem2(ref, await stat14(ref));
7278
7439
  } catch {
7279
7440
  return null;
7280
7441
  }
@@ -7468,7 +7629,7 @@ function createCodexAdapter() {
7468
7629
  * credenciales de antes de cambiarla.
7469
7630
  */
7470
7631
  protectedDirs: () => {
7471
- const dirs = [path25.join(homedir7(), ".codex")];
7632
+ const dirs = [path27.join(homedir7(), ".codex")];
7472
7633
  const home = codexHome();
7473
7634
  if (home !== null && !dirs.includes(home)) dirs.unshift(home);
7474
7635
  return dirs;
@@ -7661,7 +7822,7 @@ var DbChangeSignal = class {
7661
7822
  };
7662
7823
 
7663
7824
  // packages/server/src/agents/opencode/history.ts
7664
- import { stat as stat14 } from "node:fs/promises";
7825
+ import { stat as stat15 } from "node:fs/promises";
7665
7826
 
7666
7827
  // packages/server/src/agents/opencode/events.ts
7667
7828
  var TOOL_INPUT_PARSE_MAX_CHARS = 16e3;
@@ -8612,7 +8773,7 @@ function createOpenCodeHistory(deps) {
8612
8773
  async rootExists() {
8613
8774
  if (dbFile === null) return false;
8614
8775
  try {
8615
- await stat14(dbFile);
8776
+ await stat15(dbFile);
8616
8777
  return true;
8617
8778
  } catch {
8618
8779
  return false;
@@ -8644,13 +8805,13 @@ function createOpenCodeHistory(deps) {
8644
8805
  var OPENCODE_SESSION_ID_PATTERN = /^ses_[0-9A-Za-z]{20,40}$/;
8645
8806
 
8646
8807
  // packages/server/src/agents/opencode/paths.ts
8647
- import path26 from "node:path";
8808
+ import path28 from "node:path";
8648
8809
  function isFullyQualified2(candidate, platform) {
8649
8810
  if (platform === "win32") return /^([a-zA-Z]:[\\/]|[\\/]{2})/.test(candidate);
8650
- return path26.posix.isAbsolute(candidate);
8811
+ return path28.posix.isAbsolute(candidate);
8651
8812
  }
8652
8813
  function resolveOpenCodePaths(env, home, platform) {
8653
- const flavor = platform === "win32" ? path26.win32 : path26.posix;
8814
+ const flavor = platform === "win32" ? path28.win32 : path28.posix;
8654
8815
  const variable = (name) => {
8655
8816
  const value = env[name];
8656
8817
  return value === void 0 || value.length === 0 ? null : value;
@@ -9098,8 +9259,8 @@ function launchWithServe(deps, input) {
9098
9259
  import { execFile as execFile2, spawn as nodeSpawn } from "node:child_process";
9099
9260
  import { randomBytes } from "node:crypto";
9100
9261
  import { mkdir as mkdir4 } from "node:fs/promises";
9101
- import { tmpdir as tmpdir3 } from "node:os";
9102
- import path27 from "node:path";
9262
+ import { tmpdir as tmpdir4 } from "node:os";
9263
+ import path29 from "node:path";
9103
9264
  var OPENCODE_SERVE_HOST = "127.0.0.1";
9104
9265
  var OPENCODE_SERVE_START_TIMEOUT_MS = 2e4;
9105
9266
  var OPENCODE_SERVE_IDLE_STOP_MS = 3e5;
@@ -9131,7 +9292,7 @@ function parseListeningLine(line) {
9131
9292
  return `http://${OPENCODE_SERVE_HOST}:${found.port}`;
9132
9293
  }
9133
9294
  function defaultServeCwd() {
9134
- return path27.join(tmpdir3(), "agent-workbench", "opencode-serve");
9295
+ return path29.join(tmpdir4(), "agent-workbench", "opencode-serve");
9135
9296
  }
9136
9297
  var ServeStartError = class extends Error {
9137
9298
  };
@@ -10366,7 +10527,7 @@ async function migrateLegacyConfigDir() {
10366
10527
 
10367
10528
  // packages/server/src/conversation-hub.ts
10368
10529
  import { EventEmitter } from "node:events";
10369
- import path28 from "node:path";
10530
+ import path30 from "node:path";
10370
10531
  var INITIAL_EVENT_LIMIT = 300;
10371
10532
  var MAX_PAGE_LIMIT = 500;
10372
10533
  var PENDING_QUESTION_LOOKBACK = 50;
@@ -10427,7 +10588,7 @@ var ConversationHub = class extends EventEmitter {
10427
10588
  await entry.follower.start();
10428
10589
  debugLog(
10429
10590
  "conversation",
10430
- `following ${path28.basename(entry.follower.label)} for ${terminalId.slice(0, 8)}`
10591
+ `following ${path30.basename(entry.follower.label)} for ${terminalId.slice(0, 8)}`
10431
10592
  );
10432
10593
  entry = this.entries.get(terminalId) ?? entry;
10433
10594
  }
@@ -10592,7 +10753,7 @@ var ConversationHub = class extends EventEmitter {
10592
10753
  this.startFollowTicker(terminalId, next);
10593
10754
  debugLog(
10594
10755
  "conversation",
10595
- `${terminalId.slice(0, 8)} changed session: following ${path28.basename(next.follower.label)}`
10756
+ `${terminalId.slice(0, 8)} changed session: following ${path30.basename(next.follower.label)}`
10596
10757
  );
10597
10758
  await next.follower.start();
10598
10759
  next.primed = true;
@@ -10956,18 +11117,18 @@ function openBrowser(url) {
10956
11117
  // packages/server/src/pty-helper.ts
10957
11118
  import { chmodSync, statSync } from "node:fs";
10958
11119
  import { createRequire } from "node:module";
10959
- import path29 from "node:path";
11120
+ import path31 from "node:path";
10960
11121
  function helperCandidates(packageDir, platform, arch) {
10961
11122
  return [
10962
- path29.join(packageDir, "build", "Release", "spawn-helper"),
10963
- path29.join(packageDir, "build", "Debug", "spawn-helper"),
10964
- path29.join(packageDir, "prebuilds", `${platform}-${arch}`, "spawn-helper")
11123
+ path31.join(packageDir, "build", "Release", "spawn-helper"),
11124
+ path31.join(packageDir, "build", "Debug", "spawn-helper"),
11125
+ path31.join(packageDir, "prebuilds", `${platform}-${arch}`, "spawn-helper")
10965
11126
  ];
10966
11127
  }
10967
11128
  function locateNodePty() {
10968
11129
  try {
10969
11130
  const require2 = createRequire(import.meta.url);
10970
- return path29.resolve(path29.dirname(require2.resolve("node-pty")), "..");
11131
+ return path31.resolve(path31.dirname(require2.resolve("node-pty")), "..");
10971
11132
  } catch {
10972
11133
  return null;
10973
11134
  }
@@ -11628,24 +11789,24 @@ var RemoteAccessService = class {
11628
11789
  };
11629
11790
 
11630
11791
  // packages/server/src/remote-devices-store.ts
11631
- import { chmod, mkdir as mkdir6, readFile as readFile9, stat as stat16 } from "node:fs/promises";
11632
- import path31 from "node:path";
11792
+ import { chmod, mkdir as mkdir6, readFile as readFile10, stat as stat17 } from "node:fs/promises";
11793
+ import path33 from "node:path";
11633
11794
 
11634
11795
  // packages/server/src/vault/write.ts
11635
11796
  import { randomBytes as randomBytes2 } from "node:crypto";
11636
- import { mkdir as mkdir5, rename as rename3, rm as rm2, stat as stat15, writeFile as writeFile3 } from "node:fs/promises";
11797
+ import { mkdir as mkdir5, rename as rename3, rm as rm2, stat as stat16, writeFile as writeFile3 } from "node:fs/promises";
11637
11798
 
11638
11799
  // packages/server/src/vault/paths.ts
11639
11800
  import { createHash as createHash2 } from "node:crypto";
11640
- import path30 from "node:path";
11801
+ import path32 from "node:path";
11641
11802
  function defaultVaultDir() {
11642
- return path30.join(appConfigDir(), "vault");
11803
+ return path32.join(appConfigDir(), "vault");
11643
11804
  }
11644
11805
  function vaultMarkerFile(dir) {
11645
- return path30.join(dir, "vault.json");
11806
+ return path32.join(dir, "vault.json");
11646
11807
  }
11647
11808
  function sessionsRoot2(dir) {
11648
- return path30.join(dir, "sessions");
11809
+ return path32.join(dir, "sessions");
11649
11810
  }
11650
11811
  function isSafeSessionId(sessionId) {
11651
11812
  return isVaultSessionId(sessionId);
@@ -11659,41 +11820,41 @@ function assertSessionKey(agent, sessionId) {
11659
11820
  }
11660
11821
  function agentSessionsDir(dir, agent) {
11661
11822
  if (!isSessionAgentId(agent)) throw new Error(`Unknown source for the local copy: ${JSON.stringify(agent)}`);
11662
- return path30.join(sessionsRoot2(dir), agent);
11823
+ return path32.join(sessionsRoot2(dir), agent);
11663
11824
  }
11664
11825
  function sessionFile(dir, agent, sessionId) {
11665
11826
  assertSessionKey(agent, sessionId);
11666
- return path30.join(sessionsRoot2(dir), agent, `${sessionId}.jsonl`);
11827
+ return path32.join(sessionsRoot2(dir), agent, `${sessionId}.jsonl`);
11667
11828
  }
11668
11829
  function assetsDir(dir, agent, sessionId) {
11669
11830
  assertSessionKey(agent, sessionId);
11670
- return path30.join(sessionsRoot2(dir), agent, `${sessionId}.assets`);
11831
+ return path32.join(sessionsRoot2(dir), agent, `${sessionId}.assets`);
11671
11832
  }
11672
11833
  function assetFile(dir, agent, sessionId, asset) {
11673
11834
  if (!VAULT_ASSET_NAME_PATTERN.test(asset)) throw new Error(`Invalid asset name: ${JSON.stringify(asset)}`);
11674
- return path30.join(assetsDir(dir, agent, sessionId), asset);
11835
+ return path32.join(assetsDir(dir, agent, sessionId), asset);
11675
11836
  }
11676
11837
  function projectFolderName(cwd, platform) {
11677
11838
  const hash = createHash2("sha256").update(normalizeCwdKey(cwd, platform)).digest("hex").slice(0, 8);
11678
- const base = (platform === "win32" ? path30.win32 : path30.posix).basename(cwd);
11839
+ const base = (platform === "win32" ? path32.win32 : path32.posix).basename(cwd);
11679
11840
  const name = base.length === 0 ? "proyecto" : sanitizeFileName(base, 60);
11680
11841
  return `${name}-${hash}`;
11681
11842
  }
11682
11843
  function memoryDir(dir, cwd, platform) {
11683
- return path30.join(dir, "memory", projectFolderName(cwd, platform));
11844
+ return path32.join(dir, "memory", projectFolderName(cwd, platform));
11684
11845
  }
11685
11846
  function projectExportDir(dir, cwd, platform) {
11686
- return path30.join(dir, "export", projectFolderName(cwd, platform));
11847
+ return path32.join(dir, "export", projectFolderName(cwd, platform));
11687
11848
  }
11688
11849
  function projectExportDirFor(dir, project, platform) {
11689
11850
  if (project.cwd.length > 0) return projectExportDir(dir, project.cwd, platform);
11690
11851
  const hash = createHash2("sha256").update(project.key).digest("hex").slice(0, 8);
11691
11852
  const name = project.fallbackName.length > 0 ? sanitizeFileName(project.fallbackName, 60) : "proyecto";
11692
- return path30.join(dir, "export", `${name}-${hash}`);
11853
+ return path32.join(dir, "export", `${name}-${hash}`);
11693
11854
  }
11694
11855
  function sessionExportFile(dir, agent, sessionId) {
11695
11856
  assertSessionKey(agent, sessionId);
11696
- return path30.join(dir, "export", "sesiones", `${agent}-${sessionId}.md`);
11857
+ return path32.join(dir, "export", "sesiones", `${agent}-${sessionId}.md`);
11697
11858
  }
11698
11859
  var RESERVED_WINDOWS_NAME = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/i;
11699
11860
  function sanitizeFileName(text, max = 80) {
@@ -11748,7 +11909,7 @@ async function writeFileAtomic(target, data, deps = DEFAULT_WRITE_DEPS) {
11748
11909
  async function ensureVaultMarker(dir, deps = DEFAULT_WRITE_DEPS) {
11749
11910
  const marker = vaultMarkerFile(dir);
11750
11911
  try {
11751
- await stat15(marker);
11912
+ await stat16(marker);
11752
11913
  return;
11753
11914
  } catch {
11754
11915
  }
@@ -11758,7 +11919,7 @@ async function ensureVaultMarker(dir, deps = DEFAULT_WRITE_DEPS) {
11758
11919
  }
11759
11920
  async function assetPresent(file, size) {
11760
11921
  try {
11761
- const info = await stat15(file);
11922
+ const info = await stat16(file);
11762
11923
  return info.isFile() && info.size === size;
11763
11924
  } catch {
11764
11925
  return false;
@@ -11800,7 +11961,7 @@ var RemoteDevicesStore = class {
11800
11961
  async load() {
11801
11962
  let raw;
11802
11963
  try {
11803
- raw = await readFile9(this.filePath, "utf8");
11964
+ raw = await readFile10(this.filePath, "utf8");
11804
11965
  } catch {
11805
11966
  return [];
11806
11967
  }
@@ -11821,7 +11982,7 @@ var RemoteDevicesStore = class {
11821
11982
  save(devices) {
11822
11983
  const text = serializeRemoteDevices(devices);
11823
11984
  const run = async () => {
11824
- await mkdir6(path31.dirname(this.filePath), { recursive: true });
11985
+ await mkdir6(path33.dirname(this.filePath), { recursive: true });
11825
11986
  await writeFileAtomic(this.filePath, text);
11826
11987
  await chmod(this.filePath, 384).catch(() => void 0);
11827
11988
  };
@@ -11840,7 +12001,7 @@ var RemoteDevicesStore = class {
11840
12001
  */
11841
12002
  async stamp() {
11842
12003
  try {
11843
- const info = await stat16(this.filePath);
12004
+ const info = await stat17(this.filePath);
11844
12005
  return `${info.mtimeMs}:${info.size}`;
11845
12006
  } catch {
11846
12007
  return "";
@@ -11954,8 +12115,8 @@ import chokidar from "chokidar";
11954
12115
 
11955
12116
  // packages/server/src/git-repo.ts
11956
12117
  import { execFile as execFile4 } from "node:child_process";
11957
- import { readFile as readFile10 } from "node:fs/promises";
11958
- import path32 from "node:path";
12118
+ import { readFile as readFile11 } from "node:fs/promises";
12119
+ import path34 from "node:path";
11959
12120
  function gitOutputText(output, command) {
11960
12121
  return output.length > 0 ? serverText("raw", { text: output }) : serverText("gitCommandFailed", { command });
11961
12122
  }
@@ -12016,7 +12177,7 @@ async function resolveRepo(cwd) {
12016
12177
  const result = await runGit(cwd, ["rev-parse", "--show-toplevel"]);
12017
12178
  if (result.code === 0) {
12018
12179
  const root = result.stdout.trim();
12019
- if (root.length > 0) return { state: "ready", root: path32.resolve(root), message: null };
12180
+ if (root.length > 0) return { state: "ready", root: path34.resolve(root), message: null };
12020
12181
  }
12021
12182
  const stderr = result.stderr.trim();
12022
12183
  if (/not a git repository|no es un repositorio/i.test(stderr)) {
@@ -12043,7 +12204,7 @@ async function findGitDir(cwd) {
12043
12204
  const result = await runGit(cwd, ["rev-parse", "--absolute-git-dir"]);
12044
12205
  if (result.code !== 0) return null;
12045
12206
  const dir = result.stdout.trim();
12046
- return dir.length > 0 ? path32.resolve(dir) : null;
12207
+ return dir.length > 0 ? path34.resolve(dir) : null;
12047
12208
  }
12048
12209
  function letterToKind(letter) {
12049
12210
  switch (letter) {
@@ -12146,7 +12307,7 @@ function parseWorktrees(raw, currentRoot) {
12146
12307
  worktrees.push({
12147
12308
  path: current.path,
12148
12309
  branch: current.branch,
12149
- isCurrent: path32.resolve(current.path) === path32.resolve(currentRoot)
12310
+ isCurrent: path34.resolve(current.path) === path34.resolve(currentRoot)
12150
12311
  });
12151
12312
  current = null;
12152
12313
  };
@@ -12289,7 +12450,7 @@ function looksBinary(buffer) {
12289
12450
  async function readUntrackedAsDiff(absolutePath, relativePath) {
12290
12451
  let content;
12291
12452
  try {
12292
- content = await readFile10(absolutePath);
12453
+ content = await readFile11(absolutePath);
12293
12454
  } catch {
12294
12455
  return {
12295
12456
  path: relativePath,
@@ -12337,7 +12498,7 @@ async function readUntrackedAsDiff(absolutePath, relativePath) {
12337
12498
  async function readDiff(options) {
12338
12499
  const { repoRoot: repoRoot2, relativePath, staged, untracked } = options;
12339
12500
  if (untracked && !staged) {
12340
- return readUntrackedAsDiff(path32.join(repoRoot2, relativePath), relativePath);
12501
+ return readUntrackedAsDiff(path34.join(repoRoot2, relativePath), relativePath);
12341
12502
  }
12342
12503
  const args = [
12343
12504
  "diff",
@@ -12557,7 +12718,7 @@ var RepoHub = class extends EventEmitter2 {
12557
12718
  // packages/server/src/memory-hub.ts
12558
12719
  import { EventEmitter as EventEmitter3 } from "node:events";
12559
12720
  import { homedir as homedir10 } from "node:os";
12560
- import path34 from "node:path";
12721
+ import path36 from "node:path";
12561
12722
  import chokidar2 from "chokidar";
12562
12723
 
12563
12724
  // packages/server/src/memory-bridge.ts
@@ -12567,14 +12728,14 @@ import {
12567
12728
  mkdir as mkdir7,
12568
12729
  open as open6,
12569
12730
  readdir as readdir9,
12570
- readFile as readFile11,
12731
+ readFile as readFile12,
12571
12732
  realpath as realpath2,
12572
12733
  rename as rename4,
12573
- stat as stat17,
12734
+ stat as stat18,
12574
12735
  unlink as unlink3
12575
12736
  } from "node:fs/promises";
12576
12737
  import { homedir as homedir9 } from "node:os";
12577
- import path33 from "node:path";
12738
+ import path35 from "node:path";
12578
12739
  var MemoryBridgeError = class extends ServerTextError {
12579
12740
  };
12580
12741
  var MAX_LISTED_NOTES = 500;
@@ -12592,9 +12753,9 @@ var GITIGNORE_MEMORY_LINE = `${MEMORY_DIR}/`;
12592
12753
  var BOM2 = Buffer.from([239, 187, 191]);
12593
12754
  async function inspectMemory(cwd, home = homedir9()) {
12594
12755
  await assertMemoryDirInside(cwd);
12595
- const folder = path33.join(cwd, MEMORY_DIR);
12756
+ const folder = path35.join(cwd, MEMORY_DIR);
12596
12757
  const folderExists = await isDirectory2(folder);
12597
- const indexExists = folderExists && await isFile(path33.join(folder, MEMORY_INDEX_FILE));
12758
+ const indexExists = folderExists && await isFile(path35.join(folder, MEMORY_INDEX_FILE));
12598
12759
  const noteNames = folderExists ? await listNoteFiles(folder) : [];
12599
12760
  const notes = await describeNotes(folder, noteNames);
12600
12761
  const files = await Promise.all(
@@ -12626,7 +12787,7 @@ async function installMemory(cwd, options, home = homedir9()) {
12626
12787
  }
12627
12788
  async function importNativeMemory(cwd, home = homedir9()) {
12628
12789
  await assertMemoryDirInside(cwd);
12629
- if (!await isDirectory2(path33.join(cwd, MEMORY_DIR))) {
12790
+ if (!await isDirectory2(path35.join(cwd, MEMORY_DIR))) {
12630
12791
  throw new MemoryBridgeError(serverText("memoryNotInstalled"));
12631
12792
  }
12632
12793
  const plan = new PlanBuilder(cwd);
@@ -12644,9 +12805,9 @@ async function readMemoryNote(cwd, name) {
12644
12805
  }
12645
12806
  const absolute = await resolveInside(cwd, `${MEMORY_DIR}/${name}`);
12646
12807
  try {
12647
- const info = await stat17(absolute);
12808
+ const info = await stat18(absolute);
12648
12809
  if (!info.isFile()) return null;
12649
- const content = await readFile11(absolute);
12810
+ const content = await readFile12(absolute);
12650
12811
  return {
12651
12812
  name,
12652
12813
  text: content.subarray(0, MAX_NOTE_BYTES).toString("utf8"),
@@ -12661,7 +12822,7 @@ function isNoteName(name) {
12661
12822
  if (name.length === 0 || name.length > 255) return false;
12662
12823
  if (name.includes("\0")) return false;
12663
12824
  if (name === "." || name === "..") return false;
12664
- if (path33.basename(name) !== name) return false;
12825
+ if (path35.basename(name) !== name) return false;
12665
12826
  if (/[\\/:*?"<>|\u0000-\u001f]/.test(name)) return false;
12666
12827
  return name.toLowerCase().endsWith(".md");
12667
12828
  }
@@ -12698,7 +12859,7 @@ var PlanBuilder = class {
12698
12859
  /** Nombres de nota que habria en la carpeta, en minusculas. */
12699
12860
  async noteNames() {
12700
12861
  const names = /* @__PURE__ */ new Map();
12701
- for (const name of await listNoteFiles(path33.join(this.cwd, MEMORY_DIR))) {
12862
+ for (const name of await listNoteFiles(path35.join(this.cwd, MEMORY_DIR))) {
12702
12863
  names.set(name.toLowerCase(), name);
12703
12864
  }
12704
12865
  for (const rel of this.files.keys()) {
@@ -12741,7 +12902,7 @@ var PlanBuilder = class {
12741
12902
  continue;
12742
12903
  }
12743
12904
  const target = await realpath2(absolute);
12744
- const info = await stat17(target);
12905
+ const info = await stat18(target);
12745
12906
  if (info.nlink > 1) {
12746
12907
  throw new MemoryBridgeError(serverText("memoryHardLinks", { file: file.rel }));
12747
12908
  }
@@ -12760,7 +12921,7 @@ var PlanBuilder = class {
12760
12921
  );
12761
12922
  if (pending.length === 0) return;
12762
12923
  if (pending.some((file) => file.rel.startsWith(`${MEMORY_DIR}/`))) {
12763
- await mkdir7(path33.join(this.cwd, MEMORY_DIR), { recursive: true });
12924
+ await mkdir7(path35.join(this.cwd, MEMORY_DIR), { recursive: true });
12764
12925
  }
12765
12926
  for (const file of pending) {
12766
12927
  if (file.target === null) throw new Error(`Unvalidated plan: ${file.rel}`);
@@ -12871,7 +13032,7 @@ async function planNativeImport(plan, cwd, home) {
12871
13032
  const local = await plan.noteNames();
12872
13033
  for (const name of await listNoteFiles(folder)) {
12873
13034
  const key = name.toLowerCase();
12874
- const content = await readIfFile(path33.join(folder, name), name);
13035
+ const content = await readIfFile(path35.join(folder, name), name);
12875
13036
  if (content === null) continue;
12876
13037
  const already = chosen.get(key);
12877
13038
  if (already !== void 0) {
@@ -12885,7 +13046,7 @@ async function planNativeImport(plan, cwd, home) {
12885
13046
  if (existing !== null && !existing.equals(content)) skipped.push(name);
12886
13047
  continue;
12887
13048
  }
12888
- plan.put(`${MEMORY_DIR}/${name}`, null, content, "copy", "", path33.join(folder, name));
13049
+ plan.put(`${MEMORY_DIR}/${name}`, null, content, "copy", "", path35.join(folder, name));
12889
13050
  copied.push(name);
12890
13051
  }
12891
13052
  }
@@ -12895,7 +13056,7 @@ async function planNativeImport(plan, cwd, home) {
12895
13056
  const known = new Set(linkTargets(index.toString("utf8")));
12896
13057
  const additions = [];
12897
13058
  for (const folder of folders) {
12898
- const nativeIndex = await readIfFile(path33.join(folder, MEMORY_INDEX_FILE), MEMORY_INDEX_FILE);
13059
+ const nativeIndex = await readIfFile(path35.join(folder, MEMORY_INDEX_FILE), MEMORY_INDEX_FILE);
12899
13060
  if (nativeIndex === null) continue;
12900
13061
  for (const line of nativeIndex.toString("utf8").replace(/^\uFEFF/, "").split(/\r?\n/)) {
12901
13062
  const target = linkTargets(line)[0];
@@ -13120,7 +13281,7 @@ async function describeNotes(folder, names) {
13120
13281
  const stated = [];
13121
13282
  for (const name of names) {
13122
13283
  try {
13123
- const info = await stat17(path33.join(folder, name));
13284
+ const info = await stat18(path35.join(folder, name));
13124
13285
  if (info.isFile()) stated.push({ name, sizeBytes: info.size, modifiedAt: info.mtimeMs });
13125
13286
  } catch {
13126
13287
  }
@@ -13128,7 +13289,7 @@ async function describeNotes(folder, names) {
13128
13289
  stated.sort((a, b) => b.modifiedAt - a.modifiedAt || a.name.localeCompare(b.name));
13129
13290
  const notes = [];
13130
13291
  for (const item of stated.slice(0, MAX_LISTED_NOTES)) {
13131
- const head = await readHead(path33.join(folder, item.name));
13292
+ const head = await readHead(path35.join(folder, item.name));
13132
13293
  notes.push({ ...item, ...describeNoteText(head, item.name) });
13133
13294
  }
13134
13295
  return notes;
@@ -13186,28 +13347,28 @@ async function countNativeMemory(cwd, home, sharedNames) {
13186
13347
  return { available: names.size, pending };
13187
13348
  }
13188
13349
  async function nativeMemoryFolders(cwd, home) {
13189
- const root = path33.join(home, ".claude", "projects");
13350
+ const root = path35.join(home, ".claude", "projects");
13190
13351
  const slug = projectSlugFor(cwd).toLowerCase();
13191
13352
  try {
13192
13353
  const entries = await readdir9(root, { withFileTypes: true });
13193
- return entries.filter((entry) => entry.isDirectory() && entry.name.toLowerCase() === slug).map((entry) => entry.name).sort().map((name) => path33.join(root, name, "memory"));
13354
+ return entries.filter((entry) => entry.isDirectory() && entry.name.toLowerCase() === slug).map((entry) => entry.name).sort().map((name) => path35.join(root, name, "memory"));
13194
13355
  } catch {
13195
13356
  return [];
13196
13357
  }
13197
13358
  }
13198
13359
  function buildGlobalFragments(home) {
13199
13360
  const windows = process.platform === "win32";
13200
- const globalFile = path33.join(home, ...GLOBAL_MEMORY_RELATIVE.split("/"));
13361
+ const globalFile = path35.join(home, ...GLOBAL_MEMORY_RELATIVE.split("/"));
13201
13362
  const hardLink = (link) => windows ? `mklink /H "${link}" "${globalFile}"` : `ln "${globalFile}" "${link}"`;
13202
13363
  const hardLinkNote = windows ? serverText("memoryNoteHardLinkCmd", { path: GLOBAL_MEMORY_RELATIVE }) : serverText("memoryNoteHardLink", { path: GLOBAL_MEMORY_RELATIVE });
13203
- const codexTarget = path33.join(home, ".codex", "AGENTS.md");
13204
- const geminiTarget = path33.join(home, ".gemini", "GEMINI.md");
13364
+ const codexTarget = path35.join(home, ".codex", "AGENTS.md");
13365
+ const geminiTarget = path35.join(home, ".gemini", "GEMINI.md");
13205
13366
  const homeSlashes = home.replace(/\\/g, "/").replace(/\/+$/, "");
13206
13367
  return [
13207
13368
  {
13208
13369
  agent: "claude-code",
13209
13370
  label: MEMORY_AGENT_LABELS["claude-code"],
13210
- target: path33.join(home, ".claude", "CLAUDE.md"),
13371
+ target: path35.join(home, ".claude", "CLAUDE.md"),
13211
13372
  kind: "line",
13212
13373
  text: `@~/${GLOBAL_MEMORY_RELATIVE}`,
13213
13374
  note: serverText("memoryNoteClaude")
@@ -13231,7 +13392,7 @@ function buildGlobalFragments(home) {
13231
13392
  {
13232
13393
  agent: "opencode",
13233
13394
  label: MEMORY_AGENT_LABELS.opencode,
13234
- target: path33.join(home, ".config", "opencode", "opencode.json"),
13395
+ target: path35.join(home, ".config", "opencode", "opencode.json"),
13235
13396
  kind: "json",
13236
13397
  text: `"instructions": ["${homeSlashes}/${GLOBAL_MEMORY_RELATIVE}"]`,
13237
13398
  note: serverText("memoryNoteOpenCode")
@@ -13279,17 +13440,17 @@ async function readGit(cwd) {
13279
13440
  if (!toplevel || !gitDir || !commonDir) return fail(serverText("gitUnexpected", { command: "rev-parse" }));
13280
13441
  const ignored = await checkIgnored(cwd, INDEX_REL);
13281
13442
  if (typeof ignored !== "boolean") return fail(ignored);
13282
- const absoluteGitDir = path33.resolve(cwd, gitDir);
13283
- const absoluteCommonDir = path33.resolve(cwd, commonDir);
13443
+ const absoluteGitDir = path35.resolve(cwd, gitDir);
13444
+ const absoluteCommonDir = path35.resolve(cwd, commonDir);
13284
13445
  let worktree = null;
13285
13446
  let main2 = null;
13286
13447
  if (!await samePath(absoluteGitDir, absoluteCommonDir)) {
13287
- if (path33.basename(absoluteCommonDir).toLowerCase() === ".git") {
13288
- const mainRoot = path33.dirname(absoluteCommonDir);
13289
- const inner = path33.relative(path33.resolve(toplevel), path33.resolve(cwd));
13290
- const sameFolder = inner.length === 0 || inner.startsWith("..") || path33.isAbsolute(inner);
13291
- const mainPath = sameFolder ? mainRoot : path33.join(mainRoot, inner);
13292
- const memoryRel = sameFolder ? MEMORY_DIR : [...inner.split(path33.sep), MEMORY_DIR].join("/");
13448
+ if (path35.basename(absoluteCommonDir).toLowerCase() === ".git") {
13449
+ const mainRoot = path35.dirname(absoluteCommonDir);
13450
+ const inner = path35.relative(path35.resolve(toplevel), path35.resolve(cwd));
13451
+ const sameFolder = inner.length === 0 || inner.startsWith("..") || path35.isAbsolute(inner);
13452
+ const mainPath = sameFolder ? mainRoot : path35.join(mainRoot, inner);
13453
+ const memoryRel = sameFolder ? MEMORY_DIR : [...inner.split(path35.sep), MEMORY_DIR].join("/");
13293
13454
  main2 = { root: mainRoot, memoryRel };
13294
13455
  worktree = {
13295
13456
  mainPath,
@@ -13314,7 +13475,7 @@ async function samePath(a, b) {
13314
13475
  try {
13315
13476
  return await realpath2(value);
13316
13477
  } catch {
13317
- return path33.resolve(value);
13478
+ return path35.resolve(value);
13318
13479
  }
13319
13480
  };
13320
13481
  const [left, right] = await Promise.all([resolve(a), resolve(b)]);
@@ -13356,9 +13517,9 @@ async function listNoteFiles(folder) {
13356
13517
  }
13357
13518
  async function readIfFile(absolute, label) {
13358
13519
  try {
13359
- const info = await stat17(absolute);
13520
+ const info = await stat18(absolute);
13360
13521
  if (!info.isFile()) throw new MemoryBridgeError(serverText("memoryNotAFile", { label }));
13361
- return await readFile11(absolute);
13522
+ return await readFile12(absolute);
13362
13523
  } catch (error) {
13363
13524
  if (isNotFound(error)) return null;
13364
13525
  throw error;
@@ -13380,14 +13541,14 @@ async function readHead(absolute) {
13380
13541
  }
13381
13542
  async function isFile(absolute) {
13382
13543
  try {
13383
- return (await stat17(absolute)).isFile();
13544
+ return (await stat18(absolute)).isFile();
13384
13545
  } catch {
13385
13546
  return false;
13386
13547
  }
13387
13548
  }
13388
13549
  async function isDirectory2(absolute) {
13389
13550
  try {
13390
- return (await stat17(absolute)).isDirectory();
13551
+ return (await stat18(absolute)).isDirectory();
13391
13552
  } catch {
13392
13553
  return false;
13393
13554
  }
@@ -13405,7 +13566,7 @@ async function writeAtomic(target, content, mustNotExist) {
13405
13566
  await handle.close();
13406
13567
  }
13407
13568
  if (mustNotExist && await exists2(target)) {
13408
- throw new MemoryBridgeError(serverText("memoryAppeared", { file: path33.basename(target) }));
13569
+ throw new MemoryBridgeError(serverText("memoryAppeared", { file: path35.basename(target) }));
13409
13570
  }
13410
13571
  await renameWithRetry(temporary, target);
13411
13572
  } catch (error) {
@@ -13416,9 +13577,9 @@ async function writeAtomic(target, content, mustNotExist) {
13416
13577
  async function createTemporary(target) {
13417
13578
  for (let attempt = 1; ; attempt += 1) {
13418
13579
  const suffix = randomBytes4(6).toString("hex");
13419
- const temporary = path33.join(
13420
- path33.dirname(target),
13421
- `.${path33.basename(target)}.${process.pid}.${suffix}.tmp`
13580
+ const temporary = path35.join(
13581
+ path35.dirname(target),
13582
+ `.${path35.basename(target)}.${process.pid}.${suffix}.tmp`
13422
13583
  );
13423
13584
  try {
13424
13585
  return { temporary, handle: await open6(temporary, "wx") };
@@ -13430,7 +13591,7 @@ async function createTemporary(target) {
13430
13591
  }
13431
13592
  async function exists2(absolute) {
13432
13593
  try {
13433
- await stat17(absolute);
13594
+ await stat18(absolute);
13434
13595
  return true;
13435
13596
  } catch {
13436
13597
  return false;
@@ -13656,13 +13817,13 @@ var MemoryHub = class extends EventEmitter3 {
13656
13817
  }
13657
13818
  };
13658
13819
  function keyFor(cwd) {
13659
- const resolved = path34.resolve(cwd);
13820
+ const resolved = path36.resolve(cwd);
13660
13821
  return process.platform === "win32" ? resolved.toLowerCase() : resolved;
13661
13822
  }
13662
13823
  function isRelevantPath(cwd, candidate) {
13663
- const relative = path34.relative(cwd, candidate);
13824
+ const relative = path36.relative(cwd, candidate);
13664
13825
  if (relative.length === 0) return true;
13665
- if (relative.startsWith("..") || path34.isAbsolute(relative)) return false;
13826
+ if (relative.startsWith("..") || path36.isAbsolute(relative)) return false;
13666
13827
  const same = (a, b) => process.platform === "win32" ? a.toLowerCase() === b.toLowerCase() : a === b;
13667
13828
  const parts = relative.split(/[\\/]/);
13668
13829
  const [first = "", second = "", third = ""] = parts;
@@ -13680,9 +13841,8 @@ function isRelevantPath(cwd, candidate) {
13680
13841
 
13681
13842
  // packages/server/src/paste-store.ts
13682
13843
  import { createHash as createHash3, randomUUID as randomUUID3 } from "node:crypto";
13683
- import { mkdir as mkdir8, readdir as readdir10, rm as rm3, stat as stat18, writeFile as writeFile4 } from "node:fs/promises";
13684
- import { tmpdir as tmpdir4 } from "node:os";
13685
- import path35 from "node:path";
13844
+ import { mkdir as mkdir8, readdir as readdir10, rm as rm3, stat as stat19, writeFile as writeFile4 } from "node:fs/promises";
13845
+ import path37 from "node:path";
13686
13846
 
13687
13847
  // packages/server/src/vault/markdown.ts
13688
13848
  var pad2 = (value) => String(value).padStart(2, "0");
@@ -14197,8 +14357,8 @@ function buildContinuationMessage(input) {
14197
14357
  }
14198
14358
  return sanitizeForPaste(lines.join("\n"));
14199
14359
  }
14200
- function transcriptReferenceFor(path50, style) {
14201
- return style === "at-quoted" ? fileReference(path50, "at-quoted") : `"${path50}"`;
14360
+ function transcriptReferenceFor(path52, style) {
14361
+ return style === "at-quoted" ? fileReference(path52, "at-quoted") : `"${path52}"`;
14202
14362
  }
14203
14363
  function planTranscript(input) {
14204
14364
  const turns = splitTurns(input.events);
@@ -14322,32 +14482,6 @@ function textWithAttachments(text, lines) {
14322
14482
  return lines.length === 0 ? text : [...lines, text].filter((piece) => piece.trim().length > 0).join("\n");
14323
14483
  }
14324
14484
 
14325
- // packages/server/src/image-signature.ts
14326
- var FORMATS = [
14327
- {
14328
- format: { ext: "png", mediaType: "image/png" },
14329
- test: (b) => b.length > 8 && b.subarray(0, 8).equals(Buffer.from("89504e470d0a1a0a", "hex"))
14330
- },
14331
- {
14332
- format: { ext: "jpg", mediaType: "image/jpeg" },
14333
- test: (b) => b.length > 3 && b[0] === 255 && b[1] === 216 && b[2] === 255
14334
- },
14335
- {
14336
- format: { ext: "gif", mediaType: "image/gif" },
14337
- test: (b) => b.length > 6 && b.subarray(0, 4).toString("ascii") === "GIF8"
14338
- },
14339
- {
14340
- format: { ext: "webp", mediaType: "image/webp" },
14341
- test: (b) => b.length > 12 && b.subarray(0, 4).toString("ascii") === "RIFF" && b.subarray(8, 12).toString("ascii") === "WEBP"
14342
- }
14343
- ];
14344
- var IMAGE_MEDIA_TYPES = new Set(
14345
- FORMATS.map((entry) => entry.format.mediaType)
14346
- );
14347
- function detectImageFormat(bytes) {
14348
- return FORMATS.find((entry) => entry.test(bytes))?.format ?? null;
14349
- }
14350
-
14351
14485
  // packages/server/src/paste-store.ts
14352
14486
  var EXTENSIONS = /* @__PURE__ */ new Map([
14353
14487
  ["image/png", "png"],
@@ -14373,7 +14507,7 @@ var PasteStore = class {
14373
14507
  root;
14374
14508
  counter = 0;
14375
14509
  constructor(root) {
14376
- this.root = root ?? path35.join(tmpdir4(), "agent-workbench", "pasted");
14510
+ this.root = root ?? pasteRoot();
14377
14511
  }
14378
14512
  /**
14379
14513
  * Guarda una imagen y devuelve su ruta.
@@ -14400,11 +14534,11 @@ var PasteStore = class {
14400
14534
  if (signature === null) {
14401
14535
  throw new PasteImageError(serverText("imageUnknownFormat"));
14402
14536
  }
14403
- const directory = path35.join(this.root, safeSegment(terminalId));
14537
+ const directory = path37.join(this.root, safeSegment(terminalId));
14404
14538
  await mkdir8(directory, { recursive: true, mode: DIRECTORY_MODE });
14405
14539
  this.counter += 1;
14406
14540
  const name = `pegada-${this.counter}-${randomUUID3().slice(0, 8)}.${signature.ext}`;
14407
- const file = path35.join(directory, name);
14541
+ const file = path37.join(directory, name);
14408
14542
  await writeFile4(file, bytes, { mode: FILE_MODE });
14409
14543
  return { path: file, bytes: bytes.length };
14410
14544
  }
@@ -14422,11 +14556,11 @@ var PasteStore = class {
14422
14556
  if (bytes.length > MAX_TEXT_BYTES) {
14423
14557
  throw new PasteTextError(`The text is ${bytes.length} bytes; the maximum is ${MAX_TEXT_BYTES}.`);
14424
14558
  }
14425
- const directory = path35.join(this.root, safeSegment(terminalId));
14559
+ const directory = path37.join(this.root, safeSegment(terminalId));
14426
14560
  await mkdir8(directory, { recursive: true, mode: DIRECTORY_MODE });
14427
14561
  this.counter += 1;
14428
14562
  const name = `${baseName}-${this.counter}-${randomUUID3().slice(0, 8)}.md`;
14429
- const file = path35.join(directory, name);
14563
+ const file = path37.join(directory, name);
14430
14564
  await writeFile4(file, bytes, { mode: FILE_MODE });
14431
14565
  return { path: file, bytes: bytes.length };
14432
14566
  }
@@ -14456,17 +14590,17 @@ var PasteStore = class {
14456
14590
  })
14457
14591
  );
14458
14592
  }
14459
- const directory = path35.join(this.root, safeSegment(terminalId));
14593
+ const directory = path37.join(this.root, safeSegment(terminalId));
14460
14594
  await mkdir8(directory, { recursive: true, mode: DIRECTORY_MODE });
14461
14595
  this.counter += 1;
14462
14596
  const name = `adjunto-${this.counter}-${randomUUID3().slice(0, 8)}-${safe}`;
14463
- const file = path35.join(directory, name);
14597
+ const file = path37.join(directory, name);
14464
14598
  await writeFile4(file, bytes, { mode: FILE_MODE });
14465
14599
  return { path: file, bytes: bytes.length, name };
14466
14600
  }
14467
14601
  /** Borra lo de una pestana. Se llama al cerrarla. */
14468
14602
  async clearTerminal(terminalId) {
14469
- await rm3(path35.join(this.root, safeSegment(terminalId)), {
14603
+ await rm3(path37.join(this.root, safeSegment(terminalId)), {
14470
14604
  recursive: true,
14471
14605
  force: true
14472
14606
  }).catch(() => {
@@ -14488,9 +14622,9 @@ var PasteStore = class {
14488
14622
  }
14489
14623
  await Promise.all(
14490
14624
  entries.map(async (entry) => {
14491
- const full = path35.join(this.root, entry);
14625
+ const full = path37.join(this.root, entry);
14492
14626
  try {
14493
- const info = await stat18(full);
14627
+ const info = await stat19(full);
14494
14628
  if (now - info.mtimeMs > STALE_AFTER_MS) {
14495
14629
  await rm3(full, { recursive: true, force: true });
14496
14630
  }
@@ -14507,8 +14641,8 @@ function safeSegment(value) {
14507
14641
 
14508
14642
  // packages/server/src/session-index.ts
14509
14643
  import { EventEmitter as EventEmitter4 } from "node:events";
14510
- import { mkdir as mkdir9, readFile as readFile12, stat as stat19, writeFile as writeFile5 } from "node:fs/promises";
14511
- import path36 from "node:path";
14644
+ import { mkdir as mkdir9, readFile as readFile13, stat as stat20, writeFile as writeFile5 } from "node:fs/promises";
14645
+ import path38 from "node:path";
14512
14646
  var CACHE_VERSION = 4;
14513
14647
  var vaultPairKey = (agent, sessionId) => `${agent}/${sessionId}`;
14514
14648
  function vaultOnlySessions(natives, vault, listState, ready) {
@@ -14560,7 +14694,7 @@ function cacheKey(agent, ref) {
14560
14694
  }
14561
14695
  async function pathExists3(candidate) {
14562
14696
  try {
14563
- await stat19(candidate);
14697
+ await stat20(candidate);
14564
14698
  return true;
14565
14699
  } catch {
14566
14700
  return false;
@@ -14610,7 +14744,7 @@ function migrateEntryV3(filePath, value) {
14610
14744
  return {
14611
14745
  agent: "claude-code",
14612
14746
  ref: filePath,
14613
- group: path36.basename(path36.dirname(filePath)),
14747
+ group: path38.basename(path38.dirname(filePath)),
14614
14748
  mtimeMs,
14615
14749
  sizeBytes,
14616
14750
  cwd,
@@ -14875,7 +15009,7 @@ var SessionIndex = class extends EventEmitter4 {
14875
15009
  }
14876
15010
  async loadCache() {
14877
15011
  try {
14878
- const raw = await readFile12(sessionIndexCachePath(), "utf8");
15012
+ const raw = await readFile13(sessionIndexCachePath(), "utf8");
14879
15013
  const parsed = JSON.parse(raw);
14880
15014
  const migrated = migrateIndexCache(parsed);
14881
15015
  if (migrated === null) return;
@@ -15103,8 +15237,8 @@ var SessionIndex = class extends EventEmitter4 {
15103
15237
  };
15104
15238
 
15105
15239
  // packages/server/src/settings-store.ts
15106
- import { mkdir as mkdir10, readFile as readFile13, stat as stat20 } from "node:fs/promises";
15107
- import path37 from "node:path";
15240
+ import { mkdir as mkdir10, readFile as readFile14, stat as stat21 } from "node:fs/promises";
15241
+ import path39 from "node:path";
15108
15242
  var SETTINGS_VERSION = 1;
15109
15243
  var VAULT_TOOL_RESULT_DEFAULT_CHARS = 64e3;
15110
15244
  var VAULT_TOOL_RESULT_MIN_CHARS = 4e3;
@@ -15121,7 +15255,7 @@ function defaultAppSettings() {
15121
15255
  function isAbsoluteDir(dir, platform) {
15122
15256
  if (dir.length === 0 || dir.includes("\0")) return false;
15123
15257
  if (platform === "win32") return /^[A-Za-z]:[\\/]/.test(dir) || /^\\\\[^\\/]+[\\/][^\\/]+/.test(dir);
15124
- return path37.posix.isAbsolute(dir);
15258
+ return path39.posix.isAbsolute(dir);
15125
15259
  }
15126
15260
  function clampToolResultMaxChars(value) {
15127
15261
  if (typeof value !== "number" || !Number.isFinite(value)) return VAULT_TOOL_RESULT_DEFAULT_CHARS;
@@ -15180,7 +15314,7 @@ var SettingsStore = class {
15180
15314
  async load() {
15181
15315
  let raw;
15182
15316
  try {
15183
- raw = await readFile13(this.filePath, "utf8");
15317
+ raw = await readFile14(this.filePath, "utf8");
15184
15318
  } catch {
15185
15319
  this.current = frozen(defaultAppSettings());
15186
15320
  return;
@@ -15208,7 +15342,7 @@ var SettingsStore = class {
15208
15342
  async reloadRemote() {
15209
15343
  let parsed;
15210
15344
  try {
15211
- parsed = JSON.parse(await readFile13(this.filePath, "utf8"));
15345
+ parsed = JSON.parse(await readFile14(this.filePath, "utf8"));
15212
15346
  } catch {
15213
15347
  return;
15214
15348
  }
@@ -15219,7 +15353,7 @@ var SettingsStore = class {
15219
15353
  /** Una marca que cambia cuando el archivo cambia (fecha y tamano), o '' si no esta. */
15220
15354
  async stamp() {
15221
15355
  try {
15222
- const info = await stat20(this.filePath);
15356
+ const info = await stat21(this.filePath);
15223
15357
  return `${info.mtimeMs}:${info.size}`;
15224
15358
  } catch {
15225
15359
  return "";
@@ -15263,7 +15397,7 @@ var SettingsStore = class {
15263
15397
  if (!isRemotePort(remote.port)) throw new Error(`The remote access port isn't valid: ${JSON.stringify(remote.port)}`);
15264
15398
  next.remote.port = remote.port;
15265
15399
  }
15266
- await mkdir10(path37.dirname(this.filePath), { recursive: true });
15400
+ await mkdir10(path39.dirname(this.filePath), { recursive: true });
15267
15401
  await writeFileAtomic(this.filePath, `${JSON.stringify(next, null, 2)}
15268
15402
  `);
15269
15403
  this.current = frozen(next);
@@ -15351,8 +15485,8 @@ function supportStartupLineColored() {
15351
15485
 
15352
15486
  // packages/server/src/notes-store.ts
15353
15487
  import { randomUUID as randomUUID4 } from "node:crypto";
15354
- import { mkdir as mkdir11, readFile as readFile14, rename as rename5, rm as rm4, writeFile as writeFile6 } from "node:fs/promises";
15355
- import path38 from "node:path";
15488
+ import { mkdir as mkdir11, readFile as readFile15, rename as rename5, rm as rm4, writeFile as writeFile6 } from "node:fs/promises";
15489
+ import path40 from "node:path";
15356
15490
  var STATE_VERSION2 = 1;
15357
15491
  var WRITE_DEBOUNCE_MS2 = 500;
15358
15492
  var NotesError = class extends ServerTextError {
@@ -15395,7 +15529,7 @@ var NotesStore = class {
15395
15529
  }
15396
15530
  async load() {
15397
15531
  try {
15398
- const raw = await readFile14(this.statePath, "utf8");
15532
+ const raw = await readFile15(this.statePath, "utf8");
15399
15533
  this.notes = parseState2(raw) ?? [];
15400
15534
  } catch {
15401
15535
  this.notes = [];
@@ -15512,7 +15646,7 @@ var NotesStore = class {
15512
15646
  const image = this.findImage(imageId);
15513
15647
  if (image === null) return null;
15514
15648
  try {
15515
- const bytes = await readFile14(this.imagePath(image));
15649
+ const bytes = await readFile15(this.imagePath(image));
15516
15650
  return { mediaType: image.mediaType, data: bytes.toString("base64") };
15517
15651
  } catch {
15518
15652
  return null;
@@ -15532,7 +15666,7 @@ var NotesStore = class {
15532
15666
  const images = [];
15533
15667
  for (const image of note.images) {
15534
15668
  try {
15535
- const bytes = await readFile14(this.imagePath(image));
15669
+ const bytes = await readFile15(this.imagePath(image));
15536
15670
  images.push({ mediaType: image.mediaType, data: bytes.toString("base64") });
15537
15671
  } catch {
15538
15672
  }
@@ -15556,7 +15690,7 @@ var NotesStore = class {
15556
15690
  }
15557
15691
  imagePath(image) {
15558
15692
  const safe = image.imageId.replace(/[^a-zA-Z0-9-]/g, "");
15559
- return path38.join(this.imagesDir, `${safe}.${extensionFor(image.mediaType)}`);
15693
+ return path40.join(this.imagesDir, `${safe}.${extensionFor(image.mediaType)}`);
15560
15694
  }
15561
15695
  async unlinkImage(image) {
15562
15696
  await rm4(this.imagePath(image), { force: true }).catch(() => {
@@ -15574,8 +15708,8 @@ var NotesStore = class {
15574
15708
  async writeNow() {
15575
15709
  this.dirty = false;
15576
15710
  try {
15577
- await mkdir11(path38.dirname(this.statePath), { recursive: true });
15578
- const temporary = path38.join(path38.dirname(this.statePath), `notes.${process.pid}.tmp`);
15711
+ await mkdir11(path40.dirname(this.statePath), { recursive: true });
15712
+ const temporary = path40.join(path40.dirname(this.statePath), `notes.${process.pid}.tmp`);
15579
15713
  await writeFile6(
15580
15714
  temporary,
15581
15715
  JSON.stringify({ version: STATE_VERSION2, notes: this.notes }, null, 2),
@@ -15589,8 +15723,8 @@ var NotesStore = class {
15589
15723
  };
15590
15724
 
15591
15725
  // packages/server/src/draft-store.ts
15592
- import { mkdir as mkdir12, readFile as readFile15, rename as rename6, writeFile as writeFile7 } from "node:fs/promises";
15593
- import path39 from "node:path";
15726
+ import { mkdir as mkdir12, readFile as readFile16, rename as rename6, writeFile as writeFile7 } from "node:fs/promises";
15727
+ import path41 from "node:path";
15594
15728
  var STATE_VERSION3 = 1;
15595
15729
  var WRITE_DEBOUNCE_MS3 = 500;
15596
15730
  var MAX_STORED_DRAFTS = 100;
@@ -15684,7 +15818,7 @@ var DraftStore = class {
15684
15818
  }
15685
15819
  async load() {
15686
15820
  try {
15687
- this.drafts = parseState3(await readFile15(this.statePath, "utf8"));
15821
+ this.drafts = parseState3(await readFile16(this.statePath, "utf8"));
15688
15822
  } catch {
15689
15823
  this.drafts = /* @__PURE__ */ new Map();
15690
15824
  }
@@ -15775,7 +15909,7 @@ var DraftStore = class {
15775
15909
  async writeNow() {
15776
15910
  let onDisk = /* @__PURE__ */ new Map();
15777
15911
  try {
15778
- onDisk = parseState3(await readFile15(this.statePath, "utf8"));
15912
+ onDisk = parseState3(await readFile16(this.statePath, "utf8"));
15779
15913
  } catch {
15780
15914
  }
15781
15915
  const changed = this.changed;
@@ -15789,8 +15923,8 @@ var DraftStore = class {
15789
15923
  trimOldest(merged);
15790
15924
  this.drafts = new Map(merged);
15791
15925
  try {
15792
- await mkdir12(path39.dirname(this.statePath), { recursive: true });
15793
- const temporary = path39.join(path39.dirname(this.statePath), `composer-drafts.${process.pid}.tmp`);
15926
+ await mkdir12(path41.dirname(this.statePath), { recursive: true });
15927
+ const temporary = path41.join(path41.dirname(this.statePath), `composer-drafts.${process.pid}.tmp`);
15794
15928
  const payload = {
15795
15929
  version: STATE_VERSION3,
15796
15930
  drafts: [...merged.values()].map(({ agent, sessionId, updatedAt, draft }) => ({ agent, sessionId, updatedAt, draft }))
@@ -15807,7 +15941,7 @@ var DraftStore = class {
15807
15941
  // packages/server/src/shell-locator.ts
15808
15942
  import { access as access2 } from "node:fs/promises";
15809
15943
  import { constants as fsConstants2 } from "node:fs";
15810
- import path40 from "node:path";
15944
+ import path42 from "node:path";
15811
15945
  async function isExecutable(candidate) {
15812
15946
  try {
15813
15947
  await access2(candidate, process.platform === "win32" ? fsConstants2.R_OK : fsConstants2.X_OK);
@@ -15825,21 +15959,21 @@ var SYSTEM_PROBE = {
15825
15959
  function windowsPowerShellPath(env) {
15826
15960
  const systemRoot = env["SystemRoot"] ?? env["windir"];
15827
15961
  if (systemRoot === void 0 || systemRoot.length === 0) return null;
15828
- return path40.win32.join(systemRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
15962
+ return path42.win32.join(systemRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
15829
15963
  }
15830
15964
  function gitBashCandidates(gitPath, env) {
15831
15965
  const candidates = [];
15832
15966
  if (gitPath !== null) {
15833
- let dir = path40.win32.dirname(gitPath);
15967
+ let dir = path42.win32.dirname(gitPath);
15834
15968
  for (let level = 0; level < 3; level++) {
15835
- candidates.push(path40.win32.join(dir, "bin", "bash.exe"));
15836
- const parent = path40.win32.dirname(dir);
15969
+ candidates.push(path42.win32.join(dir, "bin", "bash.exe"));
15970
+ const parent = path42.win32.dirname(dir);
15837
15971
  if (parent === dir) break;
15838
15972
  dir = parent;
15839
15973
  }
15840
15974
  }
15841
- for (const base of [env["ProgramFiles"], env["LOCALAPPDATA"] === void 0 ? void 0 : path40.win32.join(env["LOCALAPPDATA"], "Programs")]) {
15842
- if (base !== void 0 && base.length > 0) candidates.push(path40.win32.join(base, "Git", "bin", "bash.exe"));
15975
+ for (const base of [env["ProgramFiles"], env["LOCALAPPDATA"] === void 0 ? void 0 : path42.win32.join(env["LOCALAPPDATA"], "Programs")]) {
15976
+ if (base !== void 0 && base.length > 0) candidates.push(path42.win32.join(base, "Git", "bin", "bash.exe"));
15843
15977
  }
15844
15978
  const systemRoot = (env["SystemRoot"] ?? env["windir"] ?? "").toLowerCase();
15845
15979
  return [...new Set(candidates)].filter((candidate) => systemRoot.length === 0 || !candidate.toLowerCase().startsWith(systemRoot));
@@ -15870,7 +16004,7 @@ async function locatePosixShells(probe) {
15870
16004
  const found = [];
15871
16005
  const preferred = probe.env["SHELL"];
15872
16006
  if (preferred !== void 0 && preferred.length > 0 && await probe.isExecutable(preferred)) {
15873
- const name = path40.posix.basename(preferred);
16007
+ const name = path42.posix.basename(preferred);
15874
16008
  found.push({ id: "login", label: name, location: { file: preferred, args: [], name } });
15875
16009
  }
15876
16010
  for (const [id, file] of [["bash", "/bin/bash"], ["sh", "/bin/sh"], ["zsh", "/bin/zsh"]]) {
@@ -15942,13 +16076,13 @@ var AppSettingsService = class extends EventEmitter5 {
15942
16076
  };
15943
16077
 
15944
16078
  // packages/server/src/session-watcher.ts
15945
- import { stat as stat21 } from "node:fs/promises";
16079
+ import { stat as stat22 } from "node:fs/promises";
15946
16080
  import chokidar3 from "chokidar";
15947
16081
  var INDEX_DEBOUNCE_MS = 750;
15948
16082
  var ROOT_PROBE_MS = 5e3;
15949
16083
  async function isDirectory3(target) {
15950
16084
  try {
15951
- return (await stat21(target)).isDirectory();
16085
+ return (await stat22(target)).isDirectory();
15952
16086
  } catch {
15953
16087
  return false;
15954
16088
  }
@@ -16051,7 +16185,7 @@ function watchSessions(index, hub, agents, options = {}) {
16051
16185
  // packages/server/src/terminal-registry.ts
16052
16186
  import { randomUUID as randomUUID5 } from "node:crypto";
16053
16187
  import { EventEmitter as EventEmitter6 } from "node:events";
16054
- import { stat as stat22 } from "node:fs/promises";
16188
+ import { stat as stat23 } from "node:fs/promises";
16055
16189
 
16056
16190
  // packages/server/src/launch-hook-slot.ts
16057
16191
  var LaunchHookSlot = class {
@@ -16313,8 +16447,8 @@ async function resolveLaunchPlan(launch) {
16313
16447
  }
16314
16448
 
16315
16449
  // packages/server/src/workspace-store.ts
16316
- import { mkdir as mkdir13, readFile as readFile16, writeFile as writeFile8 } from "node:fs/promises";
16317
- import path41 from "node:path";
16450
+ import { mkdir as mkdir13, readFile as readFile17, writeFile as writeFile8 } from "node:fs/promises";
16451
+ import path43 from "node:path";
16318
16452
  var STATE_VERSION4 = 1;
16319
16453
  var WRITE_DEBOUNCE_MS4 = 400;
16320
16454
  var LEGACY_TAB_AGENT = "claude-code";
@@ -16436,7 +16570,7 @@ var WorkspaceStore = class {
16436
16570
  pending = null;
16437
16571
  async load() {
16438
16572
  try {
16439
- const raw = await readFile16(workspaceStatePath(), "utf8");
16573
+ const raw = await readFile17(workspaceStatePath(), "utf8");
16440
16574
  return parseState4(raw) ?? EMPTY_STATE();
16441
16575
  } catch {
16442
16576
  return EMPTY_STATE();
@@ -16468,7 +16602,7 @@ var WorkspaceStore = class {
16468
16602
  try {
16469
16603
  await mkdir13(appConfigDir(), { recursive: true });
16470
16604
  const target = workspaceStatePath();
16471
- const temporary = path41.join(path41.dirname(target), `workspace.${process.pid}.tmp`);
16605
+ const temporary = path43.join(path43.dirname(target), `workspace.${process.pid}.tmp`);
16472
16606
  await writeFile8(temporary, JSON.stringify(serializeState(state), null, 2), "utf8");
16473
16607
  const { rename: rename7 } = await import("node:fs/promises");
16474
16608
  await rename7(temporary, target);
@@ -16705,7 +16839,7 @@ var TerminalRegistry = class extends EventEmitter6 {
16705
16839
  async assertDirectory(cwd) {
16706
16840
  let info;
16707
16841
  try {
16708
- info = await stat22(cwd);
16842
+ info = await stat23(cwd);
16709
16843
  } catch {
16710
16844
  throw new TerminalOpenError("invalid-cwd", serverText("cwdMissing", { cwd }));
16711
16845
  }
@@ -17132,19 +17266,19 @@ import { WebSocketServer } from "ws";
17132
17266
 
17133
17267
  // packages/server/src/directory-picker.ts
17134
17268
  import { randomUUID as randomUUID6 } from "node:crypto";
17135
- import { mkdir as mkdir14, readdir as readdir11, stat as stat23 } from "node:fs/promises";
17269
+ import { mkdir as mkdir14, readdir as readdir11, stat as stat24 } from "node:fs/promises";
17136
17270
  import { homedir as homedir11 } from "node:os";
17137
- import path42 from "node:path";
17271
+ import path44 from "node:path";
17138
17272
  var MAX_ENTRIES = 500;
17139
17273
  var MAX_PICKERS = 8;
17140
17274
  var SKIPPED = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "bin", "obj", "$RECYCLE.BIN"]);
17141
17275
  var DirectoryPickerError = class extends ServerTextError {
17142
17276
  };
17143
17277
  function isInsideProtected(target, dirs) {
17144
- const resolved = path42.resolve(target);
17278
+ const resolved = path44.resolve(target);
17145
17279
  return dirs.some((dir) => {
17146
- const protectedDir = path42.resolve(dir);
17147
- return resolved === protectedDir || resolved.startsWith(protectedDir + path42.sep);
17280
+ const protectedDir = path44.resolve(dir);
17281
+ return resolved === protectedDir || resolved.startsWith(protectedDir + path44.sep);
17148
17282
  });
17149
17283
  }
17150
17284
  async function listRoots() {
@@ -17156,7 +17290,7 @@ async function listRoots() {
17156
17290
  letters.map(async (letter) => {
17157
17291
  const drive = `${letter}:\\`;
17158
17292
  try {
17159
- await stat23(drive);
17293
+ await stat24(drive);
17160
17294
  return drive;
17161
17295
  } catch {
17162
17296
  return null;
@@ -17208,14 +17342,14 @@ var DirectoryPickers = class {
17208
17342
  async enter(pickerId, name) {
17209
17343
  const picker = this.require(pickerId);
17210
17344
  if (name === "..") {
17211
- const parent = path42.dirname(picker.current);
17345
+ const parent = path44.dirname(picker.current);
17212
17346
  if (parent !== picker.current) picker.current = parent;
17213
17347
  return this.listing(picker);
17214
17348
  }
17215
17349
  if (!picker.entries.has(name)) {
17216
17350
  throw new DirectoryPickerError(serverText("pickerNotListed"));
17217
17351
  }
17218
- const target = path42.join(picker.current, name);
17352
+ const target = path44.join(picker.current, name);
17219
17353
  if (isInsideProtected(target, this.protectedDirs)) {
17220
17354
  throw new DirectoryPickerError(serverText("pickerCliFolder"));
17221
17355
  }
@@ -17255,7 +17389,7 @@ var DirectoryPickers = class {
17255
17389
  throw new DirectoryPickerError(serverText("pickerNameChars"));
17256
17390
  }
17257
17391
  }
17258
- const target = path42.join(picker.current, clean);
17392
+ const target = path44.join(picker.current, clean);
17259
17393
  if (isInsideProtected(target, this.protectedDirs)) {
17260
17394
  throw new DirectoryPickerError(serverText("pickerNoProjectsHere"));
17261
17395
  }
@@ -17292,7 +17426,7 @@ var DirectoryPickers = class {
17292
17426
  let truncated = false;
17293
17427
  try {
17294
17428
  const found = await readdir11(picker.current, { withFileTypes: true });
17295
- const dirs = found.filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => !SKIPPED.has(name)).filter((name) => !isInsideProtected(path42.join(picker.current, name), this.protectedDirs)).sort((a, b) => a.localeCompare(b));
17429
+ const dirs = found.filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => !SKIPPED.has(name)).filter((name) => !isInsideProtected(path44.join(picker.current, name), this.protectedDirs)).sort((a, b) => a.localeCompare(b));
17296
17430
  truncated = dirs.length > MAX_ENTRIES;
17297
17431
  names = dirs.slice(0, MAX_ENTRIES);
17298
17432
  } catch {
@@ -17303,15 +17437,15 @@ var DirectoryPickers = class {
17303
17437
  path: picker.current,
17304
17438
  entries: names,
17305
17439
  roots,
17306
- canGoUp: path42.dirname(picker.current) !== picker.current,
17440
+ canGoUp: path44.dirname(picker.current) !== picker.current,
17307
17441
  truncated
17308
17442
  };
17309
17443
  }
17310
17444
  };
17311
17445
 
17312
17446
  // packages/server/src/file-browser.ts
17313
- import { readFile as readFile17, readdir as readdir12, stat as stat24 } from "node:fs/promises";
17314
- import path43 from "node:path";
17447
+ import { readFile as readFile18, readdir as readdir12, stat as stat25 } from "node:fs/promises";
17448
+ import path45 from "node:path";
17315
17449
  var MAX_ENTRIES2 = 1e3;
17316
17450
  var SEARCH_MAX_RESULTS = 200;
17317
17451
  var SEARCH_MAX_DIRECTORIES = 4e3;
@@ -17374,7 +17508,7 @@ function languageFor(fileName) {
17374
17508
  const lower = fileName.toLowerCase();
17375
17509
  const byName = LANGUAGE_BY_NAME[lower];
17376
17510
  if (byName !== void 0) return byName;
17377
- const extension = path43.extname(lower);
17511
+ const extension = path45.extname(lower);
17378
17512
  return LANGUAGE_BY_EXTENSION[extension] ?? null;
17379
17513
  }
17380
17514
  function looksBinary2(buffer) {
@@ -17406,7 +17540,7 @@ async function listDirectory(cwd, relativePath, options = {}) {
17406
17540
  let sizeBytes = 0;
17407
17541
  let modifiedAt = 0;
17408
17542
  try {
17409
- const info = await stat24(path43.join(absolute, candidate.name));
17543
+ const info = await stat25(path45.join(absolute, candidate.name));
17410
17544
  sizeBytes = candidate.isDirectory ? 0 : info.size;
17411
17545
  modifiedAt = info.mtimeMs;
17412
17546
  } catch {
@@ -17439,7 +17573,7 @@ async function readLevel(absolute) {
17439
17573
  const always = ALWAYS_SKIP.has(dirent.name.toLowerCase());
17440
17574
  if (dirent.isSymbolicLink()) {
17441
17575
  try {
17442
- const target = await stat24(path43.join(absolute, dirent.name));
17576
+ const target = await stat25(path45.join(absolute, dirent.name));
17443
17577
  candidates.push({
17444
17578
  name: dirent.name,
17445
17579
  isDirectory: target.isDirectory(),
@@ -17468,7 +17602,7 @@ async function markIgnored(repoRoot2, levels) {
17468
17602
  for (const level of levels) {
17469
17603
  for (const entry of level.entries) {
17470
17604
  if (entry.hidden !== null) continue;
17471
- keys.set(entry, toPosixPath(path43.relative(repoRoot2, path43.join(level.absolute, entry.name))));
17605
+ keys.set(entry, toPosixPath(path45.relative(repoRoot2, path45.join(level.absolute, entry.name))));
17472
17606
  }
17473
17607
  }
17474
17608
  if (keys.size === 0) return;
@@ -17529,7 +17663,7 @@ async function searchFiles(cwd, query, options = {}) {
17529
17663
  let sizeBytes = 0;
17530
17664
  let modifiedAt = 0;
17531
17665
  try {
17532
- const info = await stat24(path43.join(level.absolute, candidate.name));
17666
+ const info = await stat25(path45.join(level.absolute, candidate.name));
17533
17667
  sizeBytes = candidate.isDirectory ? 0 : info.size;
17534
17668
  modifiedAt = info.mtimeMs;
17535
17669
  } catch {
@@ -17563,12 +17697,12 @@ async function searchFiles(cwd, query, options = {}) {
17563
17697
  }
17564
17698
  async function readPreview(cwd, relativePath) {
17565
17699
  const absolute = await resolveInside(cwd, relativePath, { mustExist: true });
17566
- const info = await stat24(absolute);
17700
+ const info = await stat25(absolute);
17567
17701
  if (info.isDirectory()) {
17568
17702
  throw new Error("It's a directory, not a file.");
17569
17703
  }
17570
- const content = await readFile17(absolute);
17571
- const fileName = path43.basename(absolute);
17704
+ const content = await readFile18(absolute);
17705
+ const fileName = path45.basename(absolute);
17572
17706
  if (looksBinary2(content)) {
17573
17707
  return {
17574
17708
  path: relativePath,
@@ -18157,14 +18291,14 @@ var TerminalWriteQueue = class {
18157
18291
  };
18158
18292
 
18159
18293
  // packages/server/src/vault/service.ts
18160
- import { mkdir as mkdir17, stat as stat28 } from "node:fs/promises";
18294
+ import { mkdir as mkdir17, stat as stat29 } from "node:fs/promises";
18161
18295
  import { homedir as homedir12 } from "node:os";
18162
- import path47 from "node:path";
18296
+ import path49 from "node:path";
18163
18297
 
18164
18298
  // packages/server/src/vault/move.ts
18165
18299
  import { constants } from "node:fs";
18166
- import { copyFile as copyFile2, lstat, mkdir as mkdir15, readdir as readdir13, rm as rm5, stat as stat25, utimes, writeFile as writeFile9 } from "node:fs/promises";
18167
- import path44 from "node:path";
18300
+ import { copyFile as copyFile2, lstat, mkdir as mkdir15, readdir as readdir13, rm as rm5, stat as stat26, utimes, writeFile as writeFile9 } from "node:fs/promises";
18301
+ import path46 from "node:path";
18168
18302
  var MOVED_ENTRIES = ["vault.json", "sessions", "memory"];
18169
18303
  var OWN_TEMP_FILE = /\.\d+\.[0-9a-f]{12}\.tmp$/;
18170
18304
  async function copyTree(source, target, result) {
@@ -18177,12 +18311,12 @@ async function copyTree(source, target, result) {
18177
18311
  if (info.isDirectory()) {
18178
18312
  await mkdir15(target, { recursive: true });
18179
18313
  for (const name of await readdir13(source)) {
18180
- await copyTree(path44.join(source, name), path44.join(target, name), result);
18314
+ await copyTree(path46.join(source, name), path46.join(target, name), result);
18181
18315
  }
18182
18316
  return;
18183
18317
  }
18184
18318
  if (!info.isFile() || OWN_TEMP_FILE.test(source)) return;
18185
- await mkdir15(path44.dirname(target), { recursive: true });
18319
+ await mkdir15(path46.dirname(target), { recursive: true });
18186
18320
  try {
18187
18321
  await copyFile2(source, target, constants.COPYFILE_EXCL);
18188
18322
  } catch (error) {
@@ -18199,7 +18333,7 @@ async function moveVault(from, to) {
18199
18333
  const result = { copied: 0, skipped: 0 };
18200
18334
  await mkdir15(to, { recursive: true });
18201
18335
  for (const entry of MOVED_ENTRIES) {
18202
- await copyTree(path44.join(from, entry), path44.join(to, entry), result);
18336
+ await copyTree(path46.join(from, entry), path46.join(to, entry), result);
18203
18337
  }
18204
18338
  return result;
18205
18339
  }
@@ -18231,10 +18365,10 @@ function checkVaultTarget(current, target, options) {
18231
18365
  return { kind: "ok" };
18232
18366
  }
18233
18367
  async function canWriteInto(dir) {
18234
- const probe = temporaryPathFor(path44.join(dir, ".escritura"));
18368
+ const probe = temporaryPathFor(path46.join(dir, ".escritura"));
18235
18369
  try {
18236
18370
  await mkdir15(dir, { recursive: true });
18237
- if (!(await stat25(dir)).isDirectory()) return false;
18371
+ if (!(await stat26(dir)).isDirectory()) return false;
18238
18372
  await writeFile9(probe, "");
18239
18373
  return true;
18240
18374
  } catch {
@@ -18337,12 +18471,12 @@ function serializeSession(input) {
18337
18471
  }
18338
18472
 
18339
18473
  // packages/server/src/vault/writer.ts
18340
- import { readdir as readdir15, rm as rm6, stat as stat27 } from "node:fs/promises";
18341
- import path46 from "node:path";
18474
+ import { readdir as readdir15, rm as rm6, stat as stat28 } from "node:fs/promises";
18475
+ import path48 from "node:path";
18342
18476
 
18343
18477
  // packages/server/src/vault/memory-copy.ts
18344
- import { mkdir as mkdir16, readdir as readdir14, readFile as readFile18, stat as stat26, utimes as utimes2 } from "node:fs/promises";
18345
- import path45 from "node:path";
18478
+ import { mkdir as mkdir16, readdir as readdir14, readFile as readFile19, stat as stat27, utimes as utimes2 } from "node:fs/promises";
18479
+ import path47 from "node:path";
18346
18480
  var MEMORY_FILE_MAX_BYTES = 1024 * 1024;
18347
18481
  var MEMORY_MAX_FILES = 500;
18348
18482
  var MEMORY_SOURCE_FILE = "source.json";
@@ -18367,7 +18501,7 @@ async function listMemoryNotes(cwd) {
18367
18501
  let absolute;
18368
18502
  try {
18369
18503
  absolute = await resolveInside(cwd, `${MEMORY_DIR}/${name}`, { mustExist: true });
18370
- const info = await stat26(absolute);
18504
+ const info = await stat27(absolute);
18371
18505
  if (!info.isFile() || info.size > MEMORY_FILE_MAX_BYTES) continue;
18372
18506
  notes.push({ name, absolute, size: info.size, mtimeMs: info.mtimeMs });
18373
18507
  } catch {
@@ -18381,7 +18515,7 @@ async function measureProjectMemory(cwd) {
18381
18515
  }
18382
18516
  async function isUpToDate(target, note) {
18383
18517
  try {
18384
- const info = await stat26(target);
18518
+ const info = await stat27(target);
18385
18519
  return info.isFile() && info.size === note.size && Math.abs(info.mtimeMs - note.mtimeMs) < SAME_MTIME_MS;
18386
18520
  } catch {
18387
18521
  return false;
@@ -18389,7 +18523,7 @@ async function isUpToDate(target, note) {
18389
18523
  }
18390
18524
  async function exists3(file) {
18391
18525
  try {
18392
- await stat26(file);
18526
+ await stat27(file);
18393
18527
  return true;
18394
18528
  } catch {
18395
18529
  return false;
@@ -18408,11 +18542,11 @@ async function copyProjectMemory(dir, cwd, platform, deps = DEFAULT_WRITE_DEPS)
18408
18542
  await mkdir16(target, { recursive: true });
18409
18543
  };
18410
18544
  for (const note of notes) {
18411
- const destination = path45.join(target, note.name);
18545
+ const destination = path47.join(target, note.name);
18412
18546
  if (await isUpToDate(destination, note)) continue;
18413
18547
  let content;
18414
18548
  try {
18415
- content = await readFile18(note.absolute);
18549
+ content = await readFile19(note.absolute);
18416
18550
  } catch {
18417
18551
  continue;
18418
18552
  }
@@ -18424,7 +18558,7 @@ async function copyProjectMemory(dir, cwd, platform, deps = DEFAULT_WRITE_DEPS)
18424
18558
  result.files += 1;
18425
18559
  result.bytes += content.length;
18426
18560
  }
18427
- const source = path45.join(target, MEMORY_SOURCE_FILE);
18561
+ const source = path47.join(target, MEMORY_SOURCE_FILE);
18428
18562
  if (result.files > 0 || !await exists3(source)) {
18429
18563
  await prepare();
18430
18564
  await writeFileAtomic(source, `${JSON.stringify({ cwd, copiedAt: deps.now() })}
@@ -18918,7 +19052,7 @@ var VaultWriter = class {
18918
19052
  }
18919
19053
  async assetOnDisk(dir, agent, sessionId, asset, bytes) {
18920
19054
  try {
18921
- const info = await stat27(assetFile(dir, agent, sessionId, asset));
19055
+ const info = await stat28(assetFile(dir, agent, sessionId, asset));
18922
19056
  return info.isFile() && info.size === bytes;
18923
19057
  } catch {
18924
19058
  return false;
@@ -19018,17 +19152,17 @@ var VaultWriter = class {
19018
19152
  const folders = [dir];
19019
19153
  const subfolders = async (parent) => {
19020
19154
  try {
19021
- return (await readdir15(parent, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => path46.join(parent, entry.name));
19155
+ return (await readdir15(parent, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => path48.join(parent, entry.name));
19022
19156
  } catch {
19023
19157
  return [];
19024
19158
  }
19025
19159
  };
19026
19160
  for (const agentDir of await subfolders(sessionsRoot2(dir))) {
19027
- if (!SESSION_AGENT_IDS.includes(path46.basename(agentDir))) continue;
19161
+ if (!SESSION_AGENT_IDS.includes(path48.basename(agentDir))) continue;
19028
19162
  folders.push(agentDir);
19029
19163
  folders.push(...(await subfolders(agentDir)).filter((folder) => folder.endsWith(".assets")));
19030
19164
  }
19031
- folders.push(...await subfolders(path46.join(dir, "memory")));
19165
+ folders.push(...await subfolders(path48.join(dir, "memory")));
19032
19166
  for (const folder of folders) {
19033
19167
  let names;
19034
19168
  try {
@@ -19038,9 +19172,9 @@ var VaultWriter = class {
19038
19172
  }
19039
19173
  for (const name of names) {
19040
19174
  if (!OWN_TEMP_FILE2.test(name)) continue;
19041
- const file = path46.join(folder, name);
19175
+ const file = path48.join(folder, name);
19042
19176
  try {
19043
- const info = await stat27(file);
19177
+ const info = await stat28(file);
19044
19178
  if (info.isFile() && now - info.mtimeMs > TEMP_MAX_AGE_MS) await rm6(file, { force: true });
19045
19179
  } catch {
19046
19180
  }
@@ -19228,14 +19362,14 @@ var VaultService = class {
19228
19362
  async setDir(target) {
19229
19363
  const { platform, agents, settings: settings2, catalog } = this.options;
19230
19364
  const current = this.dir();
19231
- const protectedDirs = [...agents.protectedDirs(), path47.join(this.options.homeDir ?? homedir12(), ".gemini")];
19365
+ const protectedDirs = [...agents.protectedDirs(), path49.join(this.options.homeDir ?? homedir12(), ".gemini")];
19232
19366
  const check = checkVaultTarget(current, target, { protectedDirs, platform });
19233
19367
  if (check.kind === "refused") throw new VaultError(check.text);
19234
19368
  if (check.kind === "same") return;
19235
19369
  try {
19236
19370
  await this.writer.exclusive("moving", async () => {
19237
19371
  if (!await canWriteInto(target)) throw new VaultError(serverText("vaultCannotWrite"));
19238
- const hadCopy = await stat28(vaultMarkerFile(current)).then(
19372
+ const hadCopy = await stat29(vaultMarkerFile(current)).then(
19239
19373
  () => true,
19240
19374
  () => false
19241
19375
  );
@@ -19269,7 +19403,7 @@ var VaultService = class {
19269
19403
  /** Abre la carpeta de la copia con el explorador del sistema. */
19270
19404
  async reveal() {
19271
19405
  const dir = this.activeDir();
19272
- const isFolder = await stat28(dir).then(
19406
+ const isFolder = await stat29(dir).then(
19273
19407
  (info) => info.isDirectory(),
19274
19408
  () => false
19275
19409
  );
@@ -19293,7 +19427,7 @@ var VaultService = class {
19293
19427
  fromCopy: true
19294
19428
  });
19295
19429
  const file = sessionExportFile(dir, agent, sessionId);
19296
- await mkdir17(path47.dirname(file), { recursive: true });
19430
+ await mkdir17(path49.dirname(file), { recursive: true });
19297
19431
  await writeFileAtomic(file, text, this.writeDeps);
19298
19432
  this.openWithSystem(file);
19299
19433
  return file;
@@ -19397,7 +19531,7 @@ var VaultService = class {
19397
19531
  continue;
19398
19532
  }
19399
19533
  const fileName = this.exportFileName(summary, names);
19400
- await writeFileAtomic(path47.join(folder, fileName), text, this.writeDeps);
19534
+ await writeFileAtomic(path49.join(folder, fileName), text, this.writeDeps);
19401
19535
  entries.push({
19402
19536
  updatedAt: summary.updatedAt,
19403
19537
  agentLabel: this.labelOf(summary.agent),
@@ -19408,9 +19542,9 @@ var VaultService = class {
19408
19542
  });
19409
19543
  await nextTurn3();
19410
19544
  }
19411
- const name = project.cwd.length > 0 ? path47.basename(project.cwd) || project.cwd : project.fallbackName;
19545
+ const name = project.cwd.length > 0 ? path49.basename(project.cwd) || project.cwd : project.fallbackName;
19412
19546
  const index = renderProjectIndex({ name, cwd: project.cwd, exportedAt: this.now(), entries, skipped });
19413
- await writeFileAtomic(path47.join(folder, "index.md"), index, this.writeDeps);
19547
+ await writeFileAtomic(path49.join(folder, "index.md"), index, this.writeDeps);
19414
19548
  this.openWithSystem(folder);
19415
19549
  return { sessions: entries.length, skipped, folder };
19416
19550
  }
@@ -21080,8 +21214,8 @@ function attachTerminalSocket(options) {
21080
21214
  }
21081
21215
 
21082
21216
  // packages/server/src/vault/catalog.ts
21083
- import { open as open7, readdir as readdir16, stat as stat29 } from "node:fs/promises";
21084
- import path48 from "node:path";
21217
+ import { open as open7, readdir as readdir16, stat as stat30 } from "node:fs/promises";
21218
+ import path50 from "node:path";
21085
21219
  import { createInterface as createInterface2 } from "node:readline";
21086
21220
  var HEADER_MAX_BYTES = 64 * 1024;
21087
21221
  var LOAD_CONCURRENCY = 16;
@@ -21101,7 +21235,7 @@ async function assetBytesOf(dir, agent, sessionId) {
21101
21235
  for (const name of names) {
21102
21236
  if (!VAULT_ASSET_NAME_PATTERN.test(name)) continue;
21103
21237
  try {
21104
- const info = await stat29(path48.join(folder, name));
21238
+ const info = await stat30(path50.join(folder, name));
21105
21239
  if (info.isFile()) total += info.size;
21106
21240
  } catch {
21107
21241
  }
@@ -21112,7 +21246,7 @@ async function readEntry(dir, agent, sessionId) {
21112
21246
  const file = sessionFile(dir, agent, sessionId);
21113
21247
  let sizeBytes;
21114
21248
  try {
21115
- const info = await stat29(file);
21249
+ const info = await stat30(file);
21116
21250
  if (!info.isFile()) return { kind: "absent" };
21117
21251
  sizeBytes = info.size;
21118
21252
  } catch {
@@ -21321,15 +21455,15 @@ var VaultCatalog = class {
21321
21455
  };
21322
21456
 
21323
21457
  // packages/server/src/index.ts
21324
- var serverDir = path49.dirname(fileURLToPath2(import.meta.url));
21458
+ var serverDir = path51.dirname(fileURLToPath2(import.meta.url));
21325
21459
  var isPackaged = true;
21326
- var webRoot = isPackaged ? serverDir : path49.resolve(serverDir, "../../web");
21327
- var webDist = isPackaged ? path49.join(serverDir, "web") : path49.join(webRoot, "dist");
21328
- var repoRoot = path49.resolve(serverDir, "../../..");
21460
+ var webRoot = isPackaged ? serverDir : path51.resolve(serverDir, "../../web");
21461
+ var webDist = isPackaged ? path51.join(serverDir, "web") : path51.join(webRoot, "dist");
21462
+ var repoRoot = path51.resolve(serverDir, "../../..");
21329
21463
  var isProduction = isPackaged || process.argv.includes("--prod");
21330
21464
  function resolveDefaultCwd() {
21331
21465
  const override = process.env["AGENT_WORKBENCH_CWD"];
21332
- if (override !== void 0 && override.length > 0) return path49.resolve(override);
21466
+ if (override !== void 0 && override.length > 0) return path51.resolve(override);
21333
21467
  if (isPackaged) return process.cwd();
21334
21468
  return repoRoot;
21335
21469
  }
@@ -21404,7 +21538,7 @@ async function mountDevUi(app, httpServer) {
21404
21538
  }
21405
21539
  var LOOKS_LIKE_FILE = /\.[a-zA-Z0-9]{1,8}$/;
21406
21540
  function mountBuiltUi(app) {
21407
- const indexHtml = path49.join(webDist, "index.html");
21541
+ const indexHtml = path51.join(webDist, "index.html");
21408
21542
  if (!existsSync4(indexHtml)) {
21409
21543
  throw new Error(
21410
21544
  `There's no compiled interface in ${webDist}.