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 +468 -334
- package/dist/web/assets/de-DlErJERu.js +1 -0
- package/dist/web/assets/es-C_iXI_cL.js +1 -0
- package/dist/web/assets/fr-DQrvpEX-.js +1 -0
- package/dist/web/assets/{highlight-DqX1MSlE.js → highlight-BxIlYHXS.js} +1 -1
- package/dist/web/assets/{index-B09L7LWU.css → index-4vO1q72v.css} +1 -1
- package/dist/web/assets/{index-CRZuxaEg.js → index-peCduls6.js} +39 -39
- package/dist/web/assets/ja-D5vZsdVh.js +1 -0
- package/dist/web/assets/ko-BpH6AFJf.js +1 -0
- package/dist/web/assets/pt-BR-B9DfN4SI.js +1 -0
- package/dist/web/assets/ru-DLtRgmP7.js +1 -0
- package/dist/web/assets/zh-CN-qo3wh4w3.js +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/web/assets/de-D4f5KK7F.js +0 -1
- package/dist/web/assets/es-BPdfRlPL.js +0 -1
- package/dist/web/assets/fr-Cv2VZ3uf.js +0 -1
- package/dist/web/assets/ja-X1nVuf-y.js +0 -1
- package/dist/web/assets/ko-c__ksx35.js +0 -1
- package/dist/web/assets/pt-BR-Bq9Rmy51.js +0 -1
- package/dist/web/assets/ru-4tlHIIyY.js +0 -1
- package/dist/web/assets/zh-CN-B_6-wR0g.js +0 -1
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
|
|
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"]
|
|
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
|
|
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
|
|
4559
|
-
import
|
|
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
|
|
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
|
-
|
|
4921
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
5135
|
+
const relative = path17.relative(root, absolute);
|
|
5082
5136
|
if (relative.length === 0) return null;
|
|
5083
|
-
if (relative.startsWith("..") ||
|
|
5137
|
+
if (relative.startsWith("..") || path17.isAbsolute(relative)) {
|
|
5084
5138
|
if (process.platform !== "win32") return null;
|
|
5085
|
-
const lower =
|
|
5086
|
-
if (lower.length === 0 || lower.startsWith("..") ||
|
|
5087
|
-
return lower.split(
|
|
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(
|
|
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
|
-
|
|
5669
|
-
const
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
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 (
|
|
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
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
const
|
|
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" &&
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
5944
|
-
group:
|
|
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(
|
|
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 =
|
|
6140
|
+
const ref = path20.join(root, slug, file);
|
|
5980
6141
|
try {
|
|
5981
|
-
items.push(toItem(ref, await
|
|
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 =
|
|
5990
|
-
const [slug] = relative.split(
|
|
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
|
|
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: () => [
|
|
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
|
|
6352
|
+
import path27 from "node:path";
|
|
6192
6353
|
|
|
6193
6354
|
// packages/server/src/agents/codex/discovery.ts
|
|
6194
|
-
import { stat as
|
|
6195
|
-
import
|
|
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
|
|
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
|
|
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 (!
|
|
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
|
|
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 :
|
|
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 :
|
|
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
|
|
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) =>
|
|
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(
|
|
6310
|
-
for (const day of await numberedFolders(
|
|
6311
|
-
for (const file of await rolloutFilesIn(
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
6778
|
-
import
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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 =
|
|
7268
|
-
return relative.length > 0 && !relative.startsWith("..") && !
|
|
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(
|
|
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
|
|
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 = [
|
|
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
|
|
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
|
|
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
|
|
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
|
|
8811
|
+
return path28.posix.isAbsolute(candidate);
|
|
8651
8812
|
}
|
|
8652
8813
|
function resolveOpenCodePaths(env, home, platform) {
|
|
8653
|
-
const flavor = platform === "win32" ?
|
|
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
|
|
9102
|
-
import
|
|
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
|
|
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
|
|
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 ${
|
|
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 ${
|
|
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
|
|
11120
|
+
import path31 from "node:path";
|
|
10960
11121
|
function helperCandidates(packageDir, platform, arch) {
|
|
10961
11122
|
return [
|
|
10962
|
-
|
|
10963
|
-
|
|
10964
|
-
|
|
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
|
|
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
|
|
11632
|
-
import
|
|
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
|
|
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
|
|
11801
|
+
import path32 from "node:path";
|
|
11641
11802
|
function defaultVaultDir() {
|
|
11642
|
-
return
|
|
11803
|
+
return path32.join(appConfigDir(), "vault");
|
|
11643
11804
|
}
|
|
11644
11805
|
function vaultMarkerFile(dir) {
|
|
11645
|
-
return
|
|
11806
|
+
return path32.join(dir, "vault.json");
|
|
11646
11807
|
}
|
|
11647
11808
|
function sessionsRoot2(dir) {
|
|
11648
|
-
return
|
|
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
|
|
11823
|
+
return path32.join(sessionsRoot2(dir), agent);
|
|
11663
11824
|
}
|
|
11664
11825
|
function sessionFile(dir, agent, sessionId) {
|
|
11665
11826
|
assertSessionKey(agent, sessionId);
|
|
11666
|
-
return
|
|
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
|
|
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
|
|
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" ?
|
|
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
|
|
11844
|
+
return path32.join(dir, "memory", projectFolderName(cwd, platform));
|
|
11684
11845
|
}
|
|
11685
11846
|
function projectExportDir(dir, cwd, platform) {
|
|
11686
|
-
return
|
|
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
|
|
11853
|
+
return path32.join(dir, "export", `${name}-${hash}`);
|
|
11693
11854
|
}
|
|
11694
11855
|
function sessionExportFile(dir, agent, sessionId) {
|
|
11695
11856
|
assertSessionKey(agent, sessionId);
|
|
11696
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
11958
|
-
import
|
|
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:
|
|
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 ?
|
|
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:
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
12731
|
+
readFile as readFile12,
|
|
12571
12732
|
realpath as realpath2,
|
|
12572
12733
|
rename as rename4,
|
|
12573
|
-
stat as
|
|
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
|
|
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 =
|
|
12756
|
+
const folder = path35.join(cwd, MEMORY_DIR);
|
|
12596
12757
|
const folderExists = await isDirectory2(folder);
|
|
12597
|
-
const indexExists = folderExists && await isFile(
|
|
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(
|
|
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
|
|
12808
|
+
const info = await stat18(absolute);
|
|
12648
12809
|
if (!info.isFile()) return null;
|
|
12649
|
-
const content = await
|
|
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 (
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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", "",
|
|
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(
|
|
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
|
|
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(
|
|
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 =
|
|
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) =>
|
|
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 =
|
|
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 =
|
|
13204
|
-
const geminiTarget =
|
|
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:
|
|
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:
|
|
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 =
|
|
13283
|
-
const absoluteCommonDir =
|
|
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 (
|
|
13288
|
-
const mainRoot =
|
|
13289
|
-
const inner =
|
|
13290
|
-
const sameFolder = inner.length === 0 || inner.startsWith("..") ||
|
|
13291
|
-
const mainPath = sameFolder ? mainRoot :
|
|
13292
|
-
const memoryRel = sameFolder ? MEMORY_DIR : [...inner.split(
|
|
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
|
|
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
|
|
13520
|
+
const info = await stat18(absolute);
|
|
13360
13521
|
if (!info.isFile()) throw new MemoryBridgeError(serverText("memoryNotAFile", { label }));
|
|
13361
|
-
return await
|
|
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
|
|
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
|
|
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:
|
|
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 =
|
|
13420
|
-
|
|
13421
|
-
`.${
|
|
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
|
|
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 =
|
|
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 =
|
|
13824
|
+
const relative = path36.relative(cwd, candidate);
|
|
13664
13825
|
if (relative.length === 0) return true;
|
|
13665
|
-
if (relative.startsWith("..") ||
|
|
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
|
|
13684
|
-
import
|
|
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(
|
|
14201
|
-
return style === "at-quoted" ? fileReference(
|
|
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 ??
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 =
|
|
14625
|
+
const full = path37.join(this.root, entry);
|
|
14492
14626
|
try {
|
|
14493
|
-
const info = await
|
|
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
|
|
14511
|
-
import
|
|
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
|
|
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:
|
|
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
|
|
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
|
|
15107
|
-
import
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
15355
|
-
import
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
15578
|
-
const temporary =
|
|
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
|
|
15593
|
-
import
|
|
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
|
|
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
|
|
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(
|
|
15793
|
-
const temporary =
|
|
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
|
|
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
|
|
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 =
|
|
15967
|
+
let dir = path42.win32.dirname(gitPath);
|
|
15834
15968
|
for (let level = 0; level < 3; level++) {
|
|
15835
|
-
candidates.push(
|
|
15836
|
-
const parent =
|
|
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 :
|
|
15842
|
-
if (base !== void 0 && base.length > 0) candidates.push(
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
16317
|
-
import
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
17278
|
+
const resolved = path44.resolve(target);
|
|
17145
17279
|
return dirs.some((dir) => {
|
|
17146
|
-
const protectedDir =
|
|
17147
|
-
return resolved === protectedDir || resolved.startsWith(protectedDir +
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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:
|
|
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
|
|
17314
|
-
import
|
|
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 =
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
17571
|
-
const fileName =
|
|
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
|
|
18294
|
+
import { mkdir as mkdir17, stat as stat29 } from "node:fs/promises";
|
|
18161
18295
|
import { homedir as homedir12 } from "node:os";
|
|
18162
|
-
import
|
|
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
|
|
18167
|
-
import
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
18368
|
+
const probe = temporaryPathFor(path46.join(dir, ".escritura"));
|
|
18235
18369
|
try {
|
|
18236
18370
|
await mkdir15(dir, { recursive: true });
|
|
18237
|
-
if (!(await
|
|
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
|
|
18341
|
-
import
|
|
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
|
|
18345
|
-
import
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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) =>
|
|
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(
|
|
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(
|
|
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 =
|
|
19175
|
+
const file = path48.join(folder, name);
|
|
19042
19176
|
try {
|
|
19043
|
-
const info = await
|
|
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(),
|
|
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
|
|
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
|
|
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(
|
|
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(
|
|
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 ?
|
|
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(
|
|
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
|
|
21084
|
-
import
|
|
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
|
|
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
|
|
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 =
|
|
21458
|
+
var serverDir = path51.dirname(fileURLToPath2(import.meta.url));
|
|
21325
21459
|
var isPackaged = true;
|
|
21326
|
-
var webRoot = isPackaged ? serverDir :
|
|
21327
|
-
var webDist = isPackaged ?
|
|
21328
|
-
var repoRoot =
|
|
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
|
|
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 =
|
|
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}.
|