@armadra/agent 0.7.4 → 0.7.5
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/CHANGELOG.md +11 -0
- package/CHANGELOG.zh-CN.md +11 -0
- package/dist/ai/apis/anthropic-request.js +6 -1
- package/dist/ai/apis/cache-params.js +2 -1
- package/dist/ai/apis/google-request.js +2 -1
- package/dist/ai/apis/openai-request.js +3 -1
- package/dist/ai/apis/openai-responses-request.js +2 -1
- package/dist/ai/json-body.d.ts +33 -1
- package/dist/ai/json-body.js +96 -18
- package/dist/bundle/ama.cjs +699 -352
- package/dist/cli/bootstrap.js +13 -5
- package/dist/cli/deps.d.ts +1 -1
- package/dist/modes/acp/acp-server.js +17 -15
- package/dist/modes/acp/acp-sessions.d.ts +14 -1
- package/dist/modes/acp/acp-sessions.js +44 -1
- package/dist/session/manager.d.ts +16 -0
- package/dist/session/manager.js +70 -14
- package/dist/session/offload.d.ts +51 -0
- package/dist/session/offload.js +195 -0
- package/dist/session/store.d.ts +12 -4
- package/dist/session/store.js +18 -8
- package/dist/tools/read-lines.d.ts +39 -0
- package/dist/tools/read-lines.js +163 -86
- package/dist/tools/read.js +3 -3
- package/docs/acp.md +6 -3
- package/docs/en/acp.md +2 -2
- package/docs/session-format.md +10 -0
- package/package.json +1 -1
package/dist/bundle/ama.cjs
CHANGED
|
@@ -41,7 +41,7 @@ var AMA_VERSION;
|
|
|
41
41
|
var init_version = __esm({
|
|
42
42
|
"src/version.ts"() {
|
|
43
43
|
"use strict";
|
|
44
|
-
AMA_VERSION = true ? "0.7.
|
|
44
|
+
AMA_VERSION = true ? "0.7.5" : readPackageVersion();
|
|
45
45
|
}
|
|
46
46
|
});
|
|
47
47
|
|
|
@@ -10284,8 +10284,9 @@ function readSessionLines(file, options = {}) {
|
|
|
10284
10284
|
forEachLineSync(file, (buf, index2, last, offset) => {
|
|
10285
10285
|
if (last) unterminated = true;
|
|
10286
10286
|
if (isBlankLine(buf)) return;
|
|
10287
|
+
let line2;
|
|
10287
10288
|
try {
|
|
10288
|
-
|
|
10289
|
+
line2 = JSON.parse(buf.toString("utf8"));
|
|
10289
10290
|
} catch (error2) {
|
|
10290
10291
|
if (last) {
|
|
10291
10292
|
repairedTail = true;
|
|
@@ -10296,6 +10297,8 @@ function readSessionLines(file, options = {}) {
|
|
|
10296
10297
|
cause: error2
|
|
10297
10298
|
});
|
|
10298
10299
|
}
|
|
10300
|
+
options.onLine?.(line2, { offset, length: buf.length });
|
|
10301
|
+
lines2.push(line2);
|
|
10299
10302
|
});
|
|
10300
10303
|
} catch (error2) {
|
|
10301
10304
|
if (error2 instanceof AmaError) throw error2;
|
|
@@ -10304,19 +10307,20 @@ function readSessionLines(file, options = {}) {
|
|
|
10304
10307
|
if (!repairedTail && unterminated && options.repair === true) {
|
|
10305
10308
|
appendRaw(file, "\n");
|
|
10306
10309
|
}
|
|
10307
|
-
return { lines: lines2, repairedTail };
|
|
10310
|
+
if (options.onLine === void 0) return { lines: lines2, repairedTail };
|
|
10311
|
+
return { lines: lines2, repairedTail, bytes: (0, import_node_fs10.statSync)(file).size };
|
|
10308
10312
|
}
|
|
10309
10313
|
function appendRaw(file, text) {
|
|
10310
10314
|
const fd = (0, import_node_fs10.openSync)(file, "a");
|
|
10311
10315
|
try {
|
|
10312
|
-
(0, import_node_fs10.writeSync)(fd, text);
|
|
10316
|
+
return (0, import_node_fs10.writeSync)(fd, text);
|
|
10313
10317
|
} finally {
|
|
10314
10318
|
(0, import_node_fs10.closeSync)(fd);
|
|
10315
10319
|
}
|
|
10316
10320
|
}
|
|
10317
10321
|
function appendLines(file, lines2) {
|
|
10318
|
-
if (lines2.length === 0) return;
|
|
10319
|
-
appendRaw(file, lines2.map((line2) => JSON.stringify(line2)).join("\n") + "\n");
|
|
10322
|
+
if (lines2.length === 0) return 0;
|
|
10323
|
+
return appendRaw(file, lines2.map((line2) => JSON.stringify(line2)).join("\n") + "\n");
|
|
10320
10324
|
}
|
|
10321
10325
|
function writeNewSessionFile(file, lines2) {
|
|
10322
10326
|
(0, import_node_fs10.mkdirSync)((0, import_node_path13.dirname)(file), { recursive: true, mode: 448 });
|
|
@@ -10324,8 +10328,10 @@ function writeNewSessionFile(file, lines2) {
|
|
|
10324
10328
|
throw new AmaError("session_exists", `session file already exists: ${file}`);
|
|
10325
10329
|
}
|
|
10326
10330
|
const tmp = `${file}.${process.pid}.tmp`;
|
|
10327
|
-
|
|
10331
|
+
const texts2 = lines2.map((line2) => JSON.stringify(line2));
|
|
10332
|
+
(0, import_node_fs10.writeFileSync)(tmp, texts2.join("\n") + "\n", { mode: 384 });
|
|
10328
10333
|
(0, import_node_fs10.renameSync)(tmp, file);
|
|
10334
|
+
return texts2.map((text) => Buffer.byteLength(text));
|
|
10329
10335
|
}
|
|
10330
10336
|
function installExitHandler() {
|
|
10331
10337
|
if (exitHandlerInstalled) return;
|
|
@@ -10788,12 +10794,26 @@ var init_suggest = __esm({
|
|
|
10788
10794
|
|
|
10789
10795
|
// src/ai/json-body.ts
|
|
10790
10796
|
function isPlain(value) {
|
|
10797
|
+
plainScans.count++;
|
|
10791
10798
|
for (let i = 0; i < value.length; i += CHECK_CHUNK) {
|
|
10792
10799
|
const chunk = value.slice(i, i + CHECK_CHUNK);
|
|
10793
10800
|
if (JSON.stringify(chunk).length !== chunk.length + 2) return false;
|
|
10794
10801
|
}
|
|
10795
10802
|
return true;
|
|
10796
10803
|
}
|
|
10804
|
+
function largeString(prefix, key, text) {
|
|
10805
|
+
if (text.length < LARGE_STRING_BYTES || !isShortPlain(prefix)) return prefix + text;
|
|
10806
|
+
return new LargeString(prefix, key, text);
|
|
10807
|
+
}
|
|
10808
|
+
function plainLargeBytes(value) {
|
|
10809
|
+
if (!isShortPlain(value.prefix)) return void 0;
|
|
10810
|
+
const known = plainBytes.get(value.key);
|
|
10811
|
+
if (known !== void 0 && known.length === value.text.length) return known.bytes;
|
|
10812
|
+
if (!isPlain(value.text)) return void 0;
|
|
10813
|
+
const bytes = Buffer.byteLength(value.text, "utf8");
|
|
10814
|
+
plainBytes.set(value.key, { length: value.text.length, bytes });
|
|
10815
|
+
return bytes;
|
|
10816
|
+
}
|
|
10797
10817
|
function isContainer(value) {
|
|
10798
10818
|
if (typeof value !== "object" || value === null) return false;
|
|
10799
10819
|
if (typeof value.toJSON === "function") return false;
|
|
@@ -10803,6 +10823,7 @@ function isContainer(value) {
|
|
|
10803
10823
|
}
|
|
10804
10824
|
function collectLarge(value, marked, depth) {
|
|
10805
10825
|
if (isLargeString(value)) return true;
|
|
10826
|
+
if (value instanceof LargeString) return value.text.length >= LARGE_STRING_BYTES;
|
|
10806
10827
|
if (depth >= MAX_DEPTH || !isContainer(value)) return false;
|
|
10807
10828
|
let found = false;
|
|
10808
10829
|
if (Array.isArray(value)) {
|
|
@@ -10835,6 +10856,13 @@ function writeEntry(key, value, marked, out, prefix, depth) {
|
|
|
10835
10856
|
}
|
|
10836
10857
|
return true;
|
|
10837
10858
|
}
|
|
10859
|
+
if (value instanceof LargeString && value.text.length >= LARGE_STRING_BYTES) {
|
|
10860
|
+
const bytes = plainLargeBytes(value);
|
|
10861
|
+
out.text(prefix);
|
|
10862
|
+
if (bytes !== void 0) out.large(value.text, value.prefix, bytes);
|
|
10863
|
+
else out.text(JSON.stringify(value.toJSON()));
|
|
10864
|
+
return true;
|
|
10865
|
+
}
|
|
10838
10866
|
if (depth < MAX_DEPTH && isContainer(value) && marked.has(value)) {
|
|
10839
10867
|
out.text(prefix);
|
|
10840
10868
|
writeContainer(value, marked, out, depth);
|
|
@@ -10868,20 +10896,16 @@ function jsonParts(body) {
|
|
|
10868
10896
|
const marked = /* @__PURE__ */ new Set();
|
|
10869
10897
|
if (!collectLarge(body, marked, 0)) return void 0;
|
|
10870
10898
|
const out = new Pieces();
|
|
10871
|
-
|
|
10872
|
-
if (!isPlain(body)) return void 0;
|
|
10873
|
-
out.large(body);
|
|
10874
|
-
} else writeContainer(body, marked, out, 0);
|
|
10899
|
+
writeEntry("", body, marked, out, "", 0);
|
|
10875
10900
|
const parts = out.finish();
|
|
10876
|
-
|
|
10877
|
-
for (const part of parts) length += Buffer.byteLength(part, "utf8");
|
|
10878
|
-
return { parts, length };
|
|
10901
|
+
return { parts, length: out.bytes };
|
|
10879
10902
|
}
|
|
10880
10903
|
function jsonFetchBody(body) {
|
|
10881
10904
|
const split = jsonParts(body);
|
|
10882
10905
|
if (split === void 0) return { body: JSON.stringify(body) };
|
|
10883
10906
|
const { parts } = split;
|
|
10884
10907
|
let next = 0;
|
|
10908
|
+
let offset = 0;
|
|
10885
10909
|
const stream5 = new ReadableStream({
|
|
10886
10910
|
pull(controller) {
|
|
10887
10911
|
const part = parts[next];
|
|
@@ -10889,8 +10913,15 @@ function jsonFetchBody(body) {
|
|
|
10889
10913
|
controller.close();
|
|
10890
10914
|
return;
|
|
10891
10915
|
}
|
|
10892
|
-
|
|
10893
|
-
|
|
10916
|
+
let end = Math.min(part.length, offset + STREAM_CHUNK_CHARS);
|
|
10917
|
+
const last = part.charCodeAt(end - 1);
|
|
10918
|
+
if (end < part.length && last >= 55296 && last <= 56319) end--;
|
|
10919
|
+
const piece = offset === 0 && end === part.length ? part : part.slice(offset, end);
|
|
10920
|
+
if (end === part.length) {
|
|
10921
|
+
parts[next++] = "";
|
|
10922
|
+
offset = 0;
|
|
10923
|
+
} else offset = end;
|
|
10924
|
+
controller.enqueue(Buffer.from(piece, "utf8"));
|
|
10894
10925
|
},
|
|
10895
10926
|
cancel() {
|
|
10896
10927
|
parts.length = 0;
|
|
@@ -10898,31 +10929,55 @@ function jsonFetchBody(body) {
|
|
|
10898
10929
|
});
|
|
10899
10930
|
return { body: stream5, contentLength: split.length };
|
|
10900
10931
|
}
|
|
10901
|
-
var LARGE_STRING_BYTES, CHECK_CHUNK, MAX_DEPTH, isLargeString, Pieces;
|
|
10932
|
+
var LARGE_STRING_BYTES, CHECK_CHUNK, isShortPlain, plainScans, LargeString, plainBytes, MAX_DEPTH, isLargeString, Pieces, STREAM_CHUNK_CHARS;
|
|
10902
10933
|
var init_json_body = __esm({
|
|
10903
10934
|
"src/ai/json-body.ts"() {
|
|
10904
10935
|
"use strict";
|
|
10905
10936
|
LARGE_STRING_BYTES = 64 * 1024;
|
|
10906
10937
|
CHECK_CHUNK = 16 * 1024;
|
|
10938
|
+
isShortPlain = (value) => JSON.stringify(value).length === value.length + 2;
|
|
10939
|
+
plainScans = { count: 0 };
|
|
10940
|
+
LargeString = class {
|
|
10941
|
+
constructor(prefix, key, text) {
|
|
10942
|
+
this.prefix = prefix;
|
|
10943
|
+
this.key = key;
|
|
10944
|
+
this.text = text;
|
|
10945
|
+
}
|
|
10946
|
+
prefix;
|
|
10947
|
+
key;
|
|
10948
|
+
text;
|
|
10949
|
+
toJSON() {
|
|
10950
|
+
return this.prefix + this.text;
|
|
10951
|
+
}
|
|
10952
|
+
};
|
|
10953
|
+
plainBytes = /* @__PURE__ */ new WeakMap();
|
|
10907
10954
|
MAX_DEPTH = 64;
|
|
10908
10955
|
isLargeString = (value) => typeof value === "string" && value.length >= LARGE_STRING_BYTES;
|
|
10909
10956
|
Pieces = class {
|
|
10910
10957
|
parts = [];
|
|
10958
|
+
/** 已推入 `parts` 的 UTF-8 字节数。 */
|
|
10959
|
+
bytes = 0;
|
|
10911
10960
|
pending = "";
|
|
10912
10961
|
text(chunk) {
|
|
10913
10962
|
this.pending += chunk;
|
|
10914
10963
|
}
|
|
10915
|
-
/**
|
|
10916
|
-
large(value) {
|
|
10917
|
-
|
|
10964
|
+
/** 大字符串原样写入(引号与 `head` 进前一个小片段);`bytes` 已知时不再数一遍。 */
|
|
10965
|
+
large(value, head = "", bytes = Buffer.byteLength(value, "utf8")) {
|
|
10966
|
+
const before2 = `${this.pending}"${head}`;
|
|
10967
|
+
this.parts.push(before2, value);
|
|
10968
|
+
this.bytes += Buffer.byteLength(before2, "utf8") + bytes;
|
|
10918
10969
|
this.pending = '"';
|
|
10919
10970
|
}
|
|
10920
10971
|
finish() {
|
|
10921
|
-
if (this.pending.length > 0)
|
|
10972
|
+
if (this.pending.length > 0) {
|
|
10973
|
+
this.parts.push(this.pending);
|
|
10974
|
+
this.bytes += Buffer.byteLength(this.pending, "utf8");
|
|
10975
|
+
}
|
|
10922
10976
|
this.pending = "";
|
|
10923
10977
|
return this.parts;
|
|
10924
10978
|
}
|
|
10925
10979
|
};
|
|
10980
|
+
STREAM_CHUNK_CHARS = 256 * 1024;
|
|
10926
10981
|
}
|
|
10927
10982
|
});
|
|
10928
10983
|
|
|
@@ -16177,121 +16232,150 @@ var init_edit_fuzzy = __esm({
|
|
|
16177
16232
|
});
|
|
16178
16233
|
|
|
16179
16234
|
// src/tools/read-lines.ts
|
|
16180
|
-
function
|
|
16181
|
-
const
|
|
16235
|
+
async function readHeadAsync(abs, bytes) {
|
|
16236
|
+
const handle = await (0, import_promises3.open)(abs, "r");
|
|
16182
16237
|
try {
|
|
16183
16238
|
const buf = Buffer.alloc(bytes);
|
|
16184
16239
|
let got = 0;
|
|
16185
16240
|
while (got < bytes) {
|
|
16186
|
-
const
|
|
16187
|
-
if (
|
|
16188
|
-
got +=
|
|
16241
|
+
const { bytesRead } = await handle.read(buf, got, bytes - got, null);
|
|
16242
|
+
if (bytesRead === 0) break;
|
|
16243
|
+
got += bytesRead;
|
|
16189
16244
|
}
|
|
16190
16245
|
return buf.subarray(0, got);
|
|
16191
16246
|
} finally {
|
|
16192
|
-
|
|
16247
|
+
await handle.close();
|
|
16193
16248
|
}
|
|
16194
16249
|
}
|
|
16195
|
-
function
|
|
16250
|
+
function scanner(offset, limit, maxBytes) {
|
|
16196
16251
|
const first = offset - 1;
|
|
16197
|
-
|
|
16198
|
-
|
|
16199
|
-
|
|
16200
|
-
|
|
16201
|
-
let collected = 0;
|
|
16202
|
-
let index2 = 0;
|
|
16203
|
-
let parts = [];
|
|
16204
|
-
let partBytes = 0;
|
|
16205
|
-
let pending = false;
|
|
16206
|
-
let skipLF = false;
|
|
16207
|
-
let bom = false;
|
|
16208
|
-
const collecting = () => truncatedBy === void 0 && index2 >= first && index2 < stop;
|
|
16209
|
-
const take = (buf, from, to) => {
|
|
16210
|
-
if (to <= from || partBytes >= lineCap) return;
|
|
16211
|
-
const end = Math.min(to, from + lineCap - partBytes);
|
|
16212
|
-
parts.push(Buffer.from(buf.subarray(from, end)));
|
|
16213
|
-
partBytes += end - from;
|
|
16214
|
-
};
|
|
16215
|
-
const finish2 = () => {
|
|
16216
|
-
if (collecting()) {
|
|
16217
|
-
const line2 = (parts.length === 1 ? parts[0] : Buffer.concat(parts)).toString("utf8");
|
|
16218
|
-
lines2.push(line2);
|
|
16219
|
-
collected += Buffer.byteLength(line2) + 1;
|
|
16220
|
-
if (collected > maxBytes) truncatedBy = "bytes";
|
|
16221
|
-
}
|
|
16222
|
-
if (partBytes > 0) parts = [];
|
|
16223
|
-
partBytes = 0;
|
|
16224
|
-
pending = false;
|
|
16225
|
-
index2++;
|
|
16226
|
-
};
|
|
16252
|
+
return new LineScanner(first, limit === void 0 ? Infinity : first + limit, maxBytes);
|
|
16253
|
+
}
|
|
16254
|
+
async function readLineWindowAsync(abs, offset, limit, maxBytes, chunkBytes = CHUNK_BYTES) {
|
|
16255
|
+
const scan = scanner(offset, limit, maxBytes);
|
|
16227
16256
|
const size = Math.max(3, chunkBytes);
|
|
16228
|
-
const
|
|
16257
|
+
const handle = await (0, import_promises3.open)(abs, "r");
|
|
16229
16258
|
try {
|
|
16230
16259
|
const buf = Buffer.alloc(size);
|
|
16231
16260
|
let carry = 0;
|
|
16232
|
-
let firstChunk = true;
|
|
16233
16261
|
for (; ; ) {
|
|
16234
|
-
const n =
|
|
16262
|
+
const { bytesRead: n } = await handle.read(buf, carry, size - carry, null);
|
|
16235
16263
|
const end = carry + n;
|
|
16236
|
-
|
|
16237
|
-
|
|
16238
|
-
let pos = 0;
|
|
16239
|
-
if (firstChunk) {
|
|
16240
|
-
if (end < 3 && n > 0) {
|
|
16241
|
-
carry = end;
|
|
16242
|
-
continue;
|
|
16243
|
-
}
|
|
16244
|
-
firstChunk = false;
|
|
16245
|
-
if (end >= 3 && buf[0] === 239 && buf[1] === 187 && buf[2] === 191) {
|
|
16246
|
-
bom = true;
|
|
16247
|
-
pos = 3;
|
|
16248
|
-
}
|
|
16249
|
-
}
|
|
16250
|
-
if (skipLF && pos < end) {
|
|
16251
|
-
if (buf[pos] === LF2) pos++;
|
|
16252
|
-
skipLF = false;
|
|
16253
|
-
}
|
|
16254
|
-
let nextLF = buf.indexOf(LF2, pos);
|
|
16255
|
-
let nextCR = buf.indexOf(CR2, pos);
|
|
16256
|
-
while (pos < end) {
|
|
16257
|
-
if (nextLF !== -1 && nextLF < pos) nextLF = buf.indexOf(LF2, pos);
|
|
16258
|
-
if (nextCR !== -1 && nextCR < pos) nextCR = buf.indexOf(CR2, pos);
|
|
16259
|
-
const lf = nextLF === -1 || nextLF >= end ? end : nextLF;
|
|
16260
|
-
const cr = nextCR === -1 || nextCR >= end ? end : nextCR;
|
|
16261
|
-
const at = Math.min(lf, cr);
|
|
16262
|
-
if (at > pos) {
|
|
16263
|
-
pending = true;
|
|
16264
|
-
if (collecting()) take(buf, pos, at);
|
|
16265
|
-
}
|
|
16266
|
-
if (at === end) break;
|
|
16267
|
-
finish2();
|
|
16268
|
-
pos = at + 1;
|
|
16269
|
-
if (at === cr) {
|
|
16270
|
-
if (pos < end) {
|
|
16271
|
-
if (buf[pos] === LF2) pos++;
|
|
16272
|
-
} else {
|
|
16273
|
-
skipLF = true;
|
|
16274
|
-
}
|
|
16275
|
-
}
|
|
16276
|
-
}
|
|
16264
|
+
if (end === 0) break;
|
|
16265
|
+
carry = scan.feed(buf, end, n === 0);
|
|
16277
16266
|
if (n === 0) break;
|
|
16278
16267
|
}
|
|
16279
|
-
if (pending) finish2();
|
|
16280
16268
|
} finally {
|
|
16281
|
-
|
|
16269
|
+
await handle.close();
|
|
16282
16270
|
}
|
|
16283
|
-
return
|
|
16271
|
+
return scan.finish();
|
|
16284
16272
|
}
|
|
16285
|
-
var
|
|
16273
|
+
var import_promises3, STREAM_READ_THRESHOLD, CHUNK_BYTES, LINE_SLACK, LF2, CR2, LineScanner;
|
|
16286
16274
|
var init_read_lines = __esm({
|
|
16287
16275
|
"src/tools/read-lines.ts"() {
|
|
16288
16276
|
"use strict";
|
|
16289
|
-
|
|
16277
|
+
import_promises3 = require("node:fs/promises");
|
|
16290
16278
|
STREAM_READ_THRESHOLD = 1024 * 1024;
|
|
16291
16279
|
CHUNK_BYTES = 64 * 1024;
|
|
16292
16280
|
LINE_SLACK = 64;
|
|
16293
16281
|
LF2 = 10;
|
|
16294
16282
|
CR2 = 13;
|
|
16283
|
+
LineScanner = class {
|
|
16284
|
+
constructor(first, stop, maxBytes) {
|
|
16285
|
+
this.first = first;
|
|
16286
|
+
this.stop = stop;
|
|
16287
|
+
this.maxBytes = maxBytes;
|
|
16288
|
+
this.lineCap = maxBytes + LINE_SLACK;
|
|
16289
|
+
}
|
|
16290
|
+
first;
|
|
16291
|
+
stop;
|
|
16292
|
+
maxBytes;
|
|
16293
|
+
lineCap;
|
|
16294
|
+
lines = [];
|
|
16295
|
+
truncatedBy;
|
|
16296
|
+
collected = 0;
|
|
16297
|
+
index = 0;
|
|
16298
|
+
// 已完成的行数
|
|
16299
|
+
parts = [];
|
|
16300
|
+
partBytes = 0;
|
|
16301
|
+
pending = false;
|
|
16302
|
+
// 最后一个终止符之后已有字节
|
|
16303
|
+
skipLF = false;
|
|
16304
|
+
// 上一块以 `\r` 结尾:下一块开头的 `\n` 属于同一终止符
|
|
16305
|
+
bom = false;
|
|
16306
|
+
firstChunk = true;
|
|
16307
|
+
/**
|
|
16308
|
+
* 处理 `buf[0, end)`;`eof` 表示这是最后一块。返回调用方下次读取前应保留在 `buf` 开头的字节数
|
|
16309
|
+
* (只在首块不足 3 字节、还判断不了 BOM 时非零)。
|
|
16310
|
+
*/
|
|
16311
|
+
feed(buf, end, eof) {
|
|
16312
|
+
let pos = 0;
|
|
16313
|
+
if (this.firstChunk) {
|
|
16314
|
+
if (end < 3 && !eof) return end;
|
|
16315
|
+
this.firstChunk = false;
|
|
16316
|
+
if (end >= 3 && buf[0] === 239 && buf[1] === 187 && buf[2] === 191) {
|
|
16317
|
+
this.bom = true;
|
|
16318
|
+
pos = 3;
|
|
16319
|
+
}
|
|
16320
|
+
}
|
|
16321
|
+
if (this.skipLF && pos < end) {
|
|
16322
|
+
if (buf[pos] === LF2) pos++;
|
|
16323
|
+
this.skipLF = false;
|
|
16324
|
+
}
|
|
16325
|
+
let nextLF = buf.indexOf(LF2, pos);
|
|
16326
|
+
let nextCR = buf.indexOf(CR2, pos);
|
|
16327
|
+
while (pos < end) {
|
|
16328
|
+
if (nextLF !== -1 && nextLF < pos) nextLF = buf.indexOf(LF2, pos);
|
|
16329
|
+
if (nextCR !== -1 && nextCR < pos) nextCR = buf.indexOf(CR2, pos);
|
|
16330
|
+
const lf = nextLF === -1 || nextLF >= end ? end : nextLF;
|
|
16331
|
+
const cr = nextCR === -1 || nextCR >= end ? end : nextCR;
|
|
16332
|
+
const at = Math.min(lf, cr);
|
|
16333
|
+
if (at > pos) {
|
|
16334
|
+
this.pending = true;
|
|
16335
|
+
if (this.collecting()) this.take(buf, pos, at);
|
|
16336
|
+
}
|
|
16337
|
+
if (at === end) break;
|
|
16338
|
+
this.endLine();
|
|
16339
|
+
pos = at + 1;
|
|
16340
|
+
if (at === cr) {
|
|
16341
|
+
if (pos < end) {
|
|
16342
|
+
if (buf[pos] === LF2) pos++;
|
|
16343
|
+
} else {
|
|
16344
|
+
this.skipLF = true;
|
|
16345
|
+
}
|
|
16346
|
+
}
|
|
16347
|
+
}
|
|
16348
|
+
return 0;
|
|
16349
|
+
}
|
|
16350
|
+
/** 文件读完:收尾最后一行并给出结果。 */
|
|
16351
|
+
finish() {
|
|
16352
|
+
if (this.pending) this.endLine();
|
|
16353
|
+
const { lines: lines2, truncatedBy, bom } = this;
|
|
16354
|
+
return { lines: lines2, totalLines: this.index, ...truncatedBy ? { truncatedBy } : {}, bom };
|
|
16355
|
+
}
|
|
16356
|
+
collecting() {
|
|
16357
|
+
return this.truncatedBy === void 0 && this.index >= this.first && this.index < this.stop;
|
|
16358
|
+
}
|
|
16359
|
+
take(buf, from, to) {
|
|
16360
|
+
if (to <= from || this.partBytes >= this.lineCap) return;
|
|
16361
|
+
const end = Math.min(to, from + this.lineCap - this.partBytes);
|
|
16362
|
+
this.parts.push(Buffer.from(buf.subarray(from, end)));
|
|
16363
|
+
this.partBytes += end - from;
|
|
16364
|
+
}
|
|
16365
|
+
endLine() {
|
|
16366
|
+
if (this.collecting()) {
|
|
16367
|
+
const { parts } = this;
|
|
16368
|
+
const line2 = (parts.length === 1 ? parts[0] : Buffer.concat(parts)).toString("utf8");
|
|
16369
|
+
this.lines.push(line2);
|
|
16370
|
+
this.collected += Buffer.byteLength(line2) + 1;
|
|
16371
|
+
if (this.collected > this.maxBytes) this.truncatedBy = "bytes";
|
|
16372
|
+
}
|
|
16373
|
+
if (this.partBytes > 0) this.parts = [];
|
|
16374
|
+
this.partBytes = 0;
|
|
16375
|
+
this.pending = false;
|
|
16376
|
+
this.index++;
|
|
16377
|
+
}
|
|
16378
|
+
};
|
|
16295
16379
|
}
|
|
16296
16380
|
});
|
|
16297
16381
|
|
|
@@ -16363,7 +16447,7 @@ async function resizeImage(input2, target, deps = {}) {
|
|
|
16363
16447
|
const mimeType = format === "jpeg" ? "image/jpeg" : "image/png";
|
|
16364
16448
|
const long = target.size !== void 0 ? Math.max(target.size.width, target.size.height) : 0;
|
|
16365
16449
|
const start = long > 0 ? Math.min(target.maxEdge, long) : target.maxEdge;
|
|
16366
|
-
const dir = await (0,
|
|
16450
|
+
const dir = await (0, import_promises4.mkdtemp)((0, import_node_path25.join)(deps.tmpDir ?? (0, import_node_os5.tmpdir)(), "ama-resize-"));
|
|
16367
16451
|
try {
|
|
16368
16452
|
for (const tool of resizeTools(deps.platform ?? process.platform)) {
|
|
16369
16453
|
let edge = start;
|
|
@@ -16374,7 +16458,7 @@ async function resizeImage(input2, target, deps = {}) {
|
|
|
16374
16458
|
if (result.missing === true || result.code !== 0) break;
|
|
16375
16459
|
let buf;
|
|
16376
16460
|
try {
|
|
16377
|
-
buf = await (0,
|
|
16461
|
+
buf = await (0, import_promises4.readFile)(output);
|
|
16378
16462
|
} catch {
|
|
16379
16463
|
break;
|
|
16380
16464
|
}
|
|
@@ -16390,15 +16474,15 @@ async function resizeImage(input2, target, deps = {}) {
|
|
|
16390
16474
|
}
|
|
16391
16475
|
return { ok: false, reason: "no_tool" };
|
|
16392
16476
|
} finally {
|
|
16393
|
-
await (0,
|
|
16477
|
+
await (0, import_promises4.rm)(dir, { recursive: true, force: true }).catch(() => void 0);
|
|
16394
16478
|
}
|
|
16395
16479
|
}
|
|
16396
|
-
var import_node_child_process3,
|
|
16480
|
+
var import_node_child_process3, import_promises4, import_node_os5, import_node_path25, runCommand, MAX_ATTEMPTS, SHRINK, MIN_EDGE;
|
|
16397
16481
|
var init_image_resize = __esm({
|
|
16398
16482
|
"src/tools/image-resize.ts"() {
|
|
16399
16483
|
"use strict";
|
|
16400
16484
|
import_node_child_process3 = require("node:child_process");
|
|
16401
|
-
|
|
16485
|
+
import_promises4 = require("node:fs/promises");
|
|
16402
16486
|
import_node_os5 = require("node:os");
|
|
16403
16487
|
import_node_path25 = require("node:path");
|
|
16404
16488
|
init_image_limits();
|
|
@@ -16570,7 +16654,7 @@ function fitError(path, fit, limit, bytes, resizeOff) {
|
|
|
16570
16654
|
async function loadImageFile(path, options = {}) {
|
|
16571
16655
|
let info2;
|
|
16572
16656
|
try {
|
|
16573
|
-
info2 = await (0,
|
|
16657
|
+
info2 = await (0, import_promises5.stat)(path);
|
|
16574
16658
|
} catch {
|
|
16575
16659
|
throw imageError(`Image not found: ${path}`, { reason: "missing", path });
|
|
16576
16660
|
}
|
|
@@ -16586,7 +16670,7 @@ async function loadImageFile(path, options = {}) {
|
|
|
16586
16670
|
sizeMb
|
|
16587
16671
|
});
|
|
16588
16672
|
}
|
|
16589
|
-
const buf = await (0,
|
|
16673
|
+
const buf = await (0, import_promises5.readFile)(path);
|
|
16590
16674
|
const mimeType = sniffImageMime(buf) ?? imageMimeFromPath(path);
|
|
16591
16675
|
if (mimeType === void 0)
|
|
16592
16676
|
throw imageError(`Unsupported image (PNG / JPEG / GIF / WebP): ${path}`, {
|
|
@@ -16603,11 +16687,11 @@ async function loadImageFile(path, options = {}) {
|
|
|
16603
16687
|
...fit.size ? { size: fit.size } : {}
|
|
16604
16688
|
};
|
|
16605
16689
|
}
|
|
16606
|
-
var
|
|
16690
|
+
var import_promises5, import_node_path26, MAX_IMAGE_FILE_BYTES, IMAGE_EXTENSIONS, HINT_TEXT;
|
|
16607
16691
|
var init_image_file = __esm({
|
|
16608
16692
|
"src/tools/image-file.ts"() {
|
|
16609
16693
|
"use strict";
|
|
16610
|
-
|
|
16694
|
+
import_promises5 = require("node:fs/promises");
|
|
16611
16695
|
import_node_path26 = require("node:path");
|
|
16612
16696
|
init_errors();
|
|
16613
16697
|
init_image_intern();
|
|
@@ -16654,7 +16738,7 @@ function numberLines(lines2, firstLine3) {
|
|
|
16654
16738
|
return lines2.map((line2, i) => `${String(firstLine3 + i).padStart(6)} ${line2}`).join("\n");
|
|
16655
16739
|
}
|
|
16656
16740
|
async function readImage(abs, shown2, ctx, options) {
|
|
16657
|
-
const buf = await (0,
|
|
16741
|
+
const buf = await (0, import_promises6.readFile)(abs);
|
|
16658
16742
|
const mimeType = sniffImageMime(buf) ?? imageMimeFromPath(abs) ?? "application/octet-stream";
|
|
16659
16743
|
const size = imageSize(buf, mimeType);
|
|
16660
16744
|
const dims = size ? `${size.width}x${size.height}, ` : "";
|
|
@@ -16685,7 +16769,7 @@ async function executeRead(input2, ctx, options = {}) {
|
|
|
16685
16769
|
const shown2 = displayPath(abs, ctx.cwd);
|
|
16686
16770
|
let info2;
|
|
16687
16771
|
try {
|
|
16688
|
-
info2 = await (0,
|
|
16772
|
+
info2 = await (0, import_promises6.stat)(abs);
|
|
16689
16773
|
} catch {
|
|
16690
16774
|
return error(`File not found: ${shown2}`);
|
|
16691
16775
|
}
|
|
@@ -16698,9 +16782,9 @@ async function executeRead(input2, ctx, options = {}) {
|
|
|
16698
16782
|
let totalLines;
|
|
16699
16783
|
let selected;
|
|
16700
16784
|
if (info2.size > (options.streamThreshold ?? STREAM_READ_THRESHOLD)) {
|
|
16701
|
-
if (isBinary(
|
|
16785
|
+
if (isBinary(await readHeadAsync(abs, SNIFF_BYTES))) return error(binaryMessage(shown2));
|
|
16702
16786
|
const want = Math.min(input2.limit ?? Infinity, DEFAULT_MAX_LINES + 1);
|
|
16703
|
-
const win =
|
|
16787
|
+
const win = await readLineWindowAsync(
|
|
16704
16788
|
abs,
|
|
16705
16789
|
badOffset ? 1 : offset,
|
|
16706
16790
|
badOffset || badLimit ? 0 : want,
|
|
@@ -16709,7 +16793,7 @@ async function executeRead(input2, ctx, options = {}) {
|
|
|
16709
16793
|
totalLines = win.totalLines;
|
|
16710
16794
|
selected = win.lines;
|
|
16711
16795
|
} else {
|
|
16712
|
-
const buf = await (0,
|
|
16796
|
+
const buf = await (0, import_promises6.readFile)(abs);
|
|
16713
16797
|
if (isBinary(buf)) return error(binaryMessage(shown2));
|
|
16714
16798
|
const { text } = splitBom(buf.toString("utf8"));
|
|
16715
16799
|
const normalized = normalizeToLF(text);
|
|
@@ -16770,11 +16854,11 @@ function createReadTool(options = {}) {
|
|
|
16770
16854
|
execute: (input2, ctx) => executeRead(input2, ctx, options)
|
|
16771
16855
|
};
|
|
16772
16856
|
}
|
|
16773
|
-
var
|
|
16857
|
+
var import_promises6, SNIFF_BYTES, binaryMessage;
|
|
16774
16858
|
var init_read = __esm({
|
|
16775
16859
|
"src/tools/read.ts"() {
|
|
16776
16860
|
"use strict";
|
|
16777
|
-
|
|
16861
|
+
import_promises6 = require("node:fs/promises");
|
|
16778
16862
|
init_image_intern();
|
|
16779
16863
|
init_paths2();
|
|
16780
16864
|
init_truncate();
|
|
@@ -16943,7 +17027,7 @@ async function executeEdit(input2, ctx) {
|
|
|
16943
17027
|
const shown2 = displayPath(abs, ctx.cwd);
|
|
16944
17028
|
return withFileMutex(abs, async () => {
|
|
16945
17029
|
try {
|
|
16946
|
-
const info2 = await (0,
|
|
17030
|
+
const info2 = await (0, import_promises7.stat)(abs);
|
|
16947
17031
|
if (!info2.isFile()) return { content: `${shown2} is not a regular file`, isError: true };
|
|
16948
17032
|
} catch {
|
|
16949
17033
|
return { content: `File not found: ${shown2}`, isError: true };
|
|
@@ -16951,7 +17035,7 @@ async function executeEdit(input2, ctx) {
|
|
|
16951
17035
|
if (!ctx.readFiles.has(abs)) {
|
|
16952
17036
|
return { content: `Read ${shown2} with the read tool before editing it.`, isError: true };
|
|
16953
17037
|
}
|
|
16954
|
-
const raw = await (0,
|
|
17038
|
+
const raw = await (0, import_promises7.readFile)(abs, "utf8");
|
|
16955
17039
|
const { bom, text } = splitBom(raw);
|
|
16956
17040
|
const ending = detectLineEnding(text);
|
|
16957
17041
|
const content = normalizeToLF(text);
|
|
@@ -16964,7 +17048,7 @@ async function executeEdit(input2, ctx) {
|
|
|
16964
17048
|
}
|
|
16965
17049
|
const output = bom + restoreLineEndings(plan2.result, ending);
|
|
16966
17050
|
await beforeWrite(ctx, abs);
|
|
16967
|
-
await (0,
|
|
17051
|
+
await (0, import_promises7.writeFile)(abs, output, "utf8");
|
|
16968
17052
|
ctx.checkpoint?.afterWrite(abs, output);
|
|
16969
17053
|
const details = {
|
|
16970
17054
|
path: abs,
|
|
@@ -17014,11 +17098,11 @@ function createEditTool() {
|
|
|
17014
17098
|
execute: executeEdit
|
|
17015
17099
|
};
|
|
17016
17100
|
}
|
|
17017
|
-
var
|
|
17101
|
+
var import_promises7, EditError;
|
|
17018
17102
|
var init_edit = __esm({
|
|
17019
17103
|
"src/tools/edit.ts"() {
|
|
17020
17104
|
"use strict";
|
|
17021
|
-
|
|
17105
|
+
import_promises7 = require("node:fs/promises");
|
|
17022
17106
|
init_types8();
|
|
17023
17107
|
init_paths2();
|
|
17024
17108
|
init_file_mutex();
|
|
@@ -17031,7 +17115,7 @@ var init_edit = __esm({
|
|
|
17031
17115
|
// src/tools/write.ts
|
|
17032
17116
|
async function exists2(path) {
|
|
17033
17117
|
try {
|
|
17034
|
-
const info2 = await (0,
|
|
17118
|
+
const info2 = await (0, import_promises8.stat)(path);
|
|
17035
17119
|
return info2.isDirectory() ? "dir" : "file";
|
|
17036
17120
|
} catch {
|
|
17037
17121
|
return false;
|
|
@@ -17072,12 +17156,12 @@ async function executeWrite(input2, ctx) {
|
|
|
17072
17156
|
isError: true
|
|
17073
17157
|
};
|
|
17074
17158
|
}
|
|
17075
|
-
original = await (0,
|
|
17159
|
+
original = await (0, import_promises8.readFile)(abs, "utf8");
|
|
17076
17160
|
output = conformToOriginal(original, input2.content);
|
|
17077
17161
|
}
|
|
17078
17162
|
await beforeWrite(ctx, abs);
|
|
17079
|
-
await (0,
|
|
17080
|
-
await (0,
|
|
17163
|
+
await (0, import_promises8.mkdir)((0, import_node_path27.dirname)(abs), { recursive: true });
|
|
17164
|
+
await (0, import_promises8.writeFile)(abs, output, "utf8");
|
|
17081
17165
|
ctx.checkpoint?.afterWrite(abs, output);
|
|
17082
17166
|
ctx.markRead(abs);
|
|
17083
17167
|
const details = {
|
|
@@ -17113,11 +17197,11 @@ function createWriteTool() {
|
|
|
17113
17197
|
execute: executeWrite
|
|
17114
17198
|
};
|
|
17115
17199
|
}
|
|
17116
|
-
var
|
|
17200
|
+
var import_promises8, import_node_path27;
|
|
17117
17201
|
var init_write = __esm({
|
|
17118
17202
|
"src/tools/write.ts"() {
|
|
17119
17203
|
"use strict";
|
|
17120
|
-
|
|
17204
|
+
import_promises8 = require("node:fs/promises");
|
|
17121
17205
|
import_node_path27 = require("node:path");
|
|
17122
17206
|
init_paths2();
|
|
17123
17207
|
init_file_mutex();
|
|
@@ -17148,7 +17232,7 @@ function gitBashCandidates(env) {
|
|
|
17148
17232
|
function resolveShell(deps = {}) {
|
|
17149
17233
|
const platform = deps.platform ?? process.platform;
|
|
17150
17234
|
const env = deps.env ?? process.env;
|
|
17151
|
-
const exists5 = deps.exists ??
|
|
17235
|
+
const exists5 = deps.exists ?? import_node_fs22.existsSync;
|
|
17152
17236
|
const custom = env["AMA_SHELL"]?.trim();
|
|
17153
17237
|
if (custom) return { shell: custom, kind: shellKindOf(custom) };
|
|
17154
17238
|
if (platform === "win32") {
|
|
@@ -17188,11 +17272,11 @@ function buildToolEnv(base4, info2) {
|
|
|
17188
17272
|
set("AMA_DEPTH", String(info2.depth));
|
|
17189
17273
|
return env;
|
|
17190
17274
|
}
|
|
17191
|
-
var
|
|
17275
|
+
var import_node_fs22, POWERSHELL_ARGS, INJECTED_ENV_VARS;
|
|
17192
17276
|
var init_shell = __esm({
|
|
17193
17277
|
"src/tools/shell.ts"() {
|
|
17194
17278
|
"use strict";
|
|
17195
|
-
|
|
17279
|
+
import_node_fs22 = require("node:fs");
|
|
17196
17280
|
POWERSHELL_ARGS = ["-NoProfile", "-NonInteractive", "-Command"];
|
|
17197
17281
|
INJECTED_ENV_VARS = [
|
|
17198
17282
|
"AMA_SESSION_ID",
|
|
@@ -17307,11 +17391,11 @@ var init_process_tree = __esm({
|
|
|
17307
17391
|
function sanitizeOutput(text) {
|
|
17308
17392
|
return text.replace(/\r\n/g, "\n").replace(ANSI, "").replace(/\r/g, "\n").replace(CONTROL, "");
|
|
17309
17393
|
}
|
|
17310
|
-
var
|
|
17394
|
+
var import_node_fs23, import_node_path28, import_node_string_decoder2, ANSI, CONTROL, OutputAccumulator;
|
|
17311
17395
|
var init_output_accumulator = __esm({
|
|
17312
17396
|
"src/tools/output-accumulator.ts"() {
|
|
17313
17397
|
"use strict";
|
|
17314
|
-
|
|
17398
|
+
import_node_fs23 = require("node:fs");
|
|
17315
17399
|
import_node_path28 = require("node:path");
|
|
17316
17400
|
import_node_string_decoder2 = require("node:string_decoder");
|
|
17317
17401
|
init_truncate();
|
|
@@ -17353,7 +17437,7 @@ var init_output_accumulator = __esm({
|
|
|
17353
17437
|
this.tailText = sliceTailBytes(this.tailText, this.maxBytes * 2);
|
|
17354
17438
|
}
|
|
17355
17439
|
if (this.spilledTo !== void 0) {
|
|
17356
|
-
(0,
|
|
17440
|
+
(0, import_node_fs23.appendFileSync)(this.spilledTo, text);
|
|
17357
17441
|
return;
|
|
17358
17442
|
}
|
|
17359
17443
|
this.chunks.push(text);
|
|
@@ -17362,8 +17446,8 @@ var init_output_accumulator = __esm({
|
|
|
17362
17446
|
}
|
|
17363
17447
|
spill() {
|
|
17364
17448
|
const target = this.options.spillPath();
|
|
17365
|
-
(0,
|
|
17366
|
-
(0,
|
|
17449
|
+
(0, import_node_fs23.mkdirSync)((0, import_node_path28.dirname)(target), { recursive: true });
|
|
17450
|
+
(0, import_node_fs23.writeFileSync)(target, this.chunks.join(""));
|
|
17367
17451
|
this.spilledTo = target;
|
|
17368
17452
|
this.chunks = [];
|
|
17369
17453
|
this.memoryBytes = 0;
|
|
@@ -17421,11 +17505,11 @@ async function disposeSessionJobs(sessionId) {
|
|
|
17421
17505
|
registry2.delete(sessionId);
|
|
17422
17506
|
await jobs.disposeAll();
|
|
17423
17507
|
}
|
|
17424
|
-
var
|
|
17508
|
+
var import_node_fs24, import_node_path29, BackgroundJobs, registry2;
|
|
17425
17509
|
var init_background_jobs = __esm({
|
|
17426
17510
|
"src/tools/background-jobs.ts"() {
|
|
17427
17511
|
"use strict";
|
|
17428
|
-
|
|
17512
|
+
import_node_fs24 = require("node:fs");
|
|
17429
17513
|
import_node_path29 = require("node:path");
|
|
17430
17514
|
init_process_tree();
|
|
17431
17515
|
init_truncate();
|
|
@@ -17434,13 +17518,13 @@ var init_background_jobs = __esm({
|
|
|
17434
17518
|
listeners = /* @__PURE__ */ new Set();
|
|
17435
17519
|
seq = 0;
|
|
17436
17520
|
start(command3, options) {
|
|
17437
|
-
(0,
|
|
17438
|
-
const fd = (0,
|
|
17521
|
+
(0, import_node_fs24.mkdirSync)((0, import_node_path29.dirname)(options.outputPath), { recursive: true });
|
|
17522
|
+
const fd = (0, import_node_fs24.openSync)(options.outputPath, "a");
|
|
17439
17523
|
let child;
|
|
17440
17524
|
try {
|
|
17441
17525
|
child = options.spawn(fd);
|
|
17442
17526
|
} finally {
|
|
17443
|
-
(0,
|
|
17527
|
+
(0, import_node_fs24.closeSync)(fd);
|
|
17444
17528
|
}
|
|
17445
17529
|
const id = `bg${++this.seq}`;
|
|
17446
17530
|
const job = {
|
|
@@ -17521,8 +17605,8 @@ var init_background_jobs = __esm({
|
|
|
17521
17605
|
if (entry === void 0) return void 0;
|
|
17522
17606
|
let text = "";
|
|
17523
17607
|
try {
|
|
17524
|
-
if ((0,
|
|
17525
|
-
text = (0,
|
|
17608
|
+
if ((0, import_node_fs24.statSync)(entry.job.outputPath).size > 0)
|
|
17609
|
+
text = (0, import_node_fs24.readFileSync)(entry.job.outputPath, "utf8");
|
|
17526
17610
|
} catch {
|
|
17527
17611
|
}
|
|
17528
17612
|
return { ...truncateTail(text), job: entry.job };
|
|
@@ -17568,7 +17652,7 @@ var init_background_jobs = __esm({
|
|
|
17568
17652
|
});
|
|
17569
17653
|
|
|
17570
17654
|
// src/sandbox/wrap.ts
|
|
17571
|
-
function resolveWritable(dirs, realpath4 =
|
|
17655
|
+
function resolveWritable(dirs, realpath4 = import_node_fs25.realpathSync) {
|
|
17572
17656
|
const out = [];
|
|
17573
17657
|
for (const dir of dirs) {
|
|
17574
17658
|
let real2;
|
|
@@ -17583,12 +17667,12 @@ function resolveWritable(dirs, realpath4 = import_node_fs26.realpathSync) {
|
|
|
17583
17667
|
}
|
|
17584
17668
|
function isDirectory(path) {
|
|
17585
17669
|
try {
|
|
17586
|
-
return (0,
|
|
17670
|
+
return (0, import_node_fs25.statSync)(path).isDirectory();
|
|
17587
17671
|
} catch {
|
|
17588
17672
|
return false;
|
|
17589
17673
|
}
|
|
17590
17674
|
}
|
|
17591
|
-
function resolveExtras(policy, missingOk, realpath4 =
|
|
17675
|
+
function resolveExtras(policy, missingOk, realpath4 = import_node_fs25.realpathSync, isDir4 = isDirectory) {
|
|
17592
17676
|
const readOnly = [];
|
|
17593
17677
|
for (const path of policy.readOnly ?? []) {
|
|
17594
17678
|
let real2;
|
|
@@ -17660,11 +17744,11 @@ function wrapCommand(status, command3, args, policy, realpath4, isDir4) {
|
|
|
17660
17744
|
};
|
|
17661
17745
|
}
|
|
17662
17746
|
}
|
|
17663
|
-
var
|
|
17747
|
+
var import_node_fs25, import_node_path30;
|
|
17664
17748
|
var init_wrap = __esm({
|
|
17665
17749
|
"src/sandbox/wrap.ts"() {
|
|
17666
17750
|
"use strict";
|
|
17667
|
-
|
|
17751
|
+
import_node_fs25 = require("node:fs");
|
|
17668
17752
|
import_node_path30 = require("node:path");
|
|
17669
17753
|
init_profile2();
|
|
17670
17754
|
}
|
|
@@ -17827,7 +17911,7 @@ async function executeBash(input2, ctx, options = {}) {
|
|
|
17827
17911
|
}
|
|
17828
17912
|
const cwd = resolvePath(input2.cwd ?? ".", ctx.cwd);
|
|
17829
17913
|
try {
|
|
17830
|
-
if (!(await (0,
|
|
17914
|
+
if (!(await (0, import_promises9.stat)(cwd)).isDirectory())
|
|
17831
17915
|
return fail2(`Working directory is not a directory: ${cwd}`);
|
|
17832
17916
|
} catch {
|
|
17833
17917
|
return fail2(`Working directory does not exist: ${cwd}`);
|
|
@@ -18077,12 +18161,12 @@ function createBashTool(options = {}) {
|
|
|
18077
18161
|
execute: (input2, ctx) => executeBash(input2, ctx, options)
|
|
18078
18162
|
};
|
|
18079
18163
|
}
|
|
18080
|
-
var import_node_child_process5,
|
|
18164
|
+
var import_node_child_process5, import_promises9, import_node_path32, DEFAULT_BASH_TIMEOUT_MS, MAX_BASH_TIMEOUT_MS, UPDATE_THROTTLE_MS, STDIO_DRAIN_MS, DEFAULT_JOB_WAIT_MS;
|
|
18081
18165
|
var init_bash2 = __esm({
|
|
18082
18166
|
"src/tools/bash.ts"() {
|
|
18083
18167
|
"use strict";
|
|
18084
18168
|
import_node_child_process5 = require("node:child_process");
|
|
18085
|
-
|
|
18169
|
+
import_promises9 = require("node:fs/promises");
|
|
18086
18170
|
import_node_path32 = require("node:path");
|
|
18087
18171
|
init_paths2();
|
|
18088
18172
|
init_shell();
|
|
@@ -18109,9 +18193,9 @@ function compilePattern(input2) {
|
|
|
18109
18193
|
}
|
|
18110
18194
|
async function searchFile(abs, regex, firstOnly = false) {
|
|
18111
18195
|
try {
|
|
18112
|
-
const info2 = await (0,
|
|
18196
|
+
const info2 = await (0, import_promises10.stat)(abs);
|
|
18113
18197
|
if (!info2.isFile() || info2.size > GREP_MAX_FILE_BYTES) return void 0;
|
|
18114
|
-
const buf = await (0,
|
|
18198
|
+
const buf = await (0, import_promises10.readFile)(abs);
|
|
18115
18199
|
if (isBinary(buf)) return void 0;
|
|
18116
18200
|
const lines2 = buf.toString("utf8").replace(/\r\n/g, "\n").split("\n");
|
|
18117
18201
|
if (lines2[lines2.length - 1] === "") lines2.pop();
|
|
@@ -18172,7 +18256,7 @@ async function executeGrep(input2, ctx) {
|
|
|
18172
18256
|
const root = resolvePath(input2.path ?? ".", ctx.cwd);
|
|
18173
18257
|
let rootIsFile;
|
|
18174
18258
|
try {
|
|
18175
|
-
rootIsFile = (await (0,
|
|
18259
|
+
rootIsFile = (await (0, import_promises10.stat)(root)).isFile();
|
|
18176
18260
|
} catch {
|
|
18177
18261
|
return { content: `Path not found: ${displayPath(root, ctx.cwd)}`, isError: true };
|
|
18178
18262
|
}
|
|
@@ -18277,11 +18361,11 @@ function createGrepTool() {
|
|
|
18277
18361
|
execute: executeGrep
|
|
18278
18362
|
};
|
|
18279
18363
|
}
|
|
18280
|
-
var
|
|
18364
|
+
var import_promises10, DEFAULT_GREP_LIMIT, GREP_MAX_FILE_BYTES, GREP_CONCURRENCY, MAX_CONTEXT;
|
|
18281
18365
|
var init_grep = __esm({
|
|
18282
18366
|
"src/tools/grep.ts"() {
|
|
18283
18367
|
"use strict";
|
|
18284
|
-
|
|
18368
|
+
import_promises10 = require("node:fs/promises");
|
|
18285
18369
|
init_paths2();
|
|
18286
18370
|
init_ignore();
|
|
18287
18371
|
init_glob();
|
|
@@ -18298,16 +18382,16 @@ var init_grep = __esm({
|
|
|
18298
18382
|
async function describe(dir, name) {
|
|
18299
18383
|
const abs = (0, import_node_path33.join)(dir, name);
|
|
18300
18384
|
try {
|
|
18301
|
-
const info2 = await (0,
|
|
18385
|
+
const info2 = await (0, import_promises11.lstat)(abs);
|
|
18302
18386
|
if (info2.isSymbolicLink()) {
|
|
18303
18387
|
let target = "?";
|
|
18304
18388
|
try {
|
|
18305
|
-
target = await (0,
|
|
18389
|
+
target = await (0, import_promises11.readlink)(abs);
|
|
18306
18390
|
} catch {
|
|
18307
18391
|
}
|
|
18308
18392
|
let pointsToDir = false;
|
|
18309
18393
|
try {
|
|
18310
|
-
pointsToDir = (await (0,
|
|
18394
|
+
pointsToDir = (await (0, import_promises11.stat)(abs)).isDirectory();
|
|
18311
18395
|
} catch {
|
|
18312
18396
|
}
|
|
18313
18397
|
return { name: pointsToDir ? `${name}/` : name, type: "symlink", target };
|
|
@@ -18333,9 +18417,9 @@ async function executeLs(input2, ctx) {
|
|
|
18333
18417
|
const shown2 = displayPath(dir, ctx.cwd);
|
|
18334
18418
|
let names;
|
|
18335
18419
|
try {
|
|
18336
|
-
if (!(await (0,
|
|
18420
|
+
if (!(await (0, import_promises11.stat)(dir)).isDirectory())
|
|
18337
18421
|
return { content: `${shown2} is not a directory`, isError: true };
|
|
18338
|
-
names = await (0,
|
|
18422
|
+
names = await (0, import_promises11.readdir)(dir);
|
|
18339
18423
|
} catch {
|
|
18340
18424
|
return { content: `Directory not found: ${shown2}`, isError: true };
|
|
18341
18425
|
}
|
|
@@ -18370,11 +18454,11 @@ function createLsTool() {
|
|
|
18370
18454
|
execute: executeLs
|
|
18371
18455
|
};
|
|
18372
18456
|
}
|
|
18373
|
-
var
|
|
18457
|
+
var import_promises11, import_node_path33, DEFAULT_LS_LIMIT;
|
|
18374
18458
|
var init_ls = __esm({
|
|
18375
18459
|
"src/tools/ls.ts"() {
|
|
18376
18460
|
"use strict";
|
|
18377
|
-
|
|
18461
|
+
import_promises11 = require("node:fs/promises");
|
|
18378
18462
|
import_node_path33 = require("node:path");
|
|
18379
18463
|
init_paths2();
|
|
18380
18464
|
init_truncate();
|
|
@@ -18661,9 +18745,9 @@ ${tail}`, truncated: true };
|
|
|
18661
18745
|
}
|
|
18662
18746
|
function writeTaskOutput(dir, name, text) {
|
|
18663
18747
|
try {
|
|
18664
|
-
(0,
|
|
18748
|
+
(0, import_node_fs26.mkdirSync)(dir, { recursive: true });
|
|
18665
18749
|
const file = (0, import_node_path34.join)(dir, name);
|
|
18666
|
-
(0,
|
|
18750
|
+
(0, import_node_fs26.writeFileSync)(file, text);
|
|
18667
18751
|
return file;
|
|
18668
18752
|
} catch {
|
|
18669
18753
|
return void 0;
|
|
@@ -18700,11 +18784,11 @@ function backgroundedText(reason, afterMs) {
|
|
|
18700
18784
|
function waitDetachedText(taskId) {
|
|
18701
18785
|
return `Task ${taskId} is still running and was moved to the background by the user; do not wait again — a <task-notification> arrives when it finishes.`;
|
|
18702
18786
|
}
|
|
18703
|
-
var
|
|
18787
|
+
var import_node_fs26, import_node_path34, TASK_RESULT_LIMIT_BYTES, HEAD_SHARE, MAX_TURNS_NOTE, NOTIFY_HINT, TASK_NOTIFICATION_RULE;
|
|
18704
18788
|
var init_result = __esm({
|
|
18705
18789
|
"src/agents/result.ts"() {
|
|
18706
18790
|
"use strict";
|
|
18707
|
-
|
|
18791
|
+
import_node_fs26 = require("node:fs");
|
|
18708
18792
|
import_node_path34 = require("node:path");
|
|
18709
18793
|
TASK_RESULT_LIMIT_BYTES = 50 * 1024;
|
|
18710
18794
|
HEAD_SHARE = 0.7;
|
|
@@ -19303,9 +19387,9 @@ function truncateResult(call, result, options, nested = false) {
|
|
|
19303
19387
|
let where = "full output not saved";
|
|
19304
19388
|
if (options.outputDir !== void 0) {
|
|
19305
19389
|
try {
|
|
19306
|
-
(0,
|
|
19390
|
+
(0, import_node_fs27.mkdirSync)(options.outputDir, { recursive: true });
|
|
19307
19391
|
const file = (0, import_node_path35.join)(options.outputDir, `${call.id.replace(/[^A-Za-z0-9_-]/g, "_")}.txt`);
|
|
19308
|
-
(0,
|
|
19392
|
+
(0, import_node_fs27.writeFileSync)(file, text, "utf8");
|
|
19309
19393
|
where = `full output at ${file}`;
|
|
19310
19394
|
} catch {
|
|
19311
19395
|
}
|
|
@@ -19520,11 +19604,11 @@ async function runSingleToolCall(call, assistant, options, signal, nested) {
|
|
|
19520
19604
|
await emitEnd(call, result, emit);
|
|
19521
19605
|
return result;
|
|
19522
19606
|
}
|
|
19523
|
-
var
|
|
19607
|
+
var import_node_fs27, import_node_path35, ABORTED_TOOL_TEXT, DEFAULT_MAX_TOOL_RESULT_CHARS, DEFAULT_ABORT_GRACE_MS, NESTED_MAX_RESULT_CHARS, autoDecisions, deniedCalls, batchSuffixSources;
|
|
19524
19608
|
var init_tool_runner = __esm({
|
|
19525
19609
|
"src/agent/tool-runner.ts"() {
|
|
19526
19610
|
"use strict";
|
|
19527
|
-
|
|
19611
|
+
import_node_fs27 = require("node:fs");
|
|
19528
19612
|
import_node_path35 = require("node:path");
|
|
19529
19613
|
init_loop_guard();
|
|
19530
19614
|
init_schema2();
|
|
@@ -21577,9 +21661,9 @@ function materialize(candidate, outputDir) {
|
|
|
21577
21661
|
if (outputDir !== void 0) {
|
|
21578
21662
|
fullTextPath = (0, import_node_path37.join)(outputDir, `${safeFileStem(message.toolCallId)}.txt`);
|
|
21579
21663
|
try {
|
|
21580
|
-
if (!(0,
|
|
21581
|
-
(0,
|
|
21582
|
-
(0,
|
|
21664
|
+
if (!(0, import_node_fs28.existsSync)(fullTextPath)) {
|
|
21665
|
+
(0, import_node_fs28.mkdirSync)(outputDir, { recursive: true });
|
|
21666
|
+
(0, import_node_fs28.writeFileSync)(fullTextPath, text, "utf8");
|
|
21583
21667
|
}
|
|
21584
21668
|
} catch {
|
|
21585
21669
|
fullTextPath = void 0;
|
|
@@ -21614,11 +21698,11 @@ function planPrune(items, options) {
|
|
|
21614
21698
|
}
|
|
21615
21699
|
return { items: plan2, savedTokens, availableTokens };
|
|
21616
21700
|
}
|
|
21617
|
-
var
|
|
21701
|
+
var import_node_fs28, import_node_path37, PRUNE_TRIGGER_RATIO, PRUNE_TARGET_RATIO, PRUNE_KEEP_RESULTS, PRUNE_PROTECT_TOKENS, PRUNE_PROTECT_RATIO, PRUNE_CLEAR_AT_LEAST, PRUNE_CLEAR_AT_LEAST_RATIO, PRUNE_CLEAR_AT_LEAST_CAP_RATIO, PRUNE_MIN_TOKENS, REPLACEMENT_TOKENS;
|
|
21618
21702
|
var init_prune_tier = __esm({
|
|
21619
21703
|
"src/compaction/prune-tier.ts"() {
|
|
21620
21704
|
"use strict";
|
|
21621
|
-
|
|
21705
|
+
import_node_fs28 = require("node:fs");
|
|
21622
21706
|
import_node_path37 = require("node:path");
|
|
21623
21707
|
init_estimate();
|
|
21624
21708
|
PRUNE_TRIGGER_RATIO = 0.7;
|
|
@@ -22075,9 +22159,9 @@ function isTaskHead(entry) {
|
|
|
22075
22159
|
const data2 = entry.data;
|
|
22076
22160
|
return data2?.context !== "fork";
|
|
22077
22161
|
}
|
|
22078
|
-
function
|
|
22162
|
+
function readHead(file) {
|
|
22079
22163
|
try {
|
|
22080
|
-
const [header, first] = (0,
|
|
22164
|
+
const [header, first] = (0, import_node_fs29.readFileSync)(file, "utf8").split("\n", 2);
|
|
22081
22165
|
const parsed = JSON.parse(header ?? "{}");
|
|
22082
22166
|
const entry = first ? JSON.parse(first) : void 0;
|
|
22083
22167
|
return { ...parsed, task: isTaskHead(entry) };
|
|
@@ -22095,18 +22179,18 @@ function cacheKeyOf(manager) {
|
|
|
22095
22179
|
let id = manager.id;
|
|
22096
22180
|
let file = header.parentSession;
|
|
22097
22181
|
for (let depth = 0; depth < 8 && file !== void 0; depth++) {
|
|
22098
|
-
const next =
|
|
22182
|
+
const next = readHead(file);
|
|
22099
22183
|
if (next.id === void 0 || next.task) break;
|
|
22100
22184
|
id = next.id;
|
|
22101
22185
|
file = next.parentSession;
|
|
22102
22186
|
}
|
|
22103
22187
|
return id;
|
|
22104
22188
|
}
|
|
22105
|
-
var
|
|
22189
|
+
var import_node_fs29, TASK_CUSTOM_TYPE;
|
|
22106
22190
|
var init_session_cache_key = __esm({
|
|
22107
22191
|
"src/agent/session-cache-key.ts"() {
|
|
22108
22192
|
"use strict";
|
|
22109
|
-
|
|
22193
|
+
import_node_fs29 = require("node:fs");
|
|
22110
22194
|
TASK_CUSTOM_TYPE = "ama.task";
|
|
22111
22195
|
}
|
|
22112
22196
|
});
|
|
@@ -25068,7 +25152,7 @@ function listSessionItems(dir) {
|
|
|
25068
25152
|
file,
|
|
25069
25153
|
cwd: header.cwd,
|
|
25070
25154
|
createdAt: header.timestamp,
|
|
25071
|
-
modifiedAt: (0,
|
|
25155
|
+
modifiedAt: (0, import_node_fs30.statSync)(file).mtime.toISOString(),
|
|
25072
25156
|
messageCount
|
|
25073
25157
|
};
|
|
25074
25158
|
if (name !== void 0) item.name = name;
|
|
@@ -25080,11 +25164,11 @@ function listSessionItems(dir) {
|
|
|
25080
25164
|
}
|
|
25081
25165
|
return items;
|
|
25082
25166
|
}
|
|
25083
|
-
var
|
|
25167
|
+
var import_node_fs30, SkipFile;
|
|
25084
25168
|
var init_list = __esm({
|
|
25085
25169
|
"src/session/list.ts"() {
|
|
25086
25170
|
"use strict";
|
|
25087
|
-
|
|
25171
|
+
import_node_fs30 = require("node:fs");
|
|
25088
25172
|
init_line_reader();
|
|
25089
25173
|
init_store();
|
|
25090
25174
|
init_types6();
|
|
@@ -25093,6 +25177,163 @@ var init_list = __esm({
|
|
|
25093
25177
|
}
|
|
25094
25178
|
});
|
|
25095
25179
|
|
|
25180
|
+
// src/session/offload.ts
|
|
25181
|
+
function isImage(block) {
|
|
25182
|
+
return typeof block === "object" && block !== null && block.type === "image" && typeof block.data === "string";
|
|
25183
|
+
}
|
|
25184
|
+
function contentOf(entry) {
|
|
25185
|
+
if (entry.type !== "message") return void 0;
|
|
25186
|
+
const content = entry.message.content;
|
|
25187
|
+
return Array.isArray(content) ? content : void 0;
|
|
25188
|
+
}
|
|
25189
|
+
function hasImages(entry) {
|
|
25190
|
+
return contentOf(entry)?.some(isImage) === true;
|
|
25191
|
+
}
|
|
25192
|
+
function readLineAt(file, locator) {
|
|
25193
|
+
const fd = (0, import_node_fs31.openSync)(file, "r");
|
|
25194
|
+
try {
|
|
25195
|
+
const buf = Buffer.allocUnsafe(locator.length);
|
|
25196
|
+
let read2 = 0;
|
|
25197
|
+
while (read2 < locator.length) {
|
|
25198
|
+
const n = (0, import_node_fs31.readSync)(fd, buf, read2, locator.length - read2, locator.offset + read2);
|
|
25199
|
+
if (n === 0) throw new Error("unexpected end of file");
|
|
25200
|
+
read2 += n;
|
|
25201
|
+
}
|
|
25202
|
+
return JSON.parse(buf.toString("utf8"));
|
|
25203
|
+
} finally {
|
|
25204
|
+
(0, import_node_fs31.closeSync)(fd);
|
|
25205
|
+
}
|
|
25206
|
+
}
|
|
25207
|
+
function editTargets(file) {
|
|
25208
|
+
const targets = /* @__PURE__ */ new Set();
|
|
25209
|
+
try {
|
|
25210
|
+
forEachLineSync(file, (line2) => {
|
|
25211
|
+
if (lineTypeOf(line2)?.type !== "context_edit") return;
|
|
25212
|
+
try {
|
|
25213
|
+
const id = JSON.parse(line2.toString("utf8")).targetId;
|
|
25214
|
+
if (typeof id === "string") targets.add(id);
|
|
25215
|
+
} catch {
|
|
25216
|
+
}
|
|
25217
|
+
});
|
|
25218
|
+
} catch {
|
|
25219
|
+
}
|
|
25220
|
+
return targets;
|
|
25221
|
+
}
|
|
25222
|
+
var import_node_fs31, placeholder, ImageOffload;
|
|
25223
|
+
var init_offload = __esm({
|
|
25224
|
+
"src/session/offload.ts"() {
|
|
25225
|
+
"use strict";
|
|
25226
|
+
import_node_fs31 = require("node:fs");
|
|
25227
|
+
init_image_intern();
|
|
25228
|
+
init_line_reader();
|
|
25229
|
+
init_projection();
|
|
25230
|
+
placeholder = (block) => ({ ...block, data: "" });
|
|
25231
|
+
ImageOffload = class {
|
|
25232
|
+
constructor(warn2 = () => {
|
|
25233
|
+
}) {
|
|
25234
|
+
this.warn = warn2;
|
|
25235
|
+
}
|
|
25236
|
+
warn;
|
|
25237
|
+
/** 含图 message 条目的行位置(只有已落盘的条目才有)。 */
|
|
25238
|
+
locators = /* @__PURE__ */ new Map();
|
|
25239
|
+
offloaded = /* @__PURE__ */ new Set();
|
|
25240
|
+
/** 记下条目的行位置;不含图片的条目忽略。 */
|
|
25241
|
+
track(entry, locator) {
|
|
25242
|
+
if (hasImages(entry)) this.locators.set(entry.id, locator);
|
|
25243
|
+
}
|
|
25244
|
+
/** 读文件时逐行调用:记下行位置;`strip` 时就地换成占位(刚解析的对象,别处没有引用)。 */
|
|
25245
|
+
load(line2, locator, strip) {
|
|
25246
|
+
if (typeof line2.id !== "string" || !hasImages(line2)) return;
|
|
25247
|
+
this.locators.set(line2.id, locator);
|
|
25248
|
+
if (!strip) return;
|
|
25249
|
+
const content = contentOf(line2);
|
|
25250
|
+
content.forEach((block, i) => {
|
|
25251
|
+
if (isImage(block)) content[i] = placeholder(block);
|
|
25252
|
+
});
|
|
25253
|
+
this.offloaded.add(line2.id);
|
|
25254
|
+
}
|
|
25255
|
+
isOffloaded(id) {
|
|
25256
|
+
return this.offloaded.has(id);
|
|
25257
|
+
}
|
|
25258
|
+
/** 已卸载的条目数(测试与诊断用)。 */
|
|
25259
|
+
get size() {
|
|
25260
|
+
return this.offloaded.size;
|
|
25261
|
+
}
|
|
25262
|
+
/** 把条目里的图片换成占位;没有行位置(未落盘、不含图)或已卸载时返回 false。 */
|
|
25263
|
+
offload(entry) {
|
|
25264
|
+
if (entry.type !== "message" || this.offloaded.has(entry.id)) return false;
|
|
25265
|
+
const content = contentOf(entry);
|
|
25266
|
+
if (content === void 0 || !this.locators.has(entry.id)) return false;
|
|
25267
|
+
entry.message = {
|
|
25268
|
+
...entry.message,
|
|
25269
|
+
content: content.map((block) => isImage(block) ? placeholder(block) : block)
|
|
25270
|
+
};
|
|
25271
|
+
this.offloaded.add(entry.id);
|
|
25272
|
+
return true;
|
|
25273
|
+
}
|
|
25274
|
+
/** 就地放回图片;读不回时返回 false(占位保留,之后不再卸载 / 回读这一条)。 */
|
|
25275
|
+
hydrate(file, entry) {
|
|
25276
|
+
if (!this.offloaded.has(entry.id)) return true;
|
|
25277
|
+
this.offloaded.delete(entry.id);
|
|
25278
|
+
const source = this.read(file, entry);
|
|
25279
|
+
const content = contentOf(entry);
|
|
25280
|
+
if (source === void 0 || content === void 0) return false;
|
|
25281
|
+
const originals = contentOf(source) ?? [];
|
|
25282
|
+
content.forEach((block, i) => {
|
|
25283
|
+
const original = originals[i];
|
|
25284
|
+
if (isImage(block) && block.data === "" && isImage(original)) {
|
|
25285
|
+
content[i] = internImage(original);
|
|
25286
|
+
}
|
|
25287
|
+
});
|
|
25288
|
+
return true;
|
|
25289
|
+
}
|
|
25290
|
+
/** 原文:已卸载的条目从文件读一份新副本(图片驻留),否则原样返回。读不回时返回占位版本。 */
|
|
25291
|
+
original(file, entry) {
|
|
25292
|
+
if (!this.offloaded.has(entry.id)) return entry;
|
|
25293
|
+
const copy = this.read(file, entry);
|
|
25294
|
+
if (copy === void 0) return entry;
|
|
25295
|
+
const content = contentOf(copy) ?? [];
|
|
25296
|
+
content.forEach((block, i) => {
|
|
25297
|
+
if (isImage(block)) content[i] = internImage(block);
|
|
25298
|
+
});
|
|
25299
|
+
return copy;
|
|
25300
|
+
}
|
|
25301
|
+
/** 按活动分支对齐:分支上被生效编辑改写的含图条目卸载,其余已卸载的回读。 */
|
|
25302
|
+
sync(file, branch, index2) {
|
|
25303
|
+
const edits = collectContextEdits(branch);
|
|
25304
|
+
const onBranch = /* @__PURE__ */ new Set();
|
|
25305
|
+
for (const entry of branch) if (edits.has(entry.id)) onBranch.add(entry.id);
|
|
25306
|
+
for (const id of [...this.offloaded]) {
|
|
25307
|
+
const entry = index2.get(id);
|
|
25308
|
+
if (entry !== void 0 && !onBranch.has(id)) this.hydrate(file, entry);
|
|
25309
|
+
}
|
|
25310
|
+
for (const id of onBranch) {
|
|
25311
|
+
const entry = index2.get(id);
|
|
25312
|
+
if (entry !== void 0) this.offload(entry);
|
|
25313
|
+
}
|
|
25314
|
+
}
|
|
25315
|
+
/** 从文件读回条目(新对象);不成功时告警、忘掉行位置并返回 undefined。 */
|
|
25316
|
+
read(file, entry) {
|
|
25317
|
+
const locator = this.locators.get(entry.id);
|
|
25318
|
+
try {
|
|
25319
|
+
if (locator === void 0) throw new Error("no line locator");
|
|
25320
|
+
const line2 = readLineAt(file, locator);
|
|
25321
|
+
const content = line2.id === entry.id ? contentOf(line2) : void 0;
|
|
25322
|
+
if (content === void 0 || content.length !== contentOf(entry)?.length) {
|
|
25323
|
+
throw new Error("line does not match the entry");
|
|
25324
|
+
}
|
|
25325
|
+
return line2;
|
|
25326
|
+
} catch (error2) {
|
|
25327
|
+
this.locators.delete(entry.id);
|
|
25328
|
+
this.offloaded.delete(entry.id);
|
|
25329
|
+
this.warn(`cannot read session entry ${entry.id} back from ${file}: ${String(error2)}`);
|
|
25330
|
+
return void 0;
|
|
25331
|
+
}
|
|
25332
|
+
}
|
|
25333
|
+
};
|
|
25334
|
+
}
|
|
25335
|
+
});
|
|
25336
|
+
|
|
25096
25337
|
// src/session/manager.ts
|
|
25097
25338
|
function newEntryId(taken) {
|
|
25098
25339
|
for (; ; ) {
|
|
@@ -25111,6 +25352,7 @@ var init_manager = __esm({
|
|
|
25111
25352
|
init_version();
|
|
25112
25353
|
init_list();
|
|
25113
25354
|
init_migrate();
|
|
25355
|
+
init_offload();
|
|
25114
25356
|
init_store();
|
|
25115
25357
|
init_tree();
|
|
25116
25358
|
init_types6();
|
|
@@ -25124,7 +25366,11 @@ var init_manager = __esm({
|
|
|
25124
25366
|
storage;
|
|
25125
25367
|
closed = false;
|
|
25126
25368
|
now;
|
|
25127
|
-
|
|
25369
|
+
images;
|
|
25370
|
+
warn;
|
|
25371
|
+
/** 已知的会话文件字节数(新行的行首偏移)。 */
|
|
25372
|
+
fileBytes = 0;
|
|
25373
|
+
constructor(header, entries, storage, now, leafId, warn2, images) {
|
|
25128
25374
|
this._header = header;
|
|
25129
25375
|
this.id = header.id;
|
|
25130
25376
|
this.cwd = header.cwd;
|
|
@@ -25134,6 +25380,8 @@ var init_manager = __esm({
|
|
|
25134
25380
|
this.leaf = leafId === void 0 || leafId !== null && !this.index.has(leafId) ? last : leafId;
|
|
25135
25381
|
this.storage = storage;
|
|
25136
25382
|
this.now = now;
|
|
25383
|
+
this.warn = warn2;
|
|
25384
|
+
this.images = images ?? new ImageOffload(warn2);
|
|
25137
25385
|
}
|
|
25138
25386
|
static newHeader(cwd, options, now) {
|
|
25139
25387
|
const header = {
|
|
@@ -25154,7 +25402,14 @@ var init_manager = __esm({
|
|
|
25154
25402
|
/** `dir` 是会话文件所在目录(通常是 `sessionDirForCwd(sessionsRoot, cwd)`)。 */
|
|
25155
25403
|
static create(dir, cwd, options = {}) {
|
|
25156
25404
|
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
25157
|
-
return new _SessionManager(
|
|
25405
|
+
return new _SessionManager(
|
|
25406
|
+
this.newHeader(cwd, options, now()),
|
|
25407
|
+
[],
|
|
25408
|
+
{ kind: "lazy", dir },
|
|
25409
|
+
now,
|
|
25410
|
+
void 0,
|
|
25411
|
+
options.warn
|
|
25412
|
+
);
|
|
25158
25413
|
}
|
|
25159
25414
|
static createForCwd(sessionsRoot, cwd, options = {}) {
|
|
25160
25415
|
return this.create(sessionDirForCwd(sessionsRoot, cwd), cwd, options);
|
|
@@ -25162,16 +25417,29 @@ var init_manager = __esm({
|
|
|
25162
25417
|
static open(file, options = {}) {
|
|
25163
25418
|
const lock = acquireLock(file);
|
|
25164
25419
|
try {
|
|
25165
|
-
const
|
|
25420
|
+
const images = new ImageOffload(options.warn);
|
|
25421
|
+
const targets = editTargets(file);
|
|
25422
|
+
const { lines: lines2, bytes } = readSessionLines(file, {
|
|
25423
|
+
repair: true,
|
|
25424
|
+
onLine: (line2, locator) => {
|
|
25425
|
+
const entry = line2;
|
|
25426
|
+
images.load(entry, locator, targets.has(entry.id));
|
|
25427
|
+
}
|
|
25428
|
+
});
|
|
25166
25429
|
const { header, entries, leafId } = migrateSessionLines(lines2, file);
|
|
25167
25430
|
internSessionImages(entries);
|
|
25168
|
-
|
|
25431
|
+
const manager = new _SessionManager(
|
|
25169
25432
|
header,
|
|
25170
25433
|
entries,
|
|
25171
25434
|
{ kind: "file", file, lock },
|
|
25172
25435
|
options.now ?? (() => /* @__PURE__ */ new Date()),
|
|
25173
|
-
leafId
|
|
25436
|
+
leafId,
|
|
25437
|
+
options.warn,
|
|
25438
|
+
images
|
|
25174
25439
|
);
|
|
25440
|
+
manager.fileBytes = bytes ?? 0;
|
|
25441
|
+
manager.syncImages();
|
|
25442
|
+
return manager;
|
|
25175
25443
|
} catch (error2) {
|
|
25176
25444
|
lock.release();
|
|
25177
25445
|
throw error2;
|
|
@@ -25212,10 +25480,18 @@ var init_manager = __esm({
|
|
|
25212
25480
|
parentId: this.leaf,
|
|
25213
25481
|
timestamp: this.now().toISOString()
|
|
25214
25482
|
};
|
|
25215
|
-
if (this.storage.kind === "file")
|
|
25483
|
+
if (this.storage.kind === "file") {
|
|
25484
|
+
const written = appendLines(this.storage.file, [entry]);
|
|
25485
|
+
this.images.track(entry, { offset: this.fileBytes, length: written - 1 });
|
|
25486
|
+
this.fileBytes += written;
|
|
25487
|
+
}
|
|
25216
25488
|
this._entries.push(entry);
|
|
25217
25489
|
this.index.set(entry.id, entry);
|
|
25218
25490
|
this.leaf = entry.id;
|
|
25491
|
+
if (entry.type === "context_edit" && this.storage.kind === "file") {
|
|
25492
|
+
const target = this.index.get(entry.targetId);
|
|
25493
|
+
if (target !== void 0 && this.branch().includes(target)) this.images.offload(target);
|
|
25494
|
+
}
|
|
25219
25495
|
return entry;
|
|
25220
25496
|
}
|
|
25221
25497
|
setLeaf(id) {
|
|
@@ -25223,7 +25499,24 @@ var init_manager = __esm({
|
|
|
25223
25499
|
throw new AmaError("invalid_arguments", `no such session entry: ${id}`);
|
|
25224
25500
|
}
|
|
25225
25501
|
this.leaf = id;
|
|
25226
|
-
if (this.storage.kind === "file")
|
|
25502
|
+
if (this.storage.kind === "file") {
|
|
25503
|
+
this.fileBytes += appendLines(this.storage.file, [this.leafLine()]);
|
|
25504
|
+
}
|
|
25505
|
+
this.syncImages();
|
|
25506
|
+
}
|
|
25507
|
+
/** 按当前活动分支卸载 / 回读图片(只对已落盘的会话)。 */
|
|
25508
|
+
syncImages() {
|
|
25509
|
+
if (this.storage.kind === "file")
|
|
25510
|
+
this.images.sync(this.storage.file, this.branch(), this.index);
|
|
25511
|
+
}
|
|
25512
|
+
/** 原文条目(已卸载的从文件回读一份副本)。 */
|
|
25513
|
+
original(entry) {
|
|
25514
|
+
if (this.storage.kind !== "file" || !this.images.isOffloaded(entry.id)) return entry;
|
|
25515
|
+
return this.images.original(this.storage.file, entry);
|
|
25516
|
+
}
|
|
25517
|
+
/** 已卸载图片的条目数(测试与诊断用)。 */
|
|
25518
|
+
offloadedCount() {
|
|
25519
|
+
return this.images.size;
|
|
25227
25520
|
}
|
|
25228
25521
|
leafLine() {
|
|
25229
25522
|
return { type: "leaf", id: this.leaf, timestamp: this.now().toISOString() };
|
|
@@ -25232,10 +25525,9 @@ var init_manager = __esm({
|
|
|
25232
25525
|
return pathToRoot(this.index, leafId === void 0 ? this.leaf : leafId);
|
|
25233
25526
|
}
|
|
25234
25527
|
getEntries(since) {
|
|
25235
|
-
|
|
25236
|
-
const at = this._entries.findIndex((entry) => entry.id === since);
|
|
25528
|
+
const at = since === void 0 ? -1 : this._entries.findIndex((entry) => entry.id === since);
|
|
25237
25529
|
return {
|
|
25238
|
-
entries:
|
|
25530
|
+
entries: this._entries.slice(at + 1).map((entry) => this.original(entry)),
|
|
25239
25531
|
leafId: this.leaf
|
|
25240
25532
|
};
|
|
25241
25533
|
}
|
|
@@ -25254,7 +25546,10 @@ var init_manager = __esm({
|
|
|
25254
25546
|
if (!this.index.has(entryId)) {
|
|
25255
25547
|
throw new AmaError("invalid_arguments", `no such session entry: ${entryId}`);
|
|
25256
25548
|
}
|
|
25257
|
-
const copied = this.branch(entryId).map((entry) =>
|
|
25549
|
+
const copied = this.branch(entryId).map((entry) => {
|
|
25550
|
+
const original = this.original(entry);
|
|
25551
|
+
return original === entry ? structuredClone(entry) : original;
|
|
25552
|
+
});
|
|
25258
25553
|
if (forkOptions.head !== void 0) {
|
|
25259
25554
|
const head = {
|
|
25260
25555
|
...forkOptions.head,
|
|
@@ -25273,7 +25568,7 @@ var init_manager = __esm({
|
|
|
25273
25568
|
if (this.storage.kind === "memory") storage = { kind: "memory" };
|
|
25274
25569
|
else if (this.storage.kind === "lazy") storage = { kind: "lazy", dir: this.storage.dir };
|
|
25275
25570
|
else storage = { kind: "lazy", dir: (0, import_node_path41.dirname)(this.storage.file) };
|
|
25276
|
-
const forked = new _SessionManager(header, copied, storage, this.now);
|
|
25571
|
+
const forked = new _SessionManager(header, copied, storage, this.now, void 0, this.warn);
|
|
25277
25572
|
if (parentFile !== void 0) forked.flush();
|
|
25278
25573
|
return forked;
|
|
25279
25574
|
}
|
|
@@ -25287,11 +25582,18 @@ var init_manager = __esm({
|
|
|
25287
25582
|
if (this.storage.kind === "file") return this.storage.file;
|
|
25288
25583
|
const file = (0, import_node_path41.join)(this.storage.dir, sessionFileName(new Date(this._header.timestamp), this.id));
|
|
25289
25584
|
const moved = this.leaf !== (this._entries.at(-1)?.id ?? null);
|
|
25290
|
-
writeNewSessionFile(file, [
|
|
25585
|
+
const lengths = writeNewSessionFile(file, [
|
|
25291
25586
|
this._header,
|
|
25292
25587
|
...this._entries,
|
|
25293
25588
|
...moved ? [this.leafLine()] : []
|
|
25294
25589
|
]);
|
|
25590
|
+
let offset = 0;
|
|
25591
|
+
lengths.forEach((length, i) => {
|
|
25592
|
+
const entry = i === 0 ? void 0 : this._entries[i - 1];
|
|
25593
|
+
if (entry !== void 0) this.images.track(entry, { offset, length });
|
|
25594
|
+
offset += length + 1;
|
|
25595
|
+
});
|
|
25596
|
+
this.fileBytes = offset;
|
|
25295
25597
|
let lock;
|
|
25296
25598
|
try {
|
|
25297
25599
|
lock = acquireLock(file);
|
|
@@ -25299,6 +25601,7 @@ var init_manager = __esm({
|
|
|
25299
25601
|
lock = void 0;
|
|
25300
25602
|
}
|
|
25301
25603
|
this.storage = { kind: "file", file, lock };
|
|
25604
|
+
this.syncImages();
|
|
25302
25605
|
return file;
|
|
25303
25606
|
}
|
|
25304
25607
|
isPersisted() {
|
|
@@ -29168,16 +29471,16 @@ async function putBlob(dataDir, bytes, hash = hashBytes(bytes)) {
|
|
|
29168
29471
|
const target = blobPath(dataDir, hash);
|
|
29169
29472
|
if (await exists3(target)) {
|
|
29170
29473
|
const now = /* @__PURE__ */ new Date();
|
|
29171
|
-
await (0,
|
|
29474
|
+
await (0, import_promises12.utimes)(target, now, now).catch(() => void 0);
|
|
29172
29475
|
return hash;
|
|
29173
29476
|
}
|
|
29174
|
-
await (0,
|
|
29477
|
+
await (0, import_promises12.mkdir)((0, import_node_path47.dirname)(target), { recursive: true, mode: 448 });
|
|
29175
29478
|
const tmp = `${target}.tmp-${process.pid}-${tmpCounter++}`;
|
|
29176
29479
|
try {
|
|
29177
|
-
await (0,
|
|
29178
|
-
await (0,
|
|
29480
|
+
await (0, import_promises12.writeFile)(tmp, bytes, { mode: 384 });
|
|
29481
|
+
await (0, import_promises12.rename)(tmp, target);
|
|
29179
29482
|
} catch (error2) {
|
|
29180
|
-
await (0,
|
|
29483
|
+
await (0, import_promises12.rm)(tmp, { force: true });
|
|
29181
29484
|
if (await exists3(target)) return hash;
|
|
29182
29485
|
throw error2;
|
|
29183
29486
|
}
|
|
@@ -29185,7 +29488,7 @@ async function putBlob(dataDir, bytes, hash = hashBytes(bytes)) {
|
|
|
29185
29488
|
}
|
|
29186
29489
|
async function readBlob(dataDir, hash) {
|
|
29187
29490
|
try {
|
|
29188
|
-
return await (0,
|
|
29491
|
+
return await (0, import_promises12.readFile)(blobPath(dataDir, hash));
|
|
29189
29492
|
} catch (error2) {
|
|
29190
29493
|
if (isNotFound(error2)) return void 0;
|
|
29191
29494
|
throw error2;
|
|
@@ -29193,7 +29496,7 @@ async function readBlob(dataDir, hash) {
|
|
|
29193
29496
|
}
|
|
29194
29497
|
async function realParentOf(absolutePath) {
|
|
29195
29498
|
try {
|
|
29196
|
-
return await (0,
|
|
29499
|
+
return await (0, import_promises12.realpath)((0, import_node_path47.dirname)(absolutePath));
|
|
29197
29500
|
} catch (error2) {
|
|
29198
29501
|
if (isNotFound(error2)) return void 0;
|
|
29199
29502
|
throw error2;
|
|
@@ -29204,7 +29507,7 @@ async function recordFile(absolutePath, options) {
|
|
|
29204
29507
|
const max = options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES;
|
|
29205
29508
|
let info2;
|
|
29206
29509
|
try {
|
|
29207
|
-
info2 = await (0,
|
|
29510
|
+
info2 = await (0, import_promises12.lstat)(absolutePath);
|
|
29208
29511
|
} catch (error2) {
|
|
29209
29512
|
if (!isNotFound(error2)) throw error2;
|
|
29210
29513
|
const realParentDir2 = await realParentOf(absolutePath);
|
|
@@ -29218,7 +29521,7 @@ async function recordFile(absolutePath, options) {
|
|
|
29218
29521
|
const realParentDir = await realParentOf(absolutePath);
|
|
29219
29522
|
const base4 = { mode, size: info2.size, ...realParentDir !== void 0 ? { realParentDir } : {} };
|
|
29220
29523
|
if (info2.size > max) return { record: { blob: null, ...base4, skipped: "too_large" }, at };
|
|
29221
|
-
const bytes = await (0,
|
|
29524
|
+
const bytes = await (0, import_promises12.readFile)(absolutePath);
|
|
29222
29525
|
if (bytes.length > max)
|
|
29223
29526
|
return { record: { blob: null, ...base4, size: bytes.length, skipped: "too_large" }, at };
|
|
29224
29527
|
const blob = await putBlob(options.dataDir, bytes);
|
|
@@ -29245,7 +29548,7 @@ async function listBlobs(dataDir, includeTemp = false) {
|
|
|
29245
29548
|
const root = blobsDir(dataDir);
|
|
29246
29549
|
let shards;
|
|
29247
29550
|
try {
|
|
29248
|
-
shards = await (0,
|
|
29551
|
+
shards = await (0, import_promises12.readdir)(root);
|
|
29249
29552
|
} catch (error2) {
|
|
29250
29553
|
if (isNotFound(error2)) return [];
|
|
29251
29554
|
throw error2;
|
|
@@ -29255,7 +29558,7 @@ async function listBlobs(dataDir, includeTemp = false) {
|
|
|
29255
29558
|
if (!/^[0-9a-f]{2}$/.test(shard)) continue;
|
|
29256
29559
|
let names;
|
|
29257
29560
|
try {
|
|
29258
|
-
names = await (0,
|
|
29561
|
+
names = await (0, import_promises12.readdir)((0, import_node_path47.join)(root, shard));
|
|
29259
29562
|
} catch {
|
|
29260
29563
|
continue;
|
|
29261
29564
|
}
|
|
@@ -29264,7 +29567,7 @@ async function listBlobs(dataDir, includeTemp = false) {
|
|
|
29264
29567
|
if (!isBlob && !(includeTemp && name.includes(".tmp-"))) continue;
|
|
29265
29568
|
const path = (0, import_node_path47.join)(root, shard, name);
|
|
29266
29569
|
try {
|
|
29267
|
-
const info2 = await (0,
|
|
29570
|
+
const info2 = await (0, import_promises12.stat)(path);
|
|
29268
29571
|
if (!info2.isFile()) continue;
|
|
29269
29572
|
out.push({
|
|
29270
29573
|
path,
|
|
@@ -29283,19 +29586,19 @@ function isNotFound(error2) {
|
|
|
29283
29586
|
}
|
|
29284
29587
|
async function exists3(path) {
|
|
29285
29588
|
try {
|
|
29286
|
-
await (0,
|
|
29589
|
+
await (0, import_promises12.stat)(path);
|
|
29287
29590
|
return true;
|
|
29288
29591
|
} catch {
|
|
29289
29592
|
return false;
|
|
29290
29593
|
}
|
|
29291
29594
|
}
|
|
29292
|
-
var import_node_crypto9, import_node_fs34,
|
|
29595
|
+
var import_node_crypto9, import_node_fs34, import_promises12, import_node_path47, FILE_HISTORY_DIR, BLOBS_DIR, DEFAULT_MAX_FILE_BYTES, SHA256_HEX, tmpCounter;
|
|
29293
29596
|
var init_blobs = __esm({
|
|
29294
29597
|
"src/checkpoints/blobs.ts"() {
|
|
29295
29598
|
"use strict";
|
|
29296
29599
|
import_node_crypto9 = require("node:crypto");
|
|
29297
29600
|
import_node_fs34 = require("node:fs");
|
|
29298
|
-
|
|
29601
|
+
import_promises12 = require("node:fs/promises");
|
|
29299
29602
|
import_node_path47 = require("node:path");
|
|
29300
29603
|
FILE_HISTORY_DIR = "file-history";
|
|
29301
29604
|
BLOBS_DIR = "blobs";
|
|
@@ -29311,7 +29614,7 @@ function rootsFile(dataDir) {
|
|
|
29311
29614
|
}
|
|
29312
29615
|
async function readSessionRoots(dataDir) {
|
|
29313
29616
|
try {
|
|
29314
|
-
const value = JSON.parse(await (0,
|
|
29617
|
+
const value = JSON.parse(await (0, import_promises13.readFile)(rootsFile(dataDir), "utf8"));
|
|
29315
29618
|
const roots = value?.roots;
|
|
29316
29619
|
return Array.isArray(roots) ? roots.filter((r) => typeof r === "string") : [];
|
|
29317
29620
|
} catch {
|
|
@@ -29323,18 +29626,18 @@ async function registerSessionRoot(dataDir, sessionsRoot) {
|
|
|
29323
29626
|
const roots = await readSessionRoots(dataDir);
|
|
29324
29627
|
if (roots.includes(root)) return;
|
|
29325
29628
|
const dir = fileHistoryDir(dataDir);
|
|
29326
|
-
await (0,
|
|
29629
|
+
await (0, import_promises13.mkdir)(dir, { recursive: true, mode: 448 });
|
|
29327
29630
|
const tmp = `${rootsFile(dataDir)}.tmp-${process.pid}`;
|
|
29328
|
-
await (0,
|
|
29631
|
+
await (0, import_promises13.writeFile)(tmp, `${JSON.stringify({ roots: [...roots, root] }, null, 2)}
|
|
29329
29632
|
`, {
|
|
29330
29633
|
mode: 384
|
|
29331
29634
|
});
|
|
29332
|
-
await (0,
|
|
29635
|
+
await (0, import_promises13.rename)(tmp, rootsFile(dataDir));
|
|
29333
29636
|
}
|
|
29334
29637
|
async function* sessionFiles(dir) {
|
|
29335
29638
|
let entries;
|
|
29336
29639
|
try {
|
|
29337
|
-
entries = await (0,
|
|
29640
|
+
entries = await (0, import_promises13.readdir)(dir, { withFileTypes: true });
|
|
29338
29641
|
} catch (error2) {
|
|
29339
29642
|
if (isNotFound(error2)) return;
|
|
29340
29643
|
throw error2;
|
|
@@ -29356,7 +29659,7 @@ async function collectBlobRefs(sessionRoots) {
|
|
|
29356
29659
|
for await (const file of sessionFiles(abs)) {
|
|
29357
29660
|
let text;
|
|
29358
29661
|
try {
|
|
29359
|
-
text = await (0,
|
|
29662
|
+
text = await (0, import_promises13.readFile)(file, "utf8");
|
|
29360
29663
|
} catch (error2) {
|
|
29361
29664
|
if (isNotFound(error2)) continue;
|
|
29362
29665
|
throw error2;
|
|
@@ -29389,7 +29692,7 @@ async function gcBlobs(options) {
|
|
|
29389
29692
|
if (old && unreferenced) {
|
|
29390
29693
|
if (options.dryRun !== true) {
|
|
29391
29694
|
try {
|
|
29392
|
-
await (0,
|
|
29695
|
+
await (0, import_promises13.rm)(blob.path, { force: true });
|
|
29393
29696
|
} catch {
|
|
29394
29697
|
continue;
|
|
29395
29698
|
}
|
|
@@ -29414,11 +29717,11 @@ function formatBytes2(bytes) {
|
|
|
29414
29717
|
}
|
|
29415
29718
|
return `${value.toFixed(value >= 10 ? 0 : 1)} ${units[unit]}`;
|
|
29416
29719
|
}
|
|
29417
|
-
var
|
|
29720
|
+
var import_promises13, import_node_path48, GC_MIN_AGE_MS, ROOTS_FILE, HASH_IN_LINE;
|
|
29418
29721
|
var init_gc = __esm({
|
|
29419
29722
|
"src/checkpoints/gc.ts"() {
|
|
29420
29723
|
"use strict";
|
|
29421
|
-
|
|
29724
|
+
import_promises13 = require("node:fs/promises");
|
|
29422
29725
|
import_node_path48 = require("node:path");
|
|
29423
29726
|
init_blobs();
|
|
29424
29727
|
init_types10();
|
|
@@ -29547,7 +29850,7 @@ var init_replay = __esm({
|
|
|
29547
29850
|
// src/checkpoints/git-head.ts
|
|
29548
29851
|
async function readText2(path) {
|
|
29549
29852
|
try {
|
|
29550
|
-
return await (0,
|
|
29853
|
+
return await (0, import_promises14.readFile)(path, "utf8");
|
|
29551
29854
|
} catch {
|
|
29552
29855
|
return void 0;
|
|
29553
29856
|
}
|
|
@@ -29557,7 +29860,7 @@ async function findGitDir(cwd) {
|
|
|
29557
29860
|
for (; ; ) {
|
|
29558
29861
|
const candidate = (0, import_node_path49.join)(dir, ".git");
|
|
29559
29862
|
try {
|
|
29560
|
-
const info2 = await (0,
|
|
29863
|
+
const info2 = await (0, import_promises14.stat)(candidate);
|
|
29561
29864
|
if (info2.isDirectory()) return candidate;
|
|
29562
29865
|
if (info2.isFile()) {
|
|
29563
29866
|
const text = await readText2(candidate) ?? "";
|
|
@@ -29605,11 +29908,11 @@ async function readGitHead(cwd) {
|
|
|
29605
29908
|
const branch = ref.startsWith("refs/heads/") ? ref.slice("refs/heads/".length) : void 0;
|
|
29606
29909
|
return { head: sha, ...branch !== void 0 ? { branch } : {} };
|
|
29607
29910
|
}
|
|
29608
|
-
var
|
|
29911
|
+
var import_promises14, import_node_path49, SHA;
|
|
29609
29912
|
var init_git_head = __esm({
|
|
29610
29913
|
"src/checkpoints/git-head.ts"() {
|
|
29611
29914
|
"use strict";
|
|
29612
|
-
|
|
29915
|
+
import_promises14 = require("node:fs/promises");
|
|
29613
29916
|
import_node_path49 = require("node:path");
|
|
29614
29917
|
SHA = /^[0-9a-f]{40}([0-9a-f]{24})?$/;
|
|
29615
29918
|
}
|
|
@@ -29629,7 +29932,7 @@ function emptyCodeResult() {
|
|
|
29629
29932
|
}
|
|
29630
29933
|
async function lstatOrUndefined(path) {
|
|
29631
29934
|
try {
|
|
29632
|
-
return await (0,
|
|
29935
|
+
return await (0, import_promises15.lstat)(path);
|
|
29633
29936
|
} catch (error2) {
|
|
29634
29937
|
if (isNotFound(error2)) return void 0;
|
|
29635
29938
|
throw error2;
|
|
@@ -29718,7 +30021,7 @@ async function restoreFile(abs, record3, options) {
|
|
|
29718
30021
|
await checkParent(abs, record3);
|
|
29719
30022
|
const targetBytes = record3.blob === null ? void 0 : await (options.load ?? ((r) => readBlob(options.dataDir, r.blob)))(record3);
|
|
29720
30023
|
if (record3.blob !== null && targetBytes === void 0) throw new Skip("backup_missing");
|
|
29721
|
-
const currentBytes = info2 !== void 0 && info2.size <= options.maxDiff ? await (0,
|
|
30024
|
+
const currentBytes = info2 !== void 0 && info2.size <= options.maxDiff ? await (0, import_promises15.readFile)(abs) : void 0;
|
|
29722
30025
|
const counted = info2 !== void 0 && currentBytes === void 0 ? { insertions: 0, deletions: 0 } : countLineChanges(toText(currentBytes), toText(targetBytes));
|
|
29723
30026
|
const outcome = { deleted: record3.blob === null, conflict, ...counted };
|
|
29724
30027
|
if (options.dryRun === true) return outcome;
|
|
@@ -29742,17 +30045,17 @@ async function removeRegular(abs, before2) {
|
|
|
29742
30045
|
if (now.nlink > 1) throw new Skip("hardlink");
|
|
29743
30046
|
if (now.dev !== before2.dev || now.ino !== before2.ino)
|
|
29744
30047
|
throw new Error(msg().session.checkpoints.replacedDuringRestore);
|
|
29745
|
-
await (0,
|
|
30048
|
+
await (0, import_promises15.unlink)(abs);
|
|
29746
30049
|
}
|
|
29747
30050
|
async function writeBack(abs, bytes, record3, before2) {
|
|
29748
30051
|
if (before2 === void 0) {
|
|
29749
30052
|
const parent = (0, import_node_path50.dirname)(abs);
|
|
29750
|
-
await (0,
|
|
29751
|
-
if (record3.realParentDir !== void 0 && await (0,
|
|
30053
|
+
await (0, import_promises15.mkdir)(parent, { recursive: true });
|
|
30054
|
+
if (record3.realParentDir !== void 0 && await (0, import_promises15.realpath)(parent) !== record3.realParentDir) {
|
|
29752
30055
|
throw new Skip("parent_moved");
|
|
29753
30056
|
}
|
|
29754
30057
|
const flags2 = import_node_fs35.constants.O_WRONLY | import_node_fs35.constants.O_CREAT | import_node_fs35.constants.O_EXCL | NOFOLLOW;
|
|
29755
|
-
const handle2 = await (0,
|
|
30058
|
+
const handle2 = await (0, import_promises15.open)(abs, flags2, record3.mode ?? 420);
|
|
29756
30059
|
try {
|
|
29757
30060
|
await handle2.writeFile(bytes);
|
|
29758
30061
|
if (record3.mode !== void 0) await handle2.chmod(record3.mode);
|
|
@@ -29763,7 +30066,7 @@ async function writeBack(abs, bytes, record3, before2) {
|
|
|
29763
30066
|
}
|
|
29764
30067
|
let handle;
|
|
29765
30068
|
try {
|
|
29766
|
-
handle = await (0,
|
|
30069
|
+
handle = await (0, import_promises15.open)(abs, import_node_fs35.constants.O_WRONLY | NOFOLLOW);
|
|
29767
30070
|
} catch (error2) {
|
|
29768
30071
|
const code = error2.code;
|
|
29769
30072
|
if (code === "ELOOP" || code === "EMLINK") throw new Skip("symlink");
|
|
@@ -29771,7 +30074,7 @@ async function writeBack(abs, bytes, record3, before2) {
|
|
|
29771
30074
|
}
|
|
29772
30075
|
try {
|
|
29773
30076
|
const opened = await handle.stat();
|
|
29774
|
-
const now = await (0,
|
|
30077
|
+
const now = await (0, import_promises15.lstat)(abs);
|
|
29775
30078
|
if (!opened.isFile() || opened.dev !== before2.dev || opened.ino !== before2.ino || now.dev !== opened.dev || now.ino !== opened.ino) {
|
|
29776
30079
|
throw new Error(msg().session.checkpoints.replacedDuringRestore);
|
|
29777
30080
|
}
|
|
@@ -29789,12 +30092,12 @@ async function gitHintFor(cwd, target) {
|
|
|
29789
30092
|
if (current3 === void 0 || current3.head === target.git.head) return void 0;
|
|
29790
30093
|
return { recordedHead: target.git.head, currentHead: current3.head };
|
|
29791
30094
|
}
|
|
29792
|
-
var import_node_fs35,
|
|
30095
|
+
var import_node_fs35, import_promises15, import_node_path50, RestoreSkip, Skip, IS_WINDOWS, NOFOLLOW;
|
|
29793
30096
|
var init_restore = __esm({
|
|
29794
30097
|
"src/checkpoints/restore.ts"() {
|
|
29795
30098
|
"use strict";
|
|
29796
30099
|
import_node_fs35 = require("node:fs");
|
|
29797
|
-
|
|
30100
|
+
import_promises15 = require("node:fs/promises");
|
|
29798
30101
|
import_node_path50 = require("node:path");
|
|
29799
30102
|
init_edit();
|
|
29800
30103
|
init_blobs();
|
|
@@ -29845,7 +30148,7 @@ async function shadowUsage(dataDir) {
|
|
|
29845
30148
|
const usage = { repos: 0, bytes: 0 };
|
|
29846
30149
|
let names;
|
|
29847
30150
|
try {
|
|
29848
|
-
names = await (0,
|
|
30151
|
+
names = await (0, import_promises16.readdir)(shadowRoot(dataDir));
|
|
29849
30152
|
} catch {
|
|
29850
30153
|
return usage;
|
|
29851
30154
|
}
|
|
@@ -29861,7 +30164,7 @@ async function duBytes(dir) {
|
|
|
29861
30164
|
let total = 0;
|
|
29862
30165
|
let entries;
|
|
29863
30166
|
try {
|
|
29864
|
-
entries = await (0,
|
|
30167
|
+
entries = await (0, import_promises16.readdir)(dir, { withFileTypes: true });
|
|
29865
30168
|
} catch {
|
|
29866
30169
|
return 0;
|
|
29867
30170
|
}
|
|
@@ -29870,7 +30173,7 @@ async function duBytes(dir) {
|
|
|
29870
30173
|
if (entry.isDirectory()) total += await duBytes(full);
|
|
29871
30174
|
else if (entry.isFile()) {
|
|
29872
30175
|
try {
|
|
29873
|
-
total += (await (0,
|
|
30176
|
+
total += (await (0, import_promises16.stat)(full)).size;
|
|
29874
30177
|
} catch {
|
|
29875
30178
|
}
|
|
29876
30179
|
}
|
|
@@ -29954,7 +30257,7 @@ function excludeLine(path) {
|
|
|
29954
30257
|
async function removeStaleIndexes(dir) {
|
|
29955
30258
|
let names;
|
|
29956
30259
|
try {
|
|
29957
|
-
names = await (0,
|
|
30260
|
+
names = await (0, import_promises16.readdir)(dir);
|
|
29958
30261
|
} catch {
|
|
29959
30262
|
return;
|
|
29960
30263
|
}
|
|
@@ -29963,7 +30266,7 @@ async function removeStaleIndexes(dir) {
|
|
|
29963
30266
|
if (match === null) continue;
|
|
29964
30267
|
const pid = Number(match[1]);
|
|
29965
30268
|
if (pid === process.pid || isAlive(pid)) continue;
|
|
29966
|
-
await (0,
|
|
30269
|
+
await (0, import_promises16.rm)((0, import_node_path51.join)(dir, name), { force: true }).catch(() => void 0);
|
|
29967
30270
|
}
|
|
29968
30271
|
}
|
|
29969
30272
|
function isAlive(pid) {
|
|
@@ -29976,7 +30279,7 @@ function isAlive(pid) {
|
|
|
29976
30279
|
}
|
|
29977
30280
|
async function exists4(path) {
|
|
29978
30281
|
try {
|
|
29979
|
-
await (0,
|
|
30282
|
+
await (0, import_promises16.stat)(path);
|
|
29980
30283
|
return true;
|
|
29981
30284
|
} catch {
|
|
29982
30285
|
return false;
|
|
@@ -29984,18 +30287,18 @@ async function exists4(path) {
|
|
|
29984
30287
|
}
|
|
29985
30288
|
async function readSmall2(path) {
|
|
29986
30289
|
try {
|
|
29987
|
-
return (await (0,
|
|
30290
|
+
return (await (0, import_promises16.readFile)(path, "utf8")).trim();
|
|
29988
30291
|
} catch {
|
|
29989
30292
|
return void 0;
|
|
29990
30293
|
}
|
|
29991
30294
|
}
|
|
29992
|
-
var import_node_child_process7, import_node_crypto10,
|
|
30295
|
+
var import_node_child_process7, import_node_crypto10, import_promises16, import_node_os10, import_node_path51, SHADOW_DIR, SHADOW_MAX_FILES, SHADOW_MAX_SNAPSHOT_MS, GIT_TIMEOUT_MS, CONFIG_VERSION, IDENTITY, ATTRIBUTES, GitMissingError, MODE_ABSENT, MODE_SYMLINK, MODE_GITLINK, MODE_EXECUTABLE, queues2, ShadowRepo;
|
|
29993
30296
|
var init_shadow_git = __esm({
|
|
29994
30297
|
"src/checkpoints/shadow-git.ts"() {
|
|
29995
30298
|
"use strict";
|
|
29996
30299
|
import_node_child_process7 = require("node:child_process");
|
|
29997
30300
|
import_node_crypto10 = require("node:crypto");
|
|
29998
|
-
|
|
30301
|
+
import_promises16 = require("node:fs/promises");
|
|
29999
30302
|
import_node_os10 = require("node:os");
|
|
30000
30303
|
import_node_path51 = require("node:path");
|
|
30001
30304
|
init_blobs();
|
|
@@ -30079,9 +30382,9 @@ var init_shadow_git = __esm({
|
|
|
30079
30382
|
}
|
|
30080
30383
|
async doInit() {
|
|
30081
30384
|
const hooks = (0, import_node_path51.join)(this.dir, "ama-hooks");
|
|
30082
|
-
await (0,
|
|
30083
|
-
await (0,
|
|
30084
|
-
await (0,
|
|
30385
|
+
await (0, import_promises16.mkdir)(hooks, { recursive: true, mode: 448 });
|
|
30386
|
+
await (0, import_promises16.writeFile)((0, import_node_path51.join)(this.dir, "ama-empty"), "", { flag: "a", mode: 384 });
|
|
30387
|
+
await (0, import_promises16.writeFile)((0, import_node_path51.join)(this.dir, "ama-cwd"), `${this.cwd}
|
|
30085
30388
|
`, { mode: 384 });
|
|
30086
30389
|
const version = await readSmall2((0, import_node_path51.join)(this.dir, "ama-config-version"));
|
|
30087
30390
|
if (version !== CONFIG_VERSION) {
|
|
@@ -30112,9 +30415,9 @@ var init_shadow_git = __esm({
|
|
|
30112
30415
|
["user.useConfigOnly", "true"]
|
|
30113
30416
|
];
|
|
30114
30417
|
for (const [key, value] of config) await this.run(["config", key, value]);
|
|
30115
|
-
await (0,
|
|
30116
|
-
await (0,
|
|
30117
|
-
await (0,
|
|
30418
|
+
await (0, import_promises16.mkdir)((0, import_node_path51.join)(this.dir, "info"), { recursive: true });
|
|
30419
|
+
await (0, import_promises16.writeFile)((0, import_node_path51.join)(this.dir, "info", "attributes"), ATTRIBUTES);
|
|
30420
|
+
await (0, import_promises16.writeFile)((0, import_node_path51.join)(this.dir, "ama-config-version"), CONFIG_VERSION);
|
|
30118
30421
|
}
|
|
30119
30422
|
await removeStaleIndexes(this.dir);
|
|
30120
30423
|
}
|
|
@@ -30133,8 +30436,8 @@ var init_shadow_git = __esm({
|
|
|
30133
30436
|
} catch (error2) {
|
|
30134
30437
|
if (error2 instanceof GitMissingError) throw error2;
|
|
30135
30438
|
}
|
|
30136
|
-
await (0,
|
|
30137
|
-
await (0,
|
|
30439
|
+
await (0, import_promises16.mkdir)((0, import_node_path51.join)(this.dir, "info"), { recursive: true });
|
|
30440
|
+
await (0, import_promises16.writeFile)((0, import_node_path51.join)(this.dir, "info", "exclude"), `${lines2.join("\n")}
|
|
30138
30441
|
`);
|
|
30139
30442
|
}
|
|
30140
30443
|
/** 把工作区收进索引并写树,返回树 id(调用前已 writeExcludes)。 */
|
|
@@ -30291,7 +30594,7 @@ async function restoreFromShadow(options) {
|
|
|
30291
30594
|
changes.filter((c) => isRegularMode(c.oldMode)).map((c) => c.oldOid),
|
|
30292
30595
|
maxBytes
|
|
30293
30596
|
);
|
|
30294
|
-
const realCwd = await (0,
|
|
30597
|
+
const realCwd = await (0, import_promises17.realpath)(options.cwd);
|
|
30295
30598
|
const latest = latestCheckpoint(options.state);
|
|
30296
30599
|
const result = emptyCodeResult();
|
|
30297
30600
|
const touched = [];
|
|
@@ -30342,7 +30645,7 @@ function isRegularMode(mode) {
|
|
|
30342
30645
|
async function targetRecord(change, abs, realCwd, blobs) {
|
|
30343
30646
|
const slash = change.path.lastIndexOf("/");
|
|
30344
30647
|
const realParentDir = slash < 0 ? realCwd : (0, import_node_path52.join)(realCwd, ...change.path.slice(0, slash).split("/"));
|
|
30345
|
-
const info2 = await (0,
|
|
30648
|
+
const info2 = await (0, import_promises17.lstat)(abs).catch(() => void 0);
|
|
30346
30649
|
if (change.newMode === MODE_ABSENT && info2 !== void 0) {
|
|
30347
30650
|
return void 0;
|
|
30348
30651
|
}
|
|
@@ -30375,11 +30678,11 @@ function merge(into, from) {
|
|
|
30375
30678
|
into.insertions += from.insertions;
|
|
30376
30679
|
into.deletions += from.deletions;
|
|
30377
30680
|
}
|
|
30378
|
-
var
|
|
30681
|
+
var import_promises17, import_node_path52, IS_WINDOWS2;
|
|
30379
30682
|
var init_shadow_restore = __esm({
|
|
30380
30683
|
"src/checkpoints/shadow-restore.ts"() {
|
|
30381
30684
|
"use strict";
|
|
30382
|
-
|
|
30685
|
+
import_promises17 = require("node:fs/promises");
|
|
30383
30686
|
import_node_path52 = require("node:path");
|
|
30384
30687
|
init_blobs();
|
|
30385
30688
|
init_replay();
|
|
@@ -30394,11 +30697,11 @@ var init_shadow_restore = __esm({
|
|
|
30394
30697
|
function describe2(error2) {
|
|
30395
30698
|
return error2 instanceof Error ? error2.message : String(error2);
|
|
30396
30699
|
}
|
|
30397
|
-
var
|
|
30700
|
+
var import_promises18, MTIME_GRANULARITY_MS, CheckpointTracker;
|
|
30398
30701
|
var init_tracker = __esm({
|
|
30399
30702
|
"src/checkpoints/tracker.ts"() {
|
|
30400
30703
|
"use strict";
|
|
30401
|
-
|
|
30704
|
+
import_promises18 = require("node:fs/promises");
|
|
30402
30705
|
init_git_head();
|
|
30403
30706
|
init_blobs();
|
|
30404
30707
|
init_replay();
|
|
@@ -30510,7 +30813,7 @@ var init_tracker = __esm({
|
|
|
30510
30813
|
const at = this.now();
|
|
30511
30814
|
let info2;
|
|
30512
30815
|
try {
|
|
30513
|
-
info2 = await (0,
|
|
30816
|
+
info2 = await (0, import_promises18.lstat)(absolutePath);
|
|
30514
30817
|
} catch (error2) {
|
|
30515
30818
|
if (!isNotFound(error2)) throw error2;
|
|
30516
30819
|
if (prev !== void 0 && prev.record.blob === null && prev.record.skipped === void 0)
|
|
@@ -30541,7 +30844,7 @@ var init_tracker = __esm({
|
|
|
30541
30844
|
return prev;
|
|
30542
30845
|
return { record: { blob: null, ...base4, skipped: "too_large" }, at };
|
|
30543
30846
|
}
|
|
30544
|
-
const bytes = await (0,
|
|
30847
|
+
const bytes = await (0, import_promises18.readFile)(absolutePath);
|
|
30545
30848
|
const hash = hashBytes(bytes);
|
|
30546
30849
|
if (p !== void 0 && p.blob === hash && p.mode === mode && p.realParentDir === realParentDir) {
|
|
30547
30850
|
return { record: p, at };
|
|
@@ -30863,7 +31166,7 @@ function formatSkillInvocation(skill, body, args) {
|
|
|
30863
31166
|
|
|
30864
31167
|
${args}`;
|
|
30865
31168
|
}
|
|
30866
|
-
async function expandSkillCommand(text, skills, read2 = (p) => (0,
|
|
31169
|
+
async function expandSkillCommand(text, skills, read2 = (p) => (0, import_promises19.readFile)(p, "utf8")) {
|
|
30867
31170
|
const cmd = parseSkillCommand(text);
|
|
30868
31171
|
if (!cmd) return void 0;
|
|
30869
31172
|
const skill = skills.find((s2) => s2.name === cmd.name);
|
|
@@ -30871,11 +31174,11 @@ async function expandSkillCommand(text, skills, read2 = (p) => (0, import_promis
|
|
|
30871
31174
|
const body = skillBody(await read2(skill.location));
|
|
30872
31175
|
return { kind: "expanded", text: formatSkillInvocation(skill, body, cmd.args), skill };
|
|
30873
31176
|
}
|
|
30874
|
-
var
|
|
31177
|
+
var import_promises19;
|
|
30875
31178
|
var init_expand = __esm({
|
|
30876
31179
|
"src/skills/expand.ts"() {
|
|
30877
31180
|
"use strict";
|
|
30878
|
-
|
|
31181
|
+
import_promises19 = require("node:fs/promises");
|
|
30879
31182
|
init_frontmatter2();
|
|
30880
31183
|
init_index_prompt();
|
|
30881
31184
|
}
|
|
@@ -30901,8 +31204,8 @@ async function discoverPromptTemplates(sources, options) {
|
|
|
30901
31204
|
for (const source of sources) {
|
|
30902
31205
|
let names;
|
|
30903
31206
|
try {
|
|
30904
|
-
if (!(await (0,
|
|
30905
|
-
names = await (0,
|
|
31207
|
+
if (!(await (0, import_promises20.stat)(source.dir)).isDirectory()) continue;
|
|
31208
|
+
names = await (0, import_promises20.readdir)(source.dir);
|
|
30906
31209
|
} catch {
|
|
30907
31210
|
continue;
|
|
30908
31211
|
}
|
|
@@ -30924,8 +31227,8 @@ async function discoverPromptTemplates(sources, options) {
|
|
|
30924
31227
|
}
|
|
30925
31228
|
let text;
|
|
30926
31229
|
try {
|
|
30927
|
-
if (!(await (0,
|
|
30928
|
-
text = await (0,
|
|
31230
|
+
if (!(await (0, import_promises20.stat)(path)).isFile()) continue;
|
|
31231
|
+
text = await (0, import_promises20.readFile)(path, "utf8");
|
|
30929
31232
|
} catch {
|
|
30930
31233
|
continue;
|
|
30931
31234
|
}
|
|
@@ -31012,7 +31315,7 @@ function parsePromptCommand(text) {
|
|
|
31012
31315
|
const rawArgs = (m[2] ?? "").trim();
|
|
31013
31316
|
return { name: m[1], args: parseCommandArgs(rawArgs), rawArgs };
|
|
31014
31317
|
}
|
|
31015
|
-
async function expandPromptCommand(text, templates, read2 = (p) => (0,
|
|
31318
|
+
async function expandPromptCommand(text, templates, read2 = (p) => (0, import_promises20.readFile)(p, "utf8")) {
|
|
31016
31319
|
const cmd = parsePromptCommand(text);
|
|
31017
31320
|
if (!cmd) return void 0;
|
|
31018
31321
|
const template2 = templates.find((t) => t.name === cmd.name);
|
|
@@ -31020,11 +31323,11 @@ async function expandPromptCommand(text, templates, read2 = (p) => (0, import_pr
|
|
|
31020
31323
|
const body = parseFrontmatter(await read2(template2.path)).body.replace(/^\n+/, "");
|
|
31021
31324
|
return { text: expandTemplate(body, cmd.args), template: template2 };
|
|
31022
31325
|
}
|
|
31023
|
-
var
|
|
31326
|
+
var import_promises20, import_node_path53, TEMPLATE_NAME_RE, PLACEHOLDER;
|
|
31024
31327
|
var init_templates = __esm({
|
|
31025
31328
|
"src/skills/templates.ts"() {
|
|
31026
31329
|
"use strict";
|
|
31027
|
-
|
|
31330
|
+
import_promises20 = require("node:fs/promises");
|
|
31028
31331
|
import_node_path53 = require("node:path");
|
|
31029
31332
|
init_frontmatter2();
|
|
31030
31333
|
TEMPLATE_NAME_RE = /^[a-z0-9][a-z0-9_-]*$/i;
|
|
@@ -31256,8 +31559,8 @@ function candidates(items) {
|
|
|
31256
31559
|
}
|
|
31257
31560
|
return out;
|
|
31258
31561
|
}
|
|
31259
|
-
function budgetReplacement(content,
|
|
31260
|
-
return content.map((block) => block.type === "text" ? block.text :
|
|
31562
|
+
function budgetReplacement(content, placeholder2 = IMAGE_OMITTED_FOR_BUDGET) {
|
|
31563
|
+
return content.map((block) => block.type === "text" ? block.text : placeholder2).filter((text) => text !== "").join("\n");
|
|
31261
31564
|
}
|
|
31262
31565
|
function base64ImageSize(block) {
|
|
31263
31566
|
const cached = sizeCache.get(block);
|
|
@@ -31272,10 +31575,10 @@ function planImageBudget(items, budgetBytes, options = {}) {
|
|
|
31272
31575
|
const all = candidates(items);
|
|
31273
31576
|
const plan2 = [];
|
|
31274
31577
|
const drop = (c, cause) => {
|
|
31275
|
-
const
|
|
31578
|
+
const placeholder2 = cause === "per_image" ? IMAGE_OMITTED_TOO_LARGE : IMAGE_OMITTED_FOR_BUDGET;
|
|
31276
31579
|
plan2.push({
|
|
31277
31580
|
targetId: c.targetId,
|
|
31278
|
-
replacement: budgetReplacement(c.content,
|
|
31581
|
+
replacement: budgetReplacement(c.content, placeholder2),
|
|
31279
31582
|
cause,
|
|
31280
31583
|
images: c.images.length,
|
|
31281
31584
|
bytes: c.bytes
|
|
@@ -31809,7 +32112,7 @@ var init_done_markers = __esm({
|
|
|
31809
32112
|
function extractProposedPlan(text) {
|
|
31810
32113
|
const lines2 = text.split(/\r?\n/);
|
|
31811
32114
|
let fence2;
|
|
31812
|
-
let
|
|
32115
|
+
let open3;
|
|
31813
32116
|
let last;
|
|
31814
32117
|
for (const [i, line2] of lines2.entries()) {
|
|
31815
32118
|
const marker = FENCE.exec(line2)?.[1];
|
|
@@ -31820,10 +32123,10 @@ function extractProposedPlan(text) {
|
|
|
31820
32123
|
}
|
|
31821
32124
|
if (fence2 !== void 0) continue;
|
|
31822
32125
|
const trimmed = line2.trim();
|
|
31823
|
-
if (trimmed === PLAN_OPEN_TAG)
|
|
31824
|
-
else if (trimmed === PLAN_CLOSE_TAG &&
|
|
31825
|
-
last = { from:
|
|
31826
|
-
|
|
32126
|
+
if (trimmed === PLAN_OPEN_TAG) open3 = i;
|
|
32127
|
+
else if (trimmed === PLAN_CLOSE_TAG && open3 !== void 0) {
|
|
32128
|
+
last = { from: open3 + 1, to: i };
|
|
32129
|
+
open3 = void 0;
|
|
31827
32130
|
}
|
|
31828
32131
|
}
|
|
31829
32132
|
if (last === void 0) return void 0;
|
|
@@ -37196,7 +37499,7 @@ function permissionModes(currentModeId) {
|
|
|
37196
37499
|
}))
|
|
37197
37500
|
};
|
|
37198
37501
|
}
|
|
37199
|
-
function
|
|
37502
|
+
function contentOf2(content) {
|
|
37200
37503
|
if (typeof content === "string") return content === "" ? [] : [{ type: "text", text: content }];
|
|
37201
37504
|
const out = [];
|
|
37202
37505
|
for (const block of content) {
|
|
@@ -37418,7 +37721,7 @@ var init_acp_events = __esm({
|
|
|
37418
37721
|
for (const message of messages) {
|
|
37419
37722
|
if (!("role" in message)) continue;
|
|
37420
37723
|
if (message.role === "user") {
|
|
37421
|
-
for (const block of
|
|
37724
|
+
for (const block of contentOf2(message.content))
|
|
37422
37725
|
this.emit({ sessionUpdate: "user_message_chunk", content: block });
|
|
37423
37726
|
} else if (message.role === "assistant") {
|
|
37424
37727
|
for (const block of message.content) {
|
|
@@ -37825,10 +38128,11 @@ function pageSessions(items, cursor, pageSize = LIST_PAGE_SIZE) {
|
|
|
37825
38128
|
const last = all[start + pageSize - 1];
|
|
37826
38129
|
return start + pageSize < all.length && last !== void 0 ? { sessions, nextCursor: encodeCursor(last.updatedAt, last.sessionId) } : { sessions };
|
|
37827
38130
|
}
|
|
37828
|
-
async function promptWhenIdle(session, job) {
|
|
38131
|
+
async function promptWhenIdle(session, job, onStart) {
|
|
37829
38132
|
for (; ; ) {
|
|
37830
38133
|
await session.waitForIdle();
|
|
37831
38134
|
if (job.cancelRequested) return;
|
|
38135
|
+
onStart?.();
|
|
37832
38136
|
try {
|
|
37833
38137
|
await session.prompt(job.text, job.images.length > 0 ? { images: job.images } : {});
|
|
37834
38138
|
return;
|
|
@@ -37837,10 +38141,36 @@ async function promptWhenIdle(session, job) {
|
|
|
37837
38141
|
}
|
|
37838
38142
|
}
|
|
37839
38143
|
}
|
|
37840
|
-
|
|
38144
|
+
async function idleNow(session) {
|
|
38145
|
+
return await Promise.race([session.waitForIdle(), Promise.resolve(BUSY)]) !== BUSY;
|
|
38146
|
+
}
|
|
38147
|
+
async function quiesce(session, control, rounds = 50) {
|
|
38148
|
+
for (const task of control?.list() ?? [])
|
|
38149
|
+
if (task.status === "running") await control?.stop(task.taskId).catch(() => void 0);
|
|
38150
|
+
for (let i = 0; i < rounds; i++) {
|
|
38151
|
+
await session.abort();
|
|
38152
|
+
await new Promise((resolve41) => setImmediate(resolve41));
|
|
38153
|
+
if (await idleNow(session)) return true;
|
|
38154
|
+
}
|
|
38155
|
+
return false;
|
|
38156
|
+
}
|
|
38157
|
+
async function disposeQuiet(runtime, session, fallback, control, retries = 3) {
|
|
38158
|
+
for (let i = 0; ; i++) {
|
|
38159
|
+
try {
|
|
38160
|
+
await disposeSessionAlongside(runtime, session, fallback);
|
|
38161
|
+
break;
|
|
38162
|
+
} catch (error2) {
|
|
38163
|
+
if (i >= retries || !(error2 instanceof AmaError && error2.code === "busy")) throw error2;
|
|
38164
|
+
await quiesce(session, control);
|
|
38165
|
+
}
|
|
38166
|
+
}
|
|
38167
|
+
await session.abort();
|
|
38168
|
+
}
|
|
38169
|
+
var LIST_PAGE_SIZE, TITLE_LIMIT, ZERO_USAGE2, PromptQueue, BUSY;
|
|
37841
38170
|
var init_acp_sessions = __esm({
|
|
37842
38171
|
"src/modes/acp/acp-sessions.ts"() {
|
|
37843
38172
|
"use strict";
|
|
38173
|
+
init_compose_session();
|
|
37844
38174
|
init_types7();
|
|
37845
38175
|
init_jsonrpc();
|
|
37846
38176
|
init_errors();
|
|
@@ -37908,6 +38238,7 @@ var init_acp_sessions = __esm({
|
|
|
37908
38238
|
});
|
|
37909
38239
|
}
|
|
37910
38240
|
};
|
|
38241
|
+
BUSY = /* @__PURE__ */ Symbol("busy");
|
|
37911
38242
|
}
|
|
37912
38243
|
});
|
|
37913
38244
|
|
|
@@ -37955,6 +38286,7 @@ var init_acp_server = __esm({
|
|
|
37955
38286
|
init_compose_session();
|
|
37956
38287
|
init_compose_store();
|
|
37957
38288
|
init_session2();
|
|
38289
|
+
init_task_control();
|
|
37958
38290
|
init_jsonrpc();
|
|
37959
38291
|
init_types7();
|
|
37960
38292
|
init_modes();
|
|
@@ -38052,13 +38384,14 @@ var init_acp_server = __esm({
|
|
|
38052
38384
|
if (abort)
|
|
38053
38385
|
await this.session().abort().catch(() => void 0);
|
|
38054
38386
|
await this.queue.settled();
|
|
38055
|
-
for (const
|
|
38387
|
+
for (const s2 of this.sessions())
|
|
38388
|
+
if (s2 instanceof AgentSessionImpl) await quiesce(s2, taskControl(s2.state.sessionId));
|
|
38056
38389
|
const foreground = this.session();
|
|
38057
38390
|
for (const entry of this.pool.values()) entry.unsubscribe();
|
|
38058
38391
|
for (const session of this.sessions()) {
|
|
38059
38392
|
if (session === foreground || !(session instanceof AgentSessionImpl)) continue;
|
|
38060
38393
|
if (!(foreground instanceof AgentSessionImpl)) continue;
|
|
38061
|
-
await
|
|
38394
|
+
await disposeQuiet(this.runtime, session, foreground).catch(() => void 0);
|
|
38062
38395
|
}
|
|
38063
38396
|
this.pool.clear();
|
|
38064
38397
|
this.standby = void 0;
|
|
@@ -38194,12 +38527,9 @@ var init_acp_server = __esm({
|
|
|
38194
38527
|
if (entry === void 0) return {};
|
|
38195
38528
|
this.pool.delete(id);
|
|
38196
38529
|
this.queue.cancelQueued(id);
|
|
38197
|
-
|
|
38198
|
-
|
|
38199
|
-
|
|
38200
|
-
await entry.session.abort().catch(() => void 0);
|
|
38201
|
-
await this.queue.settled(id);
|
|
38202
|
-
}
|
|
38530
|
+
if (this.queue.running?.sessionId === id) this.queue.running.cancelRequested = true;
|
|
38531
|
+
await quiesce(entry.session, taskControl(id));
|
|
38532
|
+
await this.queue.settled(id);
|
|
38203
38533
|
entry.unsubscribe();
|
|
38204
38534
|
let fallback = this.session();
|
|
38205
38535
|
if (fallback === entry.session) {
|
|
@@ -38211,7 +38541,7 @@ var init_acp_server = __esm({
|
|
|
38211
38541
|
}
|
|
38212
38542
|
}
|
|
38213
38543
|
if (fallback instanceof AgentSessionImpl)
|
|
38214
|
-
await
|
|
38544
|
+
await disposeQuiet(this.runtime, entry.session, fallback, taskControl(id));
|
|
38215
38545
|
return {};
|
|
38216
38546
|
}
|
|
38217
38547
|
async prompt(params, signal) {
|
|
@@ -38250,15 +38580,15 @@ var init_acp_server = __esm({
|
|
|
38250
38580
|
const { session } = entry;
|
|
38251
38581
|
setForegroundSession(this.runtime, session);
|
|
38252
38582
|
if (this.runtime.permission.mode !== entry.mode) session.setPermissionMode(entry.mode);
|
|
38253
|
-
|
|
38583
|
+
let before2 = session.getStats().tokens;
|
|
38254
38584
|
let failure2;
|
|
38255
38585
|
try {
|
|
38256
|
-
await promptWhenIdle(session, job);
|
|
38586
|
+
await promptWhenIdle(session, job, () => void (before2 = session.getStats().tokens));
|
|
38257
38587
|
} catch (error2) {
|
|
38258
38588
|
failure2 = error2;
|
|
38259
38589
|
}
|
|
38260
|
-
await this.peer.flush();
|
|
38261
38590
|
const after = session.getStats().tokens;
|
|
38591
|
+
await this.peer.flush();
|
|
38262
38592
|
const usage = {
|
|
38263
38593
|
inputTokens: after.input - before2.input,
|
|
38264
38594
|
outputTokens: after.output - before2.output,
|
|
@@ -38668,7 +38998,7 @@ async function bootstrap(argsIn, deps, io) {
|
|
|
38668
38998
|
request = { kind: "resume", id };
|
|
38669
38999
|
}
|
|
38670
39000
|
const sessionRequest = request;
|
|
38671
|
-
|
|
39001
|
+
let sessionManager = await step(
|
|
38672
39002
|
ExitCode.Session,
|
|
38673
39003
|
m().steps.session,
|
|
38674
39004
|
() => deps.sessions.open(sessionRequest, { sessionDir: paths.sessionDir, cwd: paths.cwd })
|
|
@@ -38893,6 +39223,8 @@ async function bootstrap(argsIn, deps, io) {
|
|
|
38893
39223
|
uiBroker: () => uiBroker,
|
|
38894
39224
|
onSessionReplaced: (next) => {
|
|
38895
39225
|
session = next;
|
|
39226
|
+
sessionManager = next.manager ?? sessionManager;
|
|
39227
|
+
assembly.sessionManager = sessionManager;
|
|
38896
39228
|
},
|
|
38897
39229
|
sessionStartContext: () => sessionStartContext,
|
|
38898
39230
|
unattended,
|
|
@@ -38922,7 +39254,7 @@ async function bootstrap(argsIn, deps, io) {
|
|
|
38922
39254
|
await events.emit("session_shutdown", {});
|
|
38923
39255
|
await hooks.run("SessionEnd", { reason }).catch(() => void 0);
|
|
38924
39256
|
await disposeHost(host, (e) => warn2(m().hostDisposeFailed(String(e))));
|
|
38925
|
-
await
|
|
39257
|
+
await session?.dispose();
|
|
38926
39258
|
})();
|
|
38927
39259
|
return disposed2;
|
|
38928
39260
|
};
|
|
@@ -38955,8 +39287,13 @@ async function bootstrap(argsIn, deps, io) {
|
|
|
38955
39287
|
providers,
|
|
38956
39288
|
model,
|
|
38957
39289
|
thinkingLevel,
|
|
38958
|
-
|
|
38959
|
-
|
|
39290
|
+
// [#165] 跟随当前会话(ACP 关掉启动会话后它可被回收)
|
|
39291
|
+
get sessionManager() {
|
|
39292
|
+
return sessionManager;
|
|
39293
|
+
},
|
|
39294
|
+
get session() {
|
|
39295
|
+
return session;
|
|
39296
|
+
},
|
|
38960
39297
|
hooks,
|
|
38961
39298
|
host,
|
|
38962
39299
|
permission,
|
|
@@ -43445,18 +43782,18 @@ async function confirmContinue(options = {}) {
|
|
|
43445
43782
|
});
|
|
43446
43783
|
return index2 === 0;
|
|
43447
43784
|
}
|
|
43448
|
-
const rl = (0,
|
|
43785
|
+
const rl = (0, import_promises21.createInterface)({ input: input2, output: options.output ?? process.stderr });
|
|
43449
43786
|
try {
|
|
43450
43787
|
return /^y(es)?$/i.test((await rl.question(m.textQuestion(question))).trim());
|
|
43451
43788
|
} finally {
|
|
43452
43789
|
rl.close();
|
|
43453
43790
|
}
|
|
43454
43791
|
}
|
|
43455
|
-
var
|
|
43792
|
+
var import_promises21, HIDE_CURSOR2, SHOW_CURSOR2;
|
|
43456
43793
|
var init_choice_prompt = __esm({
|
|
43457
43794
|
"src/cli/choice-prompt.ts"() {
|
|
43458
43795
|
"use strict";
|
|
43459
|
-
|
|
43796
|
+
import_promises21 = require("node:readline/promises");
|
|
43460
43797
|
init_tui2();
|
|
43461
43798
|
init_i18n();
|
|
43462
43799
|
HIDE_CURSOR2 = "\x1B[?25l";
|
|
@@ -44312,7 +44649,7 @@ ${error2.message}`)?.[0].toLowerCase();
|
|
|
44312
44649
|
}
|
|
44313
44650
|
function stripInto(value, removed) {
|
|
44314
44651
|
if (Array.isArray(value)) return value.map((item) => stripInto(item, removed));
|
|
44315
|
-
if (typeof value !== "object" || value === null) return value;
|
|
44652
|
+
if (typeof value !== "object" || value === null || value instanceof LargeString) return value;
|
|
44316
44653
|
const out = {};
|
|
44317
44654
|
for (const [key, inner] of Object.entries(value)) {
|
|
44318
44655
|
if (key === "cache_control") removed.count++;
|
|
@@ -44351,6 +44688,7 @@ var init_cache_params = __esm({
|
|
|
44351
44688
|
"src/ai/apis/cache-params.ts"() {
|
|
44352
44689
|
"use strict";
|
|
44353
44690
|
init_http();
|
|
44691
|
+
init_json_body();
|
|
44354
44692
|
init_i18n();
|
|
44355
44693
|
DEFAULT_BASE_URLS = {
|
|
44356
44694
|
"anthropic-messages": "https://api.anthropic.com",
|
|
@@ -44433,7 +44771,11 @@ function convertBlocks(content) {
|
|
|
44433
44771
|
} else {
|
|
44434
44772
|
blocks.push({
|
|
44435
44773
|
type: "image",
|
|
44436
|
-
source: {
|
|
44774
|
+
source: {
|
|
44775
|
+
type: "base64",
|
|
44776
|
+
media_type: block.mimeType,
|
|
44777
|
+
data: largeString("", block, block.data)
|
|
44778
|
+
}
|
|
44437
44779
|
});
|
|
44438
44780
|
}
|
|
44439
44781
|
}
|
|
@@ -44607,6 +44949,7 @@ var init_anthropic_request = __esm({
|
|
|
44607
44949
|
"src/ai/apis/anthropic-request.ts"() {
|
|
44608
44950
|
"use strict";
|
|
44609
44951
|
init_context();
|
|
44952
|
+
init_json_body();
|
|
44610
44953
|
init_thinking();
|
|
44611
44954
|
init_anthropic_compat();
|
|
44612
44955
|
init_cache_params();
|
|
@@ -44656,7 +44999,7 @@ function validSignature(signature2) {
|
|
|
44656
44999
|
return signature2 !== void 0 && signature2.length > 0 && signature2.length % 4 === 0 && BASE64.test(signature2);
|
|
44657
45000
|
}
|
|
44658
45001
|
function inlineData(block) {
|
|
44659
|
-
return { inlineData: { mimeType: block.mimeType, data: block.data } };
|
|
45002
|
+
return { inlineData: { mimeType: block.mimeType, data: largeString("", block, block.data) } };
|
|
44660
45003
|
}
|
|
44661
45004
|
function convertUser2(message) {
|
|
44662
45005
|
if (typeof message.content === "string") {
|
|
@@ -44827,6 +45170,7 @@ var init_google_request = __esm({
|
|
|
44827
45170
|
"src/ai/apis/google-request.ts"() {
|
|
44828
45171
|
"use strict";
|
|
44829
45172
|
init_context();
|
|
45173
|
+
init_json_body();
|
|
44830
45174
|
init_thinking();
|
|
44831
45175
|
GOOGLE_BASE_URL = "https://generativelanguage.googleapis.com/v1beta";
|
|
44832
45176
|
GOOGLE_COMPAT_KEYS = [
|
|
@@ -45274,7 +45618,8 @@ var init_chatgpt_backend = __esm({
|
|
|
45274
45618
|
|
|
45275
45619
|
// src/ai/apis/openai-request.ts
|
|
45276
45620
|
function imagePart(block) {
|
|
45277
|
-
|
|
45621
|
+
const url = largeString(`data:${block.mimeType};base64,`, block, block.data);
|
|
45622
|
+
return { type: "image_url", image_url: { url } };
|
|
45278
45623
|
}
|
|
45279
45624
|
function convertUser3(message) {
|
|
45280
45625
|
if (typeof message.content === "string") {
|
|
@@ -45325,17 +45670,17 @@ function convertToolResults(model, results, compat) {
|
|
|
45325
45670
|
for (const result of results) {
|
|
45326
45671
|
const text = contentText2(result.content);
|
|
45327
45672
|
const blocks = typeof result.content === "string" ? [] : result.content;
|
|
45328
|
-
const
|
|
45673
|
+
const hasImages2 = blocks.some((b) => b.type === "image");
|
|
45329
45674
|
const message = {
|
|
45330
45675
|
role: "tool",
|
|
45331
45676
|
tool_call_id: normalizeCallId(model, result.toolCallId),
|
|
45332
45677
|
content: sanitizeText(
|
|
45333
|
-
text.length > 0 ? text :
|
|
45678
|
+
text.length > 0 ? text : hasImages2 ? "(see attached image)" : "(no output)"
|
|
45334
45679
|
)
|
|
45335
45680
|
};
|
|
45336
45681
|
if (compat.requiresToolResultName) message["name"] = result.toolName;
|
|
45337
45682
|
messages.push(message);
|
|
45338
|
-
if (
|
|
45683
|
+
if (hasImages2 && model.input.includes("image")) {
|
|
45339
45684
|
for (const block of blocks) if (block.type === "image") images.push(imagePart(block));
|
|
45340
45685
|
}
|
|
45341
45686
|
}
|
|
@@ -45527,6 +45872,7 @@ var init_openai_request = __esm({
|
|
|
45527
45872
|
init_thinking();
|
|
45528
45873
|
init_anthropic_request();
|
|
45529
45874
|
init_cache_params();
|
|
45875
|
+
init_json_body();
|
|
45530
45876
|
init_openai_compat();
|
|
45531
45877
|
REASONING_FIELDS = ["reasoning_content", "reasoning", "reasoning_text"];
|
|
45532
45878
|
ASSISTANT_BRIDGE_TEXT = "Tool results received.";
|
|
@@ -45581,7 +45927,7 @@ function imagePart2(block) {
|
|
|
45581
45927
|
return {
|
|
45582
45928
|
type: "input_image",
|
|
45583
45929
|
detail: "auto",
|
|
45584
|
-
image_url: `data:${block.mimeType};base64
|
|
45930
|
+
image_url: largeString(`data:${block.mimeType};base64,`, block, block.data)
|
|
45585
45931
|
};
|
|
45586
45932
|
}
|
|
45587
45933
|
function convertUser4(message) {
|
|
@@ -45726,6 +46072,7 @@ var init_openai_responses_request = __esm({
|
|
|
45726
46072
|
"src/ai/apis/openai-responses-request.ts"() {
|
|
45727
46073
|
"use strict";
|
|
45728
46074
|
init_context();
|
|
46075
|
+
init_json_body();
|
|
45729
46076
|
init_thinking();
|
|
45730
46077
|
init_cache_params();
|
|
45731
46078
|
init_chatgpt_backend();
|
|
@@ -47647,8 +47994,8 @@ var init_registry2 = __esm({
|
|
|
47647
47994
|
const id = trimmed.slice(slash + 1);
|
|
47648
47995
|
const model = provider.models.find((m) => m.id === id);
|
|
47649
47996
|
if (model) return { ok: true, model, provider };
|
|
47650
|
-
const
|
|
47651
|
-
const relayed = provider.models.length === 0 ||
|
|
47997
|
+
const open3 = this.relayed.has(provider.id) || this.openTables.has(provider.id);
|
|
47998
|
+
const relayed = provider.models.length === 0 || open3;
|
|
47652
47999
|
if (synthesize && relayed && id.length > 0) {
|
|
47653
48000
|
const known = provider.channels?.some((c) => c.name === channel) ? channel : void 0;
|
|
47654
48001
|
const synthesized = this.synthesize(provider, id, known);
|
|
@@ -48253,7 +48600,7 @@ function attempts(platform, file, env) {
|
|
|
48253
48600
|
}
|
|
48254
48601
|
async function isPng(file) {
|
|
48255
48602
|
try {
|
|
48256
|
-
return sniffImageMime(await (0,
|
|
48603
|
+
return sniffImageMime(await (0, import_promises22.readFile)(file)) === "image/png";
|
|
48257
48604
|
} catch {
|
|
48258
48605
|
return false;
|
|
48259
48606
|
}
|
|
@@ -48263,7 +48610,7 @@ async function readClipboardImage(dataDir, deps = {}) {
|
|
|
48263
48610
|
const env = deps.env ?? process.env;
|
|
48264
48611
|
const run7 = deps.run ?? runCommand;
|
|
48265
48612
|
const dir = (0, import_node_path78.join)(dataDir, CLIPBOARD_DIR);
|
|
48266
|
-
await (0,
|
|
48613
|
+
await (0, import_promises22.mkdir)(dir, { recursive: true });
|
|
48267
48614
|
const stamp = new Date((deps.now ?? Date.now)()).toISOString().replace(/[:.]/g, "-");
|
|
48268
48615
|
let file = (0, import_node_path78.join)(dir, `${stamp}.png`);
|
|
48269
48616
|
for (let n = 1; (0, import_node_fs60.existsSync)(file); n++) file = (0, import_node_path78.join)(dir, `${stamp}-${n}.png`);
|
|
@@ -48276,19 +48623,19 @@ async function readClipboardImage(dataDir, deps = {}) {
|
|
|
48276
48623
|
if (result.code !== 0) continue;
|
|
48277
48624
|
if (attempt.via === "stdout") {
|
|
48278
48625
|
if (sniffImageMime(result.stdout) !== "image/png") continue;
|
|
48279
|
-
await (0,
|
|
48626
|
+
await (0, import_promises22.writeFile)(file, result.stdout);
|
|
48280
48627
|
}
|
|
48281
48628
|
if (await isPng(file)) return { ok: true, path: file, tool: attempt.tool };
|
|
48282
|
-
await (0,
|
|
48629
|
+
await (0, import_promises22.rm)(file, { force: true });
|
|
48283
48630
|
}
|
|
48284
|
-
await (0,
|
|
48631
|
+
await (0, import_promises22.rm)(file, { force: true });
|
|
48285
48632
|
return { ok: false, reason: anyTool ? "no_image" : "no_tool" };
|
|
48286
48633
|
}
|
|
48287
48634
|
async function gcClipboardImages(dataDir, options = {}) {
|
|
48288
48635
|
const dir = (0, import_node_path78.join)(dataDir, CLIPBOARD_DIR);
|
|
48289
48636
|
let names;
|
|
48290
48637
|
try {
|
|
48291
|
-
names = await (0,
|
|
48638
|
+
names = await (0, import_promises22.readdir)(dir);
|
|
48292
48639
|
} catch {
|
|
48293
48640
|
return [];
|
|
48294
48641
|
}
|
|
@@ -48297,21 +48644,21 @@ async function gcClipboardImages(dataDir, options = {}) {
|
|
|
48297
48644
|
for (const name of names) {
|
|
48298
48645
|
const file = (0, import_node_path78.join)(dir, name);
|
|
48299
48646
|
try {
|
|
48300
|
-
const info2 = await (0,
|
|
48647
|
+
const info2 = await (0, import_promises22.stat)(file);
|
|
48301
48648
|
if (!info2.isFile() || info2.mtimeMs >= cutoff) continue;
|
|
48302
|
-
if (options.dryRun !== true) await (0,
|
|
48649
|
+
if (options.dryRun !== true) await (0, import_promises22.rm)(file, { force: true });
|
|
48303
48650
|
removed.push(file);
|
|
48304
48651
|
} catch {
|
|
48305
48652
|
}
|
|
48306
48653
|
}
|
|
48307
48654
|
return removed;
|
|
48308
48655
|
}
|
|
48309
|
-
var import_node_fs60,
|
|
48656
|
+
var import_node_fs60, import_promises22, import_node_path78, CLIPBOARD_DIR, CLIPBOARD_MAX_AGE_DAYS, OSASCRIPT, POWERSHELL;
|
|
48310
48657
|
var init_clipboard_image = __esm({
|
|
48311
48658
|
"src/tools/clipboard-image.ts"() {
|
|
48312
48659
|
"use strict";
|
|
48313
48660
|
import_node_fs60 = require("node:fs");
|
|
48314
|
-
|
|
48661
|
+
import_promises22 = require("node:fs/promises");
|
|
48315
48662
|
import_node_path78 = require("node:path");
|
|
48316
48663
|
init_image_file();
|
|
48317
48664
|
init_image_resize();
|
|
@@ -50456,8 +50803,8 @@ function barText(row3, width2, theme) {
|
|
|
50456
50803
|
const color = colors[rank3];
|
|
50457
50804
|
body += color === void 0 || plain ? ch2 : theme.fg(color, ch2);
|
|
50458
50805
|
}
|
|
50459
|
-
const [
|
|
50460
|
-
return theme.fg("border",
|
|
50806
|
+
const [open3, close] = plain ? ["[", "]"] : ["▕", "▏"];
|
|
50807
|
+
return theme.fg("border", open3) + body + theme.fg("border", close);
|
|
50461
50808
|
}
|
|
50462
50809
|
function labelPart(row3, ctx) {
|
|
50463
50810
|
const g = ctx.theme.glyphs;
|
|
@@ -51115,11 +51462,11 @@ ${skill.body}`;
|
|
|
51115
51462
|
}
|
|
51116
51463
|
async function ensureFile(path, text) {
|
|
51117
51464
|
try {
|
|
51118
|
-
if (await (0,
|
|
51465
|
+
if (await (0, import_promises23.readFile)(path, "utf8") === text) return;
|
|
51119
51466
|
} catch {
|
|
51120
51467
|
}
|
|
51121
|
-
await (0,
|
|
51122
|
-
await (0,
|
|
51468
|
+
await (0, import_promises23.mkdir)((0, import_node_path86.dirname)(path), { recursive: true });
|
|
51469
|
+
await (0, import_promises23.writeFile)(path, text, "utf8");
|
|
51123
51470
|
}
|
|
51124
51471
|
async function withBuiltinSkills(skills, dataDir, builtins = BUILTIN_SKILLS) {
|
|
51125
51472
|
const out = [...skills];
|
|
@@ -51148,11 +51495,11 @@ async function withBuiltinSkills(skills, dataDir, builtins = BUILTIN_SKILLS) {
|
|
|
51148
51495
|
}
|
|
51149
51496
|
return { skills: out, warnings };
|
|
51150
51497
|
}
|
|
51151
|
-
var
|
|
51498
|
+
var import_promises23, import_node_path86, BUILTIN_SKILLS_DIR, AMA_DOCS_BODY, BUILTIN_SKILLS;
|
|
51152
51499
|
var init_builtin3 = __esm({
|
|
51153
51500
|
"src/skills/builtin.ts"() {
|
|
51154
51501
|
"use strict";
|
|
51155
|
-
|
|
51502
|
+
import_promises23 = require("node:fs/promises");
|
|
51156
51503
|
import_node_path86 = require("node:path");
|
|
51157
51504
|
BUILTIN_SKILLS_DIR = "builtin";
|
|
51158
51505
|
AMA_DOCS_BODY = `# ama quick reference
|
|
@@ -51263,7 +51610,7 @@ function parseSkill(text, location, scope) {
|
|
|
51263
51610
|
}
|
|
51264
51611
|
async function isDir3(path) {
|
|
51265
51612
|
try {
|
|
51266
|
-
return (await (0,
|
|
51613
|
+
return (await (0, import_promises24.stat)(path)).isDirectory();
|
|
51267
51614
|
} catch {
|
|
51268
51615
|
return false;
|
|
51269
51616
|
}
|
|
@@ -51274,7 +51621,7 @@ async function findSkillFiles(dir, depth = 0) {
|
|
|
51274
51621
|
if ((0, import_node_fs65.existsSync)(own)) return [own];
|
|
51275
51622
|
let names;
|
|
51276
51623
|
try {
|
|
51277
|
-
names = await (0,
|
|
51624
|
+
names = await (0, import_promises24.readdir)(dir);
|
|
51278
51625
|
} catch {
|
|
51279
51626
|
return [];
|
|
51280
51627
|
}
|
|
@@ -51302,7 +51649,7 @@ async function discoverSkills(sources, options) {
|
|
|
51302
51649
|
for (const file of await findSkillFiles(source.dir)) {
|
|
51303
51650
|
let text;
|
|
51304
51651
|
try {
|
|
51305
|
-
text = await (0,
|
|
51652
|
+
text = await (0, import_promises24.readFile)(file, "utf8");
|
|
51306
51653
|
} catch (err) {
|
|
51307
51654
|
result.warnings.push(`${file}: ${err.message}`);
|
|
51308
51655
|
continue;
|
|
@@ -51323,12 +51670,12 @@ async function discoverSkills(sources, options) {
|
|
|
51323
51670
|
}
|
|
51324
51671
|
return result;
|
|
51325
51672
|
}
|
|
51326
|
-
var import_node_fs65,
|
|
51673
|
+
var import_node_fs65, import_promises24, import_node_path87, SKILL_FILE, SKILL_NAME_RE, MAX_SKILL_NAME, MAX_SKILL_DESCRIPTION, MAX_DEPTH3, SKIP_DIRS;
|
|
51327
51674
|
var init_discover2 = __esm({
|
|
51328
51675
|
"src/skills/discover.ts"() {
|
|
51329
51676
|
"use strict";
|
|
51330
51677
|
import_node_fs65 = require("node:fs");
|
|
51331
|
-
|
|
51678
|
+
import_promises24 = require("node:fs/promises");
|
|
51332
51679
|
import_node_path87 = require("node:path");
|
|
51333
51680
|
init_frontmatter2();
|
|
51334
51681
|
SKILL_FILE = "SKILL.md";
|
|
@@ -60456,9 +60803,9 @@ function parseLeftRight(text) {
|
|
|
60456
60803
|
async function hasUpstream(cwd, branch) {
|
|
60457
60804
|
const gitDir = await findGitDir(cwd);
|
|
60458
60805
|
if (gitDir === void 0) return false;
|
|
60459
|
-
const common = (await (0,
|
|
60806
|
+
const common = (await (0, import_promises25.readFile)((0, import_node_path95.join)(gitDir, "commondir"), "utf8").catch(() => void 0))?.trim();
|
|
60460
60807
|
const dir = common === void 0 ? gitDir : (0, import_node_path95.isAbsolute)(common) ? common : (0, import_node_path95.resolve)(gitDir, common);
|
|
60461
|
-
const text = await (0,
|
|
60808
|
+
const text = await (0, import_promises25.readFile)((0, import_node_path95.join)(dir, "config"), "utf8").catch(() => "");
|
|
60462
60809
|
let inBranch = false;
|
|
60463
60810
|
for (const raw of text.split("\n")) {
|
|
60464
60811
|
const line2 = raw.trim();
|
|
@@ -60471,7 +60818,7 @@ async function hasUpstream(cwd, branch) {
|
|
|
60471
60818
|
}
|
|
60472
60819
|
return false;
|
|
60473
60820
|
}
|
|
60474
|
-
async function
|
|
60821
|
+
async function readHead2(cwd) {
|
|
60475
60822
|
const head = await readGitHead(cwd);
|
|
60476
60823
|
if (head !== void 0) {
|
|
60477
60824
|
return {
|
|
@@ -60481,16 +60828,16 @@ async function readHead3(cwd) {
|
|
|
60481
60828
|
}
|
|
60482
60829
|
const gitDir = await findGitDir(cwd);
|
|
60483
60830
|
if (gitDir === void 0) return void 0;
|
|
60484
|
-
const text = await (0,
|
|
60831
|
+
const text = await (0, import_promises25.readFile)((0, import_node_path95.join)(gitDir, "HEAD"), "utf8").catch(() => void 0);
|
|
60485
60832
|
const match = /^ref:\s*refs\/heads\/(\S+)\s*$/.exec(text ?? "");
|
|
60486
60833
|
return match?.[1] !== void 0 ? { branch: match[1] } : void 0;
|
|
60487
60834
|
}
|
|
60488
|
-
var import_node_child_process18,
|
|
60835
|
+
var import_node_child_process18, import_promises25, import_node_path95, GIT_NUMSTAT_INTERVAL_MS, GIT_NUMSTAT_TIMEOUT_MS, sameInfo, GitInfoWatcher;
|
|
60489
60836
|
var init_info = __esm({
|
|
60490
60837
|
"src/git/info.ts"() {
|
|
60491
60838
|
"use strict";
|
|
60492
60839
|
import_node_child_process18 = require("node:child_process");
|
|
60493
|
-
|
|
60840
|
+
import_promises25 = require("node:fs/promises");
|
|
60494
60841
|
import_node_path95 = require("node:path");
|
|
60495
60842
|
init_git_head();
|
|
60496
60843
|
GIT_NUMSTAT_INTERVAL_MS = 1e4;
|
|
@@ -60545,7 +60892,7 @@ var init_info = __esm({
|
|
|
60545
60892
|
const run7 = async () => {
|
|
60546
60893
|
do {
|
|
60547
60894
|
this.headAgain = false;
|
|
60548
|
-
const head = await
|
|
60895
|
+
const head = await readHead2(this.cwd).catch(() => void 0);
|
|
60549
60896
|
this.update(head);
|
|
60550
60897
|
} while (this.headAgain && !this.disposed);
|
|
60551
60898
|
this.headReading = void 0;
|
|
@@ -62644,8 +62991,8 @@ var init_run_indicator = __esm({
|
|
|
62644
62991
|
get busy() {
|
|
62645
62992
|
return this.running || this.compacting;
|
|
62646
62993
|
}
|
|
62647
|
-
setApproval(
|
|
62648
|
-
this.approval =
|
|
62994
|
+
setApproval(open3) {
|
|
62995
|
+
this.approval = open3;
|
|
62649
62996
|
this.sync();
|
|
62650
62997
|
}
|
|
62651
62998
|
/** 会话切换后清零。 */
|
|
@@ -69698,9 +70045,9 @@ async function runSessionsTrace(argv, io, deps = {}) {
|
|
|
69698
70045
|
});
|
|
69699
70046
|
}
|
|
69700
70047
|
const outFlag = split.file ?? values.get("output");
|
|
69701
|
-
const
|
|
70048
|
+
const open3 = flags2.has("open");
|
|
69702
70049
|
let outPath = outFlag === void 0 ? void 0 : (0, import_node_path84.resolve)(io.cwd, expandHome(outFlag, { env: io.env }));
|
|
69703
|
-
if (outPath === void 0 &&
|
|
70050
|
+
if (outPath === void 0 && open3)
|
|
69704
70051
|
outPath = (0, import_node_path84.join)((0, import_node_os12.tmpdir)(), `ama-trace-${read2.header.id}.${wantsJson ? "json" : "html"}`);
|
|
69705
70052
|
if (outPath === void 0) {
|
|
69706
70053
|
io.stdout(text);
|
|
@@ -69708,7 +70055,7 @@ async function runSessionsTrace(argv, io, deps = {}) {
|
|
|
69708
70055
|
}
|
|
69709
70056
|
(0, import_node_fs64.writeFileSync)(outPath, text, { mode: 384 });
|
|
69710
70057
|
io.stderr(m.wrote(outPath));
|
|
69711
|
-
if (
|
|
70058
|
+
if (open3) {
|
|
69712
70059
|
try {
|
|
69713
70060
|
await (deps.open ?? spawnOpen)(openCommand(deps.platform ?? process.platform, outPath));
|
|
69714
70061
|
} catch (error2) {
|