agent-workbench 0.5.0 → 0.5.2
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 +487 -338
- package/dist/web/assets/de-Dn90shDf.js +1 -0
- package/dist/web/assets/es-ssi17uPF.js +1 -0
- package/dist/web/assets/fr-CqnouzuH.js +1 -0
- package/dist/web/assets/{highlight-DqX1MSlE.js → highlight-C6RpQUgN.js} +1 -1
- package/dist/web/assets/{index-CRZuxaEg.js → index-CrEDljyV.js} +44 -44
- package/dist/web/assets/index-zo2-uEwR.css +32 -0
- package/dist/web/assets/ja-1U-Ks_ON.js +1 -0
- package/dist/web/assets/ko-Ce2gOy44.js +1 -0
- package/dist/web/assets/pt-BR-BC8Km40N.js +1 -0
- package/dist/web/assets/ru-DFCLMfWY.js +1 -0
- package/dist/web/assets/zh-CN-VwZ7SeiK.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/index-B09L7LWU.css +0 -32
- 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",
|
|
@@ -4842,9 +4863,24 @@ function toPart(block, role, index, limits) {
|
|
|
4842
4863
|
const { text, truncated } = cut(cleaned, limits.textMaxChars);
|
|
4843
4864
|
return { kind: "text", text, truncated };
|
|
4844
4865
|
}
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4866
|
+
/*
|
|
4867
|
+
El contenido del razonamiento no esta en el JSONL: solo la firma. Se deja
|
|
4868
|
+
la marca de que hubo, sin prometer un texto que no existe.
|
|
4869
|
+
|
|
4870
|
+
**Salvo la nota para el usuario** (§4.9). Desde la CLI 2.1.278, alrededor
|
|
4871
|
+
de uno de cada diez bloques trae texto, y no es el razonamiento: es un
|
|
4872
|
+
aviso corto de lo que el agente encontro o va a hacer ("Encontre la
|
|
4873
|
+
causa: …"), en una linea propia detras de la del razonamiento vacio del
|
|
4874
|
+
mismo mensaje. La CLI lo dibuja como un mensaje mas, y aca va como texto:
|
|
4875
|
+
descartado con el resto del razonamiento, el hilo se lo perdia.
|
|
4876
|
+
*/
|
|
4877
|
+
case "thinking": {
|
|
4878
|
+
const raw = record["thinking"];
|
|
4879
|
+
const note = typeof raw === "string" ? raw.trim() : "";
|
|
4880
|
+
if (note.length === 0) return { kind: "thinking" };
|
|
4881
|
+
const { text, truncated } = cut(note, limits.textMaxChars);
|
|
4882
|
+
return { kind: "text", text, truncated };
|
|
4883
|
+
}
|
|
4848
4884
|
case "redacted_thinking":
|
|
4849
4885
|
return { kind: "thinking" };
|
|
4850
4886
|
case "tool_use": {
|
|
@@ -4916,9 +4952,18 @@ function toQueuedUserEvent(record, lineNumber, limits) {
|
|
|
4916
4952
|
if (!isHumanOrigin(attachmentRecord["origin"])) return null;
|
|
4917
4953
|
const prompt = attachmentRecord["prompt"];
|
|
4918
4954
|
if (typeof prompt !== "string") return null;
|
|
4919
|
-
const cleaned = cleanUserText(prompt);
|
|
4920
|
-
|
|
4921
|
-
|
|
4955
|
+
const { text: cleaned, images } = takePastedImages(cleanUserText(prompt));
|
|
4956
|
+
const parts = images.map((image, index) => ({
|
|
4957
|
+
kind: "image",
|
|
4958
|
+
index,
|
|
4959
|
+
mediaType: image.mediaType,
|
|
4960
|
+
source: "pasted"
|
|
4961
|
+
}));
|
|
4962
|
+
if (cleaned.length > 0) {
|
|
4963
|
+
const { text, truncated } = cut(cleaned, limits.textMaxChars);
|
|
4964
|
+
parts.push({ kind: "text", text, truncated });
|
|
4965
|
+
}
|
|
4966
|
+
if (parts.length === 0) return null;
|
|
4922
4967
|
const uuid = record["uuid"];
|
|
4923
4968
|
return {
|
|
4924
4969
|
eventId: typeof uuid === "string" && uuid.length > 0 ? uuid : `line-${lineNumber}`,
|
|
@@ -4926,7 +4971,7 @@ function toQueuedUserEvent(record, lineNumber, limits) {
|
|
|
4926
4971
|
// El `timestamp` de la linea es el de cuando se escribio, no el de cuando
|
|
4927
4972
|
// se absorbio. Es el que corresponde: es cuando el usuario lo mando.
|
|
4928
4973
|
at: readTimestamp(record["timestamp"] ?? attachmentRecord["timestamp"]),
|
|
4929
|
-
parts
|
|
4974
|
+
parts,
|
|
4930
4975
|
model: null,
|
|
4931
4976
|
usage: null,
|
|
4932
4977
|
effort: null,
|
|
@@ -4992,6 +5037,30 @@ function stripFileReference(text, filename) {
|
|
|
4992
5037
|
}
|
|
4993
5038
|
return text;
|
|
4994
5039
|
}
|
|
5040
|
+
function sameFilePath(a, b) {
|
|
5041
|
+
return normalizePath(a) === normalizePath(b);
|
|
5042
|
+
}
|
|
5043
|
+
function takePastedImages(text) {
|
|
5044
|
+
const images = [];
|
|
5045
|
+
const tokens = /(^|\s)@(?:"([^"]*)"|(\S+))/g;
|
|
5046
|
+
let match = tokens.exec(text);
|
|
5047
|
+
while (match !== null) {
|
|
5048
|
+
const raw = match[2] ?? match[3] ?? "";
|
|
5049
|
+
const mediaType = pastedImageMediaType(raw);
|
|
5050
|
+
if (mediaType !== null) images.push({ path: raw, mediaType });
|
|
5051
|
+
match = tokens.exec(text);
|
|
5052
|
+
}
|
|
5053
|
+
let rest = text;
|
|
5054
|
+
for (const image of images) rest = stripFileReference(rest, image.path);
|
|
5055
|
+
return { text: rest, images };
|
|
5056
|
+
}
|
|
5057
|
+
function queuedPastedImages(record) {
|
|
5058
|
+
const attachment = recordOf(record["attachment"]);
|
|
5059
|
+
if (attachment === null || attachment["type"] !== "queued_command") return [];
|
|
5060
|
+
const prompt = attachment["prompt"];
|
|
5061
|
+
if (typeof prompt !== "string") return [];
|
|
5062
|
+
return takePastedImages(cleanUserText(prompt)).images.map((image) => image.path);
|
|
5063
|
+
}
|
|
4995
5064
|
function toConversationEvent(record, lineNumber, limits = TRANSPORT_LIMITS) {
|
|
4996
5065
|
const type = record["type"];
|
|
4997
5066
|
if (record["isMeta"] === true) return null;
|
|
@@ -5069,7 +5138,7 @@ function documentRefOf(value, target) {
|
|
|
5069
5138
|
if (!value.toLowerCase().endsWith(".md")) return null;
|
|
5070
5139
|
if (value.includes("\0")) return null;
|
|
5071
5140
|
if (target.cwd.length === 0) return null;
|
|
5072
|
-
const absolute =
|
|
5141
|
+
const absolute = path17.isAbsolute(value) ? value : path17.resolve(target.cwd, value);
|
|
5073
5142
|
if (target.sessionId.length > 0) {
|
|
5074
5143
|
const inScratch = relativeInside(scratchRoot(target.cwd, target.sessionId), absolute);
|
|
5075
5144
|
if (inScratch !== null) return `tmp:${inScratch}`;
|
|
@@ -5078,15 +5147,15 @@ function documentRefOf(value, target) {
|
|
|
5078
5147
|
return inProject === null ? null : `proj:${inProject}`;
|
|
5079
5148
|
}
|
|
5080
5149
|
function relativeInside(root, absolute) {
|
|
5081
|
-
const relative =
|
|
5150
|
+
const relative = path17.relative(root, absolute);
|
|
5082
5151
|
if (relative.length === 0) return null;
|
|
5083
|
-
if (relative.startsWith("..") ||
|
|
5152
|
+
if (relative.startsWith("..") || path17.isAbsolute(relative)) {
|
|
5084
5153
|
if (process.platform !== "win32") return null;
|
|
5085
|
-
const lower =
|
|
5086
|
-
if (lower.length === 0 || lower.startsWith("..") ||
|
|
5087
|
-
return lower.split(
|
|
5154
|
+
const lower = path17.relative(root.toLowerCase(), absolute.toLowerCase());
|
|
5155
|
+
if (lower.length === 0 || lower.startsWith("..") || path17.isAbsolute(lower)) return null;
|
|
5156
|
+
return lower.split(path17.sep).join("/");
|
|
5088
5157
|
}
|
|
5089
|
-
return relative.split(
|
|
5158
|
+
return relative.split(path17.sep).join("/");
|
|
5090
5159
|
}
|
|
5091
5160
|
function planFileNameOf(value) {
|
|
5092
5161
|
if (typeof value !== "string" || value.length === 0) return null;
|
|
@@ -5636,13 +5705,50 @@ var ConversationFollower = class {
|
|
|
5636
5705
|
};
|
|
5637
5706
|
|
|
5638
5707
|
// packages/server/src/agents/claude-code/conversation-image.ts
|
|
5639
|
-
import { open as open5 } from "node:fs/promises";
|
|
5708
|
+
import { open as open5, readFile as readFile9, stat as stat10 } from "node:fs/promises";
|
|
5709
|
+
import path18 from "node:path";
|
|
5710
|
+
|
|
5711
|
+
// packages/server/src/image-signature.ts
|
|
5712
|
+
var FORMATS = [
|
|
5713
|
+
{
|
|
5714
|
+
format: { ext: "png", mediaType: "image/png" },
|
|
5715
|
+
test: (b) => b.length > 8 && b.subarray(0, 8).equals(Buffer.from("89504e470d0a1a0a", "hex"))
|
|
5716
|
+
},
|
|
5717
|
+
{
|
|
5718
|
+
format: { ext: "jpg", mediaType: "image/jpeg" },
|
|
5719
|
+
test: (b) => b.length > 3 && b[0] === 255 && b[1] === 216 && b[2] === 255
|
|
5720
|
+
},
|
|
5721
|
+
{
|
|
5722
|
+
format: { ext: "gif", mediaType: "image/gif" },
|
|
5723
|
+
test: (b) => b.length > 6 && b.subarray(0, 4).toString("ascii") === "GIF8"
|
|
5724
|
+
},
|
|
5725
|
+
{
|
|
5726
|
+
format: { ext: "webp", mediaType: "image/webp" },
|
|
5727
|
+
test: (b) => b.length > 12 && b.subarray(0, 4).toString("ascii") === "RIFF" && b.subarray(8, 12).toString("ascii") === "WEBP"
|
|
5728
|
+
}
|
|
5729
|
+
];
|
|
5730
|
+
var IMAGE_MEDIA_TYPES = new Set(
|
|
5731
|
+
FORMATS.map((entry) => entry.format.mediaType)
|
|
5732
|
+
);
|
|
5733
|
+
function detectImageFormat(bytes) {
|
|
5734
|
+
return FORMATS.find((entry) => entry.test(bytes))?.format ?? null;
|
|
5735
|
+
}
|
|
5736
|
+
|
|
5737
|
+
// packages/server/src/agents/claude-code/conversation-image.ts
|
|
5640
5738
|
var CHUNK_SIZE2 = 256 * 1024;
|
|
5641
5739
|
var NEWLINE2 = 10;
|
|
5642
5740
|
var MAX_IMAGE_BYTES = MAX_SUBMIT_IMAGE_BYTES;
|
|
5643
|
-
async function loadConversationImage(filePath, eventId, index, source = "content") {
|
|
5741
|
+
async function loadConversationImage(filePath, eventId, index, source = "content", pastedDir = pasteRoot()) {
|
|
5644
5742
|
const handle = await open5(filePath, "r").catch(() => null);
|
|
5645
5743
|
if (handle === null) return null;
|
|
5744
|
+
try {
|
|
5745
|
+
if (source === "pasted") return await findPastedImage(linesOf(handle), eventId, index, pastedDir);
|
|
5746
|
+
return await findInLines(linesOf(handle), eventId, index, source);
|
|
5747
|
+
} finally {
|
|
5748
|
+
await handle.close();
|
|
5749
|
+
}
|
|
5750
|
+
}
|
|
5751
|
+
async function findInLines(lines, eventId, index, source) {
|
|
5646
5752
|
let seen = 0;
|
|
5647
5753
|
const chain = /* @__PURE__ */ new Set([eventId]);
|
|
5648
5754
|
const consider = (line) => {
|
|
@@ -5665,56 +5771,126 @@ async function loadConversationImage(filePath, eventId, index, source = "content
|
|
|
5665
5771
|
if (typeof ownId === "string" && ownId.length > 0) chain.add(ownId);
|
|
5666
5772
|
return seen++ === index ? found : null;
|
|
5667
5773
|
};
|
|
5668
|
-
|
|
5669
|
-
const
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5774
|
+
for await (const line of lines) {
|
|
5775
|
+
const found = consider(line);
|
|
5776
|
+
if (found !== null) return found;
|
|
5777
|
+
}
|
|
5778
|
+
return null;
|
|
5779
|
+
}
|
|
5780
|
+
async function* linesOf(handle) {
|
|
5781
|
+
const buffer = Buffer.allocUnsafe(CHUNK_SIZE2);
|
|
5782
|
+
let pending = Buffer.alloc(0);
|
|
5783
|
+
let offset = 0;
|
|
5784
|
+
for (; ; ) {
|
|
5785
|
+
const { bytesRead } = await handle.read(buffer, 0, CHUNK_SIZE2, offset);
|
|
5786
|
+
if (bytesRead === 0) break;
|
|
5787
|
+
offset += bytesRead;
|
|
5788
|
+
const combined = Buffer.concat([pending, buffer.subarray(0, bytesRead)]);
|
|
5789
|
+
let start = 0;
|
|
5790
|
+
let newlineIndex = combined.indexOf(NEWLINE2, start);
|
|
5791
|
+
while (newlineIndex !== -1) {
|
|
5792
|
+
yield combined.subarray(start, newlineIndex).toString("utf8");
|
|
5793
|
+
start = newlineIndex + 1;
|
|
5794
|
+
newlineIndex = combined.indexOf(NEWLINE2, start);
|
|
5795
|
+
}
|
|
5796
|
+
pending = Buffer.from(combined.subarray(start));
|
|
5797
|
+
}
|
|
5798
|
+
if (pending.length > 0) yield pending.toString("utf8");
|
|
5799
|
+
}
|
|
5800
|
+
async function findPastedImage(lines, eventId, index, pastedDir) {
|
|
5801
|
+
let target = null;
|
|
5802
|
+
let readId = null;
|
|
5803
|
+
for await (const line of lines) {
|
|
5804
|
+
if (target === null) {
|
|
5805
|
+
if (!line.includes(eventId)) continue;
|
|
5806
|
+
const record = parseJsonlLine(line);
|
|
5807
|
+
if (record === null || record["uuid"] !== eventId) continue;
|
|
5808
|
+
target = queuedPastedImages(record)[index] ?? null;
|
|
5809
|
+
if (target === null) return null;
|
|
5810
|
+
const fromDisk = await readPastedFile(target, pastedDir);
|
|
5811
|
+
if (fromDisk !== null) return fromDisk;
|
|
5812
|
+
continue;
|
|
5813
|
+
}
|
|
5814
|
+
if (readId === null) {
|
|
5815
|
+
if (line.includes('"Read"')) readId = readToolUseOf(parseJsonlLine(line), target);
|
|
5816
|
+
continue;
|
|
5687
5817
|
}
|
|
5688
|
-
if (
|
|
5818
|
+
if (!line.includes(readId)) continue;
|
|
5819
|
+
const result = toolResultOf(parseJsonlLine(line), readId);
|
|
5820
|
+
if (result === null) continue;
|
|
5821
|
+
const content = result["content"];
|
|
5822
|
+
const image = Array.isArray(content) ? firstImage(content) : null;
|
|
5823
|
+
if (image !== null) return image;
|
|
5824
|
+
readId = null;
|
|
5825
|
+
}
|
|
5826
|
+
return null;
|
|
5827
|
+
}
|
|
5828
|
+
async function readPastedFile(target, pastedDir) {
|
|
5829
|
+
try {
|
|
5830
|
+
const inside = await resolveInside(pastedDir, path18.relative(pastedDir, target), { mustExist: true });
|
|
5831
|
+
const info = await stat10(inside);
|
|
5832
|
+
if (!info.isFile() || info.size === 0 || info.size > MAX_IMAGE_BYTES) return null;
|
|
5833
|
+
const bytes = await readFile9(inside);
|
|
5834
|
+
const format = detectImageFormat(bytes);
|
|
5835
|
+
return format === null ? null : { mediaType: format.mediaType, data: bytes.toString("base64") };
|
|
5836
|
+
} catch {
|
|
5689
5837
|
return null;
|
|
5690
|
-
} finally {
|
|
5691
|
-
await handle.close();
|
|
5692
5838
|
}
|
|
5693
5839
|
}
|
|
5840
|
+
function readToolUseOf(record, target) {
|
|
5841
|
+
if (record === null || record["type"] !== "assistant") return null;
|
|
5842
|
+
const content = recordOf(record["message"])?.["content"];
|
|
5843
|
+
if (!Array.isArray(content)) return null;
|
|
5844
|
+
for (const block of content) {
|
|
5845
|
+
const tool = recordOf(block);
|
|
5846
|
+
if (tool === null || tool["type"] !== "tool_use" || tool["name"] !== "Read") continue;
|
|
5847
|
+
const id = tool["id"];
|
|
5848
|
+
const filePath = recordOf(tool["input"])?.["file_path"];
|
|
5849
|
+
if (typeof id === "string" && id.length > 0 && typeof filePath === "string" && sameFilePath(filePath, target)) {
|
|
5850
|
+
return id;
|
|
5851
|
+
}
|
|
5852
|
+
}
|
|
5853
|
+
return null;
|
|
5854
|
+
}
|
|
5855
|
+
function toolResultOf(record, toolUseId) {
|
|
5856
|
+
if (record === null || record["type"] !== "user") return null;
|
|
5857
|
+
const content = recordOf(record["message"])?.["content"];
|
|
5858
|
+
if (!Array.isArray(content)) return null;
|
|
5859
|
+
for (const block of content) {
|
|
5860
|
+
const result = recordOf(block);
|
|
5861
|
+
if (result !== null && result["type"] === "tool_result" && result["tool_use_id"] === toolUseId) return result;
|
|
5862
|
+
}
|
|
5863
|
+
return null;
|
|
5864
|
+
}
|
|
5694
5865
|
function tooBig(data) {
|
|
5695
5866
|
return data.length > MAX_IMAGE_BYTES * 1.4;
|
|
5696
5867
|
}
|
|
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"];
|
|
5868
|
+
function imageFromBlock(value) {
|
|
5869
|
+
const block = recordOf(value);
|
|
5870
|
+
if (block === null || block["type"] !== "image") return null;
|
|
5871
|
+
const source = recordOf(block["source"]);
|
|
5872
|
+
if (source === null) return null;
|
|
5873
|
+
const data = source["data"];
|
|
5874
|
+
const mediaType = source["media_type"];
|
|
5712
5875
|
if (typeof data !== "string" || data.length === 0 || tooBig(data)) return null;
|
|
5713
5876
|
return {
|
|
5714
5877
|
mediaType: typeof mediaType === "string" ? mediaType : "image/png",
|
|
5715
5878
|
data
|
|
5716
5879
|
};
|
|
5717
5880
|
}
|
|
5881
|
+
function firstImage(blocks) {
|
|
5882
|
+
for (const block of blocks) {
|
|
5883
|
+
const image = imageFromBlock(block);
|
|
5884
|
+
if (image !== null) return image;
|
|
5885
|
+
}
|
|
5886
|
+
return null;
|
|
5887
|
+
}
|
|
5888
|
+
function imageFromContent(record, eventId, index) {
|
|
5889
|
+
if (record["uuid"] !== eventId) return null;
|
|
5890
|
+
const content = recordOf(record["message"])?.["content"];
|
|
5891
|
+
if (!Array.isArray(content)) return null;
|
|
5892
|
+
return imageFromBlock(content[index]);
|
|
5893
|
+
}
|
|
5718
5894
|
function imageFromAttachment(record) {
|
|
5719
5895
|
if (record["type"] !== "attachment") return null;
|
|
5720
5896
|
const attachment = record["attachment"];
|
|
@@ -5786,7 +5962,7 @@ var ClaudeCodeSessionFollower = class {
|
|
|
5786
5962
|
}
|
|
5787
5963
|
noticeChange(filePath) {
|
|
5788
5964
|
if (isSameFilePath(this.inner.filePath, filePath, process.platform)) return true;
|
|
5789
|
-
if (this.inner.getState() === "waiting" &&
|
|
5965
|
+
if (this.inner.getState() === "waiting" && path19.basename(filePath).toLowerCase() === `${this.sessionId.toLowerCase()}.jsonl`) {
|
|
5790
5966
|
console.warn(
|
|
5791
5967
|
`[conversation] session ${this.sessionId.slice(0, 8)} wrote to ${filePath}, not to the computed path; moving there.`
|
|
5792
5968
|
);
|
|
@@ -5833,7 +6009,7 @@ var ClaudeCodeSessionFollower = class {
|
|
|
5833
6009
|
};
|
|
5834
6010
|
|
|
5835
6011
|
// packages/server/src/agents/claude-code/session-scan.ts
|
|
5836
|
-
import { stat as
|
|
6012
|
+
import { stat as stat11 } from "node:fs/promises";
|
|
5837
6013
|
var HEAD_MAX_LINES = 40;
|
|
5838
6014
|
var HEAD_MAX_BYTES = 512 * 1024;
|
|
5839
6015
|
var TAIL_MAX_BYTES = 64 * 1024;
|
|
@@ -5858,7 +6034,7 @@ function isRealUserMessage(record) {
|
|
|
5858
6034
|
return true;
|
|
5859
6035
|
}
|
|
5860
6036
|
async function scanSessionFile(filePath, sessionId) {
|
|
5861
|
-
const info = await
|
|
6037
|
+
const info = await stat11(filePath);
|
|
5862
6038
|
const [headLines, tailLines] = await Promise.all([
|
|
5863
6039
|
readHeadLines(filePath, { maxLines: HEAD_MAX_LINES, maxBytes: HEAD_MAX_BYTES }),
|
|
5864
6040
|
readTailLines(filePath, { maxBytes: TAIL_MAX_BYTES })
|
|
@@ -5931,7 +6107,7 @@ async function scanSessionFile(filePath, sessionId) {
|
|
|
5931
6107
|
var SESSION_EXTENSION = /\.jsonl$/i;
|
|
5932
6108
|
async function pathExists(candidate) {
|
|
5933
6109
|
try {
|
|
5934
|
-
await
|
|
6110
|
+
await stat12(candidate);
|
|
5935
6111
|
return true;
|
|
5936
6112
|
} catch {
|
|
5937
6113
|
return false;
|
|
@@ -5940,8 +6116,8 @@ async function pathExists(candidate) {
|
|
|
5940
6116
|
function toItem(ref, info) {
|
|
5941
6117
|
return {
|
|
5942
6118
|
ref,
|
|
5943
|
-
sessionId:
|
|
5944
|
-
group:
|
|
6119
|
+
sessionId: path20.basename(ref).replace(SESSION_EXTENSION, ""),
|
|
6120
|
+
group: path20.basename(path20.dirname(ref)),
|
|
5945
6121
|
mtimeMs: info.mtimeMs,
|
|
5946
6122
|
sizeBytes: info.size
|
|
5947
6123
|
};
|
|
@@ -5971,14 +6147,14 @@ function createClaudeCodeHistory(variants) {
|
|
|
5971
6147
|
for (const slug of directories) {
|
|
5972
6148
|
let files;
|
|
5973
6149
|
try {
|
|
5974
|
-
files = (await readdir7(
|
|
6150
|
+
files = (await readdir7(path20.join(root, slug))).filter((name) => name.endsWith(".jsonl"));
|
|
5975
6151
|
} catch {
|
|
5976
6152
|
continue;
|
|
5977
6153
|
}
|
|
5978
6154
|
for (const file of files) {
|
|
5979
|
-
const ref =
|
|
6155
|
+
const ref = path20.join(root, slug, file);
|
|
5980
6156
|
try {
|
|
5981
|
-
items.push(toItem(ref, await
|
|
6157
|
+
items.push(toItem(ref, await stat12(ref)));
|
|
5982
6158
|
} catch {
|
|
5983
6159
|
}
|
|
5984
6160
|
}
|
|
@@ -5986,15 +6162,15 @@ function createClaudeCodeHistory(variants) {
|
|
|
5986
6162
|
return items;
|
|
5987
6163
|
},
|
|
5988
6164
|
async changedRefs(filePath) {
|
|
5989
|
-
const relative =
|
|
5990
|
-
const [slug] = relative.split(
|
|
6165
|
+
const relative = path20.relative(sessionsRoot(), filePath);
|
|
6166
|
+
const [slug] = relative.split(path20.sep);
|
|
5991
6167
|
if (slug === void 0 || slug.length === 0 || slug.startsWith("..")) return null;
|
|
5992
6168
|
if (!filePath.endsWith(".jsonl")) return null;
|
|
5993
6169
|
return [filePath];
|
|
5994
6170
|
},
|
|
5995
6171
|
async item(ref) {
|
|
5996
6172
|
try {
|
|
5997
|
-
return toItem(ref, await
|
|
6173
|
+
return toItem(ref, await stat12(ref));
|
|
5998
6174
|
} catch {
|
|
5999
6175
|
return null;
|
|
6000
6176
|
}
|
|
@@ -6181,18 +6357,18 @@ function createClaudeCodeAdapter() {
|
|
|
6181
6357
|
status,
|
|
6182
6358
|
defaults: (cwd) => readAgentDefaults(cwd),
|
|
6183
6359
|
/** La carpeta de la CLI. No se lista ni se entra: regla 2.1. */
|
|
6184
|
-
protectedDirs: () => [
|
|
6360
|
+
protectedDirs: () => [path21.join(homedir5(), ".claude")],
|
|
6185
6361
|
dispose: () => status.dispose()
|
|
6186
6362
|
};
|
|
6187
6363
|
}
|
|
6188
6364
|
|
|
6189
6365
|
// packages/server/src/agents/codex/index.ts
|
|
6190
6366
|
import { homedir as homedir7 } from "node:os";
|
|
6191
|
-
import
|
|
6367
|
+
import path27 from "node:path";
|
|
6192
6368
|
|
|
6193
6369
|
// packages/server/src/agents/codex/discovery.ts
|
|
6194
|
-
import { stat as
|
|
6195
|
-
import
|
|
6370
|
+
import { stat as stat13 } from "node:fs/promises";
|
|
6371
|
+
import path24 from "node:path";
|
|
6196
6372
|
|
|
6197
6373
|
// packages/server/src/debug.ts
|
|
6198
6374
|
var enabled = process.env["AGENT_WORKBENCH_DEBUG"] === "1";
|
|
@@ -6203,11 +6379,11 @@ function debugLog(scope, message) {
|
|
|
6203
6379
|
|
|
6204
6380
|
// packages/server/src/agents/codex/find-rollout.ts
|
|
6205
6381
|
import { readdir as readdir8 } from "node:fs/promises";
|
|
6206
|
-
import
|
|
6382
|
+
import path23 from "node:path";
|
|
6207
6383
|
|
|
6208
6384
|
// packages/server/src/agents/codex/paths.ts
|
|
6209
6385
|
import { homedir as homedir6 } from "node:os";
|
|
6210
|
-
import
|
|
6386
|
+
import path22 from "node:path";
|
|
6211
6387
|
var INTERACTIVE_SOURCES = ["cli", "vscode"];
|
|
6212
6388
|
var LISTED_HISTORY_MODES = ["legacy", "paginated"];
|
|
6213
6389
|
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 +6395,13 @@ function isUuid(value) {
|
|
|
6219
6395
|
}
|
|
6220
6396
|
var warnedHomes = /* @__PURE__ */ new Set();
|
|
6221
6397
|
function isFullyQualified(candidate) {
|
|
6222
|
-
if (!
|
|
6398
|
+
if (!path22.isAbsolute(candidate)) return false;
|
|
6223
6399
|
return process.platform !== "win32" || /^([a-zA-Z]:[\\/]|[\\/]{2})/.test(candidate);
|
|
6224
6400
|
}
|
|
6225
6401
|
function codexHome() {
|
|
6226
6402
|
const configured = process.env["CODEX_HOME"];
|
|
6227
6403
|
if (configured === void 0 || configured.length === 0) {
|
|
6228
|
-
return
|
|
6404
|
+
return path22.join(homedir6(), ".codex");
|
|
6229
6405
|
}
|
|
6230
6406
|
if (isFullyQualified(configured)) return configured;
|
|
6231
6407
|
if (!warnedHomes.has(configured)) {
|
|
@@ -6238,11 +6414,11 @@ function codexHome() {
|
|
|
6238
6414
|
}
|
|
6239
6415
|
function codexSessionsRoot() {
|
|
6240
6416
|
const home = codexHome();
|
|
6241
|
-
return home === null ? null :
|
|
6417
|
+
return home === null ? null : path22.join(home, "sessions");
|
|
6242
6418
|
}
|
|
6243
6419
|
function codexArchivedRoot() {
|
|
6244
6420
|
const home = codexHome();
|
|
6245
|
-
return home === null ? null :
|
|
6421
|
+
return home === null ? null : path22.join(home, "archived_sessions");
|
|
6246
6422
|
}
|
|
6247
6423
|
function parseRolloutFileName(name) {
|
|
6248
6424
|
const match = ROLLOUT_FILE_PATTERN.exec(name);
|
|
@@ -6269,7 +6445,7 @@ function localDayFolder(root, epochMs) {
|
|
|
6269
6445
|
const year = String(date.getFullYear()).padStart(4, "0");
|
|
6270
6446
|
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
6271
6447
|
const day = String(date.getDate()).padStart(2, "0");
|
|
6272
|
-
return
|
|
6448
|
+
return path22.join(root, year, month, day);
|
|
6273
6449
|
}
|
|
6274
6450
|
function localDayFolders(root, fromMs, toMs) {
|
|
6275
6451
|
const folders = [];
|
|
@@ -6301,14 +6477,14 @@ async function numberedFolders(folder, pattern) {
|
|
|
6301
6477
|
return (await entriesOf(folder)).filter((entry) => entry.isDirectory() && pattern.test(entry.name)).map((entry) => entry.name).sort();
|
|
6302
6478
|
}
|
|
6303
6479
|
async function rolloutFilesIn(folder) {
|
|
6304
|
-
return (await entriesOf(folder)).filter((entry) => entry.isFile() && parseRolloutFileName(entry.name) !== null).map((entry) => entry.name).sort().map((name) =>
|
|
6480
|
+
return (await entriesOf(folder)).filter((entry) => entry.isFile() && parseRolloutFileName(entry.name) !== null).map((entry) => entry.name).sort().map((name) => path23.join(folder, name));
|
|
6305
6481
|
}
|
|
6306
6482
|
async function walkSessionFiles(root, limit = Number.POSITIVE_INFINITY) {
|
|
6307
6483
|
const files = [];
|
|
6308
6484
|
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(
|
|
6485
|
+
for (const month of await numberedFolders(path23.join(root, year), TWO_DIGITS)) {
|
|
6486
|
+
for (const day of await numberedFolders(path23.join(root, year, month), TWO_DIGITS)) {
|
|
6487
|
+
for (const file of await rolloutFilesIn(path23.join(root, year, month, day))) {
|
|
6312
6488
|
files.push(file);
|
|
6313
6489
|
if (files.length >= limit) return files;
|
|
6314
6490
|
}
|
|
@@ -6319,7 +6495,7 @@ async function walkSessionFiles(root, limit = Number.POSITIVE_INFINITY) {
|
|
|
6319
6495
|
}
|
|
6320
6496
|
function matching(files, sessionId) {
|
|
6321
6497
|
for (const file of files) {
|
|
6322
|
-
if (parseRolloutFileName(
|
|
6498
|
+
if (parseRolloutFileName(path23.basename(file))?.sessionId === sessionId) return file;
|
|
6323
6499
|
}
|
|
6324
6500
|
return null;
|
|
6325
6501
|
}
|
|
@@ -6687,7 +6863,7 @@ var CodexSessionDiscovery = class {
|
|
|
6687
6863
|
if (this.seen.has(filePath)) continue;
|
|
6688
6864
|
let info;
|
|
6689
6865
|
try {
|
|
6690
|
-
info = await
|
|
6866
|
+
info = await stat13(filePath);
|
|
6691
6867
|
} catch {
|
|
6692
6868
|
continue;
|
|
6693
6869
|
}
|
|
@@ -6726,7 +6902,7 @@ var CodexSessionDiscovery = class {
|
|
|
6726
6902
|
this.stopTimerIfIdle();
|
|
6727
6903
|
}
|
|
6728
6904
|
async readHead(filePath, size) {
|
|
6729
|
-
const name = parseRolloutFileName(
|
|
6905
|
+
const name = parseRolloutFileName(path24.basename(filePath));
|
|
6730
6906
|
if (name === null) return { kind: "rejected" };
|
|
6731
6907
|
let lines;
|
|
6732
6908
|
try {
|
|
@@ -6774,8 +6950,8 @@ var CodexSessionDiscovery = class {
|
|
|
6774
6950
|
};
|
|
6775
6951
|
|
|
6776
6952
|
// packages/server/src/agents/codex/history.ts
|
|
6777
|
-
import { stat as
|
|
6778
|
-
import
|
|
6953
|
+
import { stat as stat14 } from "node:fs/promises";
|
|
6954
|
+
import path26 from "node:path";
|
|
6779
6955
|
|
|
6780
6956
|
// packages/server/src/agents/codex/rollout-scan.ts
|
|
6781
6957
|
var TAIL_MAX_BYTES2 = 256 * 1024;
|
|
@@ -6849,7 +7025,7 @@ async function scanRollout(item) {
|
|
|
6849
7025
|
}
|
|
6850
7026
|
|
|
6851
7027
|
// packages/server/src/agents/codex/session-follower.ts
|
|
6852
|
-
import
|
|
7028
|
+
import path25 from "node:path";
|
|
6853
7029
|
|
|
6854
7030
|
// packages/server/src/agents/codex/rollout-image.ts
|
|
6855
7031
|
import { createReadStream } from "node:fs";
|
|
@@ -7217,7 +7393,7 @@ var CodexSessionFollower = class {
|
|
|
7217
7393
|
return own === filePath || normalizeCwdKey(own, process.platform) === normalizeCwdKey(filePath, process.platform);
|
|
7218
7394
|
}
|
|
7219
7395
|
if (this.sessionId.length === 0) return false;
|
|
7220
|
-
if (parseRolloutFileName(
|
|
7396
|
+
if (parseRolloutFileName(path25.basename(filePath))?.sessionId !== this.sessionId.toLowerCase()) return false;
|
|
7221
7397
|
this.jsonl.setPath(filePath);
|
|
7222
7398
|
return true;
|
|
7223
7399
|
}
|
|
@@ -7255,26 +7431,26 @@ var CodexSessionFollower = class {
|
|
|
7255
7431
|
// packages/server/src/agents/codex/history.ts
|
|
7256
7432
|
async function pathExists2(candidate) {
|
|
7257
7433
|
try {
|
|
7258
|
-
await
|
|
7434
|
+
await stat14(candidate);
|
|
7259
7435
|
return true;
|
|
7260
7436
|
} catch {
|
|
7261
7437
|
return false;
|
|
7262
7438
|
}
|
|
7263
7439
|
}
|
|
7264
|
-
var accepts = (filePath) => ROLLOUT_FILE_PATTERN.test(
|
|
7440
|
+
var accepts = (filePath) => ROLLOUT_FILE_PATTERN.test(path26.basename(filePath));
|
|
7265
7441
|
var CODEX_FOLLOW_POLL_MS = 1e3;
|
|
7266
7442
|
function isInside2(root, filePath) {
|
|
7267
|
-
const relative =
|
|
7268
|
-
return relative.length > 0 && !relative.startsWith("..") && !
|
|
7443
|
+
const relative = path26.relative(root, filePath);
|
|
7444
|
+
return relative.length > 0 && !relative.startsWith("..") && !path26.isAbsolute(relative);
|
|
7269
7445
|
}
|
|
7270
7446
|
function toItem2(ref, info) {
|
|
7271
|
-
const name = parseRolloutFileName(
|
|
7447
|
+
const name = parseRolloutFileName(path26.basename(ref));
|
|
7272
7448
|
if (name === null) return null;
|
|
7273
7449
|
return { ref, sessionId: name.sessionId, group: name.sessionId, mtimeMs: info.mtimeMs, sizeBytes: info.size };
|
|
7274
7450
|
}
|
|
7275
7451
|
async function itemOf(ref) {
|
|
7276
7452
|
try {
|
|
7277
|
-
return toItem2(ref, await
|
|
7453
|
+
return toItem2(ref, await stat14(ref));
|
|
7278
7454
|
} catch {
|
|
7279
7455
|
return null;
|
|
7280
7456
|
}
|
|
@@ -7468,7 +7644,7 @@ function createCodexAdapter() {
|
|
|
7468
7644
|
* credenciales de antes de cambiarla.
|
|
7469
7645
|
*/
|
|
7470
7646
|
protectedDirs: () => {
|
|
7471
|
-
const dirs = [
|
|
7647
|
+
const dirs = [path27.join(homedir7(), ".codex")];
|
|
7472
7648
|
const home = codexHome();
|
|
7473
7649
|
if (home !== null && !dirs.includes(home)) dirs.unshift(home);
|
|
7474
7650
|
return dirs;
|
|
@@ -7661,7 +7837,7 @@ var DbChangeSignal = class {
|
|
|
7661
7837
|
};
|
|
7662
7838
|
|
|
7663
7839
|
// packages/server/src/agents/opencode/history.ts
|
|
7664
|
-
import { stat as
|
|
7840
|
+
import { stat as stat15 } from "node:fs/promises";
|
|
7665
7841
|
|
|
7666
7842
|
// packages/server/src/agents/opencode/events.ts
|
|
7667
7843
|
var TOOL_INPUT_PARSE_MAX_CHARS = 16e3;
|
|
@@ -8612,7 +8788,7 @@ function createOpenCodeHistory(deps) {
|
|
|
8612
8788
|
async rootExists() {
|
|
8613
8789
|
if (dbFile === null) return false;
|
|
8614
8790
|
try {
|
|
8615
|
-
await
|
|
8791
|
+
await stat15(dbFile);
|
|
8616
8792
|
return true;
|
|
8617
8793
|
} catch {
|
|
8618
8794
|
return false;
|
|
@@ -8644,13 +8820,13 @@ function createOpenCodeHistory(deps) {
|
|
|
8644
8820
|
var OPENCODE_SESSION_ID_PATTERN = /^ses_[0-9A-Za-z]{20,40}$/;
|
|
8645
8821
|
|
|
8646
8822
|
// packages/server/src/agents/opencode/paths.ts
|
|
8647
|
-
import
|
|
8823
|
+
import path28 from "node:path";
|
|
8648
8824
|
function isFullyQualified2(candidate, platform) {
|
|
8649
8825
|
if (platform === "win32") return /^([a-zA-Z]:[\\/]|[\\/]{2})/.test(candidate);
|
|
8650
|
-
return
|
|
8826
|
+
return path28.posix.isAbsolute(candidate);
|
|
8651
8827
|
}
|
|
8652
8828
|
function resolveOpenCodePaths(env, home, platform) {
|
|
8653
|
-
const flavor = platform === "win32" ?
|
|
8829
|
+
const flavor = platform === "win32" ? path28.win32 : path28.posix;
|
|
8654
8830
|
const variable = (name) => {
|
|
8655
8831
|
const value = env[name];
|
|
8656
8832
|
return value === void 0 || value.length === 0 ? null : value;
|
|
@@ -9098,8 +9274,8 @@ function launchWithServe(deps, input) {
|
|
|
9098
9274
|
import { execFile as execFile2, spawn as nodeSpawn } from "node:child_process";
|
|
9099
9275
|
import { randomBytes } from "node:crypto";
|
|
9100
9276
|
import { mkdir as mkdir4 } from "node:fs/promises";
|
|
9101
|
-
import { tmpdir as
|
|
9102
|
-
import
|
|
9277
|
+
import { tmpdir as tmpdir4 } from "node:os";
|
|
9278
|
+
import path29 from "node:path";
|
|
9103
9279
|
var OPENCODE_SERVE_HOST = "127.0.0.1";
|
|
9104
9280
|
var OPENCODE_SERVE_START_TIMEOUT_MS = 2e4;
|
|
9105
9281
|
var OPENCODE_SERVE_IDLE_STOP_MS = 3e5;
|
|
@@ -9131,7 +9307,7 @@ function parseListeningLine(line) {
|
|
|
9131
9307
|
return `http://${OPENCODE_SERVE_HOST}:${found.port}`;
|
|
9132
9308
|
}
|
|
9133
9309
|
function defaultServeCwd() {
|
|
9134
|
-
return
|
|
9310
|
+
return path29.join(tmpdir4(), "agent-workbench", "opencode-serve");
|
|
9135
9311
|
}
|
|
9136
9312
|
var ServeStartError = class extends Error {
|
|
9137
9313
|
};
|
|
@@ -10366,7 +10542,7 @@ async function migrateLegacyConfigDir() {
|
|
|
10366
10542
|
|
|
10367
10543
|
// packages/server/src/conversation-hub.ts
|
|
10368
10544
|
import { EventEmitter } from "node:events";
|
|
10369
|
-
import
|
|
10545
|
+
import path30 from "node:path";
|
|
10370
10546
|
var INITIAL_EVENT_LIMIT = 300;
|
|
10371
10547
|
var MAX_PAGE_LIMIT = 500;
|
|
10372
10548
|
var PENDING_QUESTION_LOOKBACK = 50;
|
|
@@ -10427,7 +10603,7 @@ var ConversationHub = class extends EventEmitter {
|
|
|
10427
10603
|
await entry.follower.start();
|
|
10428
10604
|
debugLog(
|
|
10429
10605
|
"conversation",
|
|
10430
|
-
`following ${
|
|
10606
|
+
`following ${path30.basename(entry.follower.label)} for ${terminalId.slice(0, 8)}`
|
|
10431
10607
|
);
|
|
10432
10608
|
entry = this.entries.get(terminalId) ?? entry;
|
|
10433
10609
|
}
|
|
@@ -10592,7 +10768,7 @@ var ConversationHub = class extends EventEmitter {
|
|
|
10592
10768
|
this.startFollowTicker(terminalId, next);
|
|
10593
10769
|
debugLog(
|
|
10594
10770
|
"conversation",
|
|
10595
|
-
`${terminalId.slice(0, 8)} changed session: following ${
|
|
10771
|
+
`${terminalId.slice(0, 8)} changed session: following ${path30.basename(next.follower.label)}`
|
|
10596
10772
|
);
|
|
10597
10773
|
await next.follower.start();
|
|
10598
10774
|
next.primed = true;
|
|
@@ -10956,18 +11132,18 @@ function openBrowser(url) {
|
|
|
10956
11132
|
// packages/server/src/pty-helper.ts
|
|
10957
11133
|
import { chmodSync, statSync } from "node:fs";
|
|
10958
11134
|
import { createRequire } from "node:module";
|
|
10959
|
-
import
|
|
11135
|
+
import path31 from "node:path";
|
|
10960
11136
|
function helperCandidates(packageDir, platform, arch) {
|
|
10961
11137
|
return [
|
|
10962
|
-
|
|
10963
|
-
|
|
10964
|
-
|
|
11138
|
+
path31.join(packageDir, "build", "Release", "spawn-helper"),
|
|
11139
|
+
path31.join(packageDir, "build", "Debug", "spawn-helper"),
|
|
11140
|
+
path31.join(packageDir, "prebuilds", `${platform}-${arch}`, "spawn-helper")
|
|
10965
11141
|
];
|
|
10966
11142
|
}
|
|
10967
11143
|
function locateNodePty() {
|
|
10968
11144
|
try {
|
|
10969
11145
|
const require2 = createRequire(import.meta.url);
|
|
10970
|
-
return
|
|
11146
|
+
return path31.resolve(path31.dirname(require2.resolve("node-pty")), "..");
|
|
10971
11147
|
} catch {
|
|
10972
11148
|
return null;
|
|
10973
11149
|
}
|
|
@@ -11628,24 +11804,24 @@ var RemoteAccessService = class {
|
|
|
11628
11804
|
};
|
|
11629
11805
|
|
|
11630
11806
|
// packages/server/src/remote-devices-store.ts
|
|
11631
|
-
import { chmod, mkdir as mkdir6, readFile as
|
|
11632
|
-
import
|
|
11807
|
+
import { chmod, mkdir as mkdir6, readFile as readFile10, stat as stat17 } from "node:fs/promises";
|
|
11808
|
+
import path33 from "node:path";
|
|
11633
11809
|
|
|
11634
11810
|
// packages/server/src/vault/write.ts
|
|
11635
11811
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
11636
|
-
import { mkdir as mkdir5, rename as rename3, rm as rm2, stat as
|
|
11812
|
+
import { mkdir as mkdir5, rename as rename3, rm as rm2, stat as stat16, writeFile as writeFile3 } from "node:fs/promises";
|
|
11637
11813
|
|
|
11638
11814
|
// packages/server/src/vault/paths.ts
|
|
11639
11815
|
import { createHash as createHash2 } from "node:crypto";
|
|
11640
|
-
import
|
|
11816
|
+
import path32 from "node:path";
|
|
11641
11817
|
function defaultVaultDir() {
|
|
11642
|
-
return
|
|
11818
|
+
return path32.join(appConfigDir(), "vault");
|
|
11643
11819
|
}
|
|
11644
11820
|
function vaultMarkerFile(dir) {
|
|
11645
|
-
return
|
|
11821
|
+
return path32.join(dir, "vault.json");
|
|
11646
11822
|
}
|
|
11647
11823
|
function sessionsRoot2(dir) {
|
|
11648
|
-
return
|
|
11824
|
+
return path32.join(dir, "sessions");
|
|
11649
11825
|
}
|
|
11650
11826
|
function isSafeSessionId(sessionId) {
|
|
11651
11827
|
return isVaultSessionId(sessionId);
|
|
@@ -11659,41 +11835,41 @@ function assertSessionKey(agent, sessionId) {
|
|
|
11659
11835
|
}
|
|
11660
11836
|
function agentSessionsDir(dir, agent) {
|
|
11661
11837
|
if (!isSessionAgentId(agent)) throw new Error(`Unknown source for the local copy: ${JSON.stringify(agent)}`);
|
|
11662
|
-
return
|
|
11838
|
+
return path32.join(sessionsRoot2(dir), agent);
|
|
11663
11839
|
}
|
|
11664
11840
|
function sessionFile(dir, agent, sessionId) {
|
|
11665
11841
|
assertSessionKey(agent, sessionId);
|
|
11666
|
-
return
|
|
11842
|
+
return path32.join(sessionsRoot2(dir), agent, `${sessionId}.jsonl`);
|
|
11667
11843
|
}
|
|
11668
11844
|
function assetsDir(dir, agent, sessionId) {
|
|
11669
11845
|
assertSessionKey(agent, sessionId);
|
|
11670
|
-
return
|
|
11846
|
+
return path32.join(sessionsRoot2(dir), agent, `${sessionId}.assets`);
|
|
11671
11847
|
}
|
|
11672
11848
|
function assetFile(dir, agent, sessionId, asset) {
|
|
11673
11849
|
if (!VAULT_ASSET_NAME_PATTERN.test(asset)) throw new Error(`Invalid asset name: ${JSON.stringify(asset)}`);
|
|
11674
|
-
return
|
|
11850
|
+
return path32.join(assetsDir(dir, agent, sessionId), asset);
|
|
11675
11851
|
}
|
|
11676
11852
|
function projectFolderName(cwd, platform) {
|
|
11677
11853
|
const hash = createHash2("sha256").update(normalizeCwdKey(cwd, platform)).digest("hex").slice(0, 8);
|
|
11678
|
-
const base = (platform === "win32" ?
|
|
11854
|
+
const base = (platform === "win32" ? path32.win32 : path32.posix).basename(cwd);
|
|
11679
11855
|
const name = base.length === 0 ? "proyecto" : sanitizeFileName(base, 60);
|
|
11680
11856
|
return `${name}-${hash}`;
|
|
11681
11857
|
}
|
|
11682
11858
|
function memoryDir(dir, cwd, platform) {
|
|
11683
|
-
return
|
|
11859
|
+
return path32.join(dir, "memory", projectFolderName(cwd, platform));
|
|
11684
11860
|
}
|
|
11685
11861
|
function projectExportDir(dir, cwd, platform) {
|
|
11686
|
-
return
|
|
11862
|
+
return path32.join(dir, "export", projectFolderName(cwd, platform));
|
|
11687
11863
|
}
|
|
11688
11864
|
function projectExportDirFor(dir, project, platform) {
|
|
11689
11865
|
if (project.cwd.length > 0) return projectExportDir(dir, project.cwd, platform);
|
|
11690
11866
|
const hash = createHash2("sha256").update(project.key).digest("hex").slice(0, 8);
|
|
11691
11867
|
const name = project.fallbackName.length > 0 ? sanitizeFileName(project.fallbackName, 60) : "proyecto";
|
|
11692
|
-
return
|
|
11868
|
+
return path32.join(dir, "export", `${name}-${hash}`);
|
|
11693
11869
|
}
|
|
11694
11870
|
function sessionExportFile(dir, agent, sessionId) {
|
|
11695
11871
|
assertSessionKey(agent, sessionId);
|
|
11696
|
-
return
|
|
11872
|
+
return path32.join(dir, "export", "sesiones", `${agent}-${sessionId}.md`);
|
|
11697
11873
|
}
|
|
11698
11874
|
var RESERVED_WINDOWS_NAME = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/i;
|
|
11699
11875
|
function sanitizeFileName(text, max = 80) {
|
|
@@ -11748,7 +11924,7 @@ async function writeFileAtomic(target, data, deps = DEFAULT_WRITE_DEPS) {
|
|
|
11748
11924
|
async function ensureVaultMarker(dir, deps = DEFAULT_WRITE_DEPS) {
|
|
11749
11925
|
const marker = vaultMarkerFile(dir);
|
|
11750
11926
|
try {
|
|
11751
|
-
await
|
|
11927
|
+
await stat16(marker);
|
|
11752
11928
|
return;
|
|
11753
11929
|
} catch {
|
|
11754
11930
|
}
|
|
@@ -11758,7 +11934,7 @@ async function ensureVaultMarker(dir, deps = DEFAULT_WRITE_DEPS) {
|
|
|
11758
11934
|
}
|
|
11759
11935
|
async function assetPresent(file, size) {
|
|
11760
11936
|
try {
|
|
11761
|
-
const info = await
|
|
11937
|
+
const info = await stat16(file);
|
|
11762
11938
|
return info.isFile() && info.size === size;
|
|
11763
11939
|
} catch {
|
|
11764
11940
|
return false;
|
|
@@ -11800,7 +11976,7 @@ var RemoteDevicesStore = class {
|
|
|
11800
11976
|
async load() {
|
|
11801
11977
|
let raw;
|
|
11802
11978
|
try {
|
|
11803
|
-
raw = await
|
|
11979
|
+
raw = await readFile10(this.filePath, "utf8");
|
|
11804
11980
|
} catch {
|
|
11805
11981
|
return [];
|
|
11806
11982
|
}
|
|
@@ -11821,7 +11997,7 @@ var RemoteDevicesStore = class {
|
|
|
11821
11997
|
save(devices) {
|
|
11822
11998
|
const text = serializeRemoteDevices(devices);
|
|
11823
11999
|
const run = async () => {
|
|
11824
|
-
await mkdir6(
|
|
12000
|
+
await mkdir6(path33.dirname(this.filePath), { recursive: true });
|
|
11825
12001
|
await writeFileAtomic(this.filePath, text);
|
|
11826
12002
|
await chmod(this.filePath, 384).catch(() => void 0);
|
|
11827
12003
|
};
|
|
@@ -11840,7 +12016,7 @@ var RemoteDevicesStore = class {
|
|
|
11840
12016
|
*/
|
|
11841
12017
|
async stamp() {
|
|
11842
12018
|
try {
|
|
11843
|
-
const info = await
|
|
12019
|
+
const info = await stat17(this.filePath);
|
|
11844
12020
|
return `${info.mtimeMs}:${info.size}`;
|
|
11845
12021
|
} catch {
|
|
11846
12022
|
return "";
|
|
@@ -11954,8 +12130,8 @@ import chokidar from "chokidar";
|
|
|
11954
12130
|
|
|
11955
12131
|
// packages/server/src/git-repo.ts
|
|
11956
12132
|
import { execFile as execFile4 } from "node:child_process";
|
|
11957
|
-
import { readFile as
|
|
11958
|
-
import
|
|
12133
|
+
import { readFile as readFile11 } from "node:fs/promises";
|
|
12134
|
+
import path34 from "node:path";
|
|
11959
12135
|
function gitOutputText(output, command) {
|
|
11960
12136
|
return output.length > 0 ? serverText("raw", { text: output }) : serverText("gitCommandFailed", { command });
|
|
11961
12137
|
}
|
|
@@ -12016,7 +12192,7 @@ async function resolveRepo(cwd) {
|
|
|
12016
12192
|
const result = await runGit(cwd, ["rev-parse", "--show-toplevel"]);
|
|
12017
12193
|
if (result.code === 0) {
|
|
12018
12194
|
const root = result.stdout.trim();
|
|
12019
|
-
if (root.length > 0) return { state: "ready", root:
|
|
12195
|
+
if (root.length > 0) return { state: "ready", root: path34.resolve(root), message: null };
|
|
12020
12196
|
}
|
|
12021
12197
|
const stderr = result.stderr.trim();
|
|
12022
12198
|
if (/not a git repository|no es un repositorio/i.test(stderr)) {
|
|
@@ -12043,7 +12219,7 @@ async function findGitDir(cwd) {
|
|
|
12043
12219
|
const result = await runGit(cwd, ["rev-parse", "--absolute-git-dir"]);
|
|
12044
12220
|
if (result.code !== 0) return null;
|
|
12045
12221
|
const dir = result.stdout.trim();
|
|
12046
|
-
return dir.length > 0 ?
|
|
12222
|
+
return dir.length > 0 ? path34.resolve(dir) : null;
|
|
12047
12223
|
}
|
|
12048
12224
|
function letterToKind(letter) {
|
|
12049
12225
|
switch (letter) {
|
|
@@ -12146,7 +12322,7 @@ function parseWorktrees(raw, currentRoot) {
|
|
|
12146
12322
|
worktrees.push({
|
|
12147
12323
|
path: current.path,
|
|
12148
12324
|
branch: current.branch,
|
|
12149
|
-
isCurrent:
|
|
12325
|
+
isCurrent: path34.resolve(current.path) === path34.resolve(currentRoot)
|
|
12150
12326
|
});
|
|
12151
12327
|
current = null;
|
|
12152
12328
|
};
|
|
@@ -12289,7 +12465,7 @@ function looksBinary(buffer) {
|
|
|
12289
12465
|
async function readUntrackedAsDiff(absolutePath, relativePath) {
|
|
12290
12466
|
let content;
|
|
12291
12467
|
try {
|
|
12292
|
-
content = await
|
|
12468
|
+
content = await readFile11(absolutePath);
|
|
12293
12469
|
} catch {
|
|
12294
12470
|
return {
|
|
12295
12471
|
path: relativePath,
|
|
@@ -12337,7 +12513,7 @@ async function readUntrackedAsDiff(absolutePath, relativePath) {
|
|
|
12337
12513
|
async function readDiff(options) {
|
|
12338
12514
|
const { repoRoot: repoRoot2, relativePath, staged, untracked } = options;
|
|
12339
12515
|
if (untracked && !staged) {
|
|
12340
|
-
return readUntrackedAsDiff(
|
|
12516
|
+
return readUntrackedAsDiff(path34.join(repoRoot2, relativePath), relativePath);
|
|
12341
12517
|
}
|
|
12342
12518
|
const args = [
|
|
12343
12519
|
"diff",
|
|
@@ -12557,7 +12733,7 @@ var RepoHub = class extends EventEmitter2 {
|
|
|
12557
12733
|
// packages/server/src/memory-hub.ts
|
|
12558
12734
|
import { EventEmitter as EventEmitter3 } from "node:events";
|
|
12559
12735
|
import { homedir as homedir10 } from "node:os";
|
|
12560
|
-
import
|
|
12736
|
+
import path36 from "node:path";
|
|
12561
12737
|
import chokidar2 from "chokidar";
|
|
12562
12738
|
|
|
12563
12739
|
// packages/server/src/memory-bridge.ts
|
|
@@ -12567,14 +12743,14 @@ import {
|
|
|
12567
12743
|
mkdir as mkdir7,
|
|
12568
12744
|
open as open6,
|
|
12569
12745
|
readdir as readdir9,
|
|
12570
|
-
readFile as
|
|
12746
|
+
readFile as readFile12,
|
|
12571
12747
|
realpath as realpath2,
|
|
12572
12748
|
rename as rename4,
|
|
12573
|
-
stat as
|
|
12749
|
+
stat as stat18,
|
|
12574
12750
|
unlink as unlink3
|
|
12575
12751
|
} from "node:fs/promises";
|
|
12576
12752
|
import { homedir as homedir9 } from "node:os";
|
|
12577
|
-
import
|
|
12753
|
+
import path35 from "node:path";
|
|
12578
12754
|
var MemoryBridgeError = class extends ServerTextError {
|
|
12579
12755
|
};
|
|
12580
12756
|
var MAX_LISTED_NOTES = 500;
|
|
@@ -12592,9 +12768,9 @@ var GITIGNORE_MEMORY_LINE = `${MEMORY_DIR}/`;
|
|
|
12592
12768
|
var BOM2 = Buffer.from([239, 187, 191]);
|
|
12593
12769
|
async function inspectMemory(cwd, home = homedir9()) {
|
|
12594
12770
|
await assertMemoryDirInside(cwd);
|
|
12595
|
-
const folder =
|
|
12771
|
+
const folder = path35.join(cwd, MEMORY_DIR);
|
|
12596
12772
|
const folderExists = await isDirectory2(folder);
|
|
12597
|
-
const indexExists = folderExists && await isFile(
|
|
12773
|
+
const indexExists = folderExists && await isFile(path35.join(folder, MEMORY_INDEX_FILE));
|
|
12598
12774
|
const noteNames = folderExists ? await listNoteFiles(folder) : [];
|
|
12599
12775
|
const notes = await describeNotes(folder, noteNames);
|
|
12600
12776
|
const files = await Promise.all(
|
|
@@ -12626,7 +12802,7 @@ async function installMemory(cwd, options, home = homedir9()) {
|
|
|
12626
12802
|
}
|
|
12627
12803
|
async function importNativeMemory(cwd, home = homedir9()) {
|
|
12628
12804
|
await assertMemoryDirInside(cwd);
|
|
12629
|
-
if (!await isDirectory2(
|
|
12805
|
+
if (!await isDirectory2(path35.join(cwd, MEMORY_DIR))) {
|
|
12630
12806
|
throw new MemoryBridgeError(serverText("memoryNotInstalled"));
|
|
12631
12807
|
}
|
|
12632
12808
|
const plan = new PlanBuilder(cwd);
|
|
@@ -12644,9 +12820,9 @@ async function readMemoryNote(cwd, name) {
|
|
|
12644
12820
|
}
|
|
12645
12821
|
const absolute = await resolveInside(cwd, `${MEMORY_DIR}/${name}`);
|
|
12646
12822
|
try {
|
|
12647
|
-
const info = await
|
|
12823
|
+
const info = await stat18(absolute);
|
|
12648
12824
|
if (!info.isFile()) return null;
|
|
12649
|
-
const content = await
|
|
12825
|
+
const content = await readFile12(absolute);
|
|
12650
12826
|
return {
|
|
12651
12827
|
name,
|
|
12652
12828
|
text: content.subarray(0, MAX_NOTE_BYTES).toString("utf8"),
|
|
@@ -12661,7 +12837,7 @@ function isNoteName(name) {
|
|
|
12661
12837
|
if (name.length === 0 || name.length > 255) return false;
|
|
12662
12838
|
if (name.includes("\0")) return false;
|
|
12663
12839
|
if (name === "." || name === "..") return false;
|
|
12664
|
-
if (
|
|
12840
|
+
if (path35.basename(name) !== name) return false;
|
|
12665
12841
|
if (/[\\/:*?"<>|\u0000-\u001f]/.test(name)) return false;
|
|
12666
12842
|
return name.toLowerCase().endsWith(".md");
|
|
12667
12843
|
}
|
|
@@ -12698,7 +12874,7 @@ var PlanBuilder = class {
|
|
|
12698
12874
|
/** Nombres de nota que habria en la carpeta, en minusculas. */
|
|
12699
12875
|
async noteNames() {
|
|
12700
12876
|
const names = /* @__PURE__ */ new Map();
|
|
12701
|
-
for (const name of await listNoteFiles(
|
|
12877
|
+
for (const name of await listNoteFiles(path35.join(this.cwd, MEMORY_DIR))) {
|
|
12702
12878
|
names.set(name.toLowerCase(), name);
|
|
12703
12879
|
}
|
|
12704
12880
|
for (const rel of this.files.keys()) {
|
|
@@ -12741,7 +12917,7 @@ var PlanBuilder = class {
|
|
|
12741
12917
|
continue;
|
|
12742
12918
|
}
|
|
12743
12919
|
const target = await realpath2(absolute);
|
|
12744
|
-
const info = await
|
|
12920
|
+
const info = await stat18(target);
|
|
12745
12921
|
if (info.nlink > 1) {
|
|
12746
12922
|
throw new MemoryBridgeError(serverText("memoryHardLinks", { file: file.rel }));
|
|
12747
12923
|
}
|
|
@@ -12760,7 +12936,7 @@ var PlanBuilder = class {
|
|
|
12760
12936
|
);
|
|
12761
12937
|
if (pending.length === 0) return;
|
|
12762
12938
|
if (pending.some((file) => file.rel.startsWith(`${MEMORY_DIR}/`))) {
|
|
12763
|
-
await mkdir7(
|
|
12939
|
+
await mkdir7(path35.join(this.cwd, MEMORY_DIR), { recursive: true });
|
|
12764
12940
|
}
|
|
12765
12941
|
for (const file of pending) {
|
|
12766
12942
|
if (file.target === null) throw new Error(`Unvalidated plan: ${file.rel}`);
|
|
@@ -12871,7 +13047,7 @@ async function planNativeImport(plan, cwd, home) {
|
|
|
12871
13047
|
const local = await plan.noteNames();
|
|
12872
13048
|
for (const name of await listNoteFiles(folder)) {
|
|
12873
13049
|
const key = name.toLowerCase();
|
|
12874
|
-
const content = await readIfFile(
|
|
13050
|
+
const content = await readIfFile(path35.join(folder, name), name);
|
|
12875
13051
|
if (content === null) continue;
|
|
12876
13052
|
const already = chosen.get(key);
|
|
12877
13053
|
if (already !== void 0) {
|
|
@@ -12885,7 +13061,7 @@ async function planNativeImport(plan, cwd, home) {
|
|
|
12885
13061
|
if (existing !== null && !existing.equals(content)) skipped.push(name);
|
|
12886
13062
|
continue;
|
|
12887
13063
|
}
|
|
12888
|
-
plan.put(`${MEMORY_DIR}/${name}`, null, content, "copy", "",
|
|
13064
|
+
plan.put(`${MEMORY_DIR}/${name}`, null, content, "copy", "", path35.join(folder, name));
|
|
12889
13065
|
copied.push(name);
|
|
12890
13066
|
}
|
|
12891
13067
|
}
|
|
@@ -12895,7 +13071,7 @@ async function planNativeImport(plan, cwd, home) {
|
|
|
12895
13071
|
const known = new Set(linkTargets(index.toString("utf8")));
|
|
12896
13072
|
const additions = [];
|
|
12897
13073
|
for (const folder of folders) {
|
|
12898
|
-
const nativeIndex = await readIfFile(
|
|
13074
|
+
const nativeIndex = await readIfFile(path35.join(folder, MEMORY_INDEX_FILE), MEMORY_INDEX_FILE);
|
|
12899
13075
|
if (nativeIndex === null) continue;
|
|
12900
13076
|
for (const line of nativeIndex.toString("utf8").replace(/^\uFEFF/, "").split(/\r?\n/)) {
|
|
12901
13077
|
const target = linkTargets(line)[0];
|
|
@@ -13120,7 +13296,7 @@ async function describeNotes(folder, names) {
|
|
|
13120
13296
|
const stated = [];
|
|
13121
13297
|
for (const name of names) {
|
|
13122
13298
|
try {
|
|
13123
|
-
const info = await
|
|
13299
|
+
const info = await stat18(path35.join(folder, name));
|
|
13124
13300
|
if (info.isFile()) stated.push({ name, sizeBytes: info.size, modifiedAt: info.mtimeMs });
|
|
13125
13301
|
} catch {
|
|
13126
13302
|
}
|
|
@@ -13128,7 +13304,7 @@ async function describeNotes(folder, names) {
|
|
|
13128
13304
|
stated.sort((a, b) => b.modifiedAt - a.modifiedAt || a.name.localeCompare(b.name));
|
|
13129
13305
|
const notes = [];
|
|
13130
13306
|
for (const item of stated.slice(0, MAX_LISTED_NOTES)) {
|
|
13131
|
-
const head = await readHead(
|
|
13307
|
+
const head = await readHead(path35.join(folder, item.name));
|
|
13132
13308
|
notes.push({ ...item, ...describeNoteText(head, item.name) });
|
|
13133
13309
|
}
|
|
13134
13310
|
return notes;
|
|
@@ -13186,28 +13362,28 @@ async function countNativeMemory(cwd, home, sharedNames) {
|
|
|
13186
13362
|
return { available: names.size, pending };
|
|
13187
13363
|
}
|
|
13188
13364
|
async function nativeMemoryFolders(cwd, home) {
|
|
13189
|
-
const root =
|
|
13365
|
+
const root = path35.join(home, ".claude", "projects");
|
|
13190
13366
|
const slug = projectSlugFor(cwd).toLowerCase();
|
|
13191
13367
|
try {
|
|
13192
13368
|
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) =>
|
|
13369
|
+
return entries.filter((entry) => entry.isDirectory() && entry.name.toLowerCase() === slug).map((entry) => entry.name).sort().map((name) => path35.join(root, name, "memory"));
|
|
13194
13370
|
} catch {
|
|
13195
13371
|
return [];
|
|
13196
13372
|
}
|
|
13197
13373
|
}
|
|
13198
13374
|
function buildGlobalFragments(home) {
|
|
13199
13375
|
const windows = process.platform === "win32";
|
|
13200
|
-
const globalFile =
|
|
13376
|
+
const globalFile = path35.join(home, ...GLOBAL_MEMORY_RELATIVE.split("/"));
|
|
13201
13377
|
const hardLink = (link) => windows ? `mklink /H "${link}" "${globalFile}"` : `ln "${globalFile}" "${link}"`;
|
|
13202
13378
|
const hardLinkNote = windows ? serverText("memoryNoteHardLinkCmd", { path: GLOBAL_MEMORY_RELATIVE }) : serverText("memoryNoteHardLink", { path: GLOBAL_MEMORY_RELATIVE });
|
|
13203
|
-
const codexTarget =
|
|
13204
|
-
const geminiTarget =
|
|
13379
|
+
const codexTarget = path35.join(home, ".codex", "AGENTS.md");
|
|
13380
|
+
const geminiTarget = path35.join(home, ".gemini", "GEMINI.md");
|
|
13205
13381
|
const homeSlashes = home.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
13206
13382
|
return [
|
|
13207
13383
|
{
|
|
13208
13384
|
agent: "claude-code",
|
|
13209
13385
|
label: MEMORY_AGENT_LABELS["claude-code"],
|
|
13210
|
-
target:
|
|
13386
|
+
target: path35.join(home, ".claude", "CLAUDE.md"),
|
|
13211
13387
|
kind: "line",
|
|
13212
13388
|
text: `@~/${GLOBAL_MEMORY_RELATIVE}`,
|
|
13213
13389
|
note: serverText("memoryNoteClaude")
|
|
@@ -13231,7 +13407,7 @@ function buildGlobalFragments(home) {
|
|
|
13231
13407
|
{
|
|
13232
13408
|
agent: "opencode",
|
|
13233
13409
|
label: MEMORY_AGENT_LABELS.opencode,
|
|
13234
|
-
target:
|
|
13410
|
+
target: path35.join(home, ".config", "opencode", "opencode.json"),
|
|
13235
13411
|
kind: "json",
|
|
13236
13412
|
text: `"instructions": ["${homeSlashes}/${GLOBAL_MEMORY_RELATIVE}"]`,
|
|
13237
13413
|
note: serverText("memoryNoteOpenCode")
|
|
@@ -13279,17 +13455,17 @@ async function readGit(cwd) {
|
|
|
13279
13455
|
if (!toplevel || !gitDir || !commonDir) return fail(serverText("gitUnexpected", { command: "rev-parse" }));
|
|
13280
13456
|
const ignored = await checkIgnored(cwd, INDEX_REL);
|
|
13281
13457
|
if (typeof ignored !== "boolean") return fail(ignored);
|
|
13282
|
-
const absoluteGitDir =
|
|
13283
|
-
const absoluteCommonDir =
|
|
13458
|
+
const absoluteGitDir = path35.resolve(cwd, gitDir);
|
|
13459
|
+
const absoluteCommonDir = path35.resolve(cwd, commonDir);
|
|
13284
13460
|
let worktree = null;
|
|
13285
13461
|
let main2 = null;
|
|
13286
13462
|
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(
|
|
13463
|
+
if (path35.basename(absoluteCommonDir).toLowerCase() === ".git") {
|
|
13464
|
+
const mainRoot = path35.dirname(absoluteCommonDir);
|
|
13465
|
+
const inner = path35.relative(path35.resolve(toplevel), path35.resolve(cwd));
|
|
13466
|
+
const sameFolder = inner.length === 0 || inner.startsWith("..") || path35.isAbsolute(inner);
|
|
13467
|
+
const mainPath = sameFolder ? mainRoot : path35.join(mainRoot, inner);
|
|
13468
|
+
const memoryRel = sameFolder ? MEMORY_DIR : [...inner.split(path35.sep), MEMORY_DIR].join("/");
|
|
13293
13469
|
main2 = { root: mainRoot, memoryRel };
|
|
13294
13470
|
worktree = {
|
|
13295
13471
|
mainPath,
|
|
@@ -13314,7 +13490,7 @@ async function samePath(a, b) {
|
|
|
13314
13490
|
try {
|
|
13315
13491
|
return await realpath2(value);
|
|
13316
13492
|
} catch {
|
|
13317
|
-
return
|
|
13493
|
+
return path35.resolve(value);
|
|
13318
13494
|
}
|
|
13319
13495
|
};
|
|
13320
13496
|
const [left, right] = await Promise.all([resolve(a), resolve(b)]);
|
|
@@ -13356,9 +13532,9 @@ async function listNoteFiles(folder) {
|
|
|
13356
13532
|
}
|
|
13357
13533
|
async function readIfFile(absolute, label) {
|
|
13358
13534
|
try {
|
|
13359
|
-
const info = await
|
|
13535
|
+
const info = await stat18(absolute);
|
|
13360
13536
|
if (!info.isFile()) throw new MemoryBridgeError(serverText("memoryNotAFile", { label }));
|
|
13361
|
-
return await
|
|
13537
|
+
return await readFile12(absolute);
|
|
13362
13538
|
} catch (error) {
|
|
13363
13539
|
if (isNotFound(error)) return null;
|
|
13364
13540
|
throw error;
|
|
@@ -13380,14 +13556,14 @@ async function readHead(absolute) {
|
|
|
13380
13556
|
}
|
|
13381
13557
|
async function isFile(absolute) {
|
|
13382
13558
|
try {
|
|
13383
|
-
return (await
|
|
13559
|
+
return (await stat18(absolute)).isFile();
|
|
13384
13560
|
} catch {
|
|
13385
13561
|
return false;
|
|
13386
13562
|
}
|
|
13387
13563
|
}
|
|
13388
13564
|
async function isDirectory2(absolute) {
|
|
13389
13565
|
try {
|
|
13390
|
-
return (await
|
|
13566
|
+
return (await stat18(absolute)).isDirectory();
|
|
13391
13567
|
} catch {
|
|
13392
13568
|
return false;
|
|
13393
13569
|
}
|
|
@@ -13405,7 +13581,7 @@ async function writeAtomic(target, content, mustNotExist) {
|
|
|
13405
13581
|
await handle.close();
|
|
13406
13582
|
}
|
|
13407
13583
|
if (mustNotExist && await exists2(target)) {
|
|
13408
|
-
throw new MemoryBridgeError(serverText("memoryAppeared", { file:
|
|
13584
|
+
throw new MemoryBridgeError(serverText("memoryAppeared", { file: path35.basename(target) }));
|
|
13409
13585
|
}
|
|
13410
13586
|
await renameWithRetry(temporary, target);
|
|
13411
13587
|
} catch (error) {
|
|
@@ -13416,9 +13592,9 @@ async function writeAtomic(target, content, mustNotExist) {
|
|
|
13416
13592
|
async function createTemporary(target) {
|
|
13417
13593
|
for (let attempt = 1; ; attempt += 1) {
|
|
13418
13594
|
const suffix = randomBytes4(6).toString("hex");
|
|
13419
|
-
const temporary =
|
|
13420
|
-
|
|
13421
|
-
`.${
|
|
13595
|
+
const temporary = path35.join(
|
|
13596
|
+
path35.dirname(target),
|
|
13597
|
+
`.${path35.basename(target)}.${process.pid}.${suffix}.tmp`
|
|
13422
13598
|
);
|
|
13423
13599
|
try {
|
|
13424
13600
|
return { temporary, handle: await open6(temporary, "wx") };
|
|
@@ -13430,7 +13606,7 @@ async function createTemporary(target) {
|
|
|
13430
13606
|
}
|
|
13431
13607
|
async function exists2(absolute) {
|
|
13432
13608
|
try {
|
|
13433
|
-
await
|
|
13609
|
+
await stat18(absolute);
|
|
13434
13610
|
return true;
|
|
13435
13611
|
} catch {
|
|
13436
13612
|
return false;
|
|
@@ -13656,13 +13832,13 @@ var MemoryHub = class extends EventEmitter3 {
|
|
|
13656
13832
|
}
|
|
13657
13833
|
};
|
|
13658
13834
|
function keyFor(cwd) {
|
|
13659
|
-
const resolved =
|
|
13835
|
+
const resolved = path36.resolve(cwd);
|
|
13660
13836
|
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
13661
13837
|
}
|
|
13662
13838
|
function isRelevantPath(cwd, candidate) {
|
|
13663
|
-
const relative =
|
|
13839
|
+
const relative = path36.relative(cwd, candidate);
|
|
13664
13840
|
if (relative.length === 0) return true;
|
|
13665
|
-
if (relative.startsWith("..") ||
|
|
13841
|
+
if (relative.startsWith("..") || path36.isAbsolute(relative)) return false;
|
|
13666
13842
|
const same = (a, b) => process.platform === "win32" ? a.toLowerCase() === b.toLowerCase() : a === b;
|
|
13667
13843
|
const parts = relative.split(/[\\/]/);
|
|
13668
13844
|
const [first = "", second = "", third = ""] = parts;
|
|
@@ -13680,9 +13856,8 @@ function isRelevantPath(cwd, candidate) {
|
|
|
13680
13856
|
|
|
13681
13857
|
// packages/server/src/paste-store.ts
|
|
13682
13858
|
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";
|
|
13859
|
+
import { mkdir as mkdir8, readdir as readdir10, rm as rm3, stat as stat19, writeFile as writeFile4 } from "node:fs/promises";
|
|
13860
|
+
import path37 from "node:path";
|
|
13686
13861
|
|
|
13687
13862
|
// packages/server/src/vault/markdown.ts
|
|
13688
13863
|
var pad2 = (value) => String(value).padStart(2, "0");
|
|
@@ -14197,8 +14372,8 @@ function buildContinuationMessage(input) {
|
|
|
14197
14372
|
}
|
|
14198
14373
|
return sanitizeForPaste(lines.join("\n"));
|
|
14199
14374
|
}
|
|
14200
|
-
function transcriptReferenceFor(
|
|
14201
|
-
return style === "at-quoted" ? fileReference(
|
|
14375
|
+
function transcriptReferenceFor(path52, style) {
|
|
14376
|
+
return style === "at-quoted" ? fileReference(path52, "at-quoted") : `"${path52}"`;
|
|
14202
14377
|
}
|
|
14203
14378
|
function planTranscript(input) {
|
|
14204
14379
|
const turns = splitTurns(input.events);
|
|
@@ -14322,32 +14497,6 @@ function textWithAttachments(text, lines) {
|
|
|
14322
14497
|
return lines.length === 0 ? text : [...lines, text].filter((piece) => piece.trim().length > 0).join("\n");
|
|
14323
14498
|
}
|
|
14324
14499
|
|
|
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
14500
|
// packages/server/src/paste-store.ts
|
|
14352
14501
|
var EXTENSIONS = /* @__PURE__ */ new Map([
|
|
14353
14502
|
["image/png", "png"],
|
|
@@ -14373,7 +14522,7 @@ var PasteStore = class {
|
|
|
14373
14522
|
root;
|
|
14374
14523
|
counter = 0;
|
|
14375
14524
|
constructor(root) {
|
|
14376
|
-
this.root = root ??
|
|
14525
|
+
this.root = root ?? pasteRoot();
|
|
14377
14526
|
}
|
|
14378
14527
|
/**
|
|
14379
14528
|
* Guarda una imagen y devuelve su ruta.
|
|
@@ -14400,11 +14549,11 @@ var PasteStore = class {
|
|
|
14400
14549
|
if (signature === null) {
|
|
14401
14550
|
throw new PasteImageError(serverText("imageUnknownFormat"));
|
|
14402
14551
|
}
|
|
14403
|
-
const directory =
|
|
14552
|
+
const directory = path37.join(this.root, safeSegment(terminalId));
|
|
14404
14553
|
await mkdir8(directory, { recursive: true, mode: DIRECTORY_MODE });
|
|
14405
14554
|
this.counter += 1;
|
|
14406
14555
|
const name = `pegada-${this.counter}-${randomUUID3().slice(0, 8)}.${signature.ext}`;
|
|
14407
|
-
const file =
|
|
14556
|
+
const file = path37.join(directory, name);
|
|
14408
14557
|
await writeFile4(file, bytes, { mode: FILE_MODE });
|
|
14409
14558
|
return { path: file, bytes: bytes.length };
|
|
14410
14559
|
}
|
|
@@ -14422,11 +14571,11 @@ var PasteStore = class {
|
|
|
14422
14571
|
if (bytes.length > MAX_TEXT_BYTES) {
|
|
14423
14572
|
throw new PasteTextError(`The text is ${bytes.length} bytes; the maximum is ${MAX_TEXT_BYTES}.`);
|
|
14424
14573
|
}
|
|
14425
|
-
const directory =
|
|
14574
|
+
const directory = path37.join(this.root, safeSegment(terminalId));
|
|
14426
14575
|
await mkdir8(directory, { recursive: true, mode: DIRECTORY_MODE });
|
|
14427
14576
|
this.counter += 1;
|
|
14428
14577
|
const name = `${baseName}-${this.counter}-${randomUUID3().slice(0, 8)}.md`;
|
|
14429
|
-
const file =
|
|
14578
|
+
const file = path37.join(directory, name);
|
|
14430
14579
|
await writeFile4(file, bytes, { mode: FILE_MODE });
|
|
14431
14580
|
return { path: file, bytes: bytes.length };
|
|
14432
14581
|
}
|
|
@@ -14456,17 +14605,17 @@ var PasteStore = class {
|
|
|
14456
14605
|
})
|
|
14457
14606
|
);
|
|
14458
14607
|
}
|
|
14459
|
-
const directory =
|
|
14608
|
+
const directory = path37.join(this.root, safeSegment(terminalId));
|
|
14460
14609
|
await mkdir8(directory, { recursive: true, mode: DIRECTORY_MODE });
|
|
14461
14610
|
this.counter += 1;
|
|
14462
14611
|
const name = `adjunto-${this.counter}-${randomUUID3().slice(0, 8)}-${safe}`;
|
|
14463
|
-
const file =
|
|
14612
|
+
const file = path37.join(directory, name);
|
|
14464
14613
|
await writeFile4(file, bytes, { mode: FILE_MODE });
|
|
14465
14614
|
return { path: file, bytes: bytes.length, name };
|
|
14466
14615
|
}
|
|
14467
14616
|
/** Borra lo de una pestana. Se llama al cerrarla. */
|
|
14468
14617
|
async clearTerminal(terminalId) {
|
|
14469
|
-
await rm3(
|
|
14618
|
+
await rm3(path37.join(this.root, safeSegment(terminalId)), {
|
|
14470
14619
|
recursive: true,
|
|
14471
14620
|
force: true
|
|
14472
14621
|
}).catch(() => {
|
|
@@ -14488,9 +14637,9 @@ var PasteStore = class {
|
|
|
14488
14637
|
}
|
|
14489
14638
|
await Promise.all(
|
|
14490
14639
|
entries.map(async (entry) => {
|
|
14491
|
-
const full =
|
|
14640
|
+
const full = path37.join(this.root, entry);
|
|
14492
14641
|
try {
|
|
14493
|
-
const info = await
|
|
14642
|
+
const info = await stat19(full);
|
|
14494
14643
|
if (now - info.mtimeMs > STALE_AFTER_MS) {
|
|
14495
14644
|
await rm3(full, { recursive: true, force: true });
|
|
14496
14645
|
}
|
|
@@ -14507,8 +14656,8 @@ function safeSegment(value) {
|
|
|
14507
14656
|
|
|
14508
14657
|
// packages/server/src/session-index.ts
|
|
14509
14658
|
import { EventEmitter as EventEmitter4 } from "node:events";
|
|
14510
|
-
import { mkdir as mkdir9, readFile as
|
|
14511
|
-
import
|
|
14659
|
+
import { mkdir as mkdir9, readFile as readFile13, stat as stat20, writeFile as writeFile5 } from "node:fs/promises";
|
|
14660
|
+
import path38 from "node:path";
|
|
14512
14661
|
var CACHE_VERSION = 4;
|
|
14513
14662
|
var vaultPairKey = (agent, sessionId) => `${agent}/${sessionId}`;
|
|
14514
14663
|
function vaultOnlySessions(natives, vault, listState, ready) {
|
|
@@ -14560,7 +14709,7 @@ function cacheKey(agent, ref) {
|
|
|
14560
14709
|
}
|
|
14561
14710
|
async function pathExists3(candidate) {
|
|
14562
14711
|
try {
|
|
14563
|
-
await
|
|
14712
|
+
await stat20(candidate);
|
|
14564
14713
|
return true;
|
|
14565
14714
|
} catch {
|
|
14566
14715
|
return false;
|
|
@@ -14610,7 +14759,7 @@ function migrateEntryV3(filePath, value) {
|
|
|
14610
14759
|
return {
|
|
14611
14760
|
agent: "claude-code",
|
|
14612
14761
|
ref: filePath,
|
|
14613
|
-
group:
|
|
14762
|
+
group: path38.basename(path38.dirname(filePath)),
|
|
14614
14763
|
mtimeMs,
|
|
14615
14764
|
sizeBytes,
|
|
14616
14765
|
cwd,
|
|
@@ -14875,7 +15024,7 @@ var SessionIndex = class extends EventEmitter4 {
|
|
|
14875
15024
|
}
|
|
14876
15025
|
async loadCache() {
|
|
14877
15026
|
try {
|
|
14878
|
-
const raw = await
|
|
15027
|
+
const raw = await readFile13(sessionIndexCachePath(), "utf8");
|
|
14879
15028
|
const parsed = JSON.parse(raw);
|
|
14880
15029
|
const migrated = migrateIndexCache(parsed);
|
|
14881
15030
|
if (migrated === null) return;
|
|
@@ -15103,8 +15252,8 @@ var SessionIndex = class extends EventEmitter4 {
|
|
|
15103
15252
|
};
|
|
15104
15253
|
|
|
15105
15254
|
// packages/server/src/settings-store.ts
|
|
15106
|
-
import { mkdir as mkdir10, readFile as
|
|
15107
|
-
import
|
|
15255
|
+
import { mkdir as mkdir10, readFile as readFile14, stat as stat21 } from "node:fs/promises";
|
|
15256
|
+
import path39 from "node:path";
|
|
15108
15257
|
var SETTINGS_VERSION = 1;
|
|
15109
15258
|
var VAULT_TOOL_RESULT_DEFAULT_CHARS = 64e3;
|
|
15110
15259
|
var VAULT_TOOL_RESULT_MIN_CHARS = 4e3;
|
|
@@ -15121,7 +15270,7 @@ function defaultAppSettings() {
|
|
|
15121
15270
|
function isAbsoluteDir(dir, platform) {
|
|
15122
15271
|
if (dir.length === 0 || dir.includes("\0")) return false;
|
|
15123
15272
|
if (platform === "win32") return /^[A-Za-z]:[\\/]/.test(dir) || /^\\\\[^\\/]+[\\/][^\\/]+/.test(dir);
|
|
15124
|
-
return
|
|
15273
|
+
return path39.posix.isAbsolute(dir);
|
|
15125
15274
|
}
|
|
15126
15275
|
function clampToolResultMaxChars(value) {
|
|
15127
15276
|
if (typeof value !== "number" || !Number.isFinite(value)) return VAULT_TOOL_RESULT_DEFAULT_CHARS;
|
|
@@ -15180,7 +15329,7 @@ var SettingsStore = class {
|
|
|
15180
15329
|
async load() {
|
|
15181
15330
|
let raw;
|
|
15182
15331
|
try {
|
|
15183
|
-
raw = await
|
|
15332
|
+
raw = await readFile14(this.filePath, "utf8");
|
|
15184
15333
|
} catch {
|
|
15185
15334
|
this.current = frozen(defaultAppSettings());
|
|
15186
15335
|
return;
|
|
@@ -15208,7 +15357,7 @@ var SettingsStore = class {
|
|
|
15208
15357
|
async reloadRemote() {
|
|
15209
15358
|
let parsed;
|
|
15210
15359
|
try {
|
|
15211
|
-
parsed = JSON.parse(await
|
|
15360
|
+
parsed = JSON.parse(await readFile14(this.filePath, "utf8"));
|
|
15212
15361
|
} catch {
|
|
15213
15362
|
return;
|
|
15214
15363
|
}
|
|
@@ -15219,7 +15368,7 @@ var SettingsStore = class {
|
|
|
15219
15368
|
/** Una marca que cambia cuando el archivo cambia (fecha y tamano), o '' si no esta. */
|
|
15220
15369
|
async stamp() {
|
|
15221
15370
|
try {
|
|
15222
|
-
const info = await
|
|
15371
|
+
const info = await stat21(this.filePath);
|
|
15223
15372
|
return `${info.mtimeMs}:${info.size}`;
|
|
15224
15373
|
} catch {
|
|
15225
15374
|
return "";
|
|
@@ -15263,7 +15412,7 @@ var SettingsStore = class {
|
|
|
15263
15412
|
if (!isRemotePort(remote.port)) throw new Error(`The remote access port isn't valid: ${JSON.stringify(remote.port)}`);
|
|
15264
15413
|
next.remote.port = remote.port;
|
|
15265
15414
|
}
|
|
15266
|
-
await mkdir10(
|
|
15415
|
+
await mkdir10(path39.dirname(this.filePath), { recursive: true });
|
|
15267
15416
|
await writeFileAtomic(this.filePath, `${JSON.stringify(next, null, 2)}
|
|
15268
15417
|
`);
|
|
15269
15418
|
this.current = frozen(next);
|
|
@@ -15351,8 +15500,8 @@ function supportStartupLineColored() {
|
|
|
15351
15500
|
|
|
15352
15501
|
// packages/server/src/notes-store.ts
|
|
15353
15502
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
15354
|
-
import { mkdir as mkdir11, readFile as
|
|
15355
|
-
import
|
|
15503
|
+
import { mkdir as mkdir11, readFile as readFile15, rename as rename5, rm as rm4, writeFile as writeFile6 } from "node:fs/promises";
|
|
15504
|
+
import path40 from "node:path";
|
|
15356
15505
|
var STATE_VERSION2 = 1;
|
|
15357
15506
|
var WRITE_DEBOUNCE_MS2 = 500;
|
|
15358
15507
|
var NotesError = class extends ServerTextError {
|
|
@@ -15395,7 +15544,7 @@ var NotesStore = class {
|
|
|
15395
15544
|
}
|
|
15396
15545
|
async load() {
|
|
15397
15546
|
try {
|
|
15398
|
-
const raw = await
|
|
15547
|
+
const raw = await readFile15(this.statePath, "utf8");
|
|
15399
15548
|
this.notes = parseState2(raw) ?? [];
|
|
15400
15549
|
} catch {
|
|
15401
15550
|
this.notes = [];
|
|
@@ -15512,7 +15661,7 @@ var NotesStore = class {
|
|
|
15512
15661
|
const image = this.findImage(imageId);
|
|
15513
15662
|
if (image === null) return null;
|
|
15514
15663
|
try {
|
|
15515
|
-
const bytes = await
|
|
15664
|
+
const bytes = await readFile15(this.imagePath(image));
|
|
15516
15665
|
return { mediaType: image.mediaType, data: bytes.toString("base64") };
|
|
15517
15666
|
} catch {
|
|
15518
15667
|
return null;
|
|
@@ -15532,7 +15681,7 @@ var NotesStore = class {
|
|
|
15532
15681
|
const images = [];
|
|
15533
15682
|
for (const image of note.images) {
|
|
15534
15683
|
try {
|
|
15535
|
-
const bytes = await
|
|
15684
|
+
const bytes = await readFile15(this.imagePath(image));
|
|
15536
15685
|
images.push({ mediaType: image.mediaType, data: bytes.toString("base64") });
|
|
15537
15686
|
} catch {
|
|
15538
15687
|
}
|
|
@@ -15556,7 +15705,7 @@ var NotesStore = class {
|
|
|
15556
15705
|
}
|
|
15557
15706
|
imagePath(image) {
|
|
15558
15707
|
const safe = image.imageId.replace(/[^a-zA-Z0-9-]/g, "");
|
|
15559
|
-
return
|
|
15708
|
+
return path40.join(this.imagesDir, `${safe}.${extensionFor(image.mediaType)}`);
|
|
15560
15709
|
}
|
|
15561
15710
|
async unlinkImage(image) {
|
|
15562
15711
|
await rm4(this.imagePath(image), { force: true }).catch(() => {
|
|
@@ -15574,8 +15723,8 @@ var NotesStore = class {
|
|
|
15574
15723
|
async writeNow() {
|
|
15575
15724
|
this.dirty = false;
|
|
15576
15725
|
try {
|
|
15577
|
-
await mkdir11(
|
|
15578
|
-
const temporary =
|
|
15726
|
+
await mkdir11(path40.dirname(this.statePath), { recursive: true });
|
|
15727
|
+
const temporary = path40.join(path40.dirname(this.statePath), `notes.${process.pid}.tmp`);
|
|
15579
15728
|
await writeFile6(
|
|
15580
15729
|
temporary,
|
|
15581
15730
|
JSON.stringify({ version: STATE_VERSION2, notes: this.notes }, null, 2),
|
|
@@ -15589,8 +15738,8 @@ var NotesStore = class {
|
|
|
15589
15738
|
};
|
|
15590
15739
|
|
|
15591
15740
|
// packages/server/src/draft-store.ts
|
|
15592
|
-
import { mkdir as mkdir12, readFile as
|
|
15593
|
-
import
|
|
15741
|
+
import { mkdir as mkdir12, readFile as readFile16, rename as rename6, writeFile as writeFile7 } from "node:fs/promises";
|
|
15742
|
+
import path41 from "node:path";
|
|
15594
15743
|
var STATE_VERSION3 = 1;
|
|
15595
15744
|
var WRITE_DEBOUNCE_MS3 = 500;
|
|
15596
15745
|
var MAX_STORED_DRAFTS = 100;
|
|
@@ -15684,7 +15833,7 @@ var DraftStore = class {
|
|
|
15684
15833
|
}
|
|
15685
15834
|
async load() {
|
|
15686
15835
|
try {
|
|
15687
|
-
this.drafts = parseState3(await
|
|
15836
|
+
this.drafts = parseState3(await readFile16(this.statePath, "utf8"));
|
|
15688
15837
|
} catch {
|
|
15689
15838
|
this.drafts = /* @__PURE__ */ new Map();
|
|
15690
15839
|
}
|
|
@@ -15775,7 +15924,7 @@ var DraftStore = class {
|
|
|
15775
15924
|
async writeNow() {
|
|
15776
15925
|
let onDisk = /* @__PURE__ */ new Map();
|
|
15777
15926
|
try {
|
|
15778
|
-
onDisk = parseState3(await
|
|
15927
|
+
onDisk = parseState3(await readFile16(this.statePath, "utf8"));
|
|
15779
15928
|
} catch {
|
|
15780
15929
|
}
|
|
15781
15930
|
const changed = this.changed;
|
|
@@ -15789,8 +15938,8 @@ var DraftStore = class {
|
|
|
15789
15938
|
trimOldest(merged);
|
|
15790
15939
|
this.drafts = new Map(merged);
|
|
15791
15940
|
try {
|
|
15792
|
-
await mkdir12(
|
|
15793
|
-
const temporary =
|
|
15941
|
+
await mkdir12(path41.dirname(this.statePath), { recursive: true });
|
|
15942
|
+
const temporary = path41.join(path41.dirname(this.statePath), `composer-drafts.${process.pid}.tmp`);
|
|
15794
15943
|
const payload = {
|
|
15795
15944
|
version: STATE_VERSION3,
|
|
15796
15945
|
drafts: [...merged.values()].map(({ agent, sessionId, updatedAt, draft }) => ({ agent, sessionId, updatedAt, draft }))
|
|
@@ -15807,7 +15956,7 @@ var DraftStore = class {
|
|
|
15807
15956
|
// packages/server/src/shell-locator.ts
|
|
15808
15957
|
import { access as access2 } from "node:fs/promises";
|
|
15809
15958
|
import { constants as fsConstants2 } from "node:fs";
|
|
15810
|
-
import
|
|
15959
|
+
import path42 from "node:path";
|
|
15811
15960
|
async function isExecutable(candidate) {
|
|
15812
15961
|
try {
|
|
15813
15962
|
await access2(candidate, process.platform === "win32" ? fsConstants2.R_OK : fsConstants2.X_OK);
|
|
@@ -15825,21 +15974,21 @@ var SYSTEM_PROBE = {
|
|
|
15825
15974
|
function windowsPowerShellPath(env) {
|
|
15826
15975
|
const systemRoot = env["SystemRoot"] ?? env["windir"];
|
|
15827
15976
|
if (systemRoot === void 0 || systemRoot.length === 0) return null;
|
|
15828
|
-
return
|
|
15977
|
+
return path42.win32.join(systemRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
|
|
15829
15978
|
}
|
|
15830
15979
|
function gitBashCandidates(gitPath, env) {
|
|
15831
15980
|
const candidates = [];
|
|
15832
15981
|
if (gitPath !== null) {
|
|
15833
|
-
let dir =
|
|
15982
|
+
let dir = path42.win32.dirname(gitPath);
|
|
15834
15983
|
for (let level = 0; level < 3; level++) {
|
|
15835
|
-
candidates.push(
|
|
15836
|
-
const parent =
|
|
15984
|
+
candidates.push(path42.win32.join(dir, "bin", "bash.exe"));
|
|
15985
|
+
const parent = path42.win32.dirname(dir);
|
|
15837
15986
|
if (parent === dir) break;
|
|
15838
15987
|
dir = parent;
|
|
15839
15988
|
}
|
|
15840
15989
|
}
|
|
15841
|
-
for (const base of [env["ProgramFiles"], env["LOCALAPPDATA"] === void 0 ? void 0 :
|
|
15842
|
-
if (base !== void 0 && base.length > 0) candidates.push(
|
|
15990
|
+
for (const base of [env["ProgramFiles"], env["LOCALAPPDATA"] === void 0 ? void 0 : path42.win32.join(env["LOCALAPPDATA"], "Programs")]) {
|
|
15991
|
+
if (base !== void 0 && base.length > 0) candidates.push(path42.win32.join(base, "Git", "bin", "bash.exe"));
|
|
15843
15992
|
}
|
|
15844
15993
|
const systemRoot = (env["SystemRoot"] ?? env["windir"] ?? "").toLowerCase();
|
|
15845
15994
|
return [...new Set(candidates)].filter((candidate) => systemRoot.length === 0 || !candidate.toLowerCase().startsWith(systemRoot));
|
|
@@ -15870,7 +16019,7 @@ async function locatePosixShells(probe) {
|
|
|
15870
16019
|
const found = [];
|
|
15871
16020
|
const preferred = probe.env["SHELL"];
|
|
15872
16021
|
if (preferred !== void 0 && preferred.length > 0 && await probe.isExecutable(preferred)) {
|
|
15873
|
-
const name =
|
|
16022
|
+
const name = path42.posix.basename(preferred);
|
|
15874
16023
|
found.push({ id: "login", label: name, location: { file: preferred, args: [], name } });
|
|
15875
16024
|
}
|
|
15876
16025
|
for (const [id, file] of [["bash", "/bin/bash"], ["sh", "/bin/sh"], ["zsh", "/bin/zsh"]]) {
|
|
@@ -15942,13 +16091,13 @@ var AppSettingsService = class extends EventEmitter5 {
|
|
|
15942
16091
|
};
|
|
15943
16092
|
|
|
15944
16093
|
// packages/server/src/session-watcher.ts
|
|
15945
|
-
import { stat as
|
|
16094
|
+
import { stat as stat22 } from "node:fs/promises";
|
|
15946
16095
|
import chokidar3 from "chokidar";
|
|
15947
16096
|
var INDEX_DEBOUNCE_MS = 750;
|
|
15948
16097
|
var ROOT_PROBE_MS = 5e3;
|
|
15949
16098
|
async function isDirectory3(target) {
|
|
15950
16099
|
try {
|
|
15951
|
-
return (await
|
|
16100
|
+
return (await stat22(target)).isDirectory();
|
|
15952
16101
|
} catch {
|
|
15953
16102
|
return false;
|
|
15954
16103
|
}
|
|
@@ -16051,7 +16200,7 @@ function watchSessions(index, hub, agents, options = {}) {
|
|
|
16051
16200
|
// packages/server/src/terminal-registry.ts
|
|
16052
16201
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
16053
16202
|
import { EventEmitter as EventEmitter6 } from "node:events";
|
|
16054
|
-
import { stat as
|
|
16203
|
+
import { stat as stat23 } from "node:fs/promises";
|
|
16055
16204
|
|
|
16056
16205
|
// packages/server/src/launch-hook-slot.ts
|
|
16057
16206
|
var LaunchHookSlot = class {
|
|
@@ -16313,8 +16462,8 @@ async function resolveLaunchPlan(launch) {
|
|
|
16313
16462
|
}
|
|
16314
16463
|
|
|
16315
16464
|
// packages/server/src/workspace-store.ts
|
|
16316
|
-
import { mkdir as mkdir13, readFile as
|
|
16317
|
-
import
|
|
16465
|
+
import { mkdir as mkdir13, readFile as readFile17, writeFile as writeFile8 } from "node:fs/promises";
|
|
16466
|
+
import path43 from "node:path";
|
|
16318
16467
|
var STATE_VERSION4 = 1;
|
|
16319
16468
|
var WRITE_DEBOUNCE_MS4 = 400;
|
|
16320
16469
|
var LEGACY_TAB_AGENT = "claude-code";
|
|
@@ -16436,7 +16585,7 @@ var WorkspaceStore = class {
|
|
|
16436
16585
|
pending = null;
|
|
16437
16586
|
async load() {
|
|
16438
16587
|
try {
|
|
16439
|
-
const raw = await
|
|
16588
|
+
const raw = await readFile17(workspaceStatePath(), "utf8");
|
|
16440
16589
|
return parseState4(raw) ?? EMPTY_STATE();
|
|
16441
16590
|
} catch {
|
|
16442
16591
|
return EMPTY_STATE();
|
|
@@ -16468,7 +16617,7 @@ var WorkspaceStore = class {
|
|
|
16468
16617
|
try {
|
|
16469
16618
|
await mkdir13(appConfigDir(), { recursive: true });
|
|
16470
16619
|
const target = workspaceStatePath();
|
|
16471
|
-
const temporary =
|
|
16620
|
+
const temporary = path43.join(path43.dirname(target), `workspace.${process.pid}.tmp`);
|
|
16472
16621
|
await writeFile8(temporary, JSON.stringify(serializeState(state), null, 2), "utf8");
|
|
16473
16622
|
const { rename: rename7 } = await import("node:fs/promises");
|
|
16474
16623
|
await rename7(temporary, target);
|
|
@@ -16705,7 +16854,7 @@ var TerminalRegistry = class extends EventEmitter6 {
|
|
|
16705
16854
|
async assertDirectory(cwd) {
|
|
16706
16855
|
let info;
|
|
16707
16856
|
try {
|
|
16708
|
-
info = await
|
|
16857
|
+
info = await stat23(cwd);
|
|
16709
16858
|
} catch {
|
|
16710
16859
|
throw new TerminalOpenError("invalid-cwd", serverText("cwdMissing", { cwd }));
|
|
16711
16860
|
}
|
|
@@ -17132,19 +17281,19 @@ import { WebSocketServer } from "ws";
|
|
|
17132
17281
|
|
|
17133
17282
|
// packages/server/src/directory-picker.ts
|
|
17134
17283
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
17135
|
-
import { mkdir as mkdir14, readdir as readdir11, stat as
|
|
17284
|
+
import { mkdir as mkdir14, readdir as readdir11, stat as stat24 } from "node:fs/promises";
|
|
17136
17285
|
import { homedir as homedir11 } from "node:os";
|
|
17137
|
-
import
|
|
17286
|
+
import path44 from "node:path";
|
|
17138
17287
|
var MAX_ENTRIES = 500;
|
|
17139
17288
|
var MAX_PICKERS = 8;
|
|
17140
17289
|
var SKIPPED = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "bin", "obj", "$RECYCLE.BIN"]);
|
|
17141
17290
|
var DirectoryPickerError = class extends ServerTextError {
|
|
17142
17291
|
};
|
|
17143
17292
|
function isInsideProtected(target, dirs) {
|
|
17144
|
-
const resolved =
|
|
17293
|
+
const resolved = path44.resolve(target);
|
|
17145
17294
|
return dirs.some((dir) => {
|
|
17146
|
-
const protectedDir =
|
|
17147
|
-
return resolved === protectedDir || resolved.startsWith(protectedDir +
|
|
17295
|
+
const protectedDir = path44.resolve(dir);
|
|
17296
|
+
return resolved === protectedDir || resolved.startsWith(protectedDir + path44.sep);
|
|
17148
17297
|
});
|
|
17149
17298
|
}
|
|
17150
17299
|
async function listRoots() {
|
|
@@ -17156,7 +17305,7 @@ async function listRoots() {
|
|
|
17156
17305
|
letters.map(async (letter) => {
|
|
17157
17306
|
const drive = `${letter}:\\`;
|
|
17158
17307
|
try {
|
|
17159
|
-
await
|
|
17308
|
+
await stat24(drive);
|
|
17160
17309
|
return drive;
|
|
17161
17310
|
} catch {
|
|
17162
17311
|
return null;
|
|
@@ -17208,14 +17357,14 @@ var DirectoryPickers = class {
|
|
|
17208
17357
|
async enter(pickerId, name) {
|
|
17209
17358
|
const picker = this.require(pickerId);
|
|
17210
17359
|
if (name === "..") {
|
|
17211
|
-
const parent =
|
|
17360
|
+
const parent = path44.dirname(picker.current);
|
|
17212
17361
|
if (parent !== picker.current) picker.current = parent;
|
|
17213
17362
|
return this.listing(picker);
|
|
17214
17363
|
}
|
|
17215
17364
|
if (!picker.entries.has(name)) {
|
|
17216
17365
|
throw new DirectoryPickerError(serverText("pickerNotListed"));
|
|
17217
17366
|
}
|
|
17218
|
-
const target =
|
|
17367
|
+
const target = path44.join(picker.current, name);
|
|
17219
17368
|
if (isInsideProtected(target, this.protectedDirs)) {
|
|
17220
17369
|
throw new DirectoryPickerError(serverText("pickerCliFolder"));
|
|
17221
17370
|
}
|
|
@@ -17255,7 +17404,7 @@ var DirectoryPickers = class {
|
|
|
17255
17404
|
throw new DirectoryPickerError(serverText("pickerNameChars"));
|
|
17256
17405
|
}
|
|
17257
17406
|
}
|
|
17258
|
-
const target =
|
|
17407
|
+
const target = path44.join(picker.current, clean);
|
|
17259
17408
|
if (isInsideProtected(target, this.protectedDirs)) {
|
|
17260
17409
|
throw new DirectoryPickerError(serverText("pickerNoProjectsHere"));
|
|
17261
17410
|
}
|
|
@@ -17292,7 +17441,7 @@ var DirectoryPickers = class {
|
|
|
17292
17441
|
let truncated = false;
|
|
17293
17442
|
try {
|
|
17294
17443
|
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(
|
|
17444
|
+
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
17445
|
truncated = dirs.length > MAX_ENTRIES;
|
|
17297
17446
|
names = dirs.slice(0, MAX_ENTRIES);
|
|
17298
17447
|
} catch {
|
|
@@ -17303,15 +17452,15 @@ var DirectoryPickers = class {
|
|
|
17303
17452
|
path: picker.current,
|
|
17304
17453
|
entries: names,
|
|
17305
17454
|
roots,
|
|
17306
|
-
canGoUp:
|
|
17455
|
+
canGoUp: path44.dirname(picker.current) !== picker.current,
|
|
17307
17456
|
truncated
|
|
17308
17457
|
};
|
|
17309
17458
|
}
|
|
17310
17459
|
};
|
|
17311
17460
|
|
|
17312
17461
|
// packages/server/src/file-browser.ts
|
|
17313
|
-
import { readFile as
|
|
17314
|
-
import
|
|
17462
|
+
import { readFile as readFile18, readdir as readdir12, stat as stat25 } from "node:fs/promises";
|
|
17463
|
+
import path45 from "node:path";
|
|
17315
17464
|
var MAX_ENTRIES2 = 1e3;
|
|
17316
17465
|
var SEARCH_MAX_RESULTS = 200;
|
|
17317
17466
|
var SEARCH_MAX_DIRECTORIES = 4e3;
|
|
@@ -17374,7 +17523,7 @@ function languageFor(fileName) {
|
|
|
17374
17523
|
const lower = fileName.toLowerCase();
|
|
17375
17524
|
const byName = LANGUAGE_BY_NAME[lower];
|
|
17376
17525
|
if (byName !== void 0) return byName;
|
|
17377
|
-
const extension =
|
|
17526
|
+
const extension = path45.extname(lower);
|
|
17378
17527
|
return LANGUAGE_BY_EXTENSION[extension] ?? null;
|
|
17379
17528
|
}
|
|
17380
17529
|
function looksBinary2(buffer) {
|
|
@@ -17406,7 +17555,7 @@ async function listDirectory(cwd, relativePath, options = {}) {
|
|
|
17406
17555
|
let sizeBytes = 0;
|
|
17407
17556
|
let modifiedAt = 0;
|
|
17408
17557
|
try {
|
|
17409
|
-
const info = await
|
|
17558
|
+
const info = await stat25(path45.join(absolute, candidate.name));
|
|
17410
17559
|
sizeBytes = candidate.isDirectory ? 0 : info.size;
|
|
17411
17560
|
modifiedAt = info.mtimeMs;
|
|
17412
17561
|
} catch {
|
|
@@ -17439,7 +17588,7 @@ async function readLevel(absolute) {
|
|
|
17439
17588
|
const always = ALWAYS_SKIP.has(dirent.name.toLowerCase());
|
|
17440
17589
|
if (dirent.isSymbolicLink()) {
|
|
17441
17590
|
try {
|
|
17442
|
-
const target = await
|
|
17591
|
+
const target = await stat25(path45.join(absolute, dirent.name));
|
|
17443
17592
|
candidates.push({
|
|
17444
17593
|
name: dirent.name,
|
|
17445
17594
|
isDirectory: target.isDirectory(),
|
|
@@ -17468,7 +17617,7 @@ async function markIgnored(repoRoot2, levels) {
|
|
|
17468
17617
|
for (const level of levels) {
|
|
17469
17618
|
for (const entry of level.entries) {
|
|
17470
17619
|
if (entry.hidden !== null) continue;
|
|
17471
|
-
keys.set(entry, toPosixPath(
|
|
17620
|
+
keys.set(entry, toPosixPath(path45.relative(repoRoot2, path45.join(level.absolute, entry.name))));
|
|
17472
17621
|
}
|
|
17473
17622
|
}
|
|
17474
17623
|
if (keys.size === 0) return;
|
|
@@ -17529,7 +17678,7 @@ async function searchFiles(cwd, query, options = {}) {
|
|
|
17529
17678
|
let sizeBytes = 0;
|
|
17530
17679
|
let modifiedAt = 0;
|
|
17531
17680
|
try {
|
|
17532
|
-
const info = await
|
|
17681
|
+
const info = await stat25(path45.join(level.absolute, candidate.name));
|
|
17533
17682
|
sizeBytes = candidate.isDirectory ? 0 : info.size;
|
|
17534
17683
|
modifiedAt = info.mtimeMs;
|
|
17535
17684
|
} catch {
|
|
@@ -17563,12 +17712,12 @@ async function searchFiles(cwd, query, options = {}) {
|
|
|
17563
17712
|
}
|
|
17564
17713
|
async function readPreview(cwd, relativePath) {
|
|
17565
17714
|
const absolute = await resolveInside(cwd, relativePath, { mustExist: true });
|
|
17566
|
-
const info = await
|
|
17715
|
+
const info = await stat25(absolute);
|
|
17567
17716
|
if (info.isDirectory()) {
|
|
17568
17717
|
throw new Error("It's a directory, not a file.");
|
|
17569
17718
|
}
|
|
17570
|
-
const content = await
|
|
17571
|
-
const fileName =
|
|
17719
|
+
const content = await readFile18(absolute);
|
|
17720
|
+
const fileName = path45.basename(absolute);
|
|
17572
17721
|
if (looksBinary2(content)) {
|
|
17573
17722
|
return {
|
|
17574
17723
|
path: relativePath,
|
|
@@ -18157,14 +18306,14 @@ var TerminalWriteQueue = class {
|
|
|
18157
18306
|
};
|
|
18158
18307
|
|
|
18159
18308
|
// packages/server/src/vault/service.ts
|
|
18160
|
-
import { mkdir as mkdir17, stat as
|
|
18309
|
+
import { mkdir as mkdir17, stat as stat29 } from "node:fs/promises";
|
|
18161
18310
|
import { homedir as homedir12 } from "node:os";
|
|
18162
|
-
import
|
|
18311
|
+
import path49 from "node:path";
|
|
18163
18312
|
|
|
18164
18313
|
// packages/server/src/vault/move.ts
|
|
18165
18314
|
import { constants } from "node:fs";
|
|
18166
|
-
import { copyFile as copyFile2, lstat, mkdir as mkdir15, readdir as readdir13, rm as rm5, stat as
|
|
18167
|
-
import
|
|
18315
|
+
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";
|
|
18316
|
+
import path46 from "node:path";
|
|
18168
18317
|
var MOVED_ENTRIES = ["vault.json", "sessions", "memory"];
|
|
18169
18318
|
var OWN_TEMP_FILE = /\.\d+\.[0-9a-f]{12}\.tmp$/;
|
|
18170
18319
|
async function copyTree(source, target, result) {
|
|
@@ -18177,12 +18326,12 @@ async function copyTree(source, target, result) {
|
|
|
18177
18326
|
if (info.isDirectory()) {
|
|
18178
18327
|
await mkdir15(target, { recursive: true });
|
|
18179
18328
|
for (const name of await readdir13(source)) {
|
|
18180
|
-
await copyTree(
|
|
18329
|
+
await copyTree(path46.join(source, name), path46.join(target, name), result);
|
|
18181
18330
|
}
|
|
18182
18331
|
return;
|
|
18183
18332
|
}
|
|
18184
18333
|
if (!info.isFile() || OWN_TEMP_FILE.test(source)) return;
|
|
18185
|
-
await mkdir15(
|
|
18334
|
+
await mkdir15(path46.dirname(target), { recursive: true });
|
|
18186
18335
|
try {
|
|
18187
18336
|
await copyFile2(source, target, constants.COPYFILE_EXCL);
|
|
18188
18337
|
} catch (error) {
|
|
@@ -18199,7 +18348,7 @@ async function moveVault(from, to) {
|
|
|
18199
18348
|
const result = { copied: 0, skipped: 0 };
|
|
18200
18349
|
await mkdir15(to, { recursive: true });
|
|
18201
18350
|
for (const entry of MOVED_ENTRIES) {
|
|
18202
|
-
await copyTree(
|
|
18351
|
+
await copyTree(path46.join(from, entry), path46.join(to, entry), result);
|
|
18203
18352
|
}
|
|
18204
18353
|
return result;
|
|
18205
18354
|
}
|
|
@@ -18231,10 +18380,10 @@ function checkVaultTarget(current, target, options) {
|
|
|
18231
18380
|
return { kind: "ok" };
|
|
18232
18381
|
}
|
|
18233
18382
|
async function canWriteInto(dir) {
|
|
18234
|
-
const probe = temporaryPathFor(
|
|
18383
|
+
const probe = temporaryPathFor(path46.join(dir, ".escritura"));
|
|
18235
18384
|
try {
|
|
18236
18385
|
await mkdir15(dir, { recursive: true });
|
|
18237
|
-
if (!(await
|
|
18386
|
+
if (!(await stat26(dir)).isDirectory()) return false;
|
|
18238
18387
|
await writeFile9(probe, "");
|
|
18239
18388
|
return true;
|
|
18240
18389
|
} catch {
|
|
@@ -18337,12 +18486,12 @@ function serializeSession(input) {
|
|
|
18337
18486
|
}
|
|
18338
18487
|
|
|
18339
18488
|
// packages/server/src/vault/writer.ts
|
|
18340
|
-
import { readdir as readdir15, rm as rm6, stat as
|
|
18341
|
-
import
|
|
18489
|
+
import { readdir as readdir15, rm as rm6, stat as stat28 } from "node:fs/promises";
|
|
18490
|
+
import path48 from "node:path";
|
|
18342
18491
|
|
|
18343
18492
|
// packages/server/src/vault/memory-copy.ts
|
|
18344
|
-
import { mkdir as mkdir16, readdir as readdir14, readFile as
|
|
18345
|
-
import
|
|
18493
|
+
import { mkdir as mkdir16, readdir as readdir14, readFile as readFile19, stat as stat27, utimes as utimes2 } from "node:fs/promises";
|
|
18494
|
+
import path47 from "node:path";
|
|
18346
18495
|
var MEMORY_FILE_MAX_BYTES = 1024 * 1024;
|
|
18347
18496
|
var MEMORY_MAX_FILES = 500;
|
|
18348
18497
|
var MEMORY_SOURCE_FILE = "source.json";
|
|
@@ -18367,7 +18516,7 @@ async function listMemoryNotes(cwd) {
|
|
|
18367
18516
|
let absolute;
|
|
18368
18517
|
try {
|
|
18369
18518
|
absolute = await resolveInside(cwd, `${MEMORY_DIR}/${name}`, { mustExist: true });
|
|
18370
|
-
const info = await
|
|
18519
|
+
const info = await stat27(absolute);
|
|
18371
18520
|
if (!info.isFile() || info.size > MEMORY_FILE_MAX_BYTES) continue;
|
|
18372
18521
|
notes.push({ name, absolute, size: info.size, mtimeMs: info.mtimeMs });
|
|
18373
18522
|
} catch {
|
|
@@ -18381,7 +18530,7 @@ async function measureProjectMemory(cwd) {
|
|
|
18381
18530
|
}
|
|
18382
18531
|
async function isUpToDate(target, note) {
|
|
18383
18532
|
try {
|
|
18384
|
-
const info = await
|
|
18533
|
+
const info = await stat27(target);
|
|
18385
18534
|
return info.isFile() && info.size === note.size && Math.abs(info.mtimeMs - note.mtimeMs) < SAME_MTIME_MS;
|
|
18386
18535
|
} catch {
|
|
18387
18536
|
return false;
|
|
@@ -18389,7 +18538,7 @@ async function isUpToDate(target, note) {
|
|
|
18389
18538
|
}
|
|
18390
18539
|
async function exists3(file) {
|
|
18391
18540
|
try {
|
|
18392
|
-
await
|
|
18541
|
+
await stat27(file);
|
|
18393
18542
|
return true;
|
|
18394
18543
|
} catch {
|
|
18395
18544
|
return false;
|
|
@@ -18408,11 +18557,11 @@ async function copyProjectMemory(dir, cwd, platform, deps = DEFAULT_WRITE_DEPS)
|
|
|
18408
18557
|
await mkdir16(target, { recursive: true });
|
|
18409
18558
|
};
|
|
18410
18559
|
for (const note of notes) {
|
|
18411
|
-
const destination =
|
|
18560
|
+
const destination = path47.join(target, note.name);
|
|
18412
18561
|
if (await isUpToDate(destination, note)) continue;
|
|
18413
18562
|
let content;
|
|
18414
18563
|
try {
|
|
18415
|
-
content = await
|
|
18564
|
+
content = await readFile19(note.absolute);
|
|
18416
18565
|
} catch {
|
|
18417
18566
|
continue;
|
|
18418
18567
|
}
|
|
@@ -18424,7 +18573,7 @@ async function copyProjectMemory(dir, cwd, platform, deps = DEFAULT_WRITE_DEPS)
|
|
|
18424
18573
|
result.files += 1;
|
|
18425
18574
|
result.bytes += content.length;
|
|
18426
18575
|
}
|
|
18427
|
-
const source =
|
|
18576
|
+
const source = path47.join(target, MEMORY_SOURCE_FILE);
|
|
18428
18577
|
if (result.files > 0 || !await exists3(source)) {
|
|
18429
18578
|
await prepare();
|
|
18430
18579
|
await writeFileAtomic(source, `${JSON.stringify({ cwd, copiedAt: deps.now() })}
|
|
@@ -18434,7 +18583,7 @@ async function copyProjectMemory(dir, cwd, platform, deps = DEFAULT_WRITE_DEPS)
|
|
|
18434
18583
|
}
|
|
18435
18584
|
|
|
18436
18585
|
// packages/server/src/vault/writer.ts
|
|
18437
|
-
var VAULT_WRITER_REVISION =
|
|
18586
|
+
var VAULT_WRITER_REVISION = 2;
|
|
18438
18587
|
var CALM_MS = 6e4;
|
|
18439
18588
|
var PASS_DEBOUNCE_MS = 5e3;
|
|
18440
18589
|
var TEMP_MAX_AGE_MS = 60 * 60 * 1e3;
|
|
@@ -18918,7 +19067,7 @@ var VaultWriter = class {
|
|
|
18918
19067
|
}
|
|
18919
19068
|
async assetOnDisk(dir, agent, sessionId, asset, bytes) {
|
|
18920
19069
|
try {
|
|
18921
|
-
const info = await
|
|
19070
|
+
const info = await stat28(assetFile(dir, agent, sessionId, asset));
|
|
18922
19071
|
return info.isFile() && info.size === bytes;
|
|
18923
19072
|
} catch {
|
|
18924
19073
|
return false;
|
|
@@ -19018,17 +19167,17 @@ var VaultWriter = class {
|
|
|
19018
19167
|
const folders = [dir];
|
|
19019
19168
|
const subfolders = async (parent) => {
|
|
19020
19169
|
try {
|
|
19021
|
-
return (await readdir15(parent, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) =>
|
|
19170
|
+
return (await readdir15(parent, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => path48.join(parent, entry.name));
|
|
19022
19171
|
} catch {
|
|
19023
19172
|
return [];
|
|
19024
19173
|
}
|
|
19025
19174
|
};
|
|
19026
19175
|
for (const agentDir of await subfolders(sessionsRoot2(dir))) {
|
|
19027
|
-
if (!SESSION_AGENT_IDS.includes(
|
|
19176
|
+
if (!SESSION_AGENT_IDS.includes(path48.basename(agentDir))) continue;
|
|
19028
19177
|
folders.push(agentDir);
|
|
19029
19178
|
folders.push(...(await subfolders(agentDir)).filter((folder) => folder.endsWith(".assets")));
|
|
19030
19179
|
}
|
|
19031
|
-
folders.push(...await subfolders(
|
|
19180
|
+
folders.push(...await subfolders(path48.join(dir, "memory")));
|
|
19032
19181
|
for (const folder of folders) {
|
|
19033
19182
|
let names;
|
|
19034
19183
|
try {
|
|
@@ -19038,9 +19187,9 @@ var VaultWriter = class {
|
|
|
19038
19187
|
}
|
|
19039
19188
|
for (const name of names) {
|
|
19040
19189
|
if (!OWN_TEMP_FILE2.test(name)) continue;
|
|
19041
|
-
const file =
|
|
19190
|
+
const file = path48.join(folder, name);
|
|
19042
19191
|
try {
|
|
19043
|
-
const info = await
|
|
19192
|
+
const info = await stat28(file);
|
|
19044
19193
|
if (info.isFile() && now - info.mtimeMs > TEMP_MAX_AGE_MS) await rm6(file, { force: true });
|
|
19045
19194
|
} catch {
|
|
19046
19195
|
}
|
|
@@ -19228,14 +19377,14 @@ var VaultService = class {
|
|
|
19228
19377
|
async setDir(target) {
|
|
19229
19378
|
const { platform, agents, settings: settings2, catalog } = this.options;
|
|
19230
19379
|
const current = this.dir();
|
|
19231
|
-
const protectedDirs = [...agents.protectedDirs(),
|
|
19380
|
+
const protectedDirs = [...agents.protectedDirs(), path49.join(this.options.homeDir ?? homedir12(), ".gemini")];
|
|
19232
19381
|
const check = checkVaultTarget(current, target, { protectedDirs, platform });
|
|
19233
19382
|
if (check.kind === "refused") throw new VaultError(check.text);
|
|
19234
19383
|
if (check.kind === "same") return;
|
|
19235
19384
|
try {
|
|
19236
19385
|
await this.writer.exclusive("moving", async () => {
|
|
19237
19386
|
if (!await canWriteInto(target)) throw new VaultError(serverText("vaultCannotWrite"));
|
|
19238
|
-
const hadCopy = await
|
|
19387
|
+
const hadCopy = await stat29(vaultMarkerFile(current)).then(
|
|
19239
19388
|
() => true,
|
|
19240
19389
|
() => false
|
|
19241
19390
|
);
|
|
@@ -19269,7 +19418,7 @@ var VaultService = class {
|
|
|
19269
19418
|
/** Abre la carpeta de la copia con el explorador del sistema. */
|
|
19270
19419
|
async reveal() {
|
|
19271
19420
|
const dir = this.activeDir();
|
|
19272
|
-
const isFolder = await
|
|
19421
|
+
const isFolder = await stat29(dir).then(
|
|
19273
19422
|
(info) => info.isDirectory(),
|
|
19274
19423
|
() => false
|
|
19275
19424
|
);
|
|
@@ -19293,7 +19442,7 @@ var VaultService = class {
|
|
|
19293
19442
|
fromCopy: true
|
|
19294
19443
|
});
|
|
19295
19444
|
const file = sessionExportFile(dir, agent, sessionId);
|
|
19296
|
-
await mkdir17(
|
|
19445
|
+
await mkdir17(path49.dirname(file), { recursive: true });
|
|
19297
19446
|
await writeFileAtomic(file, text, this.writeDeps);
|
|
19298
19447
|
this.openWithSystem(file);
|
|
19299
19448
|
return file;
|
|
@@ -19397,7 +19546,7 @@ var VaultService = class {
|
|
|
19397
19546
|
continue;
|
|
19398
19547
|
}
|
|
19399
19548
|
const fileName = this.exportFileName(summary, names);
|
|
19400
|
-
await writeFileAtomic(
|
|
19549
|
+
await writeFileAtomic(path49.join(folder, fileName), text, this.writeDeps);
|
|
19401
19550
|
entries.push({
|
|
19402
19551
|
updatedAt: summary.updatedAt,
|
|
19403
19552
|
agentLabel: this.labelOf(summary.agent),
|
|
@@ -19408,9 +19557,9 @@ var VaultService = class {
|
|
|
19408
19557
|
});
|
|
19409
19558
|
await nextTurn3();
|
|
19410
19559
|
}
|
|
19411
|
-
const name = project.cwd.length > 0 ?
|
|
19560
|
+
const name = project.cwd.length > 0 ? path49.basename(project.cwd) || project.cwd : project.fallbackName;
|
|
19412
19561
|
const index = renderProjectIndex({ name, cwd: project.cwd, exportedAt: this.now(), entries, skipped });
|
|
19413
|
-
await writeFileAtomic(
|
|
19562
|
+
await writeFileAtomic(path49.join(folder, "index.md"), index, this.writeDeps);
|
|
19414
19563
|
this.openWithSystem(folder);
|
|
19415
19564
|
return { sessions: entries.length, skipped, folder };
|
|
19416
19565
|
}
|
|
@@ -21080,8 +21229,8 @@ function attachTerminalSocket(options) {
|
|
|
21080
21229
|
}
|
|
21081
21230
|
|
|
21082
21231
|
// packages/server/src/vault/catalog.ts
|
|
21083
|
-
import { open as open7, readdir as readdir16, stat as
|
|
21084
|
-
import
|
|
21232
|
+
import { open as open7, readdir as readdir16, stat as stat30 } from "node:fs/promises";
|
|
21233
|
+
import path50 from "node:path";
|
|
21085
21234
|
import { createInterface as createInterface2 } from "node:readline";
|
|
21086
21235
|
var HEADER_MAX_BYTES = 64 * 1024;
|
|
21087
21236
|
var LOAD_CONCURRENCY = 16;
|
|
@@ -21101,7 +21250,7 @@ async function assetBytesOf(dir, agent, sessionId) {
|
|
|
21101
21250
|
for (const name of names) {
|
|
21102
21251
|
if (!VAULT_ASSET_NAME_PATTERN.test(name)) continue;
|
|
21103
21252
|
try {
|
|
21104
|
-
const info = await
|
|
21253
|
+
const info = await stat30(path50.join(folder, name));
|
|
21105
21254
|
if (info.isFile()) total += info.size;
|
|
21106
21255
|
} catch {
|
|
21107
21256
|
}
|
|
@@ -21112,7 +21261,7 @@ async function readEntry(dir, agent, sessionId) {
|
|
|
21112
21261
|
const file = sessionFile(dir, agent, sessionId);
|
|
21113
21262
|
let sizeBytes;
|
|
21114
21263
|
try {
|
|
21115
|
-
const info = await
|
|
21264
|
+
const info = await stat30(file);
|
|
21116
21265
|
if (!info.isFile()) return { kind: "absent" };
|
|
21117
21266
|
sizeBytes = info.size;
|
|
21118
21267
|
} catch {
|
|
@@ -21321,15 +21470,15 @@ var VaultCatalog = class {
|
|
|
21321
21470
|
};
|
|
21322
21471
|
|
|
21323
21472
|
// packages/server/src/index.ts
|
|
21324
|
-
var serverDir =
|
|
21473
|
+
var serverDir = path51.dirname(fileURLToPath2(import.meta.url));
|
|
21325
21474
|
var isPackaged = true;
|
|
21326
|
-
var webRoot = isPackaged ? serverDir :
|
|
21327
|
-
var webDist = isPackaged ?
|
|
21328
|
-
var repoRoot =
|
|
21475
|
+
var webRoot = isPackaged ? serverDir : path51.resolve(serverDir, "../../web");
|
|
21476
|
+
var webDist = isPackaged ? path51.join(serverDir, "web") : path51.join(webRoot, "dist");
|
|
21477
|
+
var repoRoot = path51.resolve(serverDir, "../../..");
|
|
21329
21478
|
var isProduction = isPackaged || process.argv.includes("--prod");
|
|
21330
21479
|
function resolveDefaultCwd() {
|
|
21331
21480
|
const override = process.env["AGENT_WORKBENCH_CWD"];
|
|
21332
|
-
if (override !== void 0 && override.length > 0) return
|
|
21481
|
+
if (override !== void 0 && override.length > 0) return path51.resolve(override);
|
|
21333
21482
|
if (isPackaged) return process.cwd();
|
|
21334
21483
|
return repoRoot;
|
|
21335
21484
|
}
|
|
@@ -21404,7 +21553,7 @@ async function mountDevUi(app, httpServer) {
|
|
|
21404
21553
|
}
|
|
21405
21554
|
var LOOKS_LIKE_FILE = /\.[a-zA-Z0-9]{1,8}$/;
|
|
21406
21555
|
function mountBuiltUi(app) {
|
|
21407
|
-
const indexHtml =
|
|
21556
|
+
const indexHtml = path51.join(webDist, "index.html");
|
|
21408
21557
|
if (!existsSync4(indexHtml)) {
|
|
21409
21558
|
throw new Error(
|
|
21410
21559
|
`There's no compiled interface in ${webDist}.
|