@armadra/agent 0.7.4 → 0.7.6
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 +32 -0
- package/CHANGELOG.zh-CN.md +32 -0
- package/dist/agent/session-classifier.d.ts +2 -0
- package/dist/agent/session-classifier.js +24 -3
- package/dist/agent/session-extensions.d.ts +1 -0
- package/dist/agent/session-extensions.js +3 -0
- package/dist/agent/session-subagent.js +9 -2
- package/dist/agent/subagent-background.d.ts +5 -1
- package/dist/agent/subagent-background.js +13 -1
- package/dist/agent/subagent-fork.d.ts +10 -5
- package/dist/agent/subagent-fork.js +22 -6
- package/dist/agent/subagent-registry.d.ts +1 -1
- package/dist/agent/subagent-registry.js +1 -1
- package/dist/agents/catalog.d.ts +1 -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/max-tokens.d.ts +4 -0
- package/dist/ai/apis/max-tokens.js +12 -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/ai/providers/enrich.d.ts +6 -2
- package/dist/ai/providers/enrich.js +13 -2
- package/dist/ai/providers/max-tokens-cache.d.ts +22 -0
- package/dist/ai/providers/max-tokens-cache.js +95 -0
- package/dist/ai/providers/registry.js +3 -3
- package/dist/bundle/ama.cjs +982 -442
- package/dist/checkpoints/shadow-git.d.ts +5 -1
- package/dist/checkpoints/shadow-git.js +11 -2
- package/dist/cli/bootstrap.js +13 -5
- package/dist/cli/compose-providers.d.ts +1 -0
- package/dist/cli/compose-providers.js +3 -0
- package/dist/cli/compose-store.d.ts +6 -2
- package/dist/cli/compose-store.js +8 -4
- package/dist/cli/compose.js +2 -2
- package/dist/cli/deps.d.ts +1 -1
- package/dist/config/json-schema.js +1 -0
- package/dist/config/key-docs.js +1 -0
- package/dist/config/schema-w5.js +2 -0
- package/dist/config/settings-registry.js +1 -0
- package/dist/config/types-w5.d.ts +5 -0
- package/dist/i18n/catalog.d.ts +2 -0
- package/dist/i18n/messages/config-keys.d.ts +2 -0
- package/dist/i18n/messages/config-keys.js +2 -0
- package/dist/i18n/messages/config.d.ts +2 -0
- package/dist/i18n/messages/interactive.d.ts +2 -0
- package/dist/i18n/messages/interactive.js +2 -0
- package/dist/i18n/messages/session.js +2 -2
- 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/modes/interactive/agent-ui.js +7 -0
- package/dist/session/manager.d.ts +18 -0
- package/dist/session/manager.js +75 -14
- package/dist/session/offload.d.ts +59 -0
- package/dist/session/offload.js +218 -0
- package/dist/session/store.d.ts +12 -4
- package/dist/session/store.js +18 -8
- package/dist/tools/background-jobs.d.ts +4 -4
- package/dist/tools/background-jobs.js +4 -4
- package/dist/tools/bash.d.ts +2 -1
- package/dist/tools/bash.js +4 -3
- 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/dist/tools/task-ctl.js +2 -1
- package/dist/tools/task.d.ts +9 -0
- package/dist/tools/task.js +27 -1
- package/docs/acp.md +6 -3
- package/docs/agents.md +14 -3
- package/docs/en/acp.md +2 -2
- package/docs/en/permissions.md +1 -1
- package/docs/en/providers.md +4 -4
- package/docs/en/sessions.md +2 -1
- package/docs/permissions.md +1 -1
- package/docs/providers.md +9 -5
- package/docs/session-format.md +11 -0
- package/docs/sessions.md +2 -1
- 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.6" : readPackageVersion();
|
|
45
45
|
}
|
|
46
46
|
});
|
|
47
47
|
|
|
@@ -1969,7 +1969,8 @@ var init_interactive = __esm({
|
|
|
1969
1969
|
backgroundExited: (jobId, code, command3) => `Background command ${jobId} exited (code ${code}): ${command3}`,
|
|
1970
1970
|
backgroundStopped: (jobId, command3) => `Background command ${jobId} stopped: ${command3}`,
|
|
1971
1971
|
compactionFailed: (error2) => `Compaction failed: ${error2}`,
|
|
1972
|
-
compactionCancelled: "Compaction cancelled"
|
|
1972
|
+
compactionCancelled: "Compaction cancelled",
|
|
1973
|
+
imageReadBackFailed: (id) => `Session image for entry ${id} could not be read back (file changed); it stays empty`
|
|
1973
1974
|
},
|
|
1974
1975
|
statusLine: {
|
|
1975
1976
|
usage: "Usage: /statusline [full|compact]",
|
|
@@ -2104,7 +2105,8 @@ var init_interactive = __esm({
|
|
|
2104
2105
|
backgroundExited: (jobId, code, command3) => `后台命令 ${jobId} 已退出(码 ${code}):${command3}`,
|
|
2105
2106
|
backgroundStopped: (jobId, command3) => `后台命令 ${jobId} 已停止:${command3}`,
|
|
2106
2107
|
compactionFailed: (error2) => `压缩失败:${error2}`,
|
|
2107
|
-
compactionCancelled: "压缩已取消"
|
|
2108
|
+
compactionCancelled: "压缩已取消",
|
|
2109
|
+
imageReadBackFailed: (id) => `会话文件已改变,条目 ${id} 的图片读不回,保留为空`
|
|
2108
2110
|
},
|
|
2109
2111
|
statusLine: {
|
|
2110
2112
|
usage: "用法:/statusline [full|compact]",
|
|
@@ -3814,6 +3816,7 @@ var init_config_keys = __esm({
|
|
|
3814
3816
|
"subagents.maxPending": "Queue limit; task fails beyond it",
|
|
3815
3817
|
"subagents.retainSessions": "Finished sub-sessions kept in memory (least recently used first out); others reopen from their session file when continued",
|
|
3816
3818
|
"subagents.defaultModel": "Default sub-session model provider/model[@channel]",
|
|
3819
|
+
"subagents.forkMaxContextRatio": "Fork sub-agents fall back to fresh when the parent's last request used more than this share of (window − compaction.reserveTokens); 0.05–0.95, default 0.5",
|
|
3817
3820
|
"subagents.background": "Whether task runs in the background by default: auto = background in the TUI / RPC / ACP and foreground with -p; always / never are fixed. The call argument and the agent type's background: override it; user, project and host level",
|
|
3818
3821
|
"subagents.autoBackgroundAfterMs": "Move a foreground task to the background after it has run this many milliseconds; 0 disables; user and project level",
|
|
3819
3822
|
models: "Model aliases and the model picker list; user level only (effective from wave 5 W5-G)",
|
|
@@ -3942,6 +3945,7 @@ var init_config_keys = __esm({
|
|
|
3942
3945
|
"subagents.maxPending": "排队上限,超出时 task 报错",
|
|
3943
3946
|
"subagents.retainSessions": "内存中保留的已结束子会话数(最久未用的先释放),其余续聊时从会话文件重开",
|
|
3944
3947
|
"subagents.defaultModel": "子会话缺省模型 provider/model[@channel]",
|
|
3948
|
+
"subagents.forkMaxContextRatio": "fork 子 Agent 的回落比例:父上一次请求超过(窗口 − compaction.reserveTokens)的这一比例时改为 fresh;0.05–0.95,缺省 0.5",
|
|
3945
3949
|
"subagents.background": "task 缺省是否后台:auto = TUI / RPC / ACP 下后台、-p 下前台;always / never 固定。调用参数与类型定义的 background: 优先;用户、项目、宿主级都认",
|
|
3946
3950
|
"subagents.autoBackgroundAfterMs": "前台任务运行超过该毫秒数自动转后台;0 关闭;用户、项目级都认",
|
|
3947
3951
|
models: "模型别名与模型选择器清单;只认用户级(第五波 W5-G 起生效)",
|
|
@@ -4439,7 +4443,7 @@ var init_session = __esm({
|
|
|
4439
4443
|
cwdIsHome: "the working directory is the home directory",
|
|
4440
4444
|
gitNotFound: "git not found",
|
|
4441
4445
|
tooManyFiles: (files, max) => `the working directory has ${plural(files, "file")} (limit ${max})`,
|
|
4442
|
-
tooSlow: (seconds2, max) => `
|
|
4446
|
+
tooSlow: (seconds2, max) => `snapshots took longer than ${max} s twice in a row (latest ${seconds2} s)`,
|
|
4443
4447
|
gitFailed: (command3, code, detail) => `git ${command3} failed (${code})${detail === "" ? "" : `: ${detail}`}`,
|
|
4444
4448
|
noShadowCommit: "the checkpoint has no shadow commit",
|
|
4445
4449
|
shadowCommitMissing: (commit) => `shadow commit ${commit} does not exist`,
|
|
@@ -4571,7 +4575,7 @@ var init_session = __esm({
|
|
|
4571
4575
|
cwdIsHome: "工作目录是家目录",
|
|
4572
4576
|
gitNotFound: "找不到 git",
|
|
4573
4577
|
tooManyFiles: (files, max) => `工作目录有 ${files} 个文件(上限 ${max})`,
|
|
4574
|
-
tooSlow: (seconds2, max) =>
|
|
4578
|
+
tooSlow: (seconds2, max) => `连续两次快照超过 ${max} 秒(最近一次 ${seconds2} 秒)`,
|
|
4575
4579
|
gitFailed: (command3, code, detail) => `git ${command3} 失败(${code})${detail === "" ? "" : `:${detail}`}`,
|
|
4576
4580
|
noShadowCommit: "检查点没有影子提交",
|
|
4577
4581
|
shadowCommitMissing: (commit) => `影子提交 ${commit} 不存在`,
|
|
@@ -6776,7 +6780,8 @@ function validateConfigW5(c, config) {
|
|
|
6776
6780
|
"defaultModel",
|
|
6777
6781
|
"background",
|
|
6778
6782
|
"autoBackgroundAfterMs",
|
|
6779
|
-
"retainSessions"
|
|
6783
|
+
"retainSessions",
|
|
6784
|
+
"forkMaxContextRatio"
|
|
6780
6785
|
],
|
|
6781
6786
|
(s2, p) => {
|
|
6782
6787
|
c.number(s2, "maxConcurrent", p, 1, 64);
|
|
@@ -6785,6 +6790,7 @@ function validateConfigW5(c, config) {
|
|
|
6785
6790
|
c.oneOf(s2, "background", p, SUBAGENT_BACKGROUND_MODES);
|
|
6786
6791
|
c.number(s2, "autoBackgroundAfterMs", p, 0);
|
|
6787
6792
|
c.number(s2, "retainSessions", p, 0);
|
|
6793
|
+
c.number(s2, "forkMaxContextRatio", p, 0.05, 0.95);
|
|
6788
6794
|
}
|
|
6789
6795
|
);
|
|
6790
6796
|
checkSection(c, config, "models", ["aliases", "enabled"], (s2, p) => {
|
|
@@ -10284,8 +10290,9 @@ function readSessionLines(file, options = {}) {
|
|
|
10284
10290
|
forEachLineSync(file, (buf, index2, last, offset) => {
|
|
10285
10291
|
if (last) unterminated = true;
|
|
10286
10292
|
if (isBlankLine(buf)) return;
|
|
10293
|
+
let line2;
|
|
10287
10294
|
try {
|
|
10288
|
-
|
|
10295
|
+
line2 = JSON.parse(buf.toString("utf8"));
|
|
10289
10296
|
} catch (error2) {
|
|
10290
10297
|
if (last) {
|
|
10291
10298
|
repairedTail = true;
|
|
@@ -10296,6 +10303,8 @@ function readSessionLines(file, options = {}) {
|
|
|
10296
10303
|
cause: error2
|
|
10297
10304
|
});
|
|
10298
10305
|
}
|
|
10306
|
+
options.onLine?.(line2, { offset, length: buf.length });
|
|
10307
|
+
lines2.push(line2);
|
|
10299
10308
|
});
|
|
10300
10309
|
} catch (error2) {
|
|
10301
10310
|
if (error2 instanceof AmaError) throw error2;
|
|
@@ -10304,19 +10313,20 @@ function readSessionLines(file, options = {}) {
|
|
|
10304
10313
|
if (!repairedTail && unterminated && options.repair === true) {
|
|
10305
10314
|
appendRaw(file, "\n");
|
|
10306
10315
|
}
|
|
10307
|
-
return { lines: lines2, repairedTail };
|
|
10316
|
+
if (options.onLine === void 0) return { lines: lines2, repairedTail };
|
|
10317
|
+
return { lines: lines2, repairedTail, bytes: (0, import_node_fs10.statSync)(file).size };
|
|
10308
10318
|
}
|
|
10309
10319
|
function appendRaw(file, text) {
|
|
10310
10320
|
const fd = (0, import_node_fs10.openSync)(file, "a");
|
|
10311
10321
|
try {
|
|
10312
|
-
(0, import_node_fs10.writeSync)(fd, text);
|
|
10322
|
+
return (0, import_node_fs10.writeSync)(fd, text);
|
|
10313
10323
|
} finally {
|
|
10314
10324
|
(0, import_node_fs10.closeSync)(fd);
|
|
10315
10325
|
}
|
|
10316
10326
|
}
|
|
10317
10327
|
function appendLines(file, lines2) {
|
|
10318
|
-
if (lines2.length === 0) return;
|
|
10319
|
-
appendRaw(file, lines2.map((line2) => JSON.stringify(line2)).join("\n") + "\n");
|
|
10328
|
+
if (lines2.length === 0) return 0;
|
|
10329
|
+
return appendRaw(file, lines2.map((line2) => JSON.stringify(line2)).join("\n") + "\n");
|
|
10320
10330
|
}
|
|
10321
10331
|
function writeNewSessionFile(file, lines2) {
|
|
10322
10332
|
(0, import_node_fs10.mkdirSync)((0, import_node_path13.dirname)(file), { recursive: true, mode: 448 });
|
|
@@ -10324,8 +10334,10 @@ function writeNewSessionFile(file, lines2) {
|
|
|
10324
10334
|
throw new AmaError("session_exists", `session file already exists: ${file}`);
|
|
10325
10335
|
}
|
|
10326
10336
|
const tmp = `${file}.${process.pid}.tmp`;
|
|
10327
|
-
|
|
10337
|
+
const texts2 = lines2.map((line2) => JSON.stringify(line2));
|
|
10338
|
+
(0, import_node_fs10.writeFileSync)(tmp, texts2.join("\n") + "\n", { mode: 384 });
|
|
10328
10339
|
(0, import_node_fs10.renameSync)(tmp, file);
|
|
10340
|
+
return texts2.map((text) => Buffer.byteLength(text));
|
|
10329
10341
|
}
|
|
10330
10342
|
function installExitHandler() {
|
|
10331
10343
|
if (exitHandlerInstalled) return;
|
|
@@ -10788,12 +10800,26 @@ var init_suggest = __esm({
|
|
|
10788
10800
|
|
|
10789
10801
|
// src/ai/json-body.ts
|
|
10790
10802
|
function isPlain(value) {
|
|
10803
|
+
plainScans.count++;
|
|
10791
10804
|
for (let i = 0; i < value.length; i += CHECK_CHUNK) {
|
|
10792
10805
|
const chunk = value.slice(i, i + CHECK_CHUNK);
|
|
10793
10806
|
if (JSON.stringify(chunk).length !== chunk.length + 2) return false;
|
|
10794
10807
|
}
|
|
10795
10808
|
return true;
|
|
10796
10809
|
}
|
|
10810
|
+
function largeString(prefix, key, text) {
|
|
10811
|
+
if (text.length < LARGE_STRING_BYTES || !isShortPlain(prefix)) return prefix + text;
|
|
10812
|
+
return new LargeString(prefix, key, text);
|
|
10813
|
+
}
|
|
10814
|
+
function plainLargeBytes(value) {
|
|
10815
|
+
if (!isShortPlain(value.prefix)) return void 0;
|
|
10816
|
+
const known = plainBytes.get(value.key);
|
|
10817
|
+
if (known !== void 0 && known.length === value.text.length) return known.bytes;
|
|
10818
|
+
if (!isPlain(value.text)) return void 0;
|
|
10819
|
+
const bytes = Buffer.byteLength(value.text, "utf8");
|
|
10820
|
+
plainBytes.set(value.key, { length: value.text.length, bytes });
|
|
10821
|
+
return bytes;
|
|
10822
|
+
}
|
|
10797
10823
|
function isContainer(value) {
|
|
10798
10824
|
if (typeof value !== "object" || value === null) return false;
|
|
10799
10825
|
if (typeof value.toJSON === "function") return false;
|
|
@@ -10803,6 +10829,7 @@ function isContainer(value) {
|
|
|
10803
10829
|
}
|
|
10804
10830
|
function collectLarge(value, marked, depth) {
|
|
10805
10831
|
if (isLargeString(value)) return true;
|
|
10832
|
+
if (value instanceof LargeString) return value.text.length >= LARGE_STRING_BYTES;
|
|
10806
10833
|
if (depth >= MAX_DEPTH || !isContainer(value)) return false;
|
|
10807
10834
|
let found = false;
|
|
10808
10835
|
if (Array.isArray(value)) {
|
|
@@ -10835,6 +10862,13 @@ function writeEntry(key, value, marked, out, prefix, depth) {
|
|
|
10835
10862
|
}
|
|
10836
10863
|
return true;
|
|
10837
10864
|
}
|
|
10865
|
+
if (value instanceof LargeString && value.text.length >= LARGE_STRING_BYTES) {
|
|
10866
|
+
const bytes = plainLargeBytes(value);
|
|
10867
|
+
out.text(prefix);
|
|
10868
|
+
if (bytes !== void 0) out.large(value.text, value.prefix, bytes);
|
|
10869
|
+
else out.text(JSON.stringify(value.toJSON()));
|
|
10870
|
+
return true;
|
|
10871
|
+
}
|
|
10838
10872
|
if (depth < MAX_DEPTH && isContainer(value) && marked.has(value)) {
|
|
10839
10873
|
out.text(prefix);
|
|
10840
10874
|
writeContainer(value, marked, out, depth);
|
|
@@ -10868,20 +10902,16 @@ function jsonParts(body) {
|
|
|
10868
10902
|
const marked = /* @__PURE__ */ new Set();
|
|
10869
10903
|
if (!collectLarge(body, marked, 0)) return void 0;
|
|
10870
10904
|
const out = new Pieces();
|
|
10871
|
-
|
|
10872
|
-
if (!isPlain(body)) return void 0;
|
|
10873
|
-
out.large(body);
|
|
10874
|
-
} else writeContainer(body, marked, out, 0);
|
|
10905
|
+
writeEntry("", body, marked, out, "", 0);
|
|
10875
10906
|
const parts = out.finish();
|
|
10876
|
-
|
|
10877
|
-
for (const part of parts) length += Buffer.byteLength(part, "utf8");
|
|
10878
|
-
return { parts, length };
|
|
10907
|
+
return { parts, length: out.bytes };
|
|
10879
10908
|
}
|
|
10880
10909
|
function jsonFetchBody(body) {
|
|
10881
10910
|
const split = jsonParts(body);
|
|
10882
10911
|
if (split === void 0) return { body: JSON.stringify(body) };
|
|
10883
10912
|
const { parts } = split;
|
|
10884
10913
|
let next = 0;
|
|
10914
|
+
let offset = 0;
|
|
10885
10915
|
const stream5 = new ReadableStream({
|
|
10886
10916
|
pull(controller) {
|
|
10887
10917
|
const part = parts[next];
|
|
@@ -10889,8 +10919,15 @@ function jsonFetchBody(body) {
|
|
|
10889
10919
|
controller.close();
|
|
10890
10920
|
return;
|
|
10891
10921
|
}
|
|
10892
|
-
|
|
10893
|
-
|
|
10922
|
+
let end = Math.min(part.length, offset + STREAM_CHUNK_CHARS);
|
|
10923
|
+
const last = part.charCodeAt(end - 1);
|
|
10924
|
+
if (end < part.length && last >= 55296 && last <= 56319) end--;
|
|
10925
|
+
const piece = offset === 0 && end === part.length ? part : part.slice(offset, end);
|
|
10926
|
+
if (end === part.length) {
|
|
10927
|
+
parts[next++] = "";
|
|
10928
|
+
offset = 0;
|
|
10929
|
+
} else offset = end;
|
|
10930
|
+
controller.enqueue(Buffer.from(piece, "utf8"));
|
|
10894
10931
|
},
|
|
10895
10932
|
cancel() {
|
|
10896
10933
|
parts.length = 0;
|
|
@@ -10898,31 +10935,55 @@ function jsonFetchBody(body) {
|
|
|
10898
10935
|
});
|
|
10899
10936
|
return { body: stream5, contentLength: split.length };
|
|
10900
10937
|
}
|
|
10901
|
-
var LARGE_STRING_BYTES, CHECK_CHUNK, MAX_DEPTH, isLargeString, Pieces;
|
|
10938
|
+
var LARGE_STRING_BYTES, CHECK_CHUNK, isShortPlain, plainScans, LargeString, plainBytes, MAX_DEPTH, isLargeString, Pieces, STREAM_CHUNK_CHARS;
|
|
10902
10939
|
var init_json_body = __esm({
|
|
10903
10940
|
"src/ai/json-body.ts"() {
|
|
10904
10941
|
"use strict";
|
|
10905
10942
|
LARGE_STRING_BYTES = 64 * 1024;
|
|
10906
10943
|
CHECK_CHUNK = 16 * 1024;
|
|
10944
|
+
isShortPlain = (value) => JSON.stringify(value).length === value.length + 2;
|
|
10945
|
+
plainScans = { count: 0 };
|
|
10946
|
+
LargeString = class {
|
|
10947
|
+
constructor(prefix, key, text) {
|
|
10948
|
+
this.prefix = prefix;
|
|
10949
|
+
this.key = key;
|
|
10950
|
+
this.text = text;
|
|
10951
|
+
}
|
|
10952
|
+
prefix;
|
|
10953
|
+
key;
|
|
10954
|
+
text;
|
|
10955
|
+
toJSON() {
|
|
10956
|
+
return this.prefix + this.text;
|
|
10957
|
+
}
|
|
10958
|
+
};
|
|
10959
|
+
plainBytes = /* @__PURE__ */ new WeakMap();
|
|
10907
10960
|
MAX_DEPTH = 64;
|
|
10908
10961
|
isLargeString = (value) => typeof value === "string" && value.length >= LARGE_STRING_BYTES;
|
|
10909
10962
|
Pieces = class {
|
|
10910
10963
|
parts = [];
|
|
10964
|
+
/** 已推入 `parts` 的 UTF-8 字节数。 */
|
|
10965
|
+
bytes = 0;
|
|
10911
10966
|
pending = "";
|
|
10912
10967
|
text(chunk) {
|
|
10913
10968
|
this.pending += chunk;
|
|
10914
10969
|
}
|
|
10915
|
-
/**
|
|
10916
|
-
large(value) {
|
|
10917
|
-
|
|
10970
|
+
/** 大字符串原样写入(引号与 `head` 进前一个小片段);`bytes` 已知时不再数一遍。 */
|
|
10971
|
+
large(value, head = "", bytes = Buffer.byteLength(value, "utf8")) {
|
|
10972
|
+
const before2 = `${this.pending}"${head}`;
|
|
10973
|
+
this.parts.push(before2, value);
|
|
10974
|
+
this.bytes += Buffer.byteLength(before2, "utf8") + bytes;
|
|
10918
10975
|
this.pending = '"';
|
|
10919
10976
|
}
|
|
10920
10977
|
finish() {
|
|
10921
|
-
if (this.pending.length > 0)
|
|
10978
|
+
if (this.pending.length > 0) {
|
|
10979
|
+
this.parts.push(this.pending);
|
|
10980
|
+
this.bytes += Buffer.byteLength(this.pending, "utf8");
|
|
10981
|
+
}
|
|
10922
10982
|
this.pending = "";
|
|
10923
10983
|
return this.parts;
|
|
10924
10984
|
}
|
|
10925
10985
|
};
|
|
10986
|
+
STREAM_CHUNK_CHARS = 256 * 1024;
|
|
10926
10987
|
}
|
|
10927
10988
|
});
|
|
10928
10989
|
|
|
@@ -12327,7 +12388,7 @@ function fillLimits(out, hit, sources) {
|
|
|
12327
12388
|
sources.maxTokens = "catalog-alias";
|
|
12328
12389
|
}
|
|
12329
12390
|
}
|
|
12330
|
-
function enrichEntry(entry, index2) {
|
|
12391
|
+
function enrichEntry(entry, index2, providerId) {
|
|
12331
12392
|
const { modelsDev, channels: _channels, catalog: _catalog, ...rest } = entry;
|
|
12332
12393
|
const sources = {};
|
|
12333
12394
|
for (const field2 of ENRICHABLE_FIELDS) {
|
|
@@ -12335,10 +12396,14 @@ function enrichEntry(entry, index2) {
|
|
|
12335
12396
|
}
|
|
12336
12397
|
const metadata = { sources, looked: false };
|
|
12337
12398
|
const out = { ...rest };
|
|
12399
|
+
const warnings = [];
|
|
12400
|
+
const ref = `${providerId ?? "?"}/${entry.id}`;
|
|
12338
12401
|
const hit = catalogHit(entry);
|
|
12339
12402
|
if (hit !== void 0) {
|
|
12340
12403
|
metadata.catalog = hit.ref;
|
|
12341
12404
|
inheritIntrinsic(out, hit, sources);
|
|
12405
|
+
} else if (typeof entry.catalog === "string") {
|
|
12406
|
+
warnings.push(`catalog "${entry.catalog}" for "${ref}" not found; ignored`);
|
|
12342
12407
|
}
|
|
12343
12408
|
const explicit = typeof modelsDev === "string" ? modelsDev : hit?.snapshotRef;
|
|
12344
12409
|
const lookup = modelsDev !== false && (needsLookup(out) || modelsDev !== void 0);
|
|
@@ -12365,7 +12430,10 @@ function enrichEntry(entry, index2) {
|
|
|
12365
12430
|
}
|
|
12366
12431
|
}
|
|
12367
12432
|
}
|
|
12433
|
+
if (typeof modelsDev === "string" && metadata.looked && metadata.match === void 0)
|
|
12434
|
+
warnings.push(`modelsDev "${modelsDev}" for "${ref}" not found`);
|
|
12368
12435
|
if (hit !== void 0 && modelsDev !== false) fillLimits(out, hit, sources);
|
|
12436
|
+
if (warnings.length > 0) metadata.warnings = warnings;
|
|
12369
12437
|
return { entry: out, metadata };
|
|
12370
12438
|
}
|
|
12371
12439
|
function catalogMetadata(model) {
|
|
@@ -16177,121 +16245,150 @@ var init_edit_fuzzy = __esm({
|
|
|
16177
16245
|
});
|
|
16178
16246
|
|
|
16179
16247
|
// src/tools/read-lines.ts
|
|
16180
|
-
function
|
|
16181
|
-
const
|
|
16248
|
+
async function readHeadAsync(abs, bytes) {
|
|
16249
|
+
const handle = await (0, import_promises3.open)(abs, "r");
|
|
16182
16250
|
try {
|
|
16183
16251
|
const buf = Buffer.alloc(bytes);
|
|
16184
16252
|
let got = 0;
|
|
16185
16253
|
while (got < bytes) {
|
|
16186
|
-
const
|
|
16187
|
-
if (
|
|
16188
|
-
got +=
|
|
16254
|
+
const { bytesRead } = await handle.read(buf, got, bytes - got, null);
|
|
16255
|
+
if (bytesRead === 0) break;
|
|
16256
|
+
got += bytesRead;
|
|
16189
16257
|
}
|
|
16190
16258
|
return buf.subarray(0, got);
|
|
16191
16259
|
} finally {
|
|
16192
|
-
|
|
16260
|
+
await handle.close();
|
|
16193
16261
|
}
|
|
16194
16262
|
}
|
|
16195
|
-
function
|
|
16263
|
+
function scanner(offset, limit, maxBytes) {
|
|
16196
16264
|
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
|
-
};
|
|
16265
|
+
return new LineScanner(first, limit === void 0 ? Infinity : first + limit, maxBytes);
|
|
16266
|
+
}
|
|
16267
|
+
async function readLineWindowAsync(abs, offset, limit, maxBytes, chunkBytes = CHUNK_BYTES) {
|
|
16268
|
+
const scan = scanner(offset, limit, maxBytes);
|
|
16227
16269
|
const size = Math.max(3, chunkBytes);
|
|
16228
|
-
const
|
|
16270
|
+
const handle = await (0, import_promises3.open)(abs, "r");
|
|
16229
16271
|
try {
|
|
16230
16272
|
const buf = Buffer.alloc(size);
|
|
16231
16273
|
let carry = 0;
|
|
16232
|
-
let firstChunk = true;
|
|
16233
16274
|
for (; ; ) {
|
|
16234
|
-
const n =
|
|
16275
|
+
const { bytesRead: n } = await handle.read(buf, carry, size - carry, null);
|
|
16235
16276
|
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
|
-
}
|
|
16277
|
+
if (end === 0) break;
|
|
16278
|
+
carry = scan.feed(buf, end, n === 0);
|
|
16277
16279
|
if (n === 0) break;
|
|
16278
16280
|
}
|
|
16279
|
-
if (pending) finish2();
|
|
16280
16281
|
} finally {
|
|
16281
|
-
|
|
16282
|
+
await handle.close();
|
|
16282
16283
|
}
|
|
16283
|
-
return
|
|
16284
|
+
return scan.finish();
|
|
16284
16285
|
}
|
|
16285
|
-
var
|
|
16286
|
+
var import_promises3, STREAM_READ_THRESHOLD, CHUNK_BYTES, LINE_SLACK, LF2, CR2, LineScanner;
|
|
16286
16287
|
var init_read_lines = __esm({
|
|
16287
16288
|
"src/tools/read-lines.ts"() {
|
|
16288
16289
|
"use strict";
|
|
16289
|
-
|
|
16290
|
+
import_promises3 = require("node:fs/promises");
|
|
16290
16291
|
STREAM_READ_THRESHOLD = 1024 * 1024;
|
|
16291
16292
|
CHUNK_BYTES = 64 * 1024;
|
|
16292
16293
|
LINE_SLACK = 64;
|
|
16293
16294
|
LF2 = 10;
|
|
16294
16295
|
CR2 = 13;
|
|
16296
|
+
LineScanner = class {
|
|
16297
|
+
constructor(first, stop, maxBytes) {
|
|
16298
|
+
this.first = first;
|
|
16299
|
+
this.stop = stop;
|
|
16300
|
+
this.maxBytes = maxBytes;
|
|
16301
|
+
this.lineCap = maxBytes + LINE_SLACK;
|
|
16302
|
+
}
|
|
16303
|
+
first;
|
|
16304
|
+
stop;
|
|
16305
|
+
maxBytes;
|
|
16306
|
+
lineCap;
|
|
16307
|
+
lines = [];
|
|
16308
|
+
truncatedBy;
|
|
16309
|
+
collected = 0;
|
|
16310
|
+
index = 0;
|
|
16311
|
+
// 已完成的行数
|
|
16312
|
+
parts = [];
|
|
16313
|
+
partBytes = 0;
|
|
16314
|
+
pending = false;
|
|
16315
|
+
// 最后一个终止符之后已有字节
|
|
16316
|
+
skipLF = false;
|
|
16317
|
+
// 上一块以 `\r` 结尾:下一块开头的 `\n` 属于同一终止符
|
|
16318
|
+
bom = false;
|
|
16319
|
+
firstChunk = true;
|
|
16320
|
+
/**
|
|
16321
|
+
* 处理 `buf[0, end)`;`eof` 表示这是最后一块。返回调用方下次读取前应保留在 `buf` 开头的字节数
|
|
16322
|
+
* (只在首块不足 3 字节、还判断不了 BOM 时非零)。
|
|
16323
|
+
*/
|
|
16324
|
+
feed(buf, end, eof) {
|
|
16325
|
+
let pos = 0;
|
|
16326
|
+
if (this.firstChunk) {
|
|
16327
|
+
if (end < 3 && !eof) return end;
|
|
16328
|
+
this.firstChunk = false;
|
|
16329
|
+
if (end >= 3 && buf[0] === 239 && buf[1] === 187 && buf[2] === 191) {
|
|
16330
|
+
this.bom = true;
|
|
16331
|
+
pos = 3;
|
|
16332
|
+
}
|
|
16333
|
+
}
|
|
16334
|
+
if (this.skipLF && pos < end) {
|
|
16335
|
+
if (buf[pos] === LF2) pos++;
|
|
16336
|
+
this.skipLF = false;
|
|
16337
|
+
}
|
|
16338
|
+
let nextLF = buf.indexOf(LF2, pos);
|
|
16339
|
+
let nextCR = buf.indexOf(CR2, pos);
|
|
16340
|
+
while (pos < end) {
|
|
16341
|
+
if (nextLF !== -1 && nextLF < pos) nextLF = buf.indexOf(LF2, pos);
|
|
16342
|
+
if (nextCR !== -1 && nextCR < pos) nextCR = buf.indexOf(CR2, pos);
|
|
16343
|
+
const lf = nextLF === -1 || nextLF >= end ? end : nextLF;
|
|
16344
|
+
const cr = nextCR === -1 || nextCR >= end ? end : nextCR;
|
|
16345
|
+
const at = Math.min(lf, cr);
|
|
16346
|
+
if (at > pos) {
|
|
16347
|
+
this.pending = true;
|
|
16348
|
+
if (this.collecting()) this.take(buf, pos, at);
|
|
16349
|
+
}
|
|
16350
|
+
if (at === end) break;
|
|
16351
|
+
this.endLine();
|
|
16352
|
+
pos = at + 1;
|
|
16353
|
+
if (at === cr) {
|
|
16354
|
+
if (pos < end) {
|
|
16355
|
+
if (buf[pos] === LF2) pos++;
|
|
16356
|
+
} else {
|
|
16357
|
+
this.skipLF = true;
|
|
16358
|
+
}
|
|
16359
|
+
}
|
|
16360
|
+
}
|
|
16361
|
+
return 0;
|
|
16362
|
+
}
|
|
16363
|
+
/** 文件读完:收尾最后一行并给出结果。 */
|
|
16364
|
+
finish() {
|
|
16365
|
+
if (this.pending) this.endLine();
|
|
16366
|
+
const { lines: lines2, truncatedBy, bom } = this;
|
|
16367
|
+
return { lines: lines2, totalLines: this.index, ...truncatedBy ? { truncatedBy } : {}, bom };
|
|
16368
|
+
}
|
|
16369
|
+
collecting() {
|
|
16370
|
+
return this.truncatedBy === void 0 && this.index >= this.first && this.index < this.stop;
|
|
16371
|
+
}
|
|
16372
|
+
take(buf, from, to) {
|
|
16373
|
+
if (to <= from || this.partBytes >= this.lineCap) return;
|
|
16374
|
+
const end = Math.min(to, from + this.lineCap - this.partBytes);
|
|
16375
|
+
this.parts.push(Buffer.from(buf.subarray(from, end)));
|
|
16376
|
+
this.partBytes += end - from;
|
|
16377
|
+
}
|
|
16378
|
+
endLine() {
|
|
16379
|
+
if (this.collecting()) {
|
|
16380
|
+
const { parts } = this;
|
|
16381
|
+
const line2 = (parts.length === 1 ? parts[0] : Buffer.concat(parts)).toString("utf8");
|
|
16382
|
+
this.lines.push(line2);
|
|
16383
|
+
this.collected += Buffer.byteLength(line2) + 1;
|
|
16384
|
+
if (this.collected > this.maxBytes) this.truncatedBy = "bytes";
|
|
16385
|
+
}
|
|
16386
|
+
if (this.partBytes > 0) this.parts = [];
|
|
16387
|
+
this.partBytes = 0;
|
|
16388
|
+
this.pending = false;
|
|
16389
|
+
this.index++;
|
|
16390
|
+
}
|
|
16391
|
+
};
|
|
16295
16392
|
}
|
|
16296
16393
|
});
|
|
16297
16394
|
|
|
@@ -16363,7 +16460,7 @@ async function resizeImage(input2, target, deps = {}) {
|
|
|
16363
16460
|
const mimeType = format === "jpeg" ? "image/jpeg" : "image/png";
|
|
16364
16461
|
const long = target.size !== void 0 ? Math.max(target.size.width, target.size.height) : 0;
|
|
16365
16462
|
const start = long > 0 ? Math.min(target.maxEdge, long) : target.maxEdge;
|
|
16366
|
-
const dir = await (0,
|
|
16463
|
+
const dir = await (0, import_promises4.mkdtemp)((0, import_node_path25.join)(deps.tmpDir ?? (0, import_node_os5.tmpdir)(), "ama-resize-"));
|
|
16367
16464
|
try {
|
|
16368
16465
|
for (const tool of resizeTools(deps.platform ?? process.platform)) {
|
|
16369
16466
|
let edge = start;
|
|
@@ -16374,7 +16471,7 @@ async function resizeImage(input2, target, deps = {}) {
|
|
|
16374
16471
|
if (result.missing === true || result.code !== 0) break;
|
|
16375
16472
|
let buf;
|
|
16376
16473
|
try {
|
|
16377
|
-
buf = await (0,
|
|
16474
|
+
buf = await (0, import_promises4.readFile)(output);
|
|
16378
16475
|
} catch {
|
|
16379
16476
|
break;
|
|
16380
16477
|
}
|
|
@@ -16390,15 +16487,15 @@ async function resizeImage(input2, target, deps = {}) {
|
|
|
16390
16487
|
}
|
|
16391
16488
|
return { ok: false, reason: "no_tool" };
|
|
16392
16489
|
} finally {
|
|
16393
|
-
await (0,
|
|
16490
|
+
await (0, import_promises4.rm)(dir, { recursive: true, force: true }).catch(() => void 0);
|
|
16394
16491
|
}
|
|
16395
16492
|
}
|
|
16396
|
-
var import_node_child_process3,
|
|
16493
|
+
var import_node_child_process3, import_promises4, import_node_os5, import_node_path25, runCommand, MAX_ATTEMPTS, SHRINK, MIN_EDGE;
|
|
16397
16494
|
var init_image_resize = __esm({
|
|
16398
16495
|
"src/tools/image-resize.ts"() {
|
|
16399
16496
|
"use strict";
|
|
16400
16497
|
import_node_child_process3 = require("node:child_process");
|
|
16401
|
-
|
|
16498
|
+
import_promises4 = require("node:fs/promises");
|
|
16402
16499
|
import_node_os5 = require("node:os");
|
|
16403
16500
|
import_node_path25 = require("node:path");
|
|
16404
16501
|
init_image_limits();
|
|
@@ -16570,7 +16667,7 @@ function fitError(path, fit, limit, bytes, resizeOff) {
|
|
|
16570
16667
|
async function loadImageFile(path, options = {}) {
|
|
16571
16668
|
let info2;
|
|
16572
16669
|
try {
|
|
16573
|
-
info2 = await (0,
|
|
16670
|
+
info2 = await (0, import_promises5.stat)(path);
|
|
16574
16671
|
} catch {
|
|
16575
16672
|
throw imageError(`Image not found: ${path}`, { reason: "missing", path });
|
|
16576
16673
|
}
|
|
@@ -16586,7 +16683,7 @@ async function loadImageFile(path, options = {}) {
|
|
|
16586
16683
|
sizeMb
|
|
16587
16684
|
});
|
|
16588
16685
|
}
|
|
16589
|
-
const buf = await (0,
|
|
16686
|
+
const buf = await (0, import_promises5.readFile)(path);
|
|
16590
16687
|
const mimeType = sniffImageMime(buf) ?? imageMimeFromPath(path);
|
|
16591
16688
|
if (mimeType === void 0)
|
|
16592
16689
|
throw imageError(`Unsupported image (PNG / JPEG / GIF / WebP): ${path}`, {
|
|
@@ -16603,11 +16700,11 @@ async function loadImageFile(path, options = {}) {
|
|
|
16603
16700
|
...fit.size ? { size: fit.size } : {}
|
|
16604
16701
|
};
|
|
16605
16702
|
}
|
|
16606
|
-
var
|
|
16703
|
+
var import_promises5, import_node_path26, MAX_IMAGE_FILE_BYTES, IMAGE_EXTENSIONS, HINT_TEXT;
|
|
16607
16704
|
var init_image_file = __esm({
|
|
16608
16705
|
"src/tools/image-file.ts"() {
|
|
16609
16706
|
"use strict";
|
|
16610
|
-
|
|
16707
|
+
import_promises5 = require("node:fs/promises");
|
|
16611
16708
|
import_node_path26 = require("node:path");
|
|
16612
16709
|
init_errors();
|
|
16613
16710
|
init_image_intern();
|
|
@@ -16654,7 +16751,7 @@ function numberLines(lines2, firstLine3) {
|
|
|
16654
16751
|
return lines2.map((line2, i) => `${String(firstLine3 + i).padStart(6)} ${line2}`).join("\n");
|
|
16655
16752
|
}
|
|
16656
16753
|
async function readImage(abs, shown2, ctx, options) {
|
|
16657
|
-
const buf = await (0,
|
|
16754
|
+
const buf = await (0, import_promises6.readFile)(abs);
|
|
16658
16755
|
const mimeType = sniffImageMime(buf) ?? imageMimeFromPath(abs) ?? "application/octet-stream";
|
|
16659
16756
|
const size = imageSize(buf, mimeType);
|
|
16660
16757
|
const dims = size ? `${size.width}x${size.height}, ` : "";
|
|
@@ -16685,7 +16782,7 @@ async function executeRead(input2, ctx, options = {}) {
|
|
|
16685
16782
|
const shown2 = displayPath(abs, ctx.cwd);
|
|
16686
16783
|
let info2;
|
|
16687
16784
|
try {
|
|
16688
|
-
info2 = await (0,
|
|
16785
|
+
info2 = await (0, import_promises6.stat)(abs);
|
|
16689
16786
|
} catch {
|
|
16690
16787
|
return error(`File not found: ${shown2}`);
|
|
16691
16788
|
}
|
|
@@ -16698,9 +16795,9 @@ async function executeRead(input2, ctx, options = {}) {
|
|
|
16698
16795
|
let totalLines;
|
|
16699
16796
|
let selected;
|
|
16700
16797
|
if (info2.size > (options.streamThreshold ?? STREAM_READ_THRESHOLD)) {
|
|
16701
|
-
if (isBinary(
|
|
16798
|
+
if (isBinary(await readHeadAsync(abs, SNIFF_BYTES))) return error(binaryMessage(shown2));
|
|
16702
16799
|
const want = Math.min(input2.limit ?? Infinity, DEFAULT_MAX_LINES + 1);
|
|
16703
|
-
const win =
|
|
16800
|
+
const win = await readLineWindowAsync(
|
|
16704
16801
|
abs,
|
|
16705
16802
|
badOffset ? 1 : offset,
|
|
16706
16803
|
badOffset || badLimit ? 0 : want,
|
|
@@ -16709,7 +16806,7 @@ async function executeRead(input2, ctx, options = {}) {
|
|
|
16709
16806
|
totalLines = win.totalLines;
|
|
16710
16807
|
selected = win.lines;
|
|
16711
16808
|
} else {
|
|
16712
|
-
const buf = await (0,
|
|
16809
|
+
const buf = await (0, import_promises6.readFile)(abs);
|
|
16713
16810
|
if (isBinary(buf)) return error(binaryMessage(shown2));
|
|
16714
16811
|
const { text } = splitBom(buf.toString("utf8"));
|
|
16715
16812
|
const normalized = normalizeToLF(text);
|
|
@@ -16770,11 +16867,11 @@ function createReadTool(options = {}) {
|
|
|
16770
16867
|
execute: (input2, ctx) => executeRead(input2, ctx, options)
|
|
16771
16868
|
};
|
|
16772
16869
|
}
|
|
16773
|
-
var
|
|
16870
|
+
var import_promises6, SNIFF_BYTES, binaryMessage;
|
|
16774
16871
|
var init_read = __esm({
|
|
16775
16872
|
"src/tools/read.ts"() {
|
|
16776
16873
|
"use strict";
|
|
16777
|
-
|
|
16874
|
+
import_promises6 = require("node:fs/promises");
|
|
16778
16875
|
init_image_intern();
|
|
16779
16876
|
init_paths2();
|
|
16780
16877
|
init_truncate();
|
|
@@ -16943,7 +17040,7 @@ async function executeEdit(input2, ctx) {
|
|
|
16943
17040
|
const shown2 = displayPath(abs, ctx.cwd);
|
|
16944
17041
|
return withFileMutex(abs, async () => {
|
|
16945
17042
|
try {
|
|
16946
|
-
const info2 = await (0,
|
|
17043
|
+
const info2 = await (0, import_promises7.stat)(abs);
|
|
16947
17044
|
if (!info2.isFile()) return { content: `${shown2} is not a regular file`, isError: true };
|
|
16948
17045
|
} catch {
|
|
16949
17046
|
return { content: `File not found: ${shown2}`, isError: true };
|
|
@@ -16951,7 +17048,7 @@ async function executeEdit(input2, ctx) {
|
|
|
16951
17048
|
if (!ctx.readFiles.has(abs)) {
|
|
16952
17049
|
return { content: `Read ${shown2} with the read tool before editing it.`, isError: true };
|
|
16953
17050
|
}
|
|
16954
|
-
const raw = await (0,
|
|
17051
|
+
const raw = await (0, import_promises7.readFile)(abs, "utf8");
|
|
16955
17052
|
const { bom, text } = splitBom(raw);
|
|
16956
17053
|
const ending = detectLineEnding(text);
|
|
16957
17054
|
const content = normalizeToLF(text);
|
|
@@ -16964,7 +17061,7 @@ async function executeEdit(input2, ctx) {
|
|
|
16964
17061
|
}
|
|
16965
17062
|
const output = bom + restoreLineEndings(plan2.result, ending);
|
|
16966
17063
|
await beforeWrite(ctx, abs);
|
|
16967
|
-
await (0,
|
|
17064
|
+
await (0, import_promises7.writeFile)(abs, output, "utf8");
|
|
16968
17065
|
ctx.checkpoint?.afterWrite(abs, output);
|
|
16969
17066
|
const details = {
|
|
16970
17067
|
path: abs,
|
|
@@ -17014,11 +17111,11 @@ function createEditTool() {
|
|
|
17014
17111
|
execute: executeEdit
|
|
17015
17112
|
};
|
|
17016
17113
|
}
|
|
17017
|
-
var
|
|
17114
|
+
var import_promises7, EditError;
|
|
17018
17115
|
var init_edit = __esm({
|
|
17019
17116
|
"src/tools/edit.ts"() {
|
|
17020
17117
|
"use strict";
|
|
17021
|
-
|
|
17118
|
+
import_promises7 = require("node:fs/promises");
|
|
17022
17119
|
init_types8();
|
|
17023
17120
|
init_paths2();
|
|
17024
17121
|
init_file_mutex();
|
|
@@ -17031,7 +17128,7 @@ var init_edit = __esm({
|
|
|
17031
17128
|
// src/tools/write.ts
|
|
17032
17129
|
async function exists2(path) {
|
|
17033
17130
|
try {
|
|
17034
|
-
const info2 = await (0,
|
|
17131
|
+
const info2 = await (0, import_promises8.stat)(path);
|
|
17035
17132
|
return info2.isDirectory() ? "dir" : "file";
|
|
17036
17133
|
} catch {
|
|
17037
17134
|
return false;
|
|
@@ -17072,12 +17169,12 @@ async function executeWrite(input2, ctx) {
|
|
|
17072
17169
|
isError: true
|
|
17073
17170
|
};
|
|
17074
17171
|
}
|
|
17075
|
-
original = await (0,
|
|
17172
|
+
original = await (0, import_promises8.readFile)(abs, "utf8");
|
|
17076
17173
|
output = conformToOriginal(original, input2.content);
|
|
17077
17174
|
}
|
|
17078
17175
|
await beforeWrite(ctx, abs);
|
|
17079
|
-
await (0,
|
|
17080
|
-
await (0,
|
|
17176
|
+
await (0, import_promises8.mkdir)((0, import_node_path27.dirname)(abs), { recursive: true });
|
|
17177
|
+
await (0, import_promises8.writeFile)(abs, output, "utf8");
|
|
17081
17178
|
ctx.checkpoint?.afterWrite(abs, output);
|
|
17082
17179
|
ctx.markRead(abs);
|
|
17083
17180
|
const details = {
|
|
@@ -17113,11 +17210,11 @@ function createWriteTool() {
|
|
|
17113
17210
|
execute: executeWrite
|
|
17114
17211
|
};
|
|
17115
17212
|
}
|
|
17116
|
-
var
|
|
17213
|
+
var import_promises8, import_node_path27;
|
|
17117
17214
|
var init_write = __esm({
|
|
17118
17215
|
"src/tools/write.ts"() {
|
|
17119
17216
|
"use strict";
|
|
17120
|
-
|
|
17217
|
+
import_promises8 = require("node:fs/promises");
|
|
17121
17218
|
import_node_path27 = require("node:path");
|
|
17122
17219
|
init_paths2();
|
|
17123
17220
|
init_file_mutex();
|
|
@@ -17148,7 +17245,7 @@ function gitBashCandidates(env) {
|
|
|
17148
17245
|
function resolveShell(deps = {}) {
|
|
17149
17246
|
const platform = deps.platform ?? process.platform;
|
|
17150
17247
|
const env = deps.env ?? process.env;
|
|
17151
|
-
const exists5 = deps.exists ??
|
|
17248
|
+
const exists5 = deps.exists ?? import_node_fs22.existsSync;
|
|
17152
17249
|
const custom = env["AMA_SHELL"]?.trim();
|
|
17153
17250
|
if (custom) return { shell: custom, kind: shellKindOf(custom) };
|
|
17154
17251
|
if (platform === "win32") {
|
|
@@ -17188,11 +17285,11 @@ function buildToolEnv(base4, info2) {
|
|
|
17188
17285
|
set("AMA_DEPTH", String(info2.depth));
|
|
17189
17286
|
return env;
|
|
17190
17287
|
}
|
|
17191
|
-
var
|
|
17288
|
+
var import_node_fs22, POWERSHELL_ARGS, INJECTED_ENV_VARS;
|
|
17192
17289
|
var init_shell = __esm({
|
|
17193
17290
|
"src/tools/shell.ts"() {
|
|
17194
17291
|
"use strict";
|
|
17195
|
-
|
|
17292
|
+
import_node_fs22 = require("node:fs");
|
|
17196
17293
|
POWERSHELL_ARGS = ["-NoProfile", "-NonInteractive", "-Command"];
|
|
17197
17294
|
INJECTED_ENV_VARS = [
|
|
17198
17295
|
"AMA_SESSION_ID",
|
|
@@ -17307,11 +17404,11 @@ var init_process_tree = __esm({
|
|
|
17307
17404
|
function sanitizeOutput(text) {
|
|
17308
17405
|
return text.replace(/\r\n/g, "\n").replace(ANSI, "").replace(/\r/g, "\n").replace(CONTROL, "");
|
|
17309
17406
|
}
|
|
17310
|
-
var
|
|
17407
|
+
var import_node_fs23, import_node_path28, import_node_string_decoder2, ANSI, CONTROL, OutputAccumulator;
|
|
17311
17408
|
var init_output_accumulator = __esm({
|
|
17312
17409
|
"src/tools/output-accumulator.ts"() {
|
|
17313
17410
|
"use strict";
|
|
17314
|
-
|
|
17411
|
+
import_node_fs23 = require("node:fs");
|
|
17315
17412
|
import_node_path28 = require("node:path");
|
|
17316
17413
|
import_node_string_decoder2 = require("node:string_decoder");
|
|
17317
17414
|
init_truncate();
|
|
@@ -17353,7 +17450,7 @@ var init_output_accumulator = __esm({
|
|
|
17353
17450
|
this.tailText = sliceTailBytes(this.tailText, this.maxBytes * 2);
|
|
17354
17451
|
}
|
|
17355
17452
|
if (this.spilledTo !== void 0) {
|
|
17356
|
-
(0,
|
|
17453
|
+
(0, import_node_fs23.appendFileSync)(this.spilledTo, text);
|
|
17357
17454
|
return;
|
|
17358
17455
|
}
|
|
17359
17456
|
this.chunks.push(text);
|
|
@@ -17362,8 +17459,8 @@ var init_output_accumulator = __esm({
|
|
|
17362
17459
|
}
|
|
17363
17460
|
spill() {
|
|
17364
17461
|
const target = this.options.spillPath();
|
|
17365
|
-
(0,
|
|
17366
|
-
(0,
|
|
17462
|
+
(0, import_node_fs23.mkdirSync)((0, import_node_path28.dirname)(target), { recursive: true });
|
|
17463
|
+
(0, import_node_fs23.writeFileSync)(target, this.chunks.join(""));
|
|
17367
17464
|
this.spilledTo = target;
|
|
17368
17465
|
this.chunks = [];
|
|
17369
17466
|
this.memoryBytes = 0;
|
|
@@ -17421,11 +17518,11 @@ async function disposeSessionJobs(sessionId) {
|
|
|
17421
17518
|
registry2.delete(sessionId);
|
|
17422
17519
|
await jobs.disposeAll();
|
|
17423
17520
|
}
|
|
17424
|
-
var
|
|
17521
|
+
var import_node_fs24, import_node_path29, BackgroundJobs, registry2;
|
|
17425
17522
|
var init_background_jobs = __esm({
|
|
17426
17523
|
"src/tools/background-jobs.ts"() {
|
|
17427
17524
|
"use strict";
|
|
17428
|
-
|
|
17525
|
+
import_node_fs24 = require("node:fs");
|
|
17429
17526
|
import_node_path29 = require("node:path");
|
|
17430
17527
|
init_process_tree();
|
|
17431
17528
|
init_truncate();
|
|
@@ -17434,13 +17531,13 @@ var init_background_jobs = __esm({
|
|
|
17434
17531
|
listeners = /* @__PURE__ */ new Set();
|
|
17435
17532
|
seq = 0;
|
|
17436
17533
|
start(command3, options) {
|
|
17437
|
-
(0,
|
|
17438
|
-
const fd = (0,
|
|
17534
|
+
(0, import_node_fs24.mkdirSync)((0, import_node_path29.dirname)(options.outputPath), { recursive: true });
|
|
17535
|
+
const fd = (0, import_node_fs24.openSync)(options.outputPath, "a");
|
|
17439
17536
|
let child;
|
|
17440
17537
|
try {
|
|
17441
17538
|
child = options.spawn(fd);
|
|
17442
17539
|
} finally {
|
|
17443
|
-
(0,
|
|
17540
|
+
(0, import_node_fs24.closeSync)(fd);
|
|
17444
17541
|
}
|
|
17445
17542
|
const id = `bg${++this.seq}`;
|
|
17446
17543
|
const job = {
|
|
@@ -17515,17 +17612,17 @@ var init_background_jobs = __esm({
|
|
|
17515
17612
|
await entry.done;
|
|
17516
17613
|
return entry.job;
|
|
17517
17614
|
}
|
|
17518
|
-
/**
|
|
17519
|
-
output(id) {
|
|
17615
|
+
/** 输出文件尾部(缺省 2000 行 / 50 KB;调用方可传字节上限,#155)。 */
|
|
17616
|
+
output(id, options = {}) {
|
|
17520
17617
|
const entry = this.entries.get(id);
|
|
17521
17618
|
if (entry === void 0) return void 0;
|
|
17522
17619
|
let text = "";
|
|
17523
17620
|
try {
|
|
17524
|
-
if ((0,
|
|
17525
|
-
text = (0,
|
|
17621
|
+
if ((0, import_node_fs24.statSync)(entry.job.outputPath).size > 0)
|
|
17622
|
+
text = (0, import_node_fs24.readFileSync)(entry.job.outputPath, "utf8");
|
|
17526
17623
|
} catch {
|
|
17527
17624
|
}
|
|
17528
|
-
return { ...truncateTail(text), job: entry.job };
|
|
17625
|
+
return { ...truncateTail(text, options), job: entry.job };
|
|
17529
17626
|
}
|
|
17530
17627
|
/** 取走已退出、尚未通知的任务(提醒通道用;wait 已看到退出的也算已知)。 */
|
|
17531
17628
|
takeExited() {
|
|
@@ -17568,7 +17665,7 @@ var init_background_jobs = __esm({
|
|
|
17568
17665
|
});
|
|
17569
17666
|
|
|
17570
17667
|
// src/sandbox/wrap.ts
|
|
17571
|
-
function resolveWritable(dirs, realpath4 =
|
|
17668
|
+
function resolveWritable(dirs, realpath4 = import_node_fs25.realpathSync) {
|
|
17572
17669
|
const out = [];
|
|
17573
17670
|
for (const dir of dirs) {
|
|
17574
17671
|
let real2;
|
|
@@ -17583,12 +17680,12 @@ function resolveWritable(dirs, realpath4 = import_node_fs26.realpathSync) {
|
|
|
17583
17680
|
}
|
|
17584
17681
|
function isDirectory(path) {
|
|
17585
17682
|
try {
|
|
17586
|
-
return (0,
|
|
17683
|
+
return (0, import_node_fs25.statSync)(path).isDirectory();
|
|
17587
17684
|
} catch {
|
|
17588
17685
|
return false;
|
|
17589
17686
|
}
|
|
17590
17687
|
}
|
|
17591
|
-
function resolveExtras(policy, missingOk, realpath4 =
|
|
17688
|
+
function resolveExtras(policy, missingOk, realpath4 = import_node_fs25.realpathSync, isDir4 = isDirectory) {
|
|
17592
17689
|
const readOnly = [];
|
|
17593
17690
|
for (const path of policy.readOnly ?? []) {
|
|
17594
17691
|
let real2;
|
|
@@ -17660,11 +17757,11 @@ function wrapCommand(status, command3, args, policy, realpath4, isDir4) {
|
|
|
17660
17757
|
};
|
|
17661
17758
|
}
|
|
17662
17759
|
}
|
|
17663
|
-
var
|
|
17760
|
+
var import_node_fs25, import_node_path30;
|
|
17664
17761
|
var init_wrap = __esm({
|
|
17665
17762
|
"src/sandbox/wrap.ts"() {
|
|
17666
17763
|
"use strict";
|
|
17667
|
-
|
|
17764
|
+
import_node_fs25 = require("node:fs");
|
|
17668
17765
|
import_node_path30 = require("node:path");
|
|
17669
17766
|
init_profile2();
|
|
17670
17767
|
}
|
|
@@ -17827,7 +17924,7 @@ async function executeBash(input2, ctx, options = {}) {
|
|
|
17827
17924
|
}
|
|
17828
17925
|
const cwd = resolvePath(input2.cwd ?? ".", ctx.cwd);
|
|
17829
17926
|
try {
|
|
17830
|
-
if (!(await (0,
|
|
17927
|
+
if (!(await (0, import_promises9.stat)(cwd)).isDirectory())
|
|
17831
17928
|
return fail2(`Working directory is not a directory: ${cwd}`);
|
|
17832
17929
|
} catch {
|
|
17833
17930
|
return fail2(`Working directory does not exist: ${cwd}`);
|
|
@@ -18013,7 +18110,7 @@ async function jobAction(input2, ctx, options) {
|
|
|
18013
18110
|
}
|
|
18014
18111
|
if (action === "stop") {
|
|
18015
18112
|
const job2 = await jobs.stop(id);
|
|
18016
|
-
const out2 = jobs.output(id);
|
|
18113
|
+
const out2 = jobs.output(id, { maxBytes: toolOutputBytes(ctx.maxResultChars) });
|
|
18017
18114
|
const text = out2?.content ?? "";
|
|
18018
18115
|
return {
|
|
18019
18116
|
content: `${text === "" ? "(no output)" : text}
|
|
@@ -18028,7 +18125,7 @@ ${jobStatusLine(job2)}`,
|
|
|
18028
18125
|
return fail2(`timeoutMs must be between 1 and ${MAX_BASH_TIMEOUT_MS}`);
|
|
18029
18126
|
await jobs.wait(id, waitMs, ctx.signal);
|
|
18030
18127
|
}
|
|
18031
|
-
const out = jobs.output(id);
|
|
18128
|
+
const out = jobs.output(id, { maxBytes: toolOutputBytes(ctx.maxResultChars) });
|
|
18032
18129
|
if (out === void 0) return fail2(`Unknown background job ${id}`);
|
|
18033
18130
|
const job = out.job;
|
|
18034
18131
|
if (job.status !== "running") jobs.markSeen(id);
|
|
@@ -18077,12 +18174,12 @@ function createBashTool(options = {}) {
|
|
|
18077
18174
|
execute: (input2, ctx) => executeBash(input2, ctx, options)
|
|
18078
18175
|
};
|
|
18079
18176
|
}
|
|
18080
|
-
var import_node_child_process5,
|
|
18177
|
+
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
18178
|
var init_bash2 = __esm({
|
|
18082
18179
|
"src/tools/bash.ts"() {
|
|
18083
18180
|
"use strict";
|
|
18084
18181
|
import_node_child_process5 = require("node:child_process");
|
|
18085
|
-
|
|
18182
|
+
import_promises9 = require("node:fs/promises");
|
|
18086
18183
|
import_node_path32 = require("node:path");
|
|
18087
18184
|
init_paths2();
|
|
18088
18185
|
init_shell();
|
|
@@ -18109,9 +18206,9 @@ function compilePattern(input2) {
|
|
|
18109
18206
|
}
|
|
18110
18207
|
async function searchFile(abs, regex, firstOnly = false) {
|
|
18111
18208
|
try {
|
|
18112
|
-
const info2 = await (0,
|
|
18209
|
+
const info2 = await (0, import_promises10.stat)(abs);
|
|
18113
18210
|
if (!info2.isFile() || info2.size > GREP_MAX_FILE_BYTES) return void 0;
|
|
18114
|
-
const buf = await (0,
|
|
18211
|
+
const buf = await (0, import_promises10.readFile)(abs);
|
|
18115
18212
|
if (isBinary(buf)) return void 0;
|
|
18116
18213
|
const lines2 = buf.toString("utf8").replace(/\r\n/g, "\n").split("\n");
|
|
18117
18214
|
if (lines2[lines2.length - 1] === "") lines2.pop();
|
|
@@ -18172,7 +18269,7 @@ async function executeGrep(input2, ctx) {
|
|
|
18172
18269
|
const root = resolvePath(input2.path ?? ".", ctx.cwd);
|
|
18173
18270
|
let rootIsFile;
|
|
18174
18271
|
try {
|
|
18175
|
-
rootIsFile = (await (0,
|
|
18272
|
+
rootIsFile = (await (0, import_promises10.stat)(root)).isFile();
|
|
18176
18273
|
} catch {
|
|
18177
18274
|
return { content: `Path not found: ${displayPath(root, ctx.cwd)}`, isError: true };
|
|
18178
18275
|
}
|
|
@@ -18277,11 +18374,11 @@ function createGrepTool() {
|
|
|
18277
18374
|
execute: executeGrep
|
|
18278
18375
|
};
|
|
18279
18376
|
}
|
|
18280
|
-
var
|
|
18377
|
+
var import_promises10, DEFAULT_GREP_LIMIT, GREP_MAX_FILE_BYTES, GREP_CONCURRENCY, MAX_CONTEXT;
|
|
18281
18378
|
var init_grep = __esm({
|
|
18282
18379
|
"src/tools/grep.ts"() {
|
|
18283
18380
|
"use strict";
|
|
18284
|
-
|
|
18381
|
+
import_promises10 = require("node:fs/promises");
|
|
18285
18382
|
init_paths2();
|
|
18286
18383
|
init_ignore();
|
|
18287
18384
|
init_glob();
|
|
@@ -18298,16 +18395,16 @@ var init_grep = __esm({
|
|
|
18298
18395
|
async function describe(dir, name) {
|
|
18299
18396
|
const abs = (0, import_node_path33.join)(dir, name);
|
|
18300
18397
|
try {
|
|
18301
|
-
const info2 = await (0,
|
|
18398
|
+
const info2 = await (0, import_promises11.lstat)(abs);
|
|
18302
18399
|
if (info2.isSymbolicLink()) {
|
|
18303
18400
|
let target = "?";
|
|
18304
18401
|
try {
|
|
18305
|
-
target = await (0,
|
|
18402
|
+
target = await (0, import_promises11.readlink)(abs);
|
|
18306
18403
|
} catch {
|
|
18307
18404
|
}
|
|
18308
18405
|
let pointsToDir = false;
|
|
18309
18406
|
try {
|
|
18310
|
-
pointsToDir = (await (0,
|
|
18407
|
+
pointsToDir = (await (0, import_promises11.stat)(abs)).isDirectory();
|
|
18311
18408
|
} catch {
|
|
18312
18409
|
}
|
|
18313
18410
|
return { name: pointsToDir ? `${name}/` : name, type: "symlink", target };
|
|
@@ -18333,9 +18430,9 @@ async function executeLs(input2, ctx) {
|
|
|
18333
18430
|
const shown2 = displayPath(dir, ctx.cwd);
|
|
18334
18431
|
let names;
|
|
18335
18432
|
try {
|
|
18336
|
-
if (!(await (0,
|
|
18433
|
+
if (!(await (0, import_promises11.stat)(dir)).isDirectory())
|
|
18337
18434
|
return { content: `${shown2} is not a directory`, isError: true };
|
|
18338
|
-
names = await (0,
|
|
18435
|
+
names = await (0, import_promises11.readdir)(dir);
|
|
18339
18436
|
} catch {
|
|
18340
18437
|
return { content: `Directory not found: ${shown2}`, isError: true };
|
|
18341
18438
|
}
|
|
@@ -18370,11 +18467,11 @@ function createLsTool() {
|
|
|
18370
18467
|
execute: executeLs
|
|
18371
18468
|
};
|
|
18372
18469
|
}
|
|
18373
|
-
var
|
|
18470
|
+
var import_promises11, import_node_path33, DEFAULT_LS_LIMIT;
|
|
18374
18471
|
var init_ls = __esm({
|
|
18375
18472
|
"src/tools/ls.ts"() {
|
|
18376
18473
|
"use strict";
|
|
18377
|
-
|
|
18474
|
+
import_promises11 = require("node:fs/promises");
|
|
18378
18475
|
import_node_path33 = require("node:path");
|
|
18379
18476
|
init_paths2();
|
|
18380
18477
|
init_truncate();
|
|
@@ -18661,9 +18758,9 @@ ${tail}`, truncated: true };
|
|
|
18661
18758
|
}
|
|
18662
18759
|
function writeTaskOutput(dir, name, text) {
|
|
18663
18760
|
try {
|
|
18664
|
-
(0,
|
|
18761
|
+
(0, import_node_fs26.mkdirSync)(dir, { recursive: true });
|
|
18665
18762
|
const file = (0, import_node_path34.join)(dir, name);
|
|
18666
|
-
(0,
|
|
18763
|
+
(0, import_node_fs26.writeFileSync)(file, text);
|
|
18667
18764
|
return file;
|
|
18668
18765
|
} catch {
|
|
18669
18766
|
return void 0;
|
|
@@ -18700,11 +18797,11 @@ function backgroundedText(reason, afterMs) {
|
|
|
18700
18797
|
function waitDetachedText(taskId) {
|
|
18701
18798
|
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
18799
|
}
|
|
18703
|
-
var
|
|
18800
|
+
var import_node_fs26, import_node_path34, TASK_RESULT_LIMIT_BYTES, HEAD_SHARE, MAX_TURNS_NOTE, NOTIFY_HINT, TASK_NOTIFICATION_RULE;
|
|
18704
18801
|
var init_result = __esm({
|
|
18705
18802
|
"src/agents/result.ts"() {
|
|
18706
18803
|
"use strict";
|
|
18707
|
-
|
|
18804
|
+
import_node_fs26 = require("node:fs");
|
|
18708
18805
|
import_node_path34 = require("node:path");
|
|
18709
18806
|
TASK_RESULT_LIMIT_BYTES = 50 * 1024;
|
|
18710
18807
|
HEAD_SHARE = 0.7;
|
|
@@ -18715,6 +18812,16 @@ var init_result = __esm({
|
|
|
18715
18812
|
});
|
|
18716
18813
|
|
|
18717
18814
|
// src/tools/task.ts
|
|
18815
|
+
function taskLine(prompt) {
|
|
18816
|
+
const line2 = prompt.split("\n").find((text) => text.trim() !== "")?.trim() ?? "";
|
|
18817
|
+
return line2.length > TASK_LINE_MAX ? `${line2.slice(0, TASK_LINE_MAX - 1)}…` : line2;
|
|
18818
|
+
}
|
|
18819
|
+
function nestedTaskRejection(ctx, tool, fallback) {
|
|
18820
|
+
const mark = ctx.session.lastCustom(FORK_CUSTOM_TYPE);
|
|
18821
|
+
if (mark === void 0 || mark === null) return fallback;
|
|
18822
|
+
const line2 = typeof mark.taskLine === "string" ? mark.taskLine : "";
|
|
18823
|
+
return `${tool} rejected: you are a sub-agent forked from the main conversation and cannot start or manage sub-agents. Do not call task or task_ctl again; complete the sub-task in your <task> block yourself with your other tools, then end with your report.` + (line2 !== "" ? ` Your task begins: "${line2}"` : "");
|
|
18824
|
+
}
|
|
18718
18825
|
function bindTaskAgents(tool, catalog) {
|
|
18719
18826
|
if (tool !== void 0) catalogs.set(tool, catalog);
|
|
18720
18827
|
}
|
|
@@ -18794,7 +18901,13 @@ function createTaskTool(_options = {}) {
|
|
|
18794
18901
|
promptGuidelines: [TASK_NOTIFICATION_RULE],
|
|
18795
18902
|
async execute(input2, ctx) {
|
|
18796
18903
|
if (ctx.depth >= MAX_TASK_DEPTH || ctx.spawnSubagent === void 0) {
|
|
18797
|
-
return fail3(
|
|
18904
|
+
return fail3(
|
|
18905
|
+
nestedTaskRejection(
|
|
18906
|
+
ctx,
|
|
18907
|
+
"task",
|
|
18908
|
+
"Sub-agents are not available here (nested tasks are not allowed)."
|
|
18909
|
+
)
|
|
18910
|
+
);
|
|
18798
18911
|
}
|
|
18799
18912
|
const request = buildSubagentRequest(input2, ctx);
|
|
18800
18913
|
if (typeof request === "string") return fail3(request);
|
|
@@ -18823,13 +18936,15 @@ function createTaskTool(_options = {}) {
|
|
|
18823
18936
|
};
|
|
18824
18937
|
return tool;
|
|
18825
18938
|
}
|
|
18826
|
-
var MAX_TASK_DEPTH, THINKING, TASK_CONTEXT_LEAD, FOREGROUND_DESCRIPTION, BACKGROUND_DESCRIPTION, TASK_AGENTS_HEADING, catalogs, backgrounds;
|
|
18939
|
+
var MAX_TASK_DEPTH, TASK_LINE_MAX, FORK_CUSTOM_TYPE, THINKING, TASK_CONTEXT_LEAD, FOREGROUND_DESCRIPTION, BACKGROUND_DESCRIPTION, TASK_AGENTS_HEADING, catalogs, backgrounds;
|
|
18827
18940
|
var init_task = __esm({
|
|
18828
18941
|
"src/tools/task.ts"() {
|
|
18829
18942
|
"use strict";
|
|
18830
18943
|
init_catalog3();
|
|
18831
18944
|
init_result();
|
|
18832
18945
|
MAX_TASK_DEPTH = 1;
|
|
18946
|
+
TASK_LINE_MAX = 120;
|
|
18947
|
+
FORK_CUSTOM_TYPE = "ama.fork";
|
|
18833
18948
|
THINKING = [
|
|
18834
18949
|
"off",
|
|
18835
18950
|
"minimal",
|
|
@@ -18911,7 +19026,10 @@ function createTaskCtlTool() {
|
|
|
18911
19026
|
executionMode: "parallel",
|
|
18912
19027
|
annotations: { pollable: true },
|
|
18913
19028
|
async execute(input2, ctx) {
|
|
18914
|
-
if (ctx.depth >= 1)
|
|
19029
|
+
if (ctx.depth >= 1)
|
|
19030
|
+
return fail4(
|
|
19031
|
+
nestedTaskRejection(ctx, "task_ctl", "task_ctl is not available inside a sub-agent.")
|
|
19032
|
+
);
|
|
18915
19033
|
const control = taskControl(ctx.sessionId);
|
|
18916
19034
|
if (input2.action === "list") {
|
|
18917
19035
|
const tasks = control?.list() ?? ctx.tasks?.list() ?? [];
|
|
@@ -18968,6 +19086,7 @@ var init_task_ctl = __esm({
|
|
|
18968
19086
|
"use strict";
|
|
18969
19087
|
init_result();
|
|
18970
19088
|
init_task_control();
|
|
19089
|
+
init_task();
|
|
18971
19090
|
TASK_CTL_TOOL = "task_ctl";
|
|
18972
19091
|
DEFAULT_WAIT_MS = 3e4;
|
|
18973
19092
|
MAX_WAIT_MS = 6e5;
|
|
@@ -19303,9 +19422,9 @@ function truncateResult(call, result, options, nested = false) {
|
|
|
19303
19422
|
let where = "full output not saved";
|
|
19304
19423
|
if (options.outputDir !== void 0) {
|
|
19305
19424
|
try {
|
|
19306
|
-
(0,
|
|
19425
|
+
(0, import_node_fs27.mkdirSync)(options.outputDir, { recursive: true });
|
|
19307
19426
|
const file = (0, import_node_path35.join)(options.outputDir, `${call.id.replace(/[^A-Za-z0-9_-]/g, "_")}.txt`);
|
|
19308
|
-
(0,
|
|
19427
|
+
(0, import_node_fs27.writeFileSync)(file, text, "utf8");
|
|
19309
19428
|
where = `full output at ${file}`;
|
|
19310
19429
|
} catch {
|
|
19311
19430
|
}
|
|
@@ -19520,11 +19639,11 @@ async function runSingleToolCall(call, assistant, options, signal, nested) {
|
|
|
19520
19639
|
await emitEnd(call, result, emit);
|
|
19521
19640
|
return result;
|
|
19522
19641
|
}
|
|
19523
|
-
var
|
|
19642
|
+
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
19643
|
var init_tool_runner = __esm({
|
|
19525
19644
|
"src/agent/tool-runner.ts"() {
|
|
19526
19645
|
"use strict";
|
|
19527
|
-
|
|
19646
|
+
import_node_fs27 = require("node:fs");
|
|
19528
19647
|
import_node_path35 = require("node:path");
|
|
19529
19648
|
init_loop_guard();
|
|
19530
19649
|
init_schema2();
|
|
@@ -20438,8 +20557,23 @@ var init_classifier = __esm({
|
|
|
20438
20557
|
function textOf(message) {
|
|
20439
20558
|
return message.content.filter((block) => block.type === "text").map((block) => block.type === "text" ? block.text : "").join("").trim();
|
|
20440
20559
|
}
|
|
20560
|
+
function inferredSmall(core, session) {
|
|
20561
|
+
const hit = catalogByAlias(session.id);
|
|
20562
|
+
if (hit === void 0) return void 0;
|
|
20563
|
+
const origin = hit.ref.slice(0, hit.ref.indexOf("/"));
|
|
20564
|
+
const small = catalogSmall(origin);
|
|
20565
|
+
const target = `${origin}/${small}`;
|
|
20566
|
+
if (small === void 0 || hit.ref === target) return void 0;
|
|
20567
|
+
const listed2 = core.options.providers.get(session.provider)?.models ?? [];
|
|
20568
|
+
return listed2.find((m) => {
|
|
20569
|
+
if (m.id === small) return true;
|
|
20570
|
+
const entry = catalogByAlias(m.id);
|
|
20571
|
+
return entry?.ref === target && entry.tier === void 0;
|
|
20572
|
+
})?.id;
|
|
20573
|
+
}
|
|
20441
20574
|
async function smallModel(core, session) {
|
|
20442
|
-
const
|
|
20575
|
+
const own = catalogSmall(session.provider);
|
|
20576
|
+
const small = own === void 0 ? inferredSmall(core, session) : own;
|
|
20443
20577
|
if (small === void 0 || small === session.id) return void 0;
|
|
20444
20578
|
const lookup = core.options.providers.findModel(`${session.provider}/${small}`);
|
|
20445
20579
|
if (!lookup.ok) return void 0;
|
|
@@ -21577,9 +21711,9 @@ function materialize(candidate, outputDir) {
|
|
|
21577
21711
|
if (outputDir !== void 0) {
|
|
21578
21712
|
fullTextPath = (0, import_node_path37.join)(outputDir, `${safeFileStem(message.toolCallId)}.txt`);
|
|
21579
21713
|
try {
|
|
21580
|
-
if (!(0,
|
|
21581
|
-
(0,
|
|
21582
|
-
(0,
|
|
21714
|
+
if (!(0, import_node_fs28.existsSync)(fullTextPath)) {
|
|
21715
|
+
(0, import_node_fs28.mkdirSync)(outputDir, { recursive: true });
|
|
21716
|
+
(0, import_node_fs28.writeFileSync)(fullTextPath, text, "utf8");
|
|
21583
21717
|
}
|
|
21584
21718
|
} catch {
|
|
21585
21719
|
fullTextPath = void 0;
|
|
@@ -21614,11 +21748,11 @@ function planPrune(items, options) {
|
|
|
21614
21748
|
}
|
|
21615
21749
|
return { items: plan2, savedTokens, availableTokens };
|
|
21616
21750
|
}
|
|
21617
|
-
var
|
|
21751
|
+
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
21752
|
var init_prune_tier = __esm({
|
|
21619
21753
|
"src/compaction/prune-tier.ts"() {
|
|
21620
21754
|
"use strict";
|
|
21621
|
-
|
|
21755
|
+
import_node_fs28 = require("node:fs");
|
|
21622
21756
|
import_node_path37 = require("node:path");
|
|
21623
21757
|
init_estimate();
|
|
21624
21758
|
PRUNE_TRIGGER_RATIO = 0.7;
|
|
@@ -22075,9 +22209,9 @@ function isTaskHead(entry) {
|
|
|
22075
22209
|
const data2 = entry.data;
|
|
22076
22210
|
return data2?.context !== "fork";
|
|
22077
22211
|
}
|
|
22078
|
-
function
|
|
22212
|
+
function readHead(file) {
|
|
22079
22213
|
try {
|
|
22080
|
-
const [header, first] = (0,
|
|
22214
|
+
const [header, first] = (0, import_node_fs29.readFileSync)(file, "utf8").split("\n", 2);
|
|
22081
22215
|
const parsed = JSON.parse(header ?? "{}");
|
|
22082
22216
|
const entry = first ? JSON.parse(first) : void 0;
|
|
22083
22217
|
return { ...parsed, task: isTaskHead(entry) };
|
|
@@ -22095,18 +22229,18 @@ function cacheKeyOf(manager) {
|
|
|
22095
22229
|
let id = manager.id;
|
|
22096
22230
|
let file = header.parentSession;
|
|
22097
22231
|
for (let depth = 0; depth < 8 && file !== void 0; depth++) {
|
|
22098
|
-
const next =
|
|
22232
|
+
const next = readHead(file);
|
|
22099
22233
|
if (next.id === void 0 || next.task) break;
|
|
22100
22234
|
id = next.id;
|
|
22101
22235
|
file = next.parentSession;
|
|
22102
22236
|
}
|
|
22103
22237
|
return id;
|
|
22104
22238
|
}
|
|
22105
|
-
var
|
|
22239
|
+
var import_node_fs29, TASK_CUSTOM_TYPE;
|
|
22106
22240
|
var init_session_cache_key = __esm({
|
|
22107
22241
|
"src/agent/session-cache-key.ts"() {
|
|
22108
22242
|
"use strict";
|
|
22109
|
-
|
|
22243
|
+
import_node_fs29 = require("node:fs");
|
|
22110
22244
|
TASK_CUSTOM_TYPE = "ama.task";
|
|
22111
22245
|
}
|
|
22112
22246
|
});
|
|
@@ -25068,7 +25202,7 @@ function listSessionItems(dir) {
|
|
|
25068
25202
|
file,
|
|
25069
25203
|
cwd: header.cwd,
|
|
25070
25204
|
createdAt: header.timestamp,
|
|
25071
|
-
modifiedAt: (0,
|
|
25205
|
+
modifiedAt: (0, import_node_fs30.statSync)(file).mtime.toISOString(),
|
|
25072
25206
|
messageCount
|
|
25073
25207
|
};
|
|
25074
25208
|
if (name !== void 0) item.name = name;
|
|
@@ -25080,11 +25214,11 @@ function listSessionItems(dir) {
|
|
|
25080
25214
|
}
|
|
25081
25215
|
return items;
|
|
25082
25216
|
}
|
|
25083
|
-
var
|
|
25217
|
+
var import_node_fs30, SkipFile;
|
|
25084
25218
|
var init_list = __esm({
|
|
25085
25219
|
"src/session/list.ts"() {
|
|
25086
25220
|
"use strict";
|
|
25087
|
-
|
|
25221
|
+
import_node_fs30 = require("node:fs");
|
|
25088
25222
|
init_line_reader();
|
|
25089
25223
|
init_store();
|
|
25090
25224
|
init_types6();
|
|
@@ -25093,6 +25227,179 @@ var init_list = __esm({
|
|
|
25093
25227
|
}
|
|
25094
25228
|
});
|
|
25095
25229
|
|
|
25230
|
+
// src/session/offload.ts
|
|
25231
|
+
function isImage(block) {
|
|
25232
|
+
return typeof block === "object" && block !== null && block.type === "image" && typeof block.data === "string";
|
|
25233
|
+
}
|
|
25234
|
+
function contentOf(entry) {
|
|
25235
|
+
if (entry.type !== "message") return void 0;
|
|
25236
|
+
const content = entry.message.content;
|
|
25237
|
+
return Array.isArray(content) ? content : void 0;
|
|
25238
|
+
}
|
|
25239
|
+
function hasImages(entry) {
|
|
25240
|
+
return contentOf(entry)?.some(isImage) === true;
|
|
25241
|
+
}
|
|
25242
|
+
function readLineAt(file, locator) {
|
|
25243
|
+
const fd = (0, import_node_fs31.openSync)(file, "r");
|
|
25244
|
+
try {
|
|
25245
|
+
const buf = Buffer.allocUnsafe(locator.length);
|
|
25246
|
+
let read2 = 0;
|
|
25247
|
+
while (read2 < locator.length) {
|
|
25248
|
+
const n = (0, import_node_fs31.readSync)(fd, buf, read2, locator.length - read2, locator.offset + read2);
|
|
25249
|
+
if (n === 0) throw new Error("unexpected end of file");
|
|
25250
|
+
read2 += n;
|
|
25251
|
+
}
|
|
25252
|
+
return JSON.parse(buf.toString("utf8"));
|
|
25253
|
+
} finally {
|
|
25254
|
+
(0, import_node_fs31.closeSync)(fd);
|
|
25255
|
+
}
|
|
25256
|
+
}
|
|
25257
|
+
function editTargets(file) {
|
|
25258
|
+
const targets = /* @__PURE__ */ new Set();
|
|
25259
|
+
try {
|
|
25260
|
+
forEachLineSync(file, (line2) => {
|
|
25261
|
+
if (lineTypeOf(line2)?.type !== "context_edit") return;
|
|
25262
|
+
try {
|
|
25263
|
+
const id = JSON.parse(line2.toString("utf8")).targetId;
|
|
25264
|
+
if (typeof id === "string") targets.add(id);
|
|
25265
|
+
} catch {
|
|
25266
|
+
}
|
|
25267
|
+
});
|
|
25268
|
+
} catch {
|
|
25269
|
+
}
|
|
25270
|
+
return targets;
|
|
25271
|
+
}
|
|
25272
|
+
var import_node_fs31, placeholder, PENDING_WARNINGS, ImageOffload;
|
|
25273
|
+
var init_offload = __esm({
|
|
25274
|
+
"src/session/offload.ts"() {
|
|
25275
|
+
"use strict";
|
|
25276
|
+
import_node_fs31 = require("node:fs");
|
|
25277
|
+
init_image_intern();
|
|
25278
|
+
init_line_reader();
|
|
25279
|
+
init_projection();
|
|
25280
|
+
placeholder = (block) => ({ ...block, data: "" });
|
|
25281
|
+
PENDING_WARNINGS = 16;
|
|
25282
|
+
ImageOffload = class {
|
|
25283
|
+
/** 含图 message 条目的行位置(只有已落盘的条目才有)。 */
|
|
25284
|
+
locators = /* @__PURE__ */ new Map();
|
|
25285
|
+
offloaded = /* @__PURE__ */ new Set();
|
|
25286
|
+
warn;
|
|
25287
|
+
pending = [];
|
|
25288
|
+
dropped = 0;
|
|
25289
|
+
constructor(warn2) {
|
|
25290
|
+
this.warn = warn2;
|
|
25291
|
+
}
|
|
25292
|
+
/** 接上(或换掉)告警通道;之前缓冲的告警按序冲出。 */
|
|
25293
|
+
setWarn(warn2) {
|
|
25294
|
+
this.warn = warn2;
|
|
25295
|
+
const pending = this.pending.splice(0);
|
|
25296
|
+
if (this.dropped > 0)
|
|
25297
|
+
pending.push(`and ${this.dropped} more session entries could not be read back`);
|
|
25298
|
+
this.dropped = 0;
|
|
25299
|
+
for (const message of pending) warn2(message);
|
|
25300
|
+
}
|
|
25301
|
+
/** 记下条目的行位置;不含图片的条目忽略。 */
|
|
25302
|
+
track(entry, locator) {
|
|
25303
|
+
if (hasImages(entry)) this.locators.set(entry.id, locator);
|
|
25304
|
+
}
|
|
25305
|
+
/** 读文件时逐行调用:记下行位置;`strip` 时就地换成占位(刚解析的对象,别处没有引用)。 */
|
|
25306
|
+
load(line2, locator, strip) {
|
|
25307
|
+
if (typeof line2.id !== "string" || !hasImages(line2)) return;
|
|
25308
|
+
this.locators.set(line2.id, locator);
|
|
25309
|
+
if (!strip) return;
|
|
25310
|
+
const content = contentOf(line2);
|
|
25311
|
+
content.forEach((block, i) => {
|
|
25312
|
+
if (isImage(block)) content[i] = placeholder(block);
|
|
25313
|
+
});
|
|
25314
|
+
this.offloaded.add(line2.id);
|
|
25315
|
+
}
|
|
25316
|
+
isOffloaded(id) {
|
|
25317
|
+
return this.offloaded.has(id);
|
|
25318
|
+
}
|
|
25319
|
+
/** 已卸载的条目数(测试与诊断用)。 */
|
|
25320
|
+
get size() {
|
|
25321
|
+
return this.offloaded.size;
|
|
25322
|
+
}
|
|
25323
|
+
/** 把条目里的图片换成占位;没有行位置(未落盘、不含图)或已卸载时返回 false。 */
|
|
25324
|
+
offload(entry) {
|
|
25325
|
+
if (entry.type !== "message" || this.offloaded.has(entry.id)) return false;
|
|
25326
|
+
const content = contentOf(entry);
|
|
25327
|
+
if (content === void 0 || !this.locators.has(entry.id)) return false;
|
|
25328
|
+
entry.message = {
|
|
25329
|
+
...entry.message,
|
|
25330
|
+
content: content.map((block) => isImage(block) ? placeholder(block) : block)
|
|
25331
|
+
};
|
|
25332
|
+
this.offloaded.add(entry.id);
|
|
25333
|
+
return true;
|
|
25334
|
+
}
|
|
25335
|
+
/** 就地放回图片;读不回时返回 false(占位保留,之后不再卸载 / 回读这一条)。 */
|
|
25336
|
+
hydrate(file, entry) {
|
|
25337
|
+
if (!this.offloaded.has(entry.id)) return true;
|
|
25338
|
+
this.offloaded.delete(entry.id);
|
|
25339
|
+
const source = this.read(file, entry);
|
|
25340
|
+
const content = contentOf(entry);
|
|
25341
|
+
if (source === void 0 || content === void 0) return false;
|
|
25342
|
+
const originals = contentOf(source) ?? [];
|
|
25343
|
+
content.forEach((block, i) => {
|
|
25344
|
+
const original = originals[i];
|
|
25345
|
+
if (isImage(block) && block.data === "" && isImage(original)) {
|
|
25346
|
+
content[i] = internImage(original);
|
|
25347
|
+
}
|
|
25348
|
+
});
|
|
25349
|
+
return true;
|
|
25350
|
+
}
|
|
25351
|
+
/** 原文:已卸载的条目从文件读一份新副本(图片驻留),否则原样返回。读不回时返回占位版本。 */
|
|
25352
|
+
original(file, entry) {
|
|
25353
|
+
if (!this.offloaded.has(entry.id)) return entry;
|
|
25354
|
+
const copy = this.read(file, entry);
|
|
25355
|
+
if (copy === void 0) return entry;
|
|
25356
|
+
const content = contentOf(copy) ?? [];
|
|
25357
|
+
content.forEach((block, i) => {
|
|
25358
|
+
if (isImage(block)) content[i] = internImage(block);
|
|
25359
|
+
});
|
|
25360
|
+
return copy;
|
|
25361
|
+
}
|
|
25362
|
+
/** 按活动分支对齐:分支上被生效编辑改写的含图条目卸载,其余已卸载的回读。 */
|
|
25363
|
+
sync(file, branch, index2) {
|
|
25364
|
+
const edits = collectContextEdits(branch);
|
|
25365
|
+
const onBranch = /* @__PURE__ */ new Set();
|
|
25366
|
+
for (const entry of branch) if (edits.has(entry.id)) onBranch.add(entry.id);
|
|
25367
|
+
for (const id of [...this.offloaded]) {
|
|
25368
|
+
const entry = index2.get(id);
|
|
25369
|
+
if (entry !== void 0 && !onBranch.has(id)) this.hydrate(file, entry);
|
|
25370
|
+
}
|
|
25371
|
+
for (const id of onBranch) {
|
|
25372
|
+
const entry = index2.get(id);
|
|
25373
|
+
if (entry !== void 0) this.offload(entry);
|
|
25374
|
+
}
|
|
25375
|
+
}
|
|
25376
|
+
/** 从文件读回条目(新对象);不成功时告警、忘掉行位置并返回 undefined。 */
|
|
25377
|
+
read(file, entry) {
|
|
25378
|
+
const locator = this.locators.get(entry.id);
|
|
25379
|
+
try {
|
|
25380
|
+
if (locator === void 0) throw new Error("no line locator");
|
|
25381
|
+
const line2 = readLineAt(file, locator);
|
|
25382
|
+
const content = line2.id === entry.id ? contentOf(line2) : void 0;
|
|
25383
|
+
if (content === void 0 || content.length !== contentOf(entry)?.length) {
|
|
25384
|
+
throw new Error("line does not match the entry");
|
|
25385
|
+
}
|
|
25386
|
+
return line2;
|
|
25387
|
+
} catch (error2) {
|
|
25388
|
+
this.locators.delete(entry.id);
|
|
25389
|
+
this.offloaded.delete(entry.id);
|
|
25390
|
+
this.report(`cannot read session entry ${entry.id} back from ${file}: ${String(error2)}`);
|
|
25391
|
+
return void 0;
|
|
25392
|
+
}
|
|
25393
|
+
}
|
|
25394
|
+
report(message) {
|
|
25395
|
+
if (this.warn !== void 0) this.warn(message);
|
|
25396
|
+
else if (this.pending.length < PENDING_WARNINGS) this.pending.push(message);
|
|
25397
|
+
else this.dropped++;
|
|
25398
|
+
}
|
|
25399
|
+
};
|
|
25400
|
+
}
|
|
25401
|
+
});
|
|
25402
|
+
|
|
25096
25403
|
// src/session/manager.ts
|
|
25097
25404
|
function newEntryId(taken) {
|
|
25098
25405
|
for (; ; ) {
|
|
@@ -25111,6 +25418,7 @@ var init_manager = __esm({
|
|
|
25111
25418
|
init_version();
|
|
25112
25419
|
init_list();
|
|
25113
25420
|
init_migrate();
|
|
25421
|
+
init_offload();
|
|
25114
25422
|
init_store();
|
|
25115
25423
|
init_tree();
|
|
25116
25424
|
init_types6();
|
|
@@ -25124,7 +25432,11 @@ var init_manager = __esm({
|
|
|
25124
25432
|
storage;
|
|
25125
25433
|
closed = false;
|
|
25126
25434
|
now;
|
|
25127
|
-
|
|
25435
|
+
images;
|
|
25436
|
+
warn;
|
|
25437
|
+
/** 已知的会话文件字节数(新行的行首偏移)。 */
|
|
25438
|
+
fileBytes = 0;
|
|
25439
|
+
constructor(header, entries, storage, now, leafId, warn2, images) {
|
|
25128
25440
|
this._header = header;
|
|
25129
25441
|
this.id = header.id;
|
|
25130
25442
|
this.cwd = header.cwd;
|
|
@@ -25134,6 +25446,8 @@ var init_manager = __esm({
|
|
|
25134
25446
|
this.leaf = leafId === void 0 || leafId !== null && !this.index.has(leafId) ? last : leafId;
|
|
25135
25447
|
this.storage = storage;
|
|
25136
25448
|
this.now = now;
|
|
25449
|
+
this.warn = warn2;
|
|
25450
|
+
this.images = images ?? new ImageOffload(warn2);
|
|
25137
25451
|
}
|
|
25138
25452
|
static newHeader(cwd, options, now) {
|
|
25139
25453
|
const header = {
|
|
@@ -25154,7 +25468,14 @@ var init_manager = __esm({
|
|
|
25154
25468
|
/** `dir` 是会话文件所在目录(通常是 `sessionDirForCwd(sessionsRoot, cwd)`)。 */
|
|
25155
25469
|
static create(dir, cwd, options = {}) {
|
|
25156
25470
|
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
25157
|
-
return new _SessionManager(
|
|
25471
|
+
return new _SessionManager(
|
|
25472
|
+
this.newHeader(cwd, options, now()),
|
|
25473
|
+
[],
|
|
25474
|
+
{ kind: "lazy", dir },
|
|
25475
|
+
now,
|
|
25476
|
+
void 0,
|
|
25477
|
+
options.warn
|
|
25478
|
+
);
|
|
25158
25479
|
}
|
|
25159
25480
|
static createForCwd(sessionsRoot, cwd, options = {}) {
|
|
25160
25481
|
return this.create(sessionDirForCwd(sessionsRoot, cwd), cwd, options);
|
|
@@ -25162,16 +25483,29 @@ var init_manager = __esm({
|
|
|
25162
25483
|
static open(file, options = {}) {
|
|
25163
25484
|
const lock = acquireLock(file);
|
|
25164
25485
|
try {
|
|
25165
|
-
const
|
|
25486
|
+
const images = new ImageOffload(options.warn);
|
|
25487
|
+
const targets = editTargets(file);
|
|
25488
|
+
const { lines: lines2, bytes } = readSessionLines(file, {
|
|
25489
|
+
repair: true,
|
|
25490
|
+
onLine: (line2, locator) => {
|
|
25491
|
+
const entry = line2;
|
|
25492
|
+
images.load(entry, locator, targets.has(entry.id));
|
|
25493
|
+
}
|
|
25494
|
+
});
|
|
25166
25495
|
const { header, entries, leafId } = migrateSessionLines(lines2, file);
|
|
25167
25496
|
internSessionImages(entries);
|
|
25168
|
-
|
|
25497
|
+
const manager = new _SessionManager(
|
|
25169
25498
|
header,
|
|
25170
25499
|
entries,
|
|
25171
25500
|
{ kind: "file", file, lock },
|
|
25172
25501
|
options.now ?? (() => /* @__PURE__ */ new Date()),
|
|
25173
|
-
leafId
|
|
25502
|
+
leafId,
|
|
25503
|
+
options.warn,
|
|
25504
|
+
images
|
|
25174
25505
|
);
|
|
25506
|
+
manager.fileBytes = bytes ?? 0;
|
|
25507
|
+
manager.syncImages();
|
|
25508
|
+
return manager;
|
|
25175
25509
|
} catch (error2) {
|
|
25176
25510
|
lock.release();
|
|
25177
25511
|
throw error2;
|
|
@@ -25212,10 +25546,18 @@ var init_manager = __esm({
|
|
|
25212
25546
|
parentId: this.leaf,
|
|
25213
25547
|
timestamp: this.now().toISOString()
|
|
25214
25548
|
};
|
|
25215
|
-
if (this.storage.kind === "file")
|
|
25549
|
+
if (this.storage.kind === "file") {
|
|
25550
|
+
const written = appendLines(this.storage.file, [entry]);
|
|
25551
|
+
this.images.track(entry, { offset: this.fileBytes, length: written - 1 });
|
|
25552
|
+
this.fileBytes += written;
|
|
25553
|
+
}
|
|
25216
25554
|
this._entries.push(entry);
|
|
25217
25555
|
this.index.set(entry.id, entry);
|
|
25218
25556
|
this.leaf = entry.id;
|
|
25557
|
+
if (entry.type === "context_edit" && this.storage.kind === "file") {
|
|
25558
|
+
const target = this.index.get(entry.targetId);
|
|
25559
|
+
if (target !== void 0 && this.branch().includes(target)) this.images.offload(target);
|
|
25560
|
+
}
|
|
25219
25561
|
return entry;
|
|
25220
25562
|
}
|
|
25221
25563
|
setLeaf(id) {
|
|
@@ -25223,7 +25565,29 @@ var init_manager = __esm({
|
|
|
25223
25565
|
throw new AmaError("invalid_arguments", `no such session entry: ${id}`);
|
|
25224
25566
|
}
|
|
25225
25567
|
this.leaf = id;
|
|
25226
|
-
if (this.storage.kind === "file")
|
|
25568
|
+
if (this.storage.kind === "file") {
|
|
25569
|
+
this.fileBytes += appendLines(this.storage.file, [this.leafLine()]);
|
|
25570
|
+
}
|
|
25571
|
+
this.syncImages();
|
|
25572
|
+
}
|
|
25573
|
+
/** 按当前活动分支卸载 / 回读图片(只对已落盘的会话)。 */
|
|
25574
|
+
syncImages() {
|
|
25575
|
+
if (this.storage.kind === "file")
|
|
25576
|
+
this.images.sync(this.storage.file, this.branch(), this.index);
|
|
25577
|
+
}
|
|
25578
|
+
/** 原文条目(已卸载的从文件回读一份副本)。 */
|
|
25579
|
+
original(entry) {
|
|
25580
|
+
if (this.storage.kind !== "file" || !this.images.isOffloaded(entry.id)) return entry;
|
|
25581
|
+
return this.images.original(this.storage.file, entry);
|
|
25582
|
+
}
|
|
25583
|
+
/** 接上(或换掉)告警出口(图片读不回等);`open()` 期间缓冲的告警随即按序冲出(#183)。 */
|
|
25584
|
+
setWarn(warn2) {
|
|
25585
|
+
this.warn = warn2;
|
|
25586
|
+
this.images.setWarn(warn2);
|
|
25587
|
+
}
|
|
25588
|
+
/** 已卸载图片的条目数(测试与诊断用)。 */
|
|
25589
|
+
offloadedCount() {
|
|
25590
|
+
return this.images.size;
|
|
25227
25591
|
}
|
|
25228
25592
|
leafLine() {
|
|
25229
25593
|
return { type: "leaf", id: this.leaf, timestamp: this.now().toISOString() };
|
|
@@ -25232,10 +25596,9 @@ var init_manager = __esm({
|
|
|
25232
25596
|
return pathToRoot(this.index, leafId === void 0 ? this.leaf : leafId);
|
|
25233
25597
|
}
|
|
25234
25598
|
getEntries(since) {
|
|
25235
|
-
|
|
25236
|
-
const at = this._entries.findIndex((entry) => entry.id === since);
|
|
25599
|
+
const at = since === void 0 ? -1 : this._entries.findIndex((entry) => entry.id === since);
|
|
25237
25600
|
return {
|
|
25238
|
-
entries:
|
|
25601
|
+
entries: this._entries.slice(at + 1).map((entry) => this.original(entry)),
|
|
25239
25602
|
leafId: this.leaf
|
|
25240
25603
|
};
|
|
25241
25604
|
}
|
|
@@ -25254,7 +25617,10 @@ var init_manager = __esm({
|
|
|
25254
25617
|
if (!this.index.has(entryId)) {
|
|
25255
25618
|
throw new AmaError("invalid_arguments", `no such session entry: ${entryId}`);
|
|
25256
25619
|
}
|
|
25257
|
-
const copied = this.branch(entryId).map((entry) =>
|
|
25620
|
+
const copied = this.branch(entryId).map((entry) => {
|
|
25621
|
+
const original = this.original(entry);
|
|
25622
|
+
return original === entry ? structuredClone(entry) : original;
|
|
25623
|
+
});
|
|
25258
25624
|
if (forkOptions.head !== void 0) {
|
|
25259
25625
|
const head = {
|
|
25260
25626
|
...forkOptions.head,
|
|
@@ -25273,7 +25639,7 @@ var init_manager = __esm({
|
|
|
25273
25639
|
if (this.storage.kind === "memory") storage = { kind: "memory" };
|
|
25274
25640
|
else if (this.storage.kind === "lazy") storage = { kind: "lazy", dir: this.storage.dir };
|
|
25275
25641
|
else storage = { kind: "lazy", dir: (0, import_node_path41.dirname)(this.storage.file) };
|
|
25276
|
-
const forked = new _SessionManager(header, copied, storage, this.now);
|
|
25642
|
+
const forked = new _SessionManager(header, copied, storage, this.now, void 0, this.warn);
|
|
25277
25643
|
if (parentFile !== void 0) forked.flush();
|
|
25278
25644
|
return forked;
|
|
25279
25645
|
}
|
|
@@ -25287,11 +25653,18 @@ var init_manager = __esm({
|
|
|
25287
25653
|
if (this.storage.kind === "file") return this.storage.file;
|
|
25288
25654
|
const file = (0, import_node_path41.join)(this.storage.dir, sessionFileName(new Date(this._header.timestamp), this.id));
|
|
25289
25655
|
const moved = this.leaf !== (this._entries.at(-1)?.id ?? null);
|
|
25290
|
-
writeNewSessionFile(file, [
|
|
25656
|
+
const lengths = writeNewSessionFile(file, [
|
|
25291
25657
|
this._header,
|
|
25292
25658
|
...this._entries,
|
|
25293
25659
|
...moved ? [this.leafLine()] : []
|
|
25294
25660
|
]);
|
|
25661
|
+
let offset = 0;
|
|
25662
|
+
lengths.forEach((length, i) => {
|
|
25663
|
+
const entry = i === 0 ? void 0 : this._entries[i - 1];
|
|
25664
|
+
if (entry !== void 0) this.images.track(entry, { offset, length });
|
|
25665
|
+
offset += length + 1;
|
|
25666
|
+
});
|
|
25667
|
+
this.fileBytes = offset;
|
|
25295
25668
|
let lock;
|
|
25296
25669
|
try {
|
|
25297
25670
|
lock = acquireLock(file);
|
|
@@ -25299,6 +25672,7 @@ var init_manager = __esm({
|
|
|
25299
25672
|
lock = void 0;
|
|
25300
25673
|
}
|
|
25301
25674
|
this.storage = { kind: "file", file, lock };
|
|
25675
|
+
this.syncImages();
|
|
25302
25676
|
return file;
|
|
25303
25677
|
}
|
|
25304
25678
|
isPersisted() {
|
|
@@ -25323,6 +25697,9 @@ var init_manager = __esm({
|
|
|
25323
25697
|
});
|
|
25324
25698
|
|
|
25325
25699
|
// src/agent/subagent-fork.ts
|
|
25700
|
+
function forkRatio(ratio) {
|
|
25701
|
+
return ratio !== void 0 && Number.isFinite(ratio) && ratio > 0 && ratio < 1 ? ratio : FORK_MAX_CONTEXT_RATIO;
|
|
25702
|
+
}
|
|
25326
25703
|
function requestedContext(request, agent) {
|
|
25327
25704
|
return request.context ?? agent.context ?? "fresh";
|
|
25328
25705
|
}
|
|
@@ -25334,7 +25711,7 @@ function forkPoint(branch, parentToolCallId) {
|
|
|
25334
25711
|
);
|
|
25335
25712
|
return index2 > 0 ? branch[index2 - 1]?.id : void 0;
|
|
25336
25713
|
}
|
|
25337
|
-
function forkPlan(parent, spec2, model, thinking) {
|
|
25714
|
+
function forkPlan(parent, spec2, model, thinking, ratio) {
|
|
25338
25715
|
const base4 = parent.childBase();
|
|
25339
25716
|
if (model.provider !== base4.model.provider || model.id !== base4.model.id)
|
|
25340
25717
|
return { fallback: `model ${model.provider}/${model.id} differs from the parent` };
|
|
@@ -25344,7 +25721,7 @@ function forkPlan(parent, spec2, model, thinking) {
|
|
|
25344
25721
|
if (last === void 0) return { fallback: "the parent has not sent a request yet" };
|
|
25345
25722
|
const reserve = parent.options.compaction?.reserveTokens ?? DEFAULT_COMPACTION_SETTINGS.reserveTokens;
|
|
25346
25723
|
const window2 = model.contextWindow;
|
|
25347
|
-
const limit = window2 === void 0 ? Infinity :
|
|
25724
|
+
const limit = window2 === void 0 ? Infinity : forkRatio(ratio) * Math.max(0, window2 - reserve);
|
|
25348
25725
|
if (last.promptTokens > limit)
|
|
25349
25726
|
return { fallback: `parent context ${last.promptTokens} tokens exceeds ${Math.floor(limit)}` };
|
|
25350
25727
|
const forkedFrom = forkPoint(parent.manager.branch(), spec2.request.parentToolCallId);
|
|
@@ -25367,12 +25744,17 @@ function forkPlan(parent, spec2, model, thinking) {
|
|
|
25367
25744
|
}
|
|
25368
25745
|
}
|
|
25369
25746
|
});
|
|
25747
|
+
manager.append({
|
|
25748
|
+
type: "custom",
|
|
25749
|
+
customType: FORK_CUSTOM_TYPE,
|
|
25750
|
+
data: { taskLine: taskLine(spec2.request.prompt) }
|
|
25751
|
+
});
|
|
25370
25752
|
return { manager, forkedFrom };
|
|
25371
25753
|
}
|
|
25372
25754
|
function forkBrief(input2) {
|
|
25373
25755
|
const lines2 = [
|
|
25374
25756
|
"<task>",
|
|
25375
|
-
"You are a sub-agent forked from the conversation above at this point. The main agent cannot see your work, only your final reply; do not delegate further. Requests above were for the main agent: do only this task. Instructions in this block take precedence over earlier plans or reminders above."
|
|
25757
|
+
"You are a sub-agent forked from the conversation above at this point. The main agent cannot see your work, only your final reply; do not delegate further. Requests above were for the main agent: do only this task. Instructions in this block take precedence over earlier plans or reminders above. Do not call task or task_ctl."
|
|
25376
25758
|
];
|
|
25377
25759
|
if (input2.worktree !== void 0)
|
|
25378
25760
|
lines2.push(
|
|
@@ -25399,6 +25781,7 @@ var FORK_MAX_CONTEXT_RATIO, TASK_CUSTOM_TYPE2;
|
|
|
25399
25781
|
var init_subagent_fork = __esm({
|
|
25400
25782
|
"src/agent/subagent-fork.ts"() {
|
|
25401
25783
|
"use strict";
|
|
25784
|
+
init_task();
|
|
25402
25785
|
init_session_compaction();
|
|
25403
25786
|
FORK_MAX_CONTEXT_RATIO = 0.5;
|
|
25404
25787
|
TASK_CUSTOM_TYPE2 = "ama.task";
|
|
@@ -26310,9 +26693,15 @@ function runningResult(record3, text, outputFile) {
|
|
|
26310
26693
|
status: "running"
|
|
26311
26694
|
};
|
|
26312
26695
|
if (outputFile !== void 0) result.outputFile = outputFile;
|
|
26696
|
+
if (record3.info.context !== void 0) result.context = record3.info.context;
|
|
26313
26697
|
return result;
|
|
26314
26698
|
}
|
|
26315
|
-
function startedResult(record3, outputFile) {
|
|
26699
|
+
async function startedResult(record3, outputFile, settle) {
|
|
26700
|
+
if (settle !== void 0)
|
|
26701
|
+
await Promise.race([
|
|
26702
|
+
settle.catch(() => void 0),
|
|
26703
|
+
new Promise((resolve41) => setImmediate(resolve41))
|
|
26704
|
+
]);
|
|
26316
26705
|
return runningResult(record3, startedText(record3.info.taskId, record3.agent.name), outputFile);
|
|
26317
26706
|
}
|
|
26318
26707
|
function backgroundedResult(record3, reason, afterMs, outputFile) {
|
|
@@ -26694,7 +27083,7 @@ var init_subagent_registry = __esm({
|
|
|
26694
27083
|
const file = this.outputFileFor(record3.info.taskId);
|
|
26695
27084
|
if (background) {
|
|
26696
27085
|
void running.then((result) => this.notifier.notify(record3, result));
|
|
26697
|
-
return
|
|
27086
|
+
return startedResult(record3, file, running);
|
|
26698
27087
|
}
|
|
26699
27088
|
const { waiter, promise } = foregroundWaiter(() => {
|
|
26700
27089
|
clearTimeout(timer);
|
|
@@ -26999,7 +27388,8 @@ async function startAmaChild(parent, spec2, createChild, run7) {
|
|
|
26999
27388
|
}
|
|
27000
27389
|
const thinkingLevel = spec2.request.thinkingLevel ?? spec2.agent.thinking ?? base4.thinkingLevel ?? "off";
|
|
27001
27390
|
const wanted = spec2.resumeFile === void 0 && requestedContext(spec2.request, spec2.agent) === "fork";
|
|
27002
|
-
const
|
|
27391
|
+
const ratio = subagentRegistryFor(parent).env.modelConfig?.subagents?.forkMaxContextRatio;
|
|
27392
|
+
const plan2 = wanted ? forkPlan(parent, spec2, model, thinkingLevel, ratio) : void 0;
|
|
27003
27393
|
if (plan2 !== void 0 && "fallback" in plan2)
|
|
27004
27394
|
parent.log("info", `task ${spec2.taskId}: fork falls back to fresh (${plan2.fallback})`);
|
|
27005
27395
|
const forked = plan2 !== void 0 && "manager" in plan2 ? plan2.manager : void 0;
|
|
@@ -27012,6 +27402,10 @@ async function startAmaChild(parent, spec2, createChild, run7) {
|
|
|
27012
27402
|
const unavailable = inherited.filter(
|
|
27013
27403
|
(name) => !allowed.includes(name) && !PARENT_ONLY_TOOLS.includes(name)
|
|
27014
27404
|
);
|
|
27405
|
+
const briefUnavailable = [
|
|
27406
|
+
...unavailable,
|
|
27407
|
+
...PARENT_ONLY_TOOLS.filter((name) => inherited.includes(name))
|
|
27408
|
+
];
|
|
27015
27409
|
const options = {
|
|
27016
27410
|
...parent.options,
|
|
27017
27411
|
...base4,
|
|
@@ -27100,7 +27494,7 @@ async function startAmaChild(parent, spec2, createChild, run7) {
|
|
|
27100
27494
|
const first = forked === void 0 ? run7.prompt : forkBrief({
|
|
27101
27495
|
prompt: run7.prompt,
|
|
27102
27496
|
role: spec2.agent.prompt,
|
|
27103
|
-
unavailable,
|
|
27497
|
+
unavailable: briefUnavailable,
|
|
27104
27498
|
...spec2.isolated ? { worktree: { cwd: spec2.cwd, parentCwd: parent.cwd } } : {}
|
|
27105
27499
|
});
|
|
27106
27500
|
let current3 = runOnce(first, spec2.origin);
|
|
@@ -27328,6 +27722,7 @@ var init_session_extensions = __esm({
|
|
|
27328
27722
|
if (extension !== void 0) list5.push(extension);
|
|
27329
27723
|
}
|
|
27330
27724
|
this.list = list5;
|
|
27725
|
+
core.manager.setWarn((message) => core.log("warn", message));
|
|
27331
27726
|
}
|
|
27332
27727
|
get size() {
|
|
27333
27728
|
return this.list.length;
|
|
@@ -29168,16 +29563,16 @@ async function putBlob(dataDir, bytes, hash = hashBytes(bytes)) {
|
|
|
29168
29563
|
const target = blobPath(dataDir, hash);
|
|
29169
29564
|
if (await exists3(target)) {
|
|
29170
29565
|
const now = /* @__PURE__ */ new Date();
|
|
29171
|
-
await (0,
|
|
29566
|
+
await (0, import_promises12.utimes)(target, now, now).catch(() => void 0);
|
|
29172
29567
|
return hash;
|
|
29173
29568
|
}
|
|
29174
|
-
await (0,
|
|
29569
|
+
await (0, import_promises12.mkdir)((0, import_node_path47.dirname)(target), { recursive: true, mode: 448 });
|
|
29175
29570
|
const tmp = `${target}.tmp-${process.pid}-${tmpCounter++}`;
|
|
29176
29571
|
try {
|
|
29177
|
-
await (0,
|
|
29178
|
-
await (0,
|
|
29572
|
+
await (0, import_promises12.writeFile)(tmp, bytes, { mode: 384 });
|
|
29573
|
+
await (0, import_promises12.rename)(tmp, target);
|
|
29179
29574
|
} catch (error2) {
|
|
29180
|
-
await (0,
|
|
29575
|
+
await (0, import_promises12.rm)(tmp, { force: true });
|
|
29181
29576
|
if (await exists3(target)) return hash;
|
|
29182
29577
|
throw error2;
|
|
29183
29578
|
}
|
|
@@ -29185,7 +29580,7 @@ async function putBlob(dataDir, bytes, hash = hashBytes(bytes)) {
|
|
|
29185
29580
|
}
|
|
29186
29581
|
async function readBlob(dataDir, hash) {
|
|
29187
29582
|
try {
|
|
29188
|
-
return await (0,
|
|
29583
|
+
return await (0, import_promises12.readFile)(blobPath(dataDir, hash));
|
|
29189
29584
|
} catch (error2) {
|
|
29190
29585
|
if (isNotFound(error2)) return void 0;
|
|
29191
29586
|
throw error2;
|
|
@@ -29193,7 +29588,7 @@ async function readBlob(dataDir, hash) {
|
|
|
29193
29588
|
}
|
|
29194
29589
|
async function realParentOf(absolutePath) {
|
|
29195
29590
|
try {
|
|
29196
|
-
return await (0,
|
|
29591
|
+
return await (0, import_promises12.realpath)((0, import_node_path47.dirname)(absolutePath));
|
|
29197
29592
|
} catch (error2) {
|
|
29198
29593
|
if (isNotFound(error2)) return void 0;
|
|
29199
29594
|
throw error2;
|
|
@@ -29204,7 +29599,7 @@ async function recordFile(absolutePath, options) {
|
|
|
29204
29599
|
const max = options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES;
|
|
29205
29600
|
let info2;
|
|
29206
29601
|
try {
|
|
29207
|
-
info2 = await (0,
|
|
29602
|
+
info2 = await (0, import_promises12.lstat)(absolutePath);
|
|
29208
29603
|
} catch (error2) {
|
|
29209
29604
|
if (!isNotFound(error2)) throw error2;
|
|
29210
29605
|
const realParentDir2 = await realParentOf(absolutePath);
|
|
@@ -29218,7 +29613,7 @@ async function recordFile(absolutePath, options) {
|
|
|
29218
29613
|
const realParentDir = await realParentOf(absolutePath);
|
|
29219
29614
|
const base4 = { mode, size: info2.size, ...realParentDir !== void 0 ? { realParentDir } : {} };
|
|
29220
29615
|
if (info2.size > max) return { record: { blob: null, ...base4, skipped: "too_large" }, at };
|
|
29221
|
-
const bytes = await (0,
|
|
29616
|
+
const bytes = await (0, import_promises12.readFile)(absolutePath);
|
|
29222
29617
|
if (bytes.length > max)
|
|
29223
29618
|
return { record: { blob: null, ...base4, size: bytes.length, skipped: "too_large" }, at };
|
|
29224
29619
|
const blob = await putBlob(options.dataDir, bytes);
|
|
@@ -29245,7 +29640,7 @@ async function listBlobs(dataDir, includeTemp = false) {
|
|
|
29245
29640
|
const root = blobsDir(dataDir);
|
|
29246
29641
|
let shards;
|
|
29247
29642
|
try {
|
|
29248
|
-
shards = await (0,
|
|
29643
|
+
shards = await (0, import_promises12.readdir)(root);
|
|
29249
29644
|
} catch (error2) {
|
|
29250
29645
|
if (isNotFound(error2)) return [];
|
|
29251
29646
|
throw error2;
|
|
@@ -29255,7 +29650,7 @@ async function listBlobs(dataDir, includeTemp = false) {
|
|
|
29255
29650
|
if (!/^[0-9a-f]{2}$/.test(shard)) continue;
|
|
29256
29651
|
let names;
|
|
29257
29652
|
try {
|
|
29258
|
-
names = await (0,
|
|
29653
|
+
names = await (0, import_promises12.readdir)((0, import_node_path47.join)(root, shard));
|
|
29259
29654
|
} catch {
|
|
29260
29655
|
continue;
|
|
29261
29656
|
}
|
|
@@ -29264,7 +29659,7 @@ async function listBlobs(dataDir, includeTemp = false) {
|
|
|
29264
29659
|
if (!isBlob && !(includeTemp && name.includes(".tmp-"))) continue;
|
|
29265
29660
|
const path = (0, import_node_path47.join)(root, shard, name);
|
|
29266
29661
|
try {
|
|
29267
|
-
const info2 = await (0,
|
|
29662
|
+
const info2 = await (0, import_promises12.stat)(path);
|
|
29268
29663
|
if (!info2.isFile()) continue;
|
|
29269
29664
|
out.push({
|
|
29270
29665
|
path,
|
|
@@ -29283,19 +29678,19 @@ function isNotFound(error2) {
|
|
|
29283
29678
|
}
|
|
29284
29679
|
async function exists3(path) {
|
|
29285
29680
|
try {
|
|
29286
|
-
await (0,
|
|
29681
|
+
await (0, import_promises12.stat)(path);
|
|
29287
29682
|
return true;
|
|
29288
29683
|
} catch {
|
|
29289
29684
|
return false;
|
|
29290
29685
|
}
|
|
29291
29686
|
}
|
|
29292
|
-
var import_node_crypto9, import_node_fs34,
|
|
29687
|
+
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
29688
|
var init_blobs = __esm({
|
|
29294
29689
|
"src/checkpoints/blobs.ts"() {
|
|
29295
29690
|
"use strict";
|
|
29296
29691
|
import_node_crypto9 = require("node:crypto");
|
|
29297
29692
|
import_node_fs34 = require("node:fs");
|
|
29298
|
-
|
|
29693
|
+
import_promises12 = require("node:fs/promises");
|
|
29299
29694
|
import_node_path47 = require("node:path");
|
|
29300
29695
|
FILE_HISTORY_DIR = "file-history";
|
|
29301
29696
|
BLOBS_DIR = "blobs";
|
|
@@ -29311,7 +29706,7 @@ function rootsFile(dataDir) {
|
|
|
29311
29706
|
}
|
|
29312
29707
|
async function readSessionRoots(dataDir) {
|
|
29313
29708
|
try {
|
|
29314
|
-
const value = JSON.parse(await (0,
|
|
29709
|
+
const value = JSON.parse(await (0, import_promises13.readFile)(rootsFile(dataDir), "utf8"));
|
|
29315
29710
|
const roots = value?.roots;
|
|
29316
29711
|
return Array.isArray(roots) ? roots.filter((r) => typeof r === "string") : [];
|
|
29317
29712
|
} catch {
|
|
@@ -29323,18 +29718,18 @@ async function registerSessionRoot(dataDir, sessionsRoot) {
|
|
|
29323
29718
|
const roots = await readSessionRoots(dataDir);
|
|
29324
29719
|
if (roots.includes(root)) return;
|
|
29325
29720
|
const dir = fileHistoryDir(dataDir);
|
|
29326
|
-
await (0,
|
|
29721
|
+
await (0, import_promises13.mkdir)(dir, { recursive: true, mode: 448 });
|
|
29327
29722
|
const tmp = `${rootsFile(dataDir)}.tmp-${process.pid}`;
|
|
29328
|
-
await (0,
|
|
29723
|
+
await (0, import_promises13.writeFile)(tmp, `${JSON.stringify({ roots: [...roots, root] }, null, 2)}
|
|
29329
29724
|
`, {
|
|
29330
29725
|
mode: 384
|
|
29331
29726
|
});
|
|
29332
|
-
await (0,
|
|
29727
|
+
await (0, import_promises13.rename)(tmp, rootsFile(dataDir));
|
|
29333
29728
|
}
|
|
29334
29729
|
async function* sessionFiles(dir) {
|
|
29335
29730
|
let entries;
|
|
29336
29731
|
try {
|
|
29337
|
-
entries = await (0,
|
|
29732
|
+
entries = await (0, import_promises13.readdir)(dir, { withFileTypes: true });
|
|
29338
29733
|
} catch (error2) {
|
|
29339
29734
|
if (isNotFound(error2)) return;
|
|
29340
29735
|
throw error2;
|
|
@@ -29356,7 +29751,7 @@ async function collectBlobRefs(sessionRoots) {
|
|
|
29356
29751
|
for await (const file of sessionFiles(abs)) {
|
|
29357
29752
|
let text;
|
|
29358
29753
|
try {
|
|
29359
|
-
text = await (0,
|
|
29754
|
+
text = await (0, import_promises13.readFile)(file, "utf8");
|
|
29360
29755
|
} catch (error2) {
|
|
29361
29756
|
if (isNotFound(error2)) continue;
|
|
29362
29757
|
throw error2;
|
|
@@ -29389,7 +29784,7 @@ async function gcBlobs(options) {
|
|
|
29389
29784
|
if (old && unreferenced) {
|
|
29390
29785
|
if (options.dryRun !== true) {
|
|
29391
29786
|
try {
|
|
29392
|
-
await (0,
|
|
29787
|
+
await (0, import_promises13.rm)(blob.path, { force: true });
|
|
29393
29788
|
} catch {
|
|
29394
29789
|
continue;
|
|
29395
29790
|
}
|
|
@@ -29414,11 +29809,11 @@ function formatBytes2(bytes) {
|
|
|
29414
29809
|
}
|
|
29415
29810
|
return `${value.toFixed(value >= 10 ? 0 : 1)} ${units[unit]}`;
|
|
29416
29811
|
}
|
|
29417
|
-
var
|
|
29812
|
+
var import_promises13, import_node_path48, GC_MIN_AGE_MS, ROOTS_FILE, HASH_IN_LINE;
|
|
29418
29813
|
var init_gc = __esm({
|
|
29419
29814
|
"src/checkpoints/gc.ts"() {
|
|
29420
29815
|
"use strict";
|
|
29421
|
-
|
|
29816
|
+
import_promises13 = require("node:fs/promises");
|
|
29422
29817
|
import_node_path48 = require("node:path");
|
|
29423
29818
|
init_blobs();
|
|
29424
29819
|
init_types10();
|
|
@@ -29547,7 +29942,7 @@ var init_replay = __esm({
|
|
|
29547
29942
|
// src/checkpoints/git-head.ts
|
|
29548
29943
|
async function readText2(path) {
|
|
29549
29944
|
try {
|
|
29550
|
-
return await (0,
|
|
29945
|
+
return await (0, import_promises14.readFile)(path, "utf8");
|
|
29551
29946
|
} catch {
|
|
29552
29947
|
return void 0;
|
|
29553
29948
|
}
|
|
@@ -29557,7 +29952,7 @@ async function findGitDir(cwd) {
|
|
|
29557
29952
|
for (; ; ) {
|
|
29558
29953
|
const candidate = (0, import_node_path49.join)(dir, ".git");
|
|
29559
29954
|
try {
|
|
29560
|
-
const info2 = await (0,
|
|
29955
|
+
const info2 = await (0, import_promises14.stat)(candidate);
|
|
29561
29956
|
if (info2.isDirectory()) return candidate;
|
|
29562
29957
|
if (info2.isFile()) {
|
|
29563
29958
|
const text = await readText2(candidate) ?? "";
|
|
@@ -29605,11 +30000,11 @@ async function readGitHead(cwd) {
|
|
|
29605
30000
|
const branch = ref.startsWith("refs/heads/") ? ref.slice("refs/heads/".length) : void 0;
|
|
29606
30001
|
return { head: sha, ...branch !== void 0 ? { branch } : {} };
|
|
29607
30002
|
}
|
|
29608
|
-
var
|
|
30003
|
+
var import_promises14, import_node_path49, SHA;
|
|
29609
30004
|
var init_git_head = __esm({
|
|
29610
30005
|
"src/checkpoints/git-head.ts"() {
|
|
29611
30006
|
"use strict";
|
|
29612
|
-
|
|
30007
|
+
import_promises14 = require("node:fs/promises");
|
|
29613
30008
|
import_node_path49 = require("node:path");
|
|
29614
30009
|
SHA = /^[0-9a-f]{40}([0-9a-f]{24})?$/;
|
|
29615
30010
|
}
|
|
@@ -29629,7 +30024,7 @@ function emptyCodeResult() {
|
|
|
29629
30024
|
}
|
|
29630
30025
|
async function lstatOrUndefined(path) {
|
|
29631
30026
|
try {
|
|
29632
|
-
return await (0,
|
|
30027
|
+
return await (0, import_promises15.lstat)(path);
|
|
29633
30028
|
} catch (error2) {
|
|
29634
30029
|
if (isNotFound(error2)) return void 0;
|
|
29635
30030
|
throw error2;
|
|
@@ -29718,7 +30113,7 @@ async function restoreFile(abs, record3, options) {
|
|
|
29718
30113
|
await checkParent(abs, record3);
|
|
29719
30114
|
const targetBytes = record3.blob === null ? void 0 : await (options.load ?? ((r) => readBlob(options.dataDir, r.blob)))(record3);
|
|
29720
30115
|
if (record3.blob !== null && targetBytes === void 0) throw new Skip("backup_missing");
|
|
29721
|
-
const currentBytes = info2 !== void 0 && info2.size <= options.maxDiff ? await (0,
|
|
30116
|
+
const currentBytes = info2 !== void 0 && info2.size <= options.maxDiff ? await (0, import_promises15.readFile)(abs) : void 0;
|
|
29722
30117
|
const counted = info2 !== void 0 && currentBytes === void 0 ? { insertions: 0, deletions: 0 } : countLineChanges(toText(currentBytes), toText(targetBytes));
|
|
29723
30118
|
const outcome = { deleted: record3.blob === null, conflict, ...counted };
|
|
29724
30119
|
if (options.dryRun === true) return outcome;
|
|
@@ -29742,17 +30137,17 @@ async function removeRegular(abs, before2) {
|
|
|
29742
30137
|
if (now.nlink > 1) throw new Skip("hardlink");
|
|
29743
30138
|
if (now.dev !== before2.dev || now.ino !== before2.ino)
|
|
29744
30139
|
throw new Error(msg().session.checkpoints.replacedDuringRestore);
|
|
29745
|
-
await (0,
|
|
30140
|
+
await (0, import_promises15.unlink)(abs);
|
|
29746
30141
|
}
|
|
29747
30142
|
async function writeBack(abs, bytes, record3, before2) {
|
|
29748
30143
|
if (before2 === void 0) {
|
|
29749
30144
|
const parent = (0, import_node_path50.dirname)(abs);
|
|
29750
|
-
await (0,
|
|
29751
|
-
if (record3.realParentDir !== void 0 && await (0,
|
|
30145
|
+
await (0, import_promises15.mkdir)(parent, { recursive: true });
|
|
30146
|
+
if (record3.realParentDir !== void 0 && await (0, import_promises15.realpath)(parent) !== record3.realParentDir) {
|
|
29752
30147
|
throw new Skip("parent_moved");
|
|
29753
30148
|
}
|
|
29754
30149
|
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,
|
|
30150
|
+
const handle2 = await (0, import_promises15.open)(abs, flags2, record3.mode ?? 420);
|
|
29756
30151
|
try {
|
|
29757
30152
|
await handle2.writeFile(bytes);
|
|
29758
30153
|
if (record3.mode !== void 0) await handle2.chmod(record3.mode);
|
|
@@ -29763,7 +30158,7 @@ async function writeBack(abs, bytes, record3, before2) {
|
|
|
29763
30158
|
}
|
|
29764
30159
|
let handle;
|
|
29765
30160
|
try {
|
|
29766
|
-
handle = await (0,
|
|
30161
|
+
handle = await (0, import_promises15.open)(abs, import_node_fs35.constants.O_WRONLY | NOFOLLOW);
|
|
29767
30162
|
} catch (error2) {
|
|
29768
30163
|
const code = error2.code;
|
|
29769
30164
|
if (code === "ELOOP" || code === "EMLINK") throw new Skip("symlink");
|
|
@@ -29771,7 +30166,7 @@ async function writeBack(abs, bytes, record3, before2) {
|
|
|
29771
30166
|
}
|
|
29772
30167
|
try {
|
|
29773
30168
|
const opened = await handle.stat();
|
|
29774
|
-
const now = await (0,
|
|
30169
|
+
const now = await (0, import_promises15.lstat)(abs);
|
|
29775
30170
|
if (!opened.isFile() || opened.dev !== before2.dev || opened.ino !== before2.ino || now.dev !== opened.dev || now.ino !== opened.ino) {
|
|
29776
30171
|
throw new Error(msg().session.checkpoints.replacedDuringRestore);
|
|
29777
30172
|
}
|
|
@@ -29789,12 +30184,12 @@ async function gitHintFor(cwd, target) {
|
|
|
29789
30184
|
if (current3 === void 0 || current3.head === target.git.head) return void 0;
|
|
29790
30185
|
return { recordedHead: target.git.head, currentHead: current3.head };
|
|
29791
30186
|
}
|
|
29792
|
-
var import_node_fs35,
|
|
30187
|
+
var import_node_fs35, import_promises15, import_node_path50, RestoreSkip, Skip, IS_WINDOWS, NOFOLLOW;
|
|
29793
30188
|
var init_restore = __esm({
|
|
29794
30189
|
"src/checkpoints/restore.ts"() {
|
|
29795
30190
|
"use strict";
|
|
29796
30191
|
import_node_fs35 = require("node:fs");
|
|
29797
|
-
|
|
30192
|
+
import_promises15 = require("node:fs/promises");
|
|
29798
30193
|
import_node_path50 = require("node:path");
|
|
29799
30194
|
init_edit();
|
|
29800
30195
|
init_blobs();
|
|
@@ -29845,7 +30240,7 @@ async function shadowUsage(dataDir) {
|
|
|
29845
30240
|
const usage = { repos: 0, bytes: 0 };
|
|
29846
30241
|
let names;
|
|
29847
30242
|
try {
|
|
29848
|
-
names = await (0,
|
|
30243
|
+
names = await (0, import_promises16.readdir)(shadowRoot(dataDir));
|
|
29849
30244
|
} catch {
|
|
29850
30245
|
return usage;
|
|
29851
30246
|
}
|
|
@@ -29861,7 +30256,7 @@ async function duBytes(dir) {
|
|
|
29861
30256
|
let total = 0;
|
|
29862
30257
|
let entries;
|
|
29863
30258
|
try {
|
|
29864
|
-
entries = await (0,
|
|
30259
|
+
entries = await (0, import_promises16.readdir)(dir, { withFileTypes: true });
|
|
29865
30260
|
} catch {
|
|
29866
30261
|
return 0;
|
|
29867
30262
|
}
|
|
@@ -29870,7 +30265,7 @@ async function duBytes(dir) {
|
|
|
29870
30265
|
if (entry.isDirectory()) total += await duBytes(full);
|
|
29871
30266
|
else if (entry.isFile()) {
|
|
29872
30267
|
try {
|
|
29873
|
-
total += (await (0,
|
|
30268
|
+
total += (await (0, import_promises16.stat)(full)).size;
|
|
29874
30269
|
} catch {
|
|
29875
30270
|
}
|
|
29876
30271
|
}
|
|
@@ -29954,7 +30349,7 @@ function excludeLine(path) {
|
|
|
29954
30349
|
async function removeStaleIndexes(dir) {
|
|
29955
30350
|
let names;
|
|
29956
30351
|
try {
|
|
29957
|
-
names = await (0,
|
|
30352
|
+
names = await (0, import_promises16.readdir)(dir);
|
|
29958
30353
|
} catch {
|
|
29959
30354
|
return;
|
|
29960
30355
|
}
|
|
@@ -29963,7 +30358,7 @@ async function removeStaleIndexes(dir) {
|
|
|
29963
30358
|
if (match === null) continue;
|
|
29964
30359
|
const pid = Number(match[1]);
|
|
29965
30360
|
if (pid === process.pid || isAlive(pid)) continue;
|
|
29966
|
-
await (0,
|
|
30361
|
+
await (0, import_promises16.rm)((0, import_node_path51.join)(dir, name), { force: true }).catch(() => void 0);
|
|
29967
30362
|
}
|
|
29968
30363
|
}
|
|
29969
30364
|
function isAlive(pid) {
|
|
@@ -29976,7 +30371,7 @@ function isAlive(pid) {
|
|
|
29976
30371
|
}
|
|
29977
30372
|
async function exists4(path) {
|
|
29978
30373
|
try {
|
|
29979
|
-
await (0,
|
|
30374
|
+
await (0, import_promises16.stat)(path);
|
|
29980
30375
|
return true;
|
|
29981
30376
|
} catch {
|
|
29982
30377
|
return false;
|
|
@@ -29984,18 +30379,18 @@ async function exists4(path) {
|
|
|
29984
30379
|
}
|
|
29985
30380
|
async function readSmall2(path) {
|
|
29986
30381
|
try {
|
|
29987
|
-
return (await (0,
|
|
30382
|
+
return (await (0, import_promises16.readFile)(path, "utf8")).trim();
|
|
29988
30383
|
} catch {
|
|
29989
30384
|
return void 0;
|
|
29990
30385
|
}
|
|
29991
30386
|
}
|
|
29992
|
-
var import_node_child_process7, import_node_crypto10,
|
|
30387
|
+
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, SHADOW_SLOW_STREAK, GIT_TIMEOUT_MS, CONFIG_VERSION, IDENTITY, ATTRIBUTES, GitMissingError, MODE_ABSENT, MODE_SYMLINK, MODE_GITLINK, MODE_EXECUTABLE, queues2, ShadowRepo;
|
|
29993
30388
|
var init_shadow_git = __esm({
|
|
29994
30389
|
"src/checkpoints/shadow-git.ts"() {
|
|
29995
30390
|
"use strict";
|
|
29996
30391
|
import_node_child_process7 = require("node:child_process");
|
|
29997
30392
|
import_node_crypto10 = require("node:crypto");
|
|
29998
|
-
|
|
30393
|
+
import_promises16 = require("node:fs/promises");
|
|
29999
30394
|
import_node_os10 = require("node:os");
|
|
30000
30395
|
import_node_path51 = require("node:path");
|
|
30001
30396
|
init_blobs();
|
|
@@ -30003,6 +30398,7 @@ var init_shadow_git = __esm({
|
|
|
30003
30398
|
SHADOW_DIR = "shadow";
|
|
30004
30399
|
SHADOW_MAX_FILES = 2e4;
|
|
30005
30400
|
SHADOW_MAX_SNAPSHOT_MS = 3e3;
|
|
30401
|
+
SHADOW_SLOW_STREAK = 2;
|
|
30006
30402
|
GIT_TIMEOUT_MS = 6e4;
|
|
30007
30403
|
CONFIG_VERSION = "1";
|
|
30008
30404
|
IDENTITY = { name: "ama", email: "ama@localhost" };
|
|
@@ -30028,6 +30424,8 @@ var init_shadow_git = __esm({
|
|
|
30028
30424
|
indexFile;
|
|
30029
30425
|
initialized;
|
|
30030
30426
|
counted = false;
|
|
30427
|
+
/** 连续超时的快照数(首次快照不计),到 `SHADOW_SLOW_STREAK` 才降级。 */
|
|
30428
|
+
slowStreak = 0;
|
|
30031
30429
|
constructor(dataDir, cwd, options = {}) {
|
|
30032
30430
|
this.cwd = (0, import_node_path51.resolve)(cwd);
|
|
30033
30431
|
this.dir = shadowRepoDir(dataDir, this.cwd);
|
|
@@ -30079,9 +30477,9 @@ var init_shadow_git = __esm({
|
|
|
30079
30477
|
}
|
|
30080
30478
|
async doInit() {
|
|
30081
30479
|
const hooks = (0, import_node_path51.join)(this.dir, "ama-hooks");
|
|
30082
|
-
await (0,
|
|
30083
|
-
await (0,
|
|
30084
|
-
await (0,
|
|
30480
|
+
await (0, import_promises16.mkdir)(hooks, { recursive: true, mode: 448 });
|
|
30481
|
+
await (0, import_promises16.writeFile)((0, import_node_path51.join)(this.dir, "ama-empty"), "", { flag: "a", mode: 384 });
|
|
30482
|
+
await (0, import_promises16.writeFile)((0, import_node_path51.join)(this.dir, "ama-cwd"), `${this.cwd}
|
|
30085
30483
|
`, { mode: 384 });
|
|
30086
30484
|
const version = await readSmall2((0, import_node_path51.join)(this.dir, "ama-config-version"));
|
|
30087
30485
|
if (version !== CONFIG_VERSION) {
|
|
@@ -30112,9 +30510,9 @@ var init_shadow_git = __esm({
|
|
|
30112
30510
|
["user.useConfigOnly", "true"]
|
|
30113
30511
|
];
|
|
30114
30512
|
for (const [key, value] of config) await this.run(["config", key, value]);
|
|
30115
|
-
await (0,
|
|
30116
|
-
await (0,
|
|
30117
|
-
await (0,
|
|
30513
|
+
await (0, import_promises16.mkdir)((0, import_node_path51.join)(this.dir, "info"), { recursive: true });
|
|
30514
|
+
await (0, import_promises16.writeFile)((0, import_node_path51.join)(this.dir, "info", "attributes"), ATTRIBUTES);
|
|
30515
|
+
await (0, import_promises16.writeFile)((0, import_node_path51.join)(this.dir, "ama-config-version"), CONFIG_VERSION);
|
|
30118
30516
|
}
|
|
30119
30517
|
await removeStaleIndexes(this.dir);
|
|
30120
30518
|
}
|
|
@@ -30133,8 +30531,8 @@ var init_shadow_git = __esm({
|
|
|
30133
30531
|
} catch (error2) {
|
|
30134
30532
|
if (error2 instanceof GitMissingError) throw error2;
|
|
30135
30533
|
}
|
|
30136
|
-
await (0,
|
|
30137
|
-
await (0,
|
|
30534
|
+
await (0, import_promises16.mkdir)((0, import_node_path51.join)(this.dir, "info"), { recursive: true });
|
|
30535
|
+
await (0, import_promises16.writeFile)((0, import_node_path51.join)(this.dir, "info", "exclude"), `${lines2.join("\n")}
|
|
30138
30536
|
`);
|
|
30139
30537
|
}
|
|
30140
30538
|
/** 把工作区收进索引并写树,返回树 id(调用前已 writeExcludes)。 */
|
|
@@ -30147,6 +30545,7 @@ var init_shadow_git = __esm({
|
|
|
30147
30545
|
return exclusive(this.dir, async () => {
|
|
30148
30546
|
await this.init();
|
|
30149
30547
|
const started = this.now();
|
|
30548
|
+
const first = !this.counted;
|
|
30150
30549
|
await this.writeExcludes();
|
|
30151
30550
|
if (!this.counted) {
|
|
30152
30551
|
const out = await this.run([
|
|
@@ -30172,7 +30571,9 @@ var init_shadow_git = __esm({
|
|
|
30172
30571
|
if (parent !== void 0 && await this.hasCommitUnlocked(parent)) args.push("-p", parent);
|
|
30173
30572
|
const commit = await this.text(args);
|
|
30174
30573
|
const elapsed = this.now() - started;
|
|
30175
|
-
if (
|
|
30574
|
+
if (first) return { commit };
|
|
30575
|
+
this.slowStreak = elapsed > this.maxSnapshotMs ? this.slowStreak + 1 : 0;
|
|
30576
|
+
if (this.slowStreak >= SHADOW_SLOW_STREAK) {
|
|
30176
30577
|
return {
|
|
30177
30578
|
commit,
|
|
30178
30579
|
degrade: {
|
|
@@ -30291,7 +30692,7 @@ async function restoreFromShadow(options) {
|
|
|
30291
30692
|
changes.filter((c) => isRegularMode(c.oldMode)).map((c) => c.oldOid),
|
|
30292
30693
|
maxBytes
|
|
30293
30694
|
);
|
|
30294
|
-
const realCwd = await (0,
|
|
30695
|
+
const realCwd = await (0, import_promises17.realpath)(options.cwd);
|
|
30295
30696
|
const latest = latestCheckpoint(options.state);
|
|
30296
30697
|
const result = emptyCodeResult();
|
|
30297
30698
|
const touched = [];
|
|
@@ -30342,7 +30743,7 @@ function isRegularMode(mode) {
|
|
|
30342
30743
|
async function targetRecord(change, abs, realCwd, blobs) {
|
|
30343
30744
|
const slash = change.path.lastIndexOf("/");
|
|
30344
30745
|
const realParentDir = slash < 0 ? realCwd : (0, import_node_path52.join)(realCwd, ...change.path.slice(0, slash).split("/"));
|
|
30345
|
-
const info2 = await (0,
|
|
30746
|
+
const info2 = await (0, import_promises17.lstat)(abs).catch(() => void 0);
|
|
30346
30747
|
if (change.newMode === MODE_ABSENT && info2 !== void 0) {
|
|
30347
30748
|
return void 0;
|
|
30348
30749
|
}
|
|
@@ -30375,11 +30776,11 @@ function merge(into, from) {
|
|
|
30375
30776
|
into.insertions += from.insertions;
|
|
30376
30777
|
into.deletions += from.deletions;
|
|
30377
30778
|
}
|
|
30378
|
-
var
|
|
30779
|
+
var import_promises17, import_node_path52, IS_WINDOWS2;
|
|
30379
30780
|
var init_shadow_restore = __esm({
|
|
30380
30781
|
"src/checkpoints/shadow-restore.ts"() {
|
|
30381
30782
|
"use strict";
|
|
30382
|
-
|
|
30783
|
+
import_promises17 = require("node:fs/promises");
|
|
30383
30784
|
import_node_path52 = require("node:path");
|
|
30384
30785
|
init_blobs();
|
|
30385
30786
|
init_replay();
|
|
@@ -30394,11 +30795,11 @@ var init_shadow_restore = __esm({
|
|
|
30394
30795
|
function describe2(error2) {
|
|
30395
30796
|
return error2 instanceof Error ? error2.message : String(error2);
|
|
30396
30797
|
}
|
|
30397
|
-
var
|
|
30798
|
+
var import_promises18, MTIME_GRANULARITY_MS, CheckpointTracker;
|
|
30398
30799
|
var init_tracker = __esm({
|
|
30399
30800
|
"src/checkpoints/tracker.ts"() {
|
|
30400
30801
|
"use strict";
|
|
30401
|
-
|
|
30802
|
+
import_promises18 = require("node:fs/promises");
|
|
30402
30803
|
init_git_head();
|
|
30403
30804
|
init_blobs();
|
|
30404
30805
|
init_replay();
|
|
@@ -30510,7 +30911,7 @@ var init_tracker = __esm({
|
|
|
30510
30911
|
const at = this.now();
|
|
30511
30912
|
let info2;
|
|
30512
30913
|
try {
|
|
30513
|
-
info2 = await (0,
|
|
30914
|
+
info2 = await (0, import_promises18.lstat)(absolutePath);
|
|
30514
30915
|
} catch (error2) {
|
|
30515
30916
|
if (!isNotFound(error2)) throw error2;
|
|
30516
30917
|
if (prev !== void 0 && prev.record.blob === null && prev.record.skipped === void 0)
|
|
@@ -30541,7 +30942,7 @@ var init_tracker = __esm({
|
|
|
30541
30942
|
return prev;
|
|
30542
30943
|
return { record: { blob: null, ...base4, skipped: "too_large" }, at };
|
|
30543
30944
|
}
|
|
30544
|
-
const bytes = await (0,
|
|
30945
|
+
const bytes = await (0, import_promises18.readFile)(absolutePath);
|
|
30545
30946
|
const hash = hashBytes(bytes);
|
|
30546
30947
|
if (p !== void 0 && p.blob === hash && p.mode === mode && p.realParentDir === realParentDir) {
|
|
30547
30948
|
return { record: p, at };
|
|
@@ -30863,7 +31264,7 @@ function formatSkillInvocation(skill, body, args) {
|
|
|
30863
31264
|
|
|
30864
31265
|
${args}`;
|
|
30865
31266
|
}
|
|
30866
|
-
async function expandSkillCommand(text, skills, read2 = (p) => (0,
|
|
31267
|
+
async function expandSkillCommand(text, skills, read2 = (p) => (0, import_promises19.readFile)(p, "utf8")) {
|
|
30867
31268
|
const cmd = parseSkillCommand(text);
|
|
30868
31269
|
if (!cmd) return void 0;
|
|
30869
31270
|
const skill = skills.find((s2) => s2.name === cmd.name);
|
|
@@ -30871,11 +31272,11 @@ async function expandSkillCommand(text, skills, read2 = (p) => (0, import_promis
|
|
|
30871
31272
|
const body = skillBody(await read2(skill.location));
|
|
30872
31273
|
return { kind: "expanded", text: formatSkillInvocation(skill, body, cmd.args), skill };
|
|
30873
31274
|
}
|
|
30874
|
-
var
|
|
31275
|
+
var import_promises19;
|
|
30875
31276
|
var init_expand = __esm({
|
|
30876
31277
|
"src/skills/expand.ts"() {
|
|
30877
31278
|
"use strict";
|
|
30878
|
-
|
|
31279
|
+
import_promises19 = require("node:fs/promises");
|
|
30879
31280
|
init_frontmatter2();
|
|
30880
31281
|
init_index_prompt();
|
|
30881
31282
|
}
|
|
@@ -30901,8 +31302,8 @@ async function discoverPromptTemplates(sources, options) {
|
|
|
30901
31302
|
for (const source of sources) {
|
|
30902
31303
|
let names;
|
|
30903
31304
|
try {
|
|
30904
|
-
if (!(await (0,
|
|
30905
|
-
names = await (0,
|
|
31305
|
+
if (!(await (0, import_promises20.stat)(source.dir)).isDirectory()) continue;
|
|
31306
|
+
names = await (0, import_promises20.readdir)(source.dir);
|
|
30906
31307
|
} catch {
|
|
30907
31308
|
continue;
|
|
30908
31309
|
}
|
|
@@ -30924,8 +31325,8 @@ async function discoverPromptTemplates(sources, options) {
|
|
|
30924
31325
|
}
|
|
30925
31326
|
let text;
|
|
30926
31327
|
try {
|
|
30927
|
-
if (!(await (0,
|
|
30928
|
-
text = await (0,
|
|
31328
|
+
if (!(await (0, import_promises20.stat)(path)).isFile()) continue;
|
|
31329
|
+
text = await (0, import_promises20.readFile)(path, "utf8");
|
|
30929
31330
|
} catch {
|
|
30930
31331
|
continue;
|
|
30931
31332
|
}
|
|
@@ -31012,7 +31413,7 @@ function parsePromptCommand(text) {
|
|
|
31012
31413
|
const rawArgs = (m[2] ?? "").trim();
|
|
31013
31414
|
return { name: m[1], args: parseCommandArgs(rawArgs), rawArgs };
|
|
31014
31415
|
}
|
|
31015
|
-
async function expandPromptCommand(text, templates, read2 = (p) => (0,
|
|
31416
|
+
async function expandPromptCommand(text, templates, read2 = (p) => (0, import_promises20.readFile)(p, "utf8")) {
|
|
31016
31417
|
const cmd = parsePromptCommand(text);
|
|
31017
31418
|
if (!cmd) return void 0;
|
|
31018
31419
|
const template2 = templates.find((t) => t.name === cmd.name);
|
|
@@ -31020,11 +31421,11 @@ async function expandPromptCommand(text, templates, read2 = (p) => (0, import_pr
|
|
|
31020
31421
|
const body = parseFrontmatter(await read2(template2.path)).body.replace(/^\n+/, "");
|
|
31021
31422
|
return { text: expandTemplate(body, cmd.args), template: template2 };
|
|
31022
31423
|
}
|
|
31023
|
-
var
|
|
31424
|
+
var import_promises20, import_node_path53, TEMPLATE_NAME_RE, PLACEHOLDER;
|
|
31024
31425
|
var init_templates = __esm({
|
|
31025
31426
|
"src/skills/templates.ts"() {
|
|
31026
31427
|
"use strict";
|
|
31027
|
-
|
|
31428
|
+
import_promises20 = require("node:fs/promises");
|
|
31028
31429
|
import_node_path53 = require("node:path");
|
|
31029
31430
|
init_frontmatter2();
|
|
31030
31431
|
TEMPLATE_NAME_RE = /^[a-z0-9][a-z0-9_-]*$/i;
|
|
@@ -31087,7 +31488,9 @@ function openSession(request, context) {
|
|
|
31087
31488
|
return file === void 0 ? SessionManager.create(dir, cwd, { id: request.id }) : SessionManager.open(file);
|
|
31088
31489
|
}
|
|
31089
31490
|
case "fork": {
|
|
31090
|
-
const source = SessionManager.open(requireFile(root, request.id, cwd)
|
|
31491
|
+
const source = SessionManager.open(requireFile(root, request.id, cwd), {
|
|
31492
|
+
warn: (message) => context.log?.("warn", message)
|
|
31493
|
+
});
|
|
31091
31494
|
try {
|
|
31092
31495
|
const leaf = source.leafId();
|
|
31093
31496
|
if (leaf === null)
|
|
@@ -31103,9 +31506,9 @@ function listSessions(context) {
|
|
|
31103
31506
|
const dirs = context.cwd === void 0 ? cwdDirs(context.sessionDir) : [sessionDirForCwd(context.sessionDir, context.cwd)];
|
|
31104
31507
|
return dirs.flatMap((dir) => SessionManager.list(dir)).filter((item) => context.includeSubagents === true || item.subagent !== true).sort((a, b) => b.modifiedAt.localeCompare(a.modifiedAt));
|
|
31105
31508
|
}
|
|
31106
|
-
function createSessionStore() {
|
|
31509
|
+
function createSessionStore(log) {
|
|
31107
31510
|
return {
|
|
31108
|
-
open: (request, context) => openSession(request, context),
|
|
31511
|
+
open: (request, context) => openSession(request, { ...context, log }),
|
|
31109
31512
|
list: async (context) => listSessions(context),
|
|
31110
31513
|
show: async (id, context) => {
|
|
31111
31514
|
const file = requireFile(context.sessionDir, id);
|
|
@@ -31256,8 +31659,8 @@ function candidates(items) {
|
|
|
31256
31659
|
}
|
|
31257
31660
|
return out;
|
|
31258
31661
|
}
|
|
31259
|
-
function budgetReplacement(content,
|
|
31260
|
-
return content.map((block) => block.type === "text" ? block.text :
|
|
31662
|
+
function budgetReplacement(content, placeholder2 = IMAGE_OMITTED_FOR_BUDGET) {
|
|
31663
|
+
return content.map((block) => block.type === "text" ? block.text : placeholder2).filter((text) => text !== "").join("\n");
|
|
31261
31664
|
}
|
|
31262
31665
|
function base64ImageSize(block) {
|
|
31263
31666
|
const cached = sizeCache.get(block);
|
|
@@ -31272,10 +31675,10 @@ function planImageBudget(items, budgetBytes, options = {}) {
|
|
|
31272
31675
|
const all = candidates(items);
|
|
31273
31676
|
const plan2 = [];
|
|
31274
31677
|
const drop = (c, cause) => {
|
|
31275
|
-
const
|
|
31678
|
+
const placeholder2 = cause === "per_image" ? IMAGE_OMITTED_TOO_LARGE : IMAGE_OMITTED_FOR_BUDGET;
|
|
31276
31679
|
plan2.push({
|
|
31277
31680
|
targetId: c.targetId,
|
|
31278
|
-
replacement: budgetReplacement(c.content,
|
|
31681
|
+
replacement: budgetReplacement(c.content, placeholder2),
|
|
31279
31682
|
cause,
|
|
31280
31683
|
images: c.images.length,
|
|
31281
31684
|
bytes: c.bytes
|
|
@@ -31809,7 +32212,7 @@ var init_done_markers = __esm({
|
|
|
31809
32212
|
function extractProposedPlan(text) {
|
|
31810
32213
|
const lines2 = text.split(/\r?\n/);
|
|
31811
32214
|
let fence2;
|
|
31812
|
-
let
|
|
32215
|
+
let open3;
|
|
31813
32216
|
let last;
|
|
31814
32217
|
for (const [i, line2] of lines2.entries()) {
|
|
31815
32218
|
const marker = FENCE.exec(line2)?.[1];
|
|
@@ -31820,10 +32223,10 @@ function extractProposedPlan(text) {
|
|
|
31820
32223
|
}
|
|
31821
32224
|
if (fence2 !== void 0) continue;
|
|
31822
32225
|
const trimmed = line2.trim();
|
|
31823
|
-
if (trimmed === PLAN_OPEN_TAG)
|
|
31824
|
-
else if (trimmed === PLAN_CLOSE_TAG &&
|
|
31825
|
-
last = { from:
|
|
31826
|
-
|
|
32226
|
+
if (trimmed === PLAN_OPEN_TAG) open3 = i;
|
|
32227
|
+
else if (trimmed === PLAN_CLOSE_TAG && open3 !== void 0) {
|
|
32228
|
+
last = { from: open3 + 1, to: i };
|
|
32229
|
+
open3 = void 0;
|
|
31827
32230
|
}
|
|
31828
32231
|
}
|
|
31829
32232
|
if (last === void 0) return void 0;
|
|
@@ -37196,7 +37599,7 @@ function permissionModes(currentModeId) {
|
|
|
37196
37599
|
}))
|
|
37197
37600
|
};
|
|
37198
37601
|
}
|
|
37199
|
-
function
|
|
37602
|
+
function contentOf2(content) {
|
|
37200
37603
|
if (typeof content === "string") return content === "" ? [] : [{ type: "text", text: content }];
|
|
37201
37604
|
const out = [];
|
|
37202
37605
|
for (const block of content) {
|
|
@@ -37418,7 +37821,7 @@ var init_acp_events = __esm({
|
|
|
37418
37821
|
for (const message of messages) {
|
|
37419
37822
|
if (!("role" in message)) continue;
|
|
37420
37823
|
if (message.role === "user") {
|
|
37421
|
-
for (const block of
|
|
37824
|
+
for (const block of contentOf2(message.content))
|
|
37422
37825
|
this.emit({ sessionUpdate: "user_message_chunk", content: block });
|
|
37423
37826
|
} else if (message.role === "assistant") {
|
|
37424
37827
|
for (const block of message.content) {
|
|
@@ -37825,10 +38228,11 @@ function pageSessions(items, cursor, pageSize = LIST_PAGE_SIZE) {
|
|
|
37825
38228
|
const last = all[start + pageSize - 1];
|
|
37826
38229
|
return start + pageSize < all.length && last !== void 0 ? { sessions, nextCursor: encodeCursor(last.updatedAt, last.sessionId) } : { sessions };
|
|
37827
38230
|
}
|
|
37828
|
-
async function promptWhenIdle(session, job) {
|
|
38231
|
+
async function promptWhenIdle(session, job, onStart) {
|
|
37829
38232
|
for (; ; ) {
|
|
37830
38233
|
await session.waitForIdle();
|
|
37831
38234
|
if (job.cancelRequested) return;
|
|
38235
|
+
onStart?.();
|
|
37832
38236
|
try {
|
|
37833
38237
|
await session.prompt(job.text, job.images.length > 0 ? { images: job.images } : {});
|
|
37834
38238
|
return;
|
|
@@ -37837,10 +38241,36 @@ async function promptWhenIdle(session, job) {
|
|
|
37837
38241
|
}
|
|
37838
38242
|
}
|
|
37839
38243
|
}
|
|
37840
|
-
|
|
38244
|
+
async function idleNow(session) {
|
|
38245
|
+
return await Promise.race([session.waitForIdle(), Promise.resolve(BUSY)]) !== BUSY;
|
|
38246
|
+
}
|
|
38247
|
+
async function quiesce(session, control, rounds = 50) {
|
|
38248
|
+
for (const task of control?.list() ?? [])
|
|
38249
|
+
if (task.status === "running") await control?.stop(task.taskId).catch(() => void 0);
|
|
38250
|
+
for (let i = 0; i < rounds; i++) {
|
|
38251
|
+
await session.abort();
|
|
38252
|
+
await new Promise((resolve41) => setImmediate(resolve41));
|
|
38253
|
+
if (await idleNow(session)) return true;
|
|
38254
|
+
}
|
|
38255
|
+
return false;
|
|
38256
|
+
}
|
|
38257
|
+
async function disposeQuiet(runtime, session, fallback, control, retries = 3) {
|
|
38258
|
+
for (let i = 0; ; i++) {
|
|
38259
|
+
try {
|
|
38260
|
+
await disposeSessionAlongside(runtime, session, fallback);
|
|
38261
|
+
break;
|
|
38262
|
+
} catch (error2) {
|
|
38263
|
+
if (i >= retries || !(error2 instanceof AmaError && error2.code === "busy")) throw error2;
|
|
38264
|
+
await quiesce(session, control);
|
|
38265
|
+
}
|
|
38266
|
+
}
|
|
38267
|
+
await session.abort();
|
|
38268
|
+
}
|
|
38269
|
+
var LIST_PAGE_SIZE, TITLE_LIMIT, ZERO_USAGE2, PromptQueue, BUSY;
|
|
37841
38270
|
var init_acp_sessions = __esm({
|
|
37842
38271
|
"src/modes/acp/acp-sessions.ts"() {
|
|
37843
38272
|
"use strict";
|
|
38273
|
+
init_compose_session();
|
|
37844
38274
|
init_types7();
|
|
37845
38275
|
init_jsonrpc();
|
|
37846
38276
|
init_errors();
|
|
@@ -37908,6 +38338,7 @@ var init_acp_sessions = __esm({
|
|
|
37908
38338
|
});
|
|
37909
38339
|
}
|
|
37910
38340
|
};
|
|
38341
|
+
BUSY = /* @__PURE__ */ Symbol("busy");
|
|
37911
38342
|
}
|
|
37912
38343
|
});
|
|
37913
38344
|
|
|
@@ -37955,6 +38386,7 @@ var init_acp_server = __esm({
|
|
|
37955
38386
|
init_compose_session();
|
|
37956
38387
|
init_compose_store();
|
|
37957
38388
|
init_session2();
|
|
38389
|
+
init_task_control();
|
|
37958
38390
|
init_jsonrpc();
|
|
37959
38391
|
init_types7();
|
|
37960
38392
|
init_modes();
|
|
@@ -38052,13 +38484,14 @@ var init_acp_server = __esm({
|
|
|
38052
38484
|
if (abort)
|
|
38053
38485
|
await this.session().abort().catch(() => void 0);
|
|
38054
38486
|
await this.queue.settled();
|
|
38055
|
-
for (const
|
|
38487
|
+
for (const s2 of this.sessions())
|
|
38488
|
+
if (s2 instanceof AgentSessionImpl) await quiesce(s2, taskControl(s2.state.sessionId));
|
|
38056
38489
|
const foreground = this.session();
|
|
38057
38490
|
for (const entry of this.pool.values()) entry.unsubscribe();
|
|
38058
38491
|
for (const session of this.sessions()) {
|
|
38059
38492
|
if (session === foreground || !(session instanceof AgentSessionImpl)) continue;
|
|
38060
38493
|
if (!(foreground instanceof AgentSessionImpl)) continue;
|
|
38061
|
-
await
|
|
38494
|
+
await disposeQuiet(this.runtime, session, foreground).catch(() => void 0);
|
|
38062
38495
|
}
|
|
38063
38496
|
this.pool.clear();
|
|
38064
38497
|
this.standby = void 0;
|
|
@@ -38194,12 +38627,9 @@ var init_acp_server = __esm({
|
|
|
38194
38627
|
if (entry === void 0) return {};
|
|
38195
38628
|
this.pool.delete(id);
|
|
38196
38629
|
this.queue.cancelQueued(id);
|
|
38197
|
-
|
|
38198
|
-
|
|
38199
|
-
|
|
38200
|
-
await entry.session.abort().catch(() => void 0);
|
|
38201
|
-
await this.queue.settled(id);
|
|
38202
|
-
}
|
|
38630
|
+
if (this.queue.running?.sessionId === id) this.queue.running.cancelRequested = true;
|
|
38631
|
+
await quiesce(entry.session, taskControl(id));
|
|
38632
|
+
await this.queue.settled(id);
|
|
38203
38633
|
entry.unsubscribe();
|
|
38204
38634
|
let fallback = this.session();
|
|
38205
38635
|
if (fallback === entry.session) {
|
|
@@ -38211,7 +38641,7 @@ var init_acp_server = __esm({
|
|
|
38211
38641
|
}
|
|
38212
38642
|
}
|
|
38213
38643
|
if (fallback instanceof AgentSessionImpl)
|
|
38214
|
-
await
|
|
38644
|
+
await disposeQuiet(this.runtime, entry.session, fallback, taskControl(id));
|
|
38215
38645
|
return {};
|
|
38216
38646
|
}
|
|
38217
38647
|
async prompt(params, signal) {
|
|
@@ -38250,15 +38680,15 @@ var init_acp_server = __esm({
|
|
|
38250
38680
|
const { session } = entry;
|
|
38251
38681
|
setForegroundSession(this.runtime, session);
|
|
38252
38682
|
if (this.runtime.permission.mode !== entry.mode) session.setPermissionMode(entry.mode);
|
|
38253
|
-
|
|
38683
|
+
let before2 = session.getStats().tokens;
|
|
38254
38684
|
let failure2;
|
|
38255
38685
|
try {
|
|
38256
|
-
await promptWhenIdle(session, job);
|
|
38686
|
+
await promptWhenIdle(session, job, () => void (before2 = session.getStats().tokens));
|
|
38257
38687
|
} catch (error2) {
|
|
38258
38688
|
failure2 = error2;
|
|
38259
38689
|
}
|
|
38260
|
-
await this.peer.flush();
|
|
38261
38690
|
const after = session.getStats().tokens;
|
|
38691
|
+
await this.peer.flush();
|
|
38262
38692
|
const usage = {
|
|
38263
38693
|
inputTokens: after.input - before2.input,
|
|
38264
38694
|
outputTokens: after.output - before2.output,
|
|
@@ -38668,7 +39098,7 @@ async function bootstrap(argsIn, deps, io) {
|
|
|
38668
39098
|
request = { kind: "resume", id };
|
|
38669
39099
|
}
|
|
38670
39100
|
const sessionRequest = request;
|
|
38671
|
-
|
|
39101
|
+
let sessionManager = await step(
|
|
38672
39102
|
ExitCode.Session,
|
|
38673
39103
|
m().steps.session,
|
|
38674
39104
|
() => deps.sessions.open(sessionRequest, { sessionDir: paths.sessionDir, cwd: paths.cwd })
|
|
@@ -38893,6 +39323,8 @@ async function bootstrap(argsIn, deps, io) {
|
|
|
38893
39323
|
uiBroker: () => uiBroker,
|
|
38894
39324
|
onSessionReplaced: (next) => {
|
|
38895
39325
|
session = next;
|
|
39326
|
+
sessionManager = next.manager ?? sessionManager;
|
|
39327
|
+
assembly.sessionManager = sessionManager;
|
|
38896
39328
|
},
|
|
38897
39329
|
sessionStartContext: () => sessionStartContext,
|
|
38898
39330
|
unattended,
|
|
@@ -38922,7 +39354,7 @@ async function bootstrap(argsIn, deps, io) {
|
|
|
38922
39354
|
await events.emit("session_shutdown", {});
|
|
38923
39355
|
await hooks.run("SessionEnd", { reason }).catch(() => void 0);
|
|
38924
39356
|
await disposeHost(host, (e) => warn2(m().hostDisposeFailed(String(e))));
|
|
38925
|
-
await
|
|
39357
|
+
await session?.dispose();
|
|
38926
39358
|
})();
|
|
38927
39359
|
return disposed2;
|
|
38928
39360
|
};
|
|
@@ -38955,8 +39387,13 @@ async function bootstrap(argsIn, deps, io) {
|
|
|
38955
39387
|
providers,
|
|
38956
39388
|
model,
|
|
38957
39389
|
thinkingLevel,
|
|
38958
|
-
|
|
38959
|
-
|
|
39390
|
+
// [#165] 跟随当前会话(ACP 关掉启动会话后它可被回收)
|
|
39391
|
+
get sessionManager() {
|
|
39392
|
+
return sessionManager;
|
|
39393
|
+
},
|
|
39394
|
+
get session() {
|
|
39395
|
+
return session;
|
|
39396
|
+
},
|
|
38960
39397
|
hooks,
|
|
38961
39398
|
host,
|
|
38962
39399
|
permission,
|
|
@@ -43445,18 +43882,18 @@ async function confirmContinue(options = {}) {
|
|
|
43445
43882
|
});
|
|
43446
43883
|
return index2 === 0;
|
|
43447
43884
|
}
|
|
43448
|
-
const rl = (0,
|
|
43885
|
+
const rl = (0, import_promises21.createInterface)({ input: input2, output: options.output ?? process.stderr });
|
|
43449
43886
|
try {
|
|
43450
43887
|
return /^y(es)?$/i.test((await rl.question(m.textQuestion(question))).trim());
|
|
43451
43888
|
} finally {
|
|
43452
43889
|
rl.close();
|
|
43453
43890
|
}
|
|
43454
43891
|
}
|
|
43455
|
-
var
|
|
43892
|
+
var import_promises21, HIDE_CURSOR2, SHOW_CURSOR2;
|
|
43456
43893
|
var init_choice_prompt = __esm({
|
|
43457
43894
|
"src/cli/choice-prompt.ts"() {
|
|
43458
43895
|
"use strict";
|
|
43459
|
-
|
|
43896
|
+
import_promises21 = require("node:readline/promises");
|
|
43460
43897
|
init_tui2();
|
|
43461
43898
|
init_i18n();
|
|
43462
43899
|
HIDE_CURSOR2 = "\x1B[?25l";
|
|
@@ -43644,7 +44081,8 @@ var init_key_docs = __esm({
|
|
|
43644
44081
|
maxPending: 16,
|
|
43645
44082
|
background: "auto",
|
|
43646
44083
|
autoBackgroundAfterMs: 0,
|
|
43647
|
-
retainSessions: 4
|
|
44084
|
+
retainSessions: 4,
|
|
44085
|
+
forkMaxContextRatio: 0.5
|
|
43648
44086
|
},
|
|
43649
44087
|
reminders: { todo: true, fileChanges: true, contextPressure: true, budget: true },
|
|
43650
44088
|
todo: { reminder: 10 }
|
|
@@ -43909,7 +44347,8 @@ function w5Sections() {
|
|
|
43909
44347
|
defaultModel: str3(),
|
|
43910
44348
|
background: oneOf(SUBAGENT_BACKGROUND_MODES),
|
|
43911
44349
|
autoBackgroundAfterMs: num2(0),
|
|
43912
|
-
retainSessions: num2(0)
|
|
44350
|
+
retainSessions: num2(0),
|
|
44351
|
+
forkMaxContextRatio: num2(0.05, 0.95)
|
|
43913
44352
|
}),
|
|
43914
44353
|
models: object({ aliases: object({ fast: str3(), strong: str3() }), enabled: strings2 }),
|
|
43915
44354
|
fallbackModel: str3(),
|
|
@@ -44312,7 +44751,7 @@ ${error2.message}`)?.[0].toLowerCase();
|
|
|
44312
44751
|
}
|
|
44313
44752
|
function stripInto(value, removed) {
|
|
44314
44753
|
if (Array.isArray(value)) return value.map((item) => stripInto(item, removed));
|
|
44315
|
-
if (typeof value !== "object" || value === null) return value;
|
|
44754
|
+
if (typeof value !== "object" || value === null || value instanceof LargeString) return value;
|
|
44316
44755
|
const out = {};
|
|
44317
44756
|
for (const [key, inner] of Object.entries(value)) {
|
|
44318
44757
|
if (key === "cache_control") removed.count++;
|
|
@@ -44351,6 +44790,7 @@ var init_cache_params = __esm({
|
|
|
44351
44790
|
"src/ai/apis/cache-params.ts"() {
|
|
44352
44791
|
"use strict";
|
|
44353
44792
|
init_http();
|
|
44793
|
+
init_json_body();
|
|
44354
44794
|
init_i18n();
|
|
44355
44795
|
DEFAULT_BASE_URLS = {
|
|
44356
44796
|
"anthropic-messages": "https://api.anthropic.com",
|
|
@@ -44433,7 +44873,11 @@ function convertBlocks(content) {
|
|
|
44433
44873
|
} else {
|
|
44434
44874
|
blocks.push({
|
|
44435
44875
|
type: "image",
|
|
44436
|
-
source: {
|
|
44876
|
+
source: {
|
|
44877
|
+
type: "base64",
|
|
44878
|
+
media_type: block.mimeType,
|
|
44879
|
+
data: largeString("", block, block.data)
|
|
44880
|
+
}
|
|
44437
44881
|
});
|
|
44438
44882
|
}
|
|
44439
44883
|
}
|
|
@@ -44607,6 +45051,7 @@ var init_anthropic_request = __esm({
|
|
|
44607
45051
|
"src/ai/apis/anthropic-request.ts"() {
|
|
44608
45052
|
"use strict";
|
|
44609
45053
|
init_context();
|
|
45054
|
+
init_json_body();
|
|
44610
45055
|
init_thinking();
|
|
44611
45056
|
init_anthropic_compat();
|
|
44612
45057
|
init_cache_params();
|
|
@@ -44656,7 +45101,7 @@ function validSignature(signature2) {
|
|
|
44656
45101
|
return signature2 !== void 0 && signature2.length > 0 && signature2.length % 4 === 0 && BASE64.test(signature2);
|
|
44657
45102
|
}
|
|
44658
45103
|
function inlineData(block) {
|
|
44659
|
-
return { inlineData: { mimeType: block.mimeType, data: block.data } };
|
|
45104
|
+
return { inlineData: { mimeType: block.mimeType, data: largeString("", block, block.data) } };
|
|
44660
45105
|
}
|
|
44661
45106
|
function convertUser2(message) {
|
|
44662
45107
|
if (typeof message.content === "string") {
|
|
@@ -44827,6 +45272,7 @@ var init_google_request = __esm({
|
|
|
44827
45272
|
"src/ai/apis/google-request.ts"() {
|
|
44828
45273
|
"use strict";
|
|
44829
45274
|
init_context();
|
|
45275
|
+
init_json_body();
|
|
44830
45276
|
init_thinking();
|
|
44831
45277
|
GOOGLE_BASE_URL = "https://generativelanguage.googleapis.com/v1beta";
|
|
44832
45278
|
GOOGLE_COMPAT_KEYS = [
|
|
@@ -45274,7 +45720,8 @@ var init_chatgpt_backend = __esm({
|
|
|
45274
45720
|
|
|
45275
45721
|
// src/ai/apis/openai-request.ts
|
|
45276
45722
|
function imagePart(block) {
|
|
45277
|
-
|
|
45723
|
+
const url = largeString(`data:${block.mimeType};base64,`, block, block.data);
|
|
45724
|
+
return { type: "image_url", image_url: { url } };
|
|
45278
45725
|
}
|
|
45279
45726
|
function convertUser3(message) {
|
|
45280
45727
|
if (typeof message.content === "string") {
|
|
@@ -45325,17 +45772,17 @@ function convertToolResults(model, results, compat) {
|
|
|
45325
45772
|
for (const result of results) {
|
|
45326
45773
|
const text = contentText2(result.content);
|
|
45327
45774
|
const blocks = typeof result.content === "string" ? [] : result.content;
|
|
45328
|
-
const
|
|
45775
|
+
const hasImages2 = blocks.some((b) => b.type === "image");
|
|
45329
45776
|
const message = {
|
|
45330
45777
|
role: "tool",
|
|
45331
45778
|
tool_call_id: normalizeCallId(model, result.toolCallId),
|
|
45332
45779
|
content: sanitizeText(
|
|
45333
|
-
text.length > 0 ? text :
|
|
45780
|
+
text.length > 0 ? text : hasImages2 ? "(see attached image)" : "(no output)"
|
|
45334
45781
|
)
|
|
45335
45782
|
};
|
|
45336
45783
|
if (compat.requiresToolResultName) message["name"] = result.toolName;
|
|
45337
45784
|
messages.push(message);
|
|
45338
|
-
if (
|
|
45785
|
+
if (hasImages2 && model.input.includes("image")) {
|
|
45339
45786
|
for (const block of blocks) if (block.type === "image") images.push(imagePart(block));
|
|
45340
45787
|
}
|
|
45341
45788
|
}
|
|
@@ -45527,6 +45974,7 @@ var init_openai_request = __esm({
|
|
|
45527
45974
|
init_thinking();
|
|
45528
45975
|
init_anthropic_request();
|
|
45529
45976
|
init_cache_params();
|
|
45977
|
+
init_json_body();
|
|
45530
45978
|
init_openai_compat();
|
|
45531
45979
|
REASONING_FIELDS = ["reasoning_content", "reasoning", "reasoning_text"];
|
|
45532
45980
|
ASSISTANT_BRIDGE_TEXT = "Tool results received.";
|
|
@@ -45581,7 +46029,7 @@ function imagePart2(block) {
|
|
|
45581
46029
|
return {
|
|
45582
46030
|
type: "input_image",
|
|
45583
46031
|
detail: "auto",
|
|
45584
|
-
image_url: `data:${block.mimeType};base64
|
|
46032
|
+
image_url: largeString(`data:${block.mimeType};base64,`, block, block.data)
|
|
45585
46033
|
};
|
|
45586
46034
|
}
|
|
45587
46035
|
function convertUser4(message) {
|
|
@@ -45726,6 +46174,7 @@ var init_openai_responses_request = __esm({
|
|
|
45726
46174
|
"src/ai/apis/openai-responses-request.ts"() {
|
|
45727
46175
|
"use strict";
|
|
45728
46176
|
init_context();
|
|
46177
|
+
init_json_body();
|
|
45729
46178
|
init_thinking();
|
|
45730
46179
|
init_cache_params();
|
|
45731
46180
|
init_chatgpt_backend();
|
|
@@ -45886,6 +46335,10 @@ var init_sse = __esm({
|
|
|
45886
46335
|
});
|
|
45887
46336
|
|
|
45888
46337
|
// src/ai/apis/max-tokens.ts
|
|
46338
|
+
function onMaxTokensCap(listener) {
|
|
46339
|
+
capListeners.add(listener);
|
|
46340
|
+
return () => capListeners.delete(listener);
|
|
46341
|
+
}
|
|
45889
46342
|
function clampMaxTokens(requested, window2, estimatedInput, fixed) {
|
|
45890
46343
|
if (fixed || window2 === void 0 || !Number.isFinite(window2) || window2 <= 0) return requested;
|
|
45891
46344
|
const room = Math.floor(window2 - estimatedInput - OUTPUT_HEADROOM_TOKENS);
|
|
@@ -45946,14 +46399,17 @@ async function postWithMaxTokensFallback(model, url, options, field2) {
|
|
|
45946
46399
|
const sent = body[field2];
|
|
45947
46400
|
if (rejection === void 0 || !("cap" in rejection) || typeof sent !== "number") throw error2;
|
|
45948
46401
|
if (rejection.cap >= sent || !budgetFits(body, rejection.cap)) throw error2;
|
|
45949
|
-
if (!rejection.transient)
|
|
46402
|
+
if (!rejection.transient) {
|
|
46403
|
+
maxTokensCaps.set(key, rejection.cap);
|
|
46404
|
+
for (const listener of capListeners) listener(key, rejection.cap);
|
|
46405
|
+
}
|
|
45950
46406
|
return postWithCacheFallback(model, url, {
|
|
45951
46407
|
...options,
|
|
45952
46408
|
body: withCap(body, field2, rejection.cap)
|
|
45953
46409
|
});
|
|
45954
46410
|
}
|
|
45955
46411
|
}
|
|
45956
|
-
var MIN_OUTPUT_TOKENS, OUTPUT_HEADROOM_TOKENS, maxTokensCaps, NUM, toInt, RANGE, LIMIT, CONTEXT_LIMIT;
|
|
46412
|
+
var MIN_OUTPUT_TOKENS, OUTPUT_HEADROOM_TOKENS, maxTokensCaps, capListeners, NUM, toInt, RANGE, LIMIT, CONTEXT_LIMIT;
|
|
45957
46413
|
var init_max_tokens = __esm({
|
|
45958
46414
|
"src/ai/apis/max-tokens.ts"() {
|
|
45959
46415
|
"use strict";
|
|
@@ -45962,6 +46418,7 @@ var init_max_tokens = __esm({
|
|
|
45962
46418
|
MIN_OUTPUT_TOKENS = 1024;
|
|
45963
46419
|
OUTPUT_HEADROOM_TOKENS = 2048;
|
|
45964
46420
|
maxTokensCaps = /* @__PURE__ */ new Map();
|
|
46421
|
+
capListeners = /* @__PURE__ */ new Set();
|
|
45965
46422
|
NUM = "`?(\\d[\\d,_]*)`?";
|
|
45966
46423
|
toInt = (text) => Number((text ?? "").replace(/[,_]/g, ""));
|
|
45967
46424
|
RANGE = new RegExp(
|
|
@@ -47505,9 +47962,8 @@ var init_registry2 = __esm({
|
|
|
47505
47962
|
(name) => this.warn(`model "${id}/${modelId}" channel "${name}" not found; ignored`)
|
|
47506
47963
|
);
|
|
47507
47964
|
for (const entry of config.models ?? []) {
|
|
47508
|
-
const { entry: filled, metadata } = enrichEntry(entry, this.modelsDev);
|
|
47509
|
-
|
|
47510
|
-
this.warn(`modelsDev "${entry.modelsDev}" for "${id}/${entry.id}" not found`);
|
|
47965
|
+
const { entry: filled, metadata } = enrichEntry(entry, this.modelsDev, id);
|
|
47966
|
+
for (const warning of metadata.warnings ?? []) this.warn(warning);
|
|
47511
47967
|
const model = withCustomDefaults(filled, id, entry.api ?? provider.api);
|
|
47512
47968
|
if (provider.channels !== void 0 && (entry.channels !== void 0 || !provider.builtin))
|
|
47513
47969
|
model.channels = channelsOf(entry.channels, entry.id);
|
|
@@ -47647,8 +48103,8 @@ var init_registry2 = __esm({
|
|
|
47647
48103
|
const id = trimmed.slice(slash + 1);
|
|
47648
48104
|
const model = provider.models.find((m) => m.id === id);
|
|
47649
48105
|
if (model) return { ok: true, model, provider };
|
|
47650
|
-
const
|
|
47651
|
-
const relayed = provider.models.length === 0 ||
|
|
48106
|
+
const open3 = this.relayed.has(provider.id) || this.openTables.has(provider.id);
|
|
48107
|
+
const relayed = provider.models.length === 0 || open3;
|
|
47652
48108
|
if (synthesize && relayed && id.length > 0) {
|
|
47653
48109
|
const known = provider.channels?.some((c) => c.name === channel) ? channel : void 0;
|
|
47654
48110
|
const synthesized = this.synthesize(provider, id, known);
|
|
@@ -47860,6 +48316,7 @@ var init_settings_registry = __esm({
|
|
|
47860
48316
|
row2("subagents.maxConcurrent", "agents", "nextSession", "deny"),
|
|
47861
48317
|
row2("subagents.maxPending", "agents", "nextSession", "deny"),
|
|
47862
48318
|
row2("subagents.retainSessions", "agents", "nextSession", "deny"),
|
|
48319
|
+
row2("subagents.forkMaxContextRatio", "agents", "nextSession", "deny"),
|
|
47863
48320
|
// [W7-B2] 改 task 工具描述(缺省后台 / 前台两种文案),故 prefix
|
|
47864
48321
|
row2("subagents.background", "agents", "restart", "any", { prefix: true }),
|
|
47865
48322
|
row2("subagents.autoBackgroundAfterMs", "agents", "restart", "any"),
|
|
@@ -48253,7 +48710,7 @@ function attempts(platform, file, env) {
|
|
|
48253
48710
|
}
|
|
48254
48711
|
async function isPng(file) {
|
|
48255
48712
|
try {
|
|
48256
|
-
return sniffImageMime(await (0,
|
|
48713
|
+
return sniffImageMime(await (0, import_promises22.readFile)(file)) === "image/png";
|
|
48257
48714
|
} catch {
|
|
48258
48715
|
return false;
|
|
48259
48716
|
}
|
|
@@ -48263,7 +48720,7 @@ async function readClipboardImage(dataDir, deps = {}) {
|
|
|
48263
48720
|
const env = deps.env ?? process.env;
|
|
48264
48721
|
const run7 = deps.run ?? runCommand;
|
|
48265
48722
|
const dir = (0, import_node_path78.join)(dataDir, CLIPBOARD_DIR);
|
|
48266
|
-
await (0,
|
|
48723
|
+
await (0, import_promises22.mkdir)(dir, { recursive: true });
|
|
48267
48724
|
const stamp = new Date((deps.now ?? Date.now)()).toISOString().replace(/[:.]/g, "-");
|
|
48268
48725
|
let file = (0, import_node_path78.join)(dir, `${stamp}.png`);
|
|
48269
48726
|
for (let n = 1; (0, import_node_fs60.existsSync)(file); n++) file = (0, import_node_path78.join)(dir, `${stamp}-${n}.png`);
|
|
@@ -48276,19 +48733,19 @@ async function readClipboardImage(dataDir, deps = {}) {
|
|
|
48276
48733
|
if (result.code !== 0) continue;
|
|
48277
48734
|
if (attempt.via === "stdout") {
|
|
48278
48735
|
if (sniffImageMime(result.stdout) !== "image/png") continue;
|
|
48279
|
-
await (0,
|
|
48736
|
+
await (0, import_promises22.writeFile)(file, result.stdout);
|
|
48280
48737
|
}
|
|
48281
48738
|
if (await isPng(file)) return { ok: true, path: file, tool: attempt.tool };
|
|
48282
|
-
await (0,
|
|
48739
|
+
await (0, import_promises22.rm)(file, { force: true });
|
|
48283
48740
|
}
|
|
48284
|
-
await (0,
|
|
48741
|
+
await (0, import_promises22.rm)(file, { force: true });
|
|
48285
48742
|
return { ok: false, reason: anyTool ? "no_image" : "no_tool" };
|
|
48286
48743
|
}
|
|
48287
48744
|
async function gcClipboardImages(dataDir, options = {}) {
|
|
48288
48745
|
const dir = (0, import_node_path78.join)(dataDir, CLIPBOARD_DIR);
|
|
48289
48746
|
let names;
|
|
48290
48747
|
try {
|
|
48291
|
-
names = await (0,
|
|
48748
|
+
names = await (0, import_promises22.readdir)(dir);
|
|
48292
48749
|
} catch {
|
|
48293
48750
|
return [];
|
|
48294
48751
|
}
|
|
@@ -48297,21 +48754,21 @@ async function gcClipboardImages(dataDir, options = {}) {
|
|
|
48297
48754
|
for (const name of names) {
|
|
48298
48755
|
const file = (0, import_node_path78.join)(dir, name);
|
|
48299
48756
|
try {
|
|
48300
|
-
const info2 = await (0,
|
|
48757
|
+
const info2 = await (0, import_promises22.stat)(file);
|
|
48301
48758
|
if (!info2.isFile() || info2.mtimeMs >= cutoff) continue;
|
|
48302
|
-
if (options.dryRun !== true) await (0,
|
|
48759
|
+
if (options.dryRun !== true) await (0, import_promises22.rm)(file, { force: true });
|
|
48303
48760
|
removed.push(file);
|
|
48304
48761
|
} catch {
|
|
48305
48762
|
}
|
|
48306
48763
|
}
|
|
48307
48764
|
return removed;
|
|
48308
48765
|
}
|
|
48309
|
-
var import_node_fs60,
|
|
48766
|
+
var import_node_fs60, import_promises22, import_node_path78, CLIPBOARD_DIR, CLIPBOARD_MAX_AGE_DAYS, OSASCRIPT, POWERSHELL;
|
|
48310
48767
|
var init_clipboard_image = __esm({
|
|
48311
48768
|
"src/tools/clipboard-image.ts"() {
|
|
48312
48769
|
"use strict";
|
|
48313
48770
|
import_node_fs60 = require("node:fs");
|
|
48314
|
-
|
|
48771
|
+
import_promises22 = require("node:fs/promises");
|
|
48315
48772
|
import_node_path78 = require("node:path");
|
|
48316
48773
|
init_image_file();
|
|
48317
48774
|
init_image_resize();
|
|
@@ -49699,7 +50156,7 @@ function statusCost(stats) {
|
|
|
49699
50156
|
function layoutRow(parts, width2, theme, style = {}) {
|
|
49700
50157
|
const sep5 = style.sep ?? " · ";
|
|
49701
50158
|
const dim = (text) => text === "" ? "" : theme.fg("dim", text);
|
|
49702
|
-
const
|
|
50159
|
+
const join67 = (list5) => {
|
|
49703
50160
|
let out = "";
|
|
49704
50161
|
let size = 0;
|
|
49705
50162
|
const add3 = (text, measured = visibleWidth(text)) => {
|
|
@@ -49731,7 +50188,7 @@ function layoutRow(parts, width2, theme, style = {}) {
|
|
|
49731
50188
|
const left = zone("left");
|
|
49732
50189
|
const right = zone("right");
|
|
49733
50190
|
const between = left.length === 0 || right.length === 0 ? 0 : sep5.length;
|
|
49734
|
-
return
|
|
50191
|
+
return join67(left)[1] + between + join67(right)[1] <= width2;
|
|
49735
50192
|
};
|
|
49736
50193
|
while (!fits()) {
|
|
49737
50194
|
const droppable = kept.filter((p) => p.priority !== void 0);
|
|
@@ -49739,8 +50196,8 @@ function layoutRow(parts, width2, theme, style = {}) {
|
|
|
49739
50196
|
const drop = droppable.reduce((worst, p) => p.priority > worst.priority ? p : worst);
|
|
49740
50197
|
kept = kept.filter((p) => p !== drop);
|
|
49741
50198
|
}
|
|
49742
|
-
const l =
|
|
49743
|
-
const r =
|
|
50199
|
+
const l = join67(zone("left"))[0];
|
|
50200
|
+
const r = join67(zone("right"))[0];
|
|
49744
50201
|
const gap = width2 - visibleWidth(l) - visibleWidth(r);
|
|
49745
50202
|
const line2 = r === "" ? l : l === "" ? " ".repeat(Math.max(0, gap)) + r : gap >= MIN_GAP ? l + " ".repeat(gap) + r : l + dim(sep5) + r;
|
|
49746
50203
|
return truncateToWidth(line2, width2);
|
|
@@ -50456,8 +50913,8 @@ function barText(row3, width2, theme) {
|
|
|
50456
50913
|
const color = colors[rank3];
|
|
50457
50914
|
body += color === void 0 || plain ? ch2 : theme.fg(color, ch2);
|
|
50458
50915
|
}
|
|
50459
|
-
const [
|
|
50460
|
-
return theme.fg("border",
|
|
50916
|
+
const [open3, close] = plain ? ["[", "]"] : ["▕", "▏"];
|
|
50917
|
+
return theme.fg("border", open3) + body + theme.fg("border", close);
|
|
50461
50918
|
}
|
|
50462
50919
|
function labelPart(row3, ctx) {
|
|
50463
50920
|
const g = ctx.theme.glyphs;
|
|
@@ -51115,11 +51572,11 @@ ${skill.body}`;
|
|
|
51115
51572
|
}
|
|
51116
51573
|
async function ensureFile(path, text) {
|
|
51117
51574
|
try {
|
|
51118
|
-
if (await (0,
|
|
51575
|
+
if (await (0, import_promises23.readFile)(path, "utf8") === text) return;
|
|
51119
51576
|
} catch {
|
|
51120
51577
|
}
|
|
51121
|
-
await (0,
|
|
51122
|
-
await (0,
|
|
51578
|
+
await (0, import_promises23.mkdir)((0, import_node_path86.dirname)(path), { recursive: true });
|
|
51579
|
+
await (0, import_promises23.writeFile)(path, text, "utf8");
|
|
51123
51580
|
}
|
|
51124
51581
|
async function withBuiltinSkills(skills, dataDir, builtins = BUILTIN_SKILLS) {
|
|
51125
51582
|
const out = [...skills];
|
|
@@ -51148,11 +51605,11 @@ async function withBuiltinSkills(skills, dataDir, builtins = BUILTIN_SKILLS) {
|
|
|
51148
51605
|
}
|
|
51149
51606
|
return { skills: out, warnings };
|
|
51150
51607
|
}
|
|
51151
|
-
var
|
|
51608
|
+
var import_promises23, import_node_path86, BUILTIN_SKILLS_DIR, AMA_DOCS_BODY, BUILTIN_SKILLS;
|
|
51152
51609
|
var init_builtin3 = __esm({
|
|
51153
51610
|
"src/skills/builtin.ts"() {
|
|
51154
51611
|
"use strict";
|
|
51155
|
-
|
|
51612
|
+
import_promises23 = require("node:fs/promises");
|
|
51156
51613
|
import_node_path86 = require("node:path");
|
|
51157
51614
|
BUILTIN_SKILLS_DIR = "builtin";
|
|
51158
51615
|
AMA_DOCS_BODY = `# ama quick reference
|
|
@@ -51263,7 +51720,7 @@ function parseSkill(text, location, scope) {
|
|
|
51263
51720
|
}
|
|
51264
51721
|
async function isDir3(path) {
|
|
51265
51722
|
try {
|
|
51266
|
-
return (await (0,
|
|
51723
|
+
return (await (0, import_promises24.stat)(path)).isDirectory();
|
|
51267
51724
|
} catch {
|
|
51268
51725
|
return false;
|
|
51269
51726
|
}
|
|
@@ -51274,7 +51731,7 @@ async function findSkillFiles(dir, depth = 0) {
|
|
|
51274
51731
|
if ((0, import_node_fs65.existsSync)(own)) return [own];
|
|
51275
51732
|
let names;
|
|
51276
51733
|
try {
|
|
51277
|
-
names = await (0,
|
|
51734
|
+
names = await (0, import_promises24.readdir)(dir);
|
|
51278
51735
|
} catch {
|
|
51279
51736
|
return [];
|
|
51280
51737
|
}
|
|
@@ -51302,7 +51759,7 @@ async function discoverSkills(sources, options) {
|
|
|
51302
51759
|
for (const file of await findSkillFiles(source.dir)) {
|
|
51303
51760
|
let text;
|
|
51304
51761
|
try {
|
|
51305
|
-
text = await (0,
|
|
51762
|
+
text = await (0, import_promises24.readFile)(file, "utf8");
|
|
51306
51763
|
} catch (err) {
|
|
51307
51764
|
result.warnings.push(`${file}: ${err.message}`);
|
|
51308
51765
|
continue;
|
|
@@ -51323,12 +51780,12 @@ async function discoverSkills(sources, options) {
|
|
|
51323
51780
|
}
|
|
51324
51781
|
return result;
|
|
51325
51782
|
}
|
|
51326
|
-
var import_node_fs65,
|
|
51783
|
+
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
51784
|
var init_discover2 = __esm({
|
|
51328
51785
|
"src/skills/discover.ts"() {
|
|
51329
51786
|
"use strict";
|
|
51330
51787
|
import_node_fs65 = require("node:fs");
|
|
51331
|
-
|
|
51788
|
+
import_promises24 = require("node:fs/promises");
|
|
51332
51789
|
import_node_path87 = require("node:path");
|
|
51333
51790
|
init_frontmatter2();
|
|
51334
51791
|
SKILL_FILE = "SKILL.md";
|
|
@@ -52172,6 +52629,81 @@ var init_codemode_notice = __esm({
|
|
|
52172
52629
|
}
|
|
52173
52630
|
});
|
|
52174
52631
|
|
|
52632
|
+
// src/ai/providers/max-tokens-cache.ts
|
|
52633
|
+
function maxTokensCachePath(dataDir) {
|
|
52634
|
+
return (0, import_node_path91.join)(dataDir, "models", "max-tokens-caps.json");
|
|
52635
|
+
}
|
|
52636
|
+
function readEntries(dataDir, now) {
|
|
52637
|
+
const out = /* @__PURE__ */ new Map();
|
|
52638
|
+
let parsed;
|
|
52639
|
+
try {
|
|
52640
|
+
parsed = JSON.parse((0, import_node_fs69.readFileSync)(maxTokensCachePath(dataDir), "utf8"));
|
|
52641
|
+
} catch {
|
|
52642
|
+
return out;
|
|
52643
|
+
}
|
|
52644
|
+
if (typeof parsed !== "object" || parsed === null) return out;
|
|
52645
|
+
const file = parsed;
|
|
52646
|
+
if (file.version !== MAX_TOKENS_CACHE_VERSION) return out;
|
|
52647
|
+
if (typeof file.caps !== "object" || file.caps === null) return out;
|
|
52648
|
+
for (const [key, value] of Object.entries(file.caps)) {
|
|
52649
|
+
if (typeof value !== "object" || value === null) continue;
|
|
52650
|
+
const { cap, learnedAt } = value;
|
|
52651
|
+
if (typeof cap !== "number" || !Number.isInteger(cap) || cap < 1) continue;
|
|
52652
|
+
if (typeof learnedAt !== "number" || !Number.isFinite(learnedAt)) continue;
|
|
52653
|
+
if (now - learnedAt > MAX_TOKENS_CACHE_TTL_MS) continue;
|
|
52654
|
+
out.set(key, { cap, learnedAt });
|
|
52655
|
+
}
|
|
52656
|
+
return out;
|
|
52657
|
+
}
|
|
52658
|
+
function loadMaxTokensCaps(dataDir, now = Date.now) {
|
|
52659
|
+
let loaded = 0;
|
|
52660
|
+
for (const [key, entry] of readEntries(dataDir, now())) {
|
|
52661
|
+
if (maxTokensCaps.has(key)) continue;
|
|
52662
|
+
maxTokensCaps.set(key, entry.cap);
|
|
52663
|
+
loaded++;
|
|
52664
|
+
}
|
|
52665
|
+
return loaded;
|
|
52666
|
+
}
|
|
52667
|
+
function recordMaxTokensCap(dataDir, key, cap, now = Date.now) {
|
|
52668
|
+
const at = now();
|
|
52669
|
+
const entries = readEntries(dataDir, at);
|
|
52670
|
+
entries.set(key, { cap, learnedAt: at });
|
|
52671
|
+
const path = maxTokensCachePath(dataDir);
|
|
52672
|
+
const tmp = `${path}.${process.pid}.tmp`;
|
|
52673
|
+
try {
|
|
52674
|
+
(0, import_node_fs69.mkdirSync)((0, import_node_path91.dirname)(path), { recursive: true, mode: 448 });
|
|
52675
|
+
const caps = Object.fromEntries([...entries].sort(([a], [b]) => a < b ? -1 : 1));
|
|
52676
|
+
(0, import_node_fs69.writeFileSync)(tmp, `${JSON.stringify({ version: MAX_TOKENS_CACHE_VERSION, caps }, null, 2)}
|
|
52677
|
+
`);
|
|
52678
|
+
(0, import_node_fs69.renameSync)(tmp, path);
|
|
52679
|
+
} catch {
|
|
52680
|
+
}
|
|
52681
|
+
}
|
|
52682
|
+
function attachMaxTokensCache(dataDir, now = Date.now) {
|
|
52683
|
+
const existing = attached2.get(dataDir);
|
|
52684
|
+
if (existing !== void 0) return existing;
|
|
52685
|
+
loadMaxTokensCaps(dataDir, now);
|
|
52686
|
+
const unsubscribe = onMaxTokensCap((key, cap) => recordMaxTokensCap(dataDir, key, cap, now));
|
|
52687
|
+
const detach = () => {
|
|
52688
|
+
unsubscribe();
|
|
52689
|
+
attached2.delete(dataDir);
|
|
52690
|
+
};
|
|
52691
|
+
attached2.set(dataDir, detach);
|
|
52692
|
+
return detach;
|
|
52693
|
+
}
|
|
52694
|
+
var import_node_fs69, import_node_path91, MAX_TOKENS_CACHE_VERSION, MAX_TOKENS_CACHE_TTL_MS, attached2;
|
|
52695
|
+
var init_max_tokens_cache = __esm({
|
|
52696
|
+
"src/ai/providers/max-tokens-cache.ts"() {
|
|
52697
|
+
"use strict";
|
|
52698
|
+
import_node_fs69 = require("node:fs");
|
|
52699
|
+
import_node_path91 = require("node:path");
|
|
52700
|
+
init_max_tokens();
|
|
52701
|
+
MAX_TOKENS_CACHE_VERSION = 1;
|
|
52702
|
+
MAX_TOKENS_CACHE_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
52703
|
+
attached2 = /* @__PURE__ */ new Map();
|
|
52704
|
+
}
|
|
52705
|
+
});
|
|
52706
|
+
|
|
52175
52707
|
// src/cli/compose-providers.ts
|
|
52176
52708
|
function modelConfigOf(model, providerApi) {
|
|
52177
52709
|
const { provider: _p, api, ...rest } = model;
|
|
@@ -52252,6 +52784,7 @@ async function buildProviderRegistry(input2, options = {}) {
|
|
|
52252
52784
|
if (provider !== void 0) registry3 = make({ provider, apiKey: cli.apiKey });
|
|
52253
52785
|
}
|
|
52254
52786
|
if (dataDir !== void 0) {
|
|
52787
|
+
attachMaxTokensCache(dataDir);
|
|
52255
52788
|
const flavor = readOAuthEntry(input2.authFile, CHATGPT_PROVIDER_ID)?.flavor;
|
|
52256
52789
|
mergeDiscoveredModels(
|
|
52257
52790
|
registry3,
|
|
@@ -52292,6 +52825,7 @@ var init_compose_providers = __esm({
|
|
|
52292
52825
|
init_models_dev_cache();
|
|
52293
52826
|
init_registry2();
|
|
52294
52827
|
init_discovered_cache();
|
|
52828
|
+
init_max_tokens_cache();
|
|
52295
52829
|
init_enrich();
|
|
52296
52830
|
init_token_store();
|
|
52297
52831
|
init_presets();
|
|
@@ -52303,7 +52837,7 @@ var init_compose_providers = __esm({
|
|
|
52303
52837
|
// src/modes/image-input.ts
|
|
52304
52838
|
function expand(path, cwd) {
|
|
52305
52839
|
const home = path === "~" || path.startsWith("~/") ? (0, import_node_os14.homedir)() + path.slice(1) : path;
|
|
52306
|
-
return (0,
|
|
52840
|
+
return (0, import_node_path92.resolve)(cwd, home);
|
|
52307
52841
|
}
|
|
52308
52842
|
function findImageRefs(text, cwd) {
|
|
52309
52843
|
const out = [];
|
|
@@ -52315,7 +52849,7 @@ function findImageRefs(text, cwd) {
|
|
|
52315
52849
|
token = token.replace(/\\ /g, " ").replace(/[,\uFF0C\u3002;\uFF1B)\uFF09]+$/, "");
|
|
52316
52850
|
if (token === "" || imageMimeFromPath(token) === void 0) continue;
|
|
52317
52851
|
const path = expand(token, cwd);
|
|
52318
|
-
if (!explicit && !(0,
|
|
52852
|
+
if (!explicit && !(0, import_node_fs70.existsSync)(path)) continue;
|
|
52319
52853
|
if (seen.has(path)) continue;
|
|
52320
52854
|
seen.add(path);
|
|
52321
52855
|
out.push({ path, explicit });
|
|
@@ -52374,13 +52908,13 @@ async function loadLocalized(path, options) {
|
|
|
52374
52908
|
throw error2;
|
|
52375
52909
|
}
|
|
52376
52910
|
}
|
|
52377
|
-
var
|
|
52911
|
+
var import_node_fs70, import_node_os14, import_node_path92, TOKEN;
|
|
52378
52912
|
var init_image_input = __esm({
|
|
52379
52913
|
"src/modes/image-input.ts"() {
|
|
52380
52914
|
"use strict";
|
|
52381
|
-
|
|
52915
|
+
import_node_fs70 = require("node:fs");
|
|
52382
52916
|
import_node_os14 = require("node:os");
|
|
52383
|
-
|
|
52917
|
+
import_node_path92 = require("node:path");
|
|
52384
52918
|
init_channels();
|
|
52385
52919
|
init_errors();
|
|
52386
52920
|
init_image_limits();
|
|
@@ -53177,7 +53711,7 @@ function trustChoices() {
|
|
|
53177
53711
|
}
|
|
53178
53712
|
function isDirectory2(path) {
|
|
53179
53713
|
try {
|
|
53180
|
-
return (0,
|
|
53714
|
+
return (0, import_node_fs71.statSync)(path).isDirectory();
|
|
53181
53715
|
} catch {
|
|
53182
53716
|
return false;
|
|
53183
53717
|
}
|
|
@@ -53231,8 +53765,8 @@ function createStartupUi(options = {}) {
|
|
|
53231
53765
|
placeholder: m.cwdPlaceholder,
|
|
53232
53766
|
validate: (text) => {
|
|
53233
53767
|
if (text === "") return m.cwdEmpty;
|
|
53234
|
-
const abs = (0,
|
|
53235
|
-
if (!(0,
|
|
53768
|
+
const abs = (0, import_node_path93.resolve)(text);
|
|
53769
|
+
if (!(0, import_node_fs71.existsSync)(abs)) return m.cwdMissing(abs);
|
|
53236
53770
|
if (!isDirectory2(abs)) return m.cwdNotDir(abs);
|
|
53237
53771
|
return void 0;
|
|
53238
53772
|
}
|
|
@@ -53240,13 +53774,13 @@ function createStartupUi(options = {}) {
|
|
|
53240
53774
|
}
|
|
53241
53775
|
};
|
|
53242
53776
|
}
|
|
53243
|
-
var
|
|
53777
|
+
var import_node_fs71, import_node_path93;
|
|
53244
53778
|
var init_startup_ui = __esm({
|
|
53245
53779
|
"src/modes/interactive/startup-ui.ts"() {
|
|
53246
53780
|
"use strict";
|
|
53247
53781
|
init_i18n();
|
|
53248
|
-
|
|
53249
|
-
|
|
53782
|
+
import_node_fs71 = require("node:fs");
|
|
53783
|
+
import_node_path93 = require("node:path");
|
|
53250
53784
|
init_tui2();
|
|
53251
53785
|
init_model_items();
|
|
53252
53786
|
init_model_items();
|
|
@@ -53384,7 +53918,7 @@ function oneLine7(text, max = 60) {
|
|
|
53384
53918
|
const flat2 = text.replace(/\s+/g, " ").trim();
|
|
53385
53919
|
return flat2.length > max ? `${flat2.slice(0, max - 1)}…` : flat2;
|
|
53386
53920
|
}
|
|
53387
|
-
function
|
|
53921
|
+
function taskLine2(task, now) {
|
|
53388
53922
|
const m = msg().panels.tasks;
|
|
53389
53923
|
const agent = task.runner !== "ama" && task.runner !== task.agent ? m.agentRunner(task.agent, task.runner) : task.agent;
|
|
53390
53924
|
const parts = [agent, ...taskFacts(task, now)];
|
|
@@ -53398,7 +53932,7 @@ function describeTasks(sessionId, now) {
|
|
|
53398
53932
|
if (tasks.length === 0) return m.none;
|
|
53399
53933
|
return [
|
|
53400
53934
|
m.heading(tasks.length),
|
|
53401
|
-
...tasks.map((task) => ` ${
|
|
53935
|
+
...tasks.map((task) => ` ${taskLine2(task, now)}`),
|
|
53402
53936
|
m.footer
|
|
53403
53937
|
].join("\n");
|
|
53404
53938
|
}
|
|
@@ -53409,7 +53943,7 @@ function describeTaskOutput(sessionId, taskId, now) {
|
|
|
53409
53943
|
const output = taskOutput(sessionId, taskId) ?? "";
|
|
53410
53944
|
const file = task.outputFile !== void 0 ? `
|
|
53411
53945
|
${m.fullOutput(task.outputFile)}` : "";
|
|
53412
|
-
return `${
|
|
53946
|
+
return `${taskLine2(task, now)}${file}
|
|
53413
53947
|
${output.trim() === "" ? m.noOutput : output.trimEnd()}`;
|
|
53414
53948
|
}
|
|
53415
53949
|
function sourceText3(source) {
|
|
@@ -53663,7 +54197,7 @@ function startupInfo(runtime, home) {
|
|
|
53663
54197
|
permissionMode: runtime.session.state.permissionMode,
|
|
53664
54198
|
preset: runtime.config.tools?.preset ?? "default",
|
|
53665
54199
|
codemode: effectiveCodemodeMode(runtime.config),
|
|
53666
|
-
contextFiles: resources.contextFiles.map((f) => (0,
|
|
54200
|
+
contextFiles: resources.contextFiles.map((f) => (0, import_node_path94.basename)(f.path)),
|
|
53667
54201
|
skills: resources.skills.filter((s2) => !isBuiltinSkill(s2)).length,
|
|
53668
54202
|
prompts: resources.prompts.length,
|
|
53669
54203
|
hooks: runtime.hooks.list().length,
|
|
@@ -53672,12 +54206,12 @@ function startupInfo(runtime, home) {
|
|
|
53672
54206
|
if (runtime.host !== void 0) info2.host = runtime.host.adapter.id;
|
|
53673
54207
|
return info2;
|
|
53674
54208
|
}
|
|
53675
|
-
var
|
|
54209
|
+
var import_node_path94;
|
|
53676
54210
|
var init_startup_screen = __esm({
|
|
53677
54211
|
"src/cli/startup-screen.ts"() {
|
|
53678
54212
|
"use strict";
|
|
53679
54213
|
init_builtin3();
|
|
53680
|
-
|
|
54214
|
+
import_node_path94 = require("node:path");
|
|
53681
54215
|
init_channels();
|
|
53682
54216
|
init_presets2();
|
|
53683
54217
|
init_i18n();
|
|
@@ -56420,29 +56954,29 @@ function runEditor(command3, file) {
|
|
|
56420
56954
|
return result.status;
|
|
56421
56955
|
}
|
|
56422
56956
|
async function editExternally(text, name, deps) {
|
|
56423
|
-
const dir = (0,
|
|
56424
|
-
const file = (0,
|
|
56425
|
-
(0,
|
|
56957
|
+
const dir = (0, import_node_fs72.mkdtempSync)((0, import_node_path95.join)((0, import_node_os15.tmpdir)(), "ama-edit-"));
|
|
56958
|
+
const file = (0, import_node_path95.join)(dir, name);
|
|
56959
|
+
(0, import_node_fs72.writeFileSync)(file, text);
|
|
56426
56960
|
deps.suspend();
|
|
56427
56961
|
try {
|
|
56428
56962
|
const code = (deps.run ?? runEditor)(editorCommand(deps.env, deps.platform), file);
|
|
56429
56963
|
if (code !== 0) return void 0;
|
|
56430
|
-
return (0,
|
|
56964
|
+
return (0, import_node_fs72.readFileSync)(file, "utf8");
|
|
56431
56965
|
} catch {
|
|
56432
56966
|
return void 0;
|
|
56433
56967
|
} finally {
|
|
56434
56968
|
deps.resume();
|
|
56435
|
-
(0,
|
|
56969
|
+
(0, import_node_fs72.rmSync)(dir, { recursive: true, force: true });
|
|
56436
56970
|
}
|
|
56437
56971
|
}
|
|
56438
|
-
var import_node_child_process17,
|
|
56972
|
+
var import_node_child_process17, import_node_fs72, import_node_os15, import_node_path95;
|
|
56439
56973
|
var init_external_editor = __esm({
|
|
56440
56974
|
"src/modes/interactive/external-editor.ts"() {
|
|
56441
56975
|
"use strict";
|
|
56442
56976
|
import_node_child_process17 = require("node:child_process");
|
|
56443
|
-
|
|
56977
|
+
import_node_fs72 = require("node:fs");
|
|
56444
56978
|
import_node_os15 = require("node:os");
|
|
56445
|
-
|
|
56979
|
+
import_node_path95 = require("node:path");
|
|
56446
56980
|
}
|
|
56447
56981
|
});
|
|
56448
56982
|
|
|
@@ -59406,7 +59940,7 @@ function agentCommandHooks(get) {
|
|
|
59406
59940
|
agentView: (taskId) => get().openView(taskId)
|
|
59407
59941
|
};
|
|
59408
59942
|
}
|
|
59409
|
-
var TASK_NOTICE, AgentUi;
|
|
59943
|
+
var TASK_NOTICE, SESSION_NOTICE, AgentUi;
|
|
59410
59944
|
var init_agent_ui = __esm({
|
|
59411
59945
|
"src/modes/interactive/agent-ui.ts"() {
|
|
59412
59946
|
"use strict";
|
|
@@ -59426,6 +59960,7 @@ var init_agent_ui = __esm({
|
|
|
59426
59960
|
init_task_background();
|
|
59427
59961
|
init_tasks_report();
|
|
59428
59962
|
TASK_NOTICE = /^\[task (t\d+)\] ([\s\S]*)$/;
|
|
59963
|
+
SESSION_NOTICE = /^cannot read session entry (\S+) back from /;
|
|
59429
59964
|
AgentUi = class {
|
|
59430
59965
|
constructor(deps) {
|
|
59431
59966
|
this.deps = deps;
|
|
@@ -59536,6 +60071,11 @@ var init_agent_ui = __esm({
|
|
|
59536
60071
|
this.deps.notice(level === "warn" ? "warn" : "info", `[${agent} · ${taskId}] ${match[2]}`);
|
|
59537
60072
|
return;
|
|
59538
60073
|
}
|
|
60074
|
+
const image = level === "warn" ? SESSION_NOTICE.exec(message) : null;
|
|
60075
|
+
if (image !== null) {
|
|
60076
|
+
this.deps.notice("warn", msg().interactive.events.imageReadBackFailed(image[1]));
|
|
60077
|
+
return;
|
|
60078
|
+
}
|
|
59539
60079
|
original?.call(holder, level, message);
|
|
59540
60080
|
};
|
|
59541
60081
|
holder.log = routed;
|
|
@@ -59760,7 +60300,7 @@ var init_agent_ui = __esm({
|
|
|
59760
60300
|
const now = this.deps.now();
|
|
59761
60301
|
const picked = await this.deps.pick({
|
|
59762
60302
|
title: msg().interactive.agentUi.tasksTitle,
|
|
59763
|
-
items: [...tasks].reverse().map((task2) => ({ value: task2.taskId, label:
|
|
60303
|
+
items: [...tasks].reverse().map((task2) => ({ value: task2.taskId, label: taskLine2(task2, now) })),
|
|
59764
60304
|
footer: msg().interactive.agentUi.tasksFooter("↑↓")
|
|
59765
60305
|
});
|
|
59766
60306
|
if (picked === void 0) return;
|
|
@@ -60456,9 +60996,9 @@ function parseLeftRight(text) {
|
|
|
60456
60996
|
async function hasUpstream(cwd, branch) {
|
|
60457
60997
|
const gitDir = await findGitDir(cwd);
|
|
60458
60998
|
if (gitDir === void 0) return false;
|
|
60459
|
-
const common = (await (0,
|
|
60460
|
-
const dir = common === void 0 ? gitDir : (0,
|
|
60461
|
-
const text = await (0,
|
|
60999
|
+
const common = (await (0, import_promises25.readFile)((0, import_node_path96.join)(gitDir, "commondir"), "utf8").catch(() => void 0))?.trim();
|
|
61000
|
+
const dir = common === void 0 ? gitDir : (0, import_node_path96.isAbsolute)(common) ? common : (0, import_node_path96.resolve)(gitDir, common);
|
|
61001
|
+
const text = await (0, import_promises25.readFile)((0, import_node_path96.join)(dir, "config"), "utf8").catch(() => "");
|
|
60462
61002
|
let inBranch = false;
|
|
60463
61003
|
for (const raw of text.split("\n")) {
|
|
60464
61004
|
const line2 = raw.trim();
|
|
@@ -60471,7 +61011,7 @@ async function hasUpstream(cwd, branch) {
|
|
|
60471
61011
|
}
|
|
60472
61012
|
return false;
|
|
60473
61013
|
}
|
|
60474
|
-
async function
|
|
61014
|
+
async function readHead2(cwd) {
|
|
60475
61015
|
const head = await readGitHead(cwd);
|
|
60476
61016
|
if (head !== void 0) {
|
|
60477
61017
|
return {
|
|
@@ -60481,17 +61021,17 @@ async function readHead3(cwd) {
|
|
|
60481
61021
|
}
|
|
60482
61022
|
const gitDir = await findGitDir(cwd);
|
|
60483
61023
|
if (gitDir === void 0) return void 0;
|
|
60484
|
-
const text = await (0,
|
|
61024
|
+
const text = await (0, import_promises25.readFile)((0, import_node_path96.join)(gitDir, "HEAD"), "utf8").catch(() => void 0);
|
|
60485
61025
|
const match = /^ref:\s*refs\/heads\/(\S+)\s*$/.exec(text ?? "");
|
|
60486
61026
|
return match?.[1] !== void 0 ? { branch: match[1] } : void 0;
|
|
60487
61027
|
}
|
|
60488
|
-
var import_node_child_process18,
|
|
61028
|
+
var import_node_child_process18, import_promises25, import_node_path96, GIT_NUMSTAT_INTERVAL_MS, GIT_NUMSTAT_TIMEOUT_MS, sameInfo, GitInfoWatcher;
|
|
60489
61029
|
var init_info = __esm({
|
|
60490
61030
|
"src/git/info.ts"() {
|
|
60491
61031
|
"use strict";
|
|
60492
61032
|
import_node_child_process18 = require("node:child_process");
|
|
60493
|
-
|
|
60494
|
-
|
|
61033
|
+
import_promises25 = require("node:fs/promises");
|
|
61034
|
+
import_node_path96 = require("node:path");
|
|
60495
61035
|
init_git_head();
|
|
60496
61036
|
GIT_NUMSTAT_INTERVAL_MS = 1e4;
|
|
60497
61037
|
GIT_NUMSTAT_TIMEOUT_MS = 2e3;
|
|
@@ -60545,7 +61085,7 @@ var init_info = __esm({
|
|
|
60545
61085
|
const run7 = async () => {
|
|
60546
61086
|
do {
|
|
60547
61087
|
this.headAgain = false;
|
|
60548
|
-
const head = await
|
|
61088
|
+
const head = await readHead2(this.cwd).catch(() => void 0);
|
|
60549
61089
|
this.update(head);
|
|
60550
61090
|
} while (this.headAgain && !this.disposed);
|
|
60551
61091
|
this.headReading = void 0;
|
|
@@ -60787,12 +61327,12 @@ function statusLineText(mode) {
|
|
|
60787
61327
|
const m = msg().interactive.statusLine;
|
|
60788
61328
|
return mode === "full" ? m.full : m.compact;
|
|
60789
61329
|
}
|
|
60790
|
-
var
|
|
61330
|
+
var import_node_path97, WRITE_TOOLS3, QUOTA_TICK_MS, HintLine, StatusArea;
|
|
60791
61331
|
var init_status_area = __esm({
|
|
60792
61332
|
"src/modes/interactive/status-area.ts"() {
|
|
60793
61333
|
"use strict";
|
|
60794
61334
|
init_i18n();
|
|
60795
|
-
|
|
61335
|
+
import_node_path97 = require("node:path");
|
|
60796
61336
|
init_capability();
|
|
60797
61337
|
init_channels();
|
|
60798
61338
|
init_info();
|
|
@@ -60982,7 +61522,7 @@ var init_status_area = __esm({
|
|
|
60982
61522
|
gitView() {
|
|
60983
61523
|
const cwd = this.gitCwd;
|
|
60984
61524
|
if (cwd === void 0) return void 0;
|
|
60985
|
-
return { dir: (0,
|
|
61525
|
+
return { dir: (0, import_node_path97.basename)(cwd), info: this.git?.current() };
|
|
60986
61526
|
}
|
|
60987
61527
|
watchGit() {
|
|
60988
61528
|
const cwd = this.deps.session().state.cwd;
|
|
@@ -62644,8 +63184,8 @@ var init_run_indicator = __esm({
|
|
|
62644
63184
|
get busy() {
|
|
62645
63185
|
return this.running || this.compacting;
|
|
62646
63186
|
}
|
|
62647
|
-
setApproval(
|
|
62648
|
-
this.approval =
|
|
63187
|
+
setApproval(open3) {
|
|
63188
|
+
this.approval = open3;
|
|
62649
63189
|
this.sync();
|
|
62650
63190
|
}
|
|
62651
63191
|
/** 会话切换后清零。 */
|
|
@@ -63309,15 +63849,15 @@ function processTerminal() {
|
|
|
63309
63849
|
return new ProcessTerminal();
|
|
63310
63850
|
}
|
|
63311
63851
|
function loadKeys(runtime, warn2) {
|
|
63312
|
-
const parsed = loadKeybindingsFile((0,
|
|
63852
|
+
const parsed = loadKeybindingsFile((0, import_node_path98.join)(runtime.paths.configDir, KEYBINDINGS_FILE));
|
|
63313
63853
|
for (const w of parsed.warnings) warn2(msg().interactive.app.keybindingsWarning(w));
|
|
63314
63854
|
return new Keybindings(parsed.overrides);
|
|
63315
63855
|
}
|
|
63316
|
-
var
|
|
63856
|
+
var import_node_path98;
|
|
63317
63857
|
var init_terminal_setup = __esm({
|
|
63318
63858
|
"src/modes/interactive/terminal-setup.ts"() {
|
|
63319
63859
|
"use strict";
|
|
63320
|
-
|
|
63860
|
+
import_node_path98 = require("node:path");
|
|
63321
63861
|
init_paths();
|
|
63322
63862
|
init_errors();
|
|
63323
63863
|
init_i18n();
|
|
@@ -63383,7 +63923,7 @@ function runInteractiveMode(runtime, context, options = {}) {
|
|
|
63383
63923
|
...options.statusLine !== void 0 ? { layout: options.statusLine } : {}
|
|
63384
63924
|
});
|
|
63385
63925
|
const { hint, bar: status } = area;
|
|
63386
|
-
const historyFile = options.historyFile === false ? void 0 : options.historyFile ?? (0,
|
|
63926
|
+
const historyFile = options.historyFile === false ? void 0 : options.historyFile ?? (0, import_node_path99.join)(runtime.paths.dataDir, "history");
|
|
63387
63927
|
const completion = new InteractiveCompletion({
|
|
63388
63928
|
commands: () => ALL_COMMANDS,
|
|
63389
63929
|
prompts: () => runtime.resources.prompts,
|
|
@@ -63747,12 +64287,12 @@ function runInteractiveMode(runtime, context, options = {}) {
|
|
|
63747
64287
|
}
|
|
63748
64288
|
});
|
|
63749
64289
|
}
|
|
63750
|
-
var
|
|
64290
|
+
var import_node_path99, HINT_MS;
|
|
63751
64291
|
var init_interactive_mode = __esm({
|
|
63752
64292
|
"src/modes/interactive/interactive-mode.ts"() {
|
|
63753
64293
|
"use strict";
|
|
63754
64294
|
init_image_input();
|
|
63755
|
-
|
|
64295
|
+
import_node_path99 = require("node:path");
|
|
63756
64296
|
init_session2();
|
|
63757
64297
|
init_compose_session();
|
|
63758
64298
|
init_startup_screen();
|
|
@@ -63828,7 +64368,7 @@ function choose(answer, values) {
|
|
|
63828
64368
|
}
|
|
63829
64369
|
function isDirectory3(path) {
|
|
63830
64370
|
try {
|
|
63831
|
-
return (0,
|
|
64371
|
+
return (0, import_node_fs73.statSync)(path).isDirectory();
|
|
63832
64372
|
} catch {
|
|
63833
64373
|
return false;
|
|
63834
64374
|
}
|
|
@@ -63872,8 +64412,8 @@ function createTextStartupUi(io) {
|
|
|
63872
64412
|
const m = msg().report.startup;
|
|
63873
64413
|
const answer = (await ask([m.cwdMissing(missing)], m.cwdAnswer))?.trim();
|
|
63874
64414
|
if (answer === void 0 || answer === "") return void 0;
|
|
63875
|
-
const abs = (0,
|
|
63876
|
-
if (!(0,
|
|
64415
|
+
const abs = (0, import_node_path100.resolve)(answer);
|
|
64416
|
+
if (!(0, import_node_fs73.existsSync)(abs) || !isDirectory3(abs)) {
|
|
63877
64417
|
io.write(m.notDirectory(abs));
|
|
63878
64418
|
return void 0;
|
|
63879
64419
|
}
|
|
@@ -63881,12 +64421,12 @@ function createTextStartupUi(io) {
|
|
|
63881
64421
|
}
|
|
63882
64422
|
};
|
|
63883
64423
|
}
|
|
63884
|
-
var
|
|
64424
|
+
var import_node_fs73, import_node_path100;
|
|
63885
64425
|
var init_startup_ui_text = __esm({
|
|
63886
64426
|
"src/modes/startup-ui-text.ts"() {
|
|
63887
64427
|
"use strict";
|
|
63888
|
-
|
|
63889
|
-
|
|
64428
|
+
import_node_fs73 = require("node:fs");
|
|
64429
|
+
import_node_path100 = require("node:path");
|
|
63890
64430
|
init_i18n();
|
|
63891
64431
|
}
|
|
63892
64432
|
});
|
|
@@ -63911,7 +64451,7 @@ function createTools(input2, options, state) {
|
|
|
63911
64451
|
const osStatus = configureOsSandbox(input2.config.sandbox?.enabled);
|
|
63912
64452
|
const bashSandbox = options.bashSandbox ?? resolveBashSandbox(input2.config.sandbox, {
|
|
63913
64453
|
status: osStatus,
|
|
63914
|
-
...input2.paths === void 0 ? {} : { hidden: [(0,
|
|
64454
|
+
...input2.paths === void 0 ? {} : { hidden: [(0, import_node_path101.join)(input2.paths.configDir, AUTH_FILE)] }
|
|
63915
64455
|
});
|
|
63916
64456
|
state.bashSandbox = bashSandbox;
|
|
63917
64457
|
const capability = options.sandboxCapability ?? sandboxCapabilityFor(input2.config);
|
|
@@ -64032,7 +64572,7 @@ function createRuntimeDeps(options = {}) {
|
|
|
64032
64572
|
return registry3;
|
|
64033
64573
|
}
|
|
64034
64574
|
},
|
|
64035
|
-
sessions: createSessionStore(),
|
|
64575
|
+
sessions: createSessionStore(options.log ?? stderrLog()),
|
|
64036
64576
|
tools: { create: (input2) => createTools(input2, options, state) },
|
|
64037
64577
|
permissions: {
|
|
64038
64578
|
create: (input2) => new PermissionPipeline({
|
|
@@ -64101,7 +64641,7 @@ function createRuntimeDeps(options = {}) {
|
|
|
64101
64641
|
if (ui !== void 0) deps.ui = ui;
|
|
64102
64642
|
return deps;
|
|
64103
64643
|
}
|
|
64104
|
-
var
|
|
64644
|
+
var import_node_path101, DEFAULT_TOOL_FACTORIES, DEFAULT_MODES;
|
|
64105
64645
|
var init_compose2 = __esm({
|
|
64106
64646
|
"src/cli/compose.ts"() {
|
|
64107
64647
|
"use strict";
|
|
@@ -64116,7 +64656,7 @@ var init_compose2 = __esm({
|
|
|
64116
64656
|
init_tool();
|
|
64117
64657
|
init_detect();
|
|
64118
64658
|
init_bash();
|
|
64119
|
-
|
|
64659
|
+
import_node_path101 = require("node:path");
|
|
64120
64660
|
init_paths();
|
|
64121
64661
|
init_presets2();
|
|
64122
64662
|
init_registry();
|
|
@@ -64331,8 +64871,8 @@ var init_memory3 = __esm({
|
|
|
64331
64871
|
});
|
|
64332
64872
|
|
|
64333
64873
|
// src/cli/main.ts
|
|
64334
|
-
var
|
|
64335
|
-
var
|
|
64874
|
+
var import_node_fs74 = require("node:fs");
|
|
64875
|
+
var import_node_path102 = require("node:path");
|
|
64336
64876
|
var import_node_url3 = require("node:url");
|
|
64337
64877
|
init_version();
|
|
64338
64878
|
init_args();
|
|
@@ -69698,9 +70238,9 @@ async function runSessionsTrace(argv, io, deps = {}) {
|
|
|
69698
70238
|
});
|
|
69699
70239
|
}
|
|
69700
70240
|
const outFlag = split.file ?? values.get("output");
|
|
69701
|
-
const
|
|
70241
|
+
const open3 = flags2.has("open");
|
|
69702
70242
|
let outPath = outFlag === void 0 ? void 0 : (0, import_node_path84.resolve)(io.cwd, expandHome(outFlag, { env: io.env }));
|
|
69703
|
-
if (outPath === void 0 &&
|
|
70243
|
+
if (outPath === void 0 && open3)
|
|
69704
70244
|
outPath = (0, import_node_path84.join)((0, import_node_os12.tmpdir)(), `ama-trace-${read2.header.id}.${wantsJson ? "json" : "html"}`);
|
|
69705
70245
|
if (outPath === void 0) {
|
|
69706
70246
|
io.stdout(text);
|
|
@@ -69708,7 +70248,7 @@ async function runSessionsTrace(argv, io, deps = {}) {
|
|
|
69708
70248
|
}
|
|
69709
70249
|
(0, import_node_fs64.writeFileSync)(outPath, text, { mode: 384 });
|
|
69710
70250
|
io.stderr(m.wrote(outPath));
|
|
69711
|
-
if (
|
|
70251
|
+
if (open3) {
|
|
69712
70252
|
try {
|
|
69713
70253
|
await (deps.open ?? spawnOpen)(openCommand(deps.platform ?? process.platform, outPath));
|
|
69714
70254
|
} catch (error2) {
|
|
@@ -69907,7 +70447,7 @@ function readStdinDefault() {
|
|
|
69907
70447
|
}
|
|
69908
70448
|
function stdinKindDefault() {
|
|
69909
70449
|
try {
|
|
69910
|
-
const stat16 = (0,
|
|
70450
|
+
const stat16 = (0, import_node_fs74.fstatSync)(0);
|
|
69911
70451
|
if (stat16.isFile()) return "file";
|
|
69912
70452
|
if (stat16.isFIFO()) return "fifo";
|
|
69913
70453
|
if (stat16.isSocket()) return "socket";
|
|
@@ -69967,7 +70507,7 @@ function defaultIo() {
|
|
|
69967
70507
|
}
|
|
69968
70508
|
function peekUserLanguage(env) {
|
|
69969
70509
|
try {
|
|
69970
|
-
const raw = (0,
|
|
70510
|
+
const raw = (0, import_node_fs74.readFileSync)((0, import_node_path102.join)(resolveConfigDir({ env }), "config.json"), "utf8");
|
|
69971
70511
|
const value = JSON.parse(raw).ui?.language;
|
|
69972
70512
|
return value === "auto" || value === "zh" || value === "en" ? value : void 0;
|
|
69973
70513
|
} catch {
|
|
@@ -70055,7 +70595,7 @@ function isDirectRun() {
|
|
|
70055
70595
|
const entry = process.argv[1];
|
|
70056
70596
|
if (entry === void 0) return false;
|
|
70057
70597
|
try {
|
|
70058
|
-
return (0,
|
|
70598
|
+
return (0, import_node_fs74.realpathSync)(entry) === (0, import_node_fs74.realpathSync)((0, import_node_url3.fileURLToPath)(__ama_import_meta_url));
|
|
70059
70599
|
} catch {
|
|
70060
70600
|
return false;
|
|
70061
70601
|
}
|