deepseeker-code 1.0.54 → 1.0.55

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.
Files changed (3) hide show
  1. package/README.md +20 -0
  2. package/dist/cli.mjs +1493 -581
  3. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -171,6 +171,7 @@ ${dim} \u8FD0\u884C npm i -g deepseeker-code@latest \u66F4\u65B0${reset}
171
171
  cmdExit: "\u9000\u51FA CLI",
172
172
  cmdSessions: "\u9009\u62E9\u5E76\u8F7D\u5165\u5386\u53F2\u4F1A\u8BDD\uFF08\u7EED\u63A5\u5BF9\u8BDD\uFF09",
173
173
  cmdUsage: "\u67E5\u770B\u672C\u4F1A\u8BDD token \u7528\u91CF\uFF08\u4E3B/\u5B50 agent\u3001\u7F13\u5B58\u547D\u4E2D\uFF09",
174
+ cmdBudget: "\u9884\u7B97\u5236\u8FD0\u884C\uFF1A/budget 0.5 \u8BBE\u7F6E\u6BCF run \u4E0A\u9650 \xB7 /budget off \u5173\u95ED \xB7 /budget \u67E5\u770B",
174
175
  cmdContext: "\u67E5\u770B\u4E0A\u4E0B\u6587\u7A97\u53E3\u6CBB\u7406\uFF08\u9608\u503C\u3001\u586B\u5145\u7387\u3001\u5DF2\u5F52\u6863\uFF09",
175
176
  cmdPermissions: "\u67E5\u770B\u5DF2\u52A0\u8F7D\u7684\u6743\u9650\u89C4\u5219\uFF08allow/ask/deny\uFF09",
176
177
  cmdMcp: "\u67E5\u770B\u5DF2\u8FDE\u63A5\u7684 MCP server \u4E0E\u5DE5\u5177\u6570",
@@ -325,6 +326,7 @@ ${dim} Run npm i -g deepseeker-code@latest to update${reset}
325
326
  cmdExit: "Quit the CLI",
326
327
  cmdSessions: "Pick a past session to resume",
327
328
  cmdUsage: "Show this session's token usage (main/sub agent, cache hit)",
329
+ cmdBudget: "Budget mode: /budget 0.5 set per-run cap \xB7 /budget off disable \xB7 /budget view",
328
330
  cmdContext: "Show context window governance (threshold, fill, archived)",
329
331
  cmdPermissions: "Show loaded permission rules (allow/ask/deny)",
330
332
  cmdMcp: "Show connected MCP servers and tool counts",
@@ -409,7 +411,7 @@ DeepSeeker-Code will read, edit, and execute files here.`,
409
411
  S = new Proxy({}, {
410
412
  get: (_t, k) => typeof k === "string" ? STRINGS[locale][k] : void 0
411
413
  });
412
- LOCAL_COMMAND_NAMES = ["help", "status", "plan", "auto", "model", "switch", "thinking", "lang", "output-style", "new", "sessions", "fork", "usage", "context", "permissions", "mcp", "hooks", "trust", "debug", "clear", "exit"];
414
+ LOCAL_COMMAND_NAMES = ["help", "status", "plan", "auto", "model", "switch", "thinking", "lang", "output-style", "new", "sessions", "fork", "usage", "budget", "context", "permissions", "mcp", "hooks", "trust", "debug", "clear", "exit"];
413
415
  }
414
416
  });
415
417
 
@@ -792,6 +794,279 @@ var init_trust = __esm({
792
794
  }
793
795
  });
794
796
 
797
+ // ../core/src/batch/ticket.ts
798
+ import fs4 from "fs/promises";
799
+ var generateBatchId, parseToolsValue, parsePositiveNumber, parseBatchTicket, readBatchTicket;
800
+ var init_ticket = __esm({
801
+ "../core/src/batch/ticket.ts"() {
802
+ "use strict";
803
+ generateBatchId = (now = /* @__PURE__ */ new Date()) => {
804
+ const p = (n, w = 2) => String(n).padStart(w, "0");
805
+ const rand = Math.random().toString(36).slice(2, 6);
806
+ return `${now.getFullYear()}${p(now.getMonth() + 1)}${p(now.getDate())}-${p(now.getHours())}${p(now.getMinutes())}${p(now.getSeconds())}-${rand}`;
807
+ };
808
+ parseToolsValue = (raw) => raw.replace(/^\[|\]$/g, "").split(",").map((s) => s.trim().replace(/^["']|["']$/g, "")).filter(Boolean);
809
+ parsePositiveNumber = (raw) => {
810
+ const n = Number(raw.trim());
811
+ return Number.isFinite(n) && n > 0 ? n : null;
812
+ };
813
+ parseBatchTicket = (source) => {
814
+ const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(source);
815
+ if (!m) return { ok: false, error: "\u7F3A\u5C11 frontmatter\uFF08--- \u5305\u88F9\u7684\u5934\u90E8\u5757\uFF09\u3002\u5DE5\u5355\u683C\u5F0F\u89C1 batch add \u5E2E\u52A9\u3002" };
816
+ const [, fmRaw, bodyRaw] = m;
817
+ const fm = {};
818
+ for (const line of fmRaw.split(/\r?\n/)) {
819
+ const kv = /^([A-Za-z][\w-]*)\s*:\s*(.*)$/.exec(line.trim());
820
+ if (!kv) continue;
821
+ fm[kv[1].toLowerCase()] = kv[2].trim();
822
+ }
823
+ const accept = (fm["accept"] ?? "").trim();
824
+ if (!accept) return { ok: false, error: "frontmatter \u7F3A accept\uFF08\u9A8C\u6536\u547D\u4EE4\uFF09\u3002\u6302\u673A\u4EFB\u52A1\u5FC5\u987B\u5E26\u53EF\u6267\u884C\u9A8C\u6536\uFF0C\u7F3A\u9A8C\u6536\u62D2\u7EDD\u5165\u961F\u3002" };
825
+ let budgetYuan;
826
+ if (fm["budget-yuan"] !== void 0) {
827
+ const n = parsePositiveNumber(fm["budget-yuan"]);
828
+ if (n === null) return { ok: false, error: `budget-yuan \u975E\u6CD5\uFF08"${fm["budget-yuan"]}"\uFF09\uFF1A\u987B\u4E3A\u6B63\u6570\uFF08\u5143\uFF09\u3002` };
829
+ budgetYuan = n;
830
+ }
831
+ let timeoutMin;
832
+ if (fm["timeout-min"] !== void 0) {
833
+ const n = parsePositiveNumber(fm["timeout-min"]);
834
+ if (n === null) return { ok: false, error: `timeout-min \u975E\u6CD5\uFF08"${fm["timeout-min"]}"\uFF09\uFF1A\u987B\u4E3A\u6B63\u6574\u6570\uFF08\u5206\u949F\uFF09\u3002` };
835
+ timeoutMin = n;
836
+ }
837
+ const tools = fm["tools"] !== void 0 ? parseToolsValue(fm["tools"]) : void 0;
838
+ if (tools && tools.length === 0) return { ok: false, error: "tools \u4E3A\u7A7A\uFF1A\u8981\u4E48\u5220\u6389\u8BE5\u884C\uFF08\u7528\u7F3A\u7701\u7981\u7528\u6E05\u5355\uFF09\uFF0C\u8981\u4E48\u5217\u5DE5\u5177\u540D\uFF08\u9017\u53F7\u5206\u9694\uFF09\u3002" };
839
+ const body = bodyRaw.trim();
840
+ if (!body) return { ok: false, error: "\u4EFB\u52A1\u6B63\u6587\u4E3A\u7A7A\uFF1Afrontmatter \u4E4B\u540E\u5E94\u5199\u4EFB\u52A1\u63CF\u8FF0\u3002" };
841
+ const title = (fm["title"] ?? "").trim() || body.split(/\r?\n/).find((l) => l.trim())?.slice(0, 40) || "(\u672A\u547D\u540D\u4EFB\u52A1)";
842
+ return { ok: true, ticket: { title, accept, budgetYuan, timeoutMin, tools: tools && tools.length > 0 ? tools : void 0, body } };
843
+ };
844
+ readBatchTicket = async (filePath) => {
845
+ let source;
846
+ try {
847
+ source = await fs4.readFile(filePath, "utf-8");
848
+ } catch (e) {
849
+ return { ok: false, error: `\u8BFB\u5DE5\u5355\u5931\u8D25\uFF1A${e?.message ?? e}` };
850
+ }
851
+ return parseBatchTicket(source);
852
+ };
853
+ }
854
+ });
855
+
856
+ // ../core/src/batch/queue.ts
857
+ import fs5 from "fs/promises";
858
+ import path6 from "path";
859
+ var batchQueueRoot, stateDir, lockPath, listState, snapshotQueue, reportPath, enqueueTicketFile, takeNextTicket, requeueStaleRunning, finishTicket, cleanDone, pidAlive, acquireRunLock, releaseRunLock;
860
+ var init_queue = __esm({
861
+ "../core/src/batch/queue.ts"() {
862
+ "use strict";
863
+ init_ticket();
864
+ batchQueueRoot = () => process.env.DEEPSEEKER_CODE_BATCH_DIR || path6.join(process.cwd(), ".deepseeker-code", "batch");
865
+ stateDir = (s) => path6.join(batchQueueRoot(), s);
866
+ lockPath = () => path6.join(batchQueueRoot(), ".lock");
867
+ listState = async (s) => {
868
+ try {
869
+ return (await fs5.readdir(stateDir(s))).filter((f) => f.endsWith(".md") && !f.endsWith(".report.md")).sort();
870
+ } catch {
871
+ return [];
872
+ }
873
+ };
874
+ snapshotQueue = async () => ({
875
+ pending: await listState("pending"),
876
+ running: await listState("running"),
877
+ done: (await listState("done")).map((f) => f.replace(/\.md$/, ""))
878
+ });
879
+ reportPath = (id) => path6.join(stateDir("done"), `${id}.report.md`);
880
+ enqueueTicketFile = async (srcPath) => {
881
+ const parsed = await readBatchTicket(srcPath);
882
+ if (!parsed.ok) return parsed;
883
+ const source = await fs5.readFile(srcPath, "utf-8");
884
+ const id = generateBatchId();
885
+ await fs5.mkdir(stateDir("pending"), { recursive: true });
886
+ await fs5.writeFile(path6.join(stateDir("pending"), `${id}.md`), source, "utf-8");
887
+ return { ok: true, id, title: parsed.ticket.title };
888
+ };
889
+ takeNextTicket = async () => {
890
+ await requeueStaleRunning();
891
+ const pending = await listState("pending");
892
+ if (pending.length === 0) return null;
893
+ const file = pending[0];
894
+ const from = path6.join(stateDir("pending"), file);
895
+ const to = path6.join(stateDir("running"), file);
896
+ await fs5.mkdir(stateDir("running"), { recursive: true });
897
+ await fs5.rename(from, to);
898
+ return { id: file.replace(/\.md$/, ""), path: to };
899
+ };
900
+ requeueStaleRunning = async () => {
901
+ const stale = await listState("running");
902
+ if (stale.length === 0) return 0;
903
+ await fs5.mkdir(stateDir("pending"), { recursive: true });
904
+ for (const f of stale) {
905
+ await fs5.rename(path6.join(stateDir("running"), f), path6.join(stateDir("pending"), f)).catch(() => {
906
+ });
907
+ }
908
+ return stale.length;
909
+ };
910
+ finishTicket = async (id, reportMd) => {
911
+ try {
912
+ await fs5.mkdir(stateDir("done"), { recursive: true });
913
+ await fs5.writeFile(reportPath(id), reportMd, "utf-8");
914
+ await fs5.rename(path6.join(stateDir("running"), `${id}.md`), path6.join(stateDir("done"), `${id}.md`)).catch(() => {
915
+ });
916
+ } catch (e) {
917
+ console.warn(`\u26A0\uFE0F [batch] \u62A5\u544A\u843D\u76D8\u5931\u8D25\uFF08\u4EFB\u52A1\u7ED3\u679C\u4EE5\u63A7\u5236\u53F0\u8F93\u51FA\u4E3A\u51C6\uFF09: ${e?.message ?? e}`);
918
+ }
919
+ };
920
+ cleanDone = async () => {
921
+ const files = await listState("done");
922
+ for (const f of await fs5.readdir(stateDir("done")).catch(() => [])) {
923
+ if (f.endsWith(".md") || f.endsWith(".report.md")) {
924
+ await fs5.rm(path6.join(stateDir("done"), f), { force: true }).catch(() => {
925
+ });
926
+ }
927
+ }
928
+ return files.length;
929
+ };
930
+ pidAlive = (pid) => {
931
+ try {
932
+ process.kill(pid, 0);
933
+ return true;
934
+ } catch (e) {
935
+ return e?.code === "EPERM";
936
+ }
937
+ };
938
+ acquireRunLock = async () => {
939
+ await fs5.mkdir(batchQueueRoot(), { recursive: true });
940
+ const payload = `${process.pid} ${(/* @__PURE__ */ new Date()).toISOString()}`;
941
+ try {
942
+ await fs5.writeFile(lockPath(), payload, { flag: "wx" });
943
+ return { ok: true };
944
+ } catch (e) {
945
+ if (e?.code !== "EEXIST") return { ok: false, error: `\u9501\u521B\u5EFA\u5931\u8D25\uFF1A${e?.message ?? e}` };
946
+ const raw = await fs5.readFile(lockPath(), "utf-8").catch(() => "");
947
+ const ownerPid = parseInt(raw.split(" ")[0], 10);
948
+ if (Number.isFinite(ownerPid) && pidAlive(ownerPid)) {
949
+ return { ok: false, error: `\u5DF2\u6709 batch runner \u5728\u8FD0\u884C\uFF08pid ${ownerPid}\uFF09\u3002\u6302\u673A\u6A21\u5F0F\u4E32\u884C\uFF0C\u52FF\u5E76\u53D1\u8DD1\u4E24\u4E2A runner\u3002` };
950
+ }
951
+ await fs5.writeFile(lockPath(), payload).catch(() => {
952
+ });
953
+ return { ok: true };
954
+ }
955
+ };
956
+ releaseRunLock = async () => {
957
+ const raw = await fs5.readFile(lockPath(), "utf-8").catch(() => "");
958
+ if (parseInt(raw.split(" ")[0], 10) === process.pid) {
959
+ await fs5.rm(lockPath(), { force: true }).catch(() => {
960
+ });
961
+ }
962
+ };
963
+ }
964
+ });
965
+
966
+ // src/batchAdmin.ts
967
+ var batchAdmin_exports = {};
968
+ __export(batchAdmin_exports, {
969
+ handleBatchAdmin: () => handleBatchAdmin,
970
+ parseBatchArgv: () => parseBatchArgv
971
+ });
972
+ import fs6 from "fs/promises";
973
+ import path7 from "path";
974
+ var emit, parseBatchArgv, USAGE, handleBatchAdmin, describeDone;
975
+ var init_batchAdmin = __esm({
976
+ "src/batchAdmin.ts"() {
977
+ "use strict";
978
+ init_queue();
979
+ emit = (s = "") => {
980
+ process.stdout.write(s + "\n");
981
+ };
982
+ parseBatchArgv = (argv) => {
983
+ if (argv[0] !== "batch") return null;
984
+ const sub = argv[1];
985
+ if (sub === "add") return { sub: "add", files: argv.slice(2) };
986
+ if (sub === "run") {
987
+ const wi = argv.indexOf("--wait-window");
988
+ const waitWindow = wi !== -1 ? argv[wi + 1] : void 0;
989
+ return { sub: "run", waitWindow };
990
+ }
991
+ if (sub === "list") return { sub: "list" };
992
+ if (sub === "clean") return { sub: "clean" };
993
+ return { sub: "help" };
994
+ };
995
+ USAGE = `deepseeker-code batch \u2014\u2014 \u6302\u673A\u6279\u5904\u7406\uFF08\u6210\u672C\u4FE1\u4EFB\u94FE\u7B2C\u56DB\u73AF\uFF09
996
+
997
+ \u7528\u6CD5\uFF1Adeepseeker-code batch <\u5B50\u547D\u4EE4>
998
+ add <\u5DE5\u5355.md> [...] \u6295\u9012\u4EFB\u52A1\uFF08\u53EF\u4E00\u6B21\u591A\u4E2A\u6587\u4EF6\uFF09
999
+ list \u67E5\u770B pending / running / done \u4E09\u6001\u961F\u5217
1000
+ run [--wait-window HH:MM-HH:MM] \u6267\u884C\u961F\u5217\uFF08\u4E32\u884C\uFF0C\u9010\u4EFB\u52A1\u51FA\u62A5\u544A\uFF1B--wait-window \u5230\u70B9\u518D\u5F00\u8DD1\uFF09
1001
+ clean \u6E05\u7A7A done/\uFF08\u5DF2\u8BFB\u8FC7\u7684\u62A5\u544A\u4E0E\u5DE5\u5355\u5B58\u6863\uFF09
1002
+
1003
+ \u5DE5\u5355\u683C\u5F0F\uFF08Markdown\uFF0Cfrontmatter \u7684 accept \u5FC5\u586B\u2014\u2014\u7F3A\u9A8C\u6536\u62D2\u7EDD\u5165\u961F\uFF09\uFF1A
1004
+ ---
1005
+ title: \u4FEE\u590D\u65E5\u671F\u89E3\u6790 bug
1006
+ accept: npm test
1007
+ budget-yuan: 0.5 # \u53EF\u9009\uFF1A\u672C\u4EFB\u52A1\u82B1\u8D39\u4E0A\u9650\uFF08\u5143\uFF09
1008
+ timeout-min: 30 # \u53EF\u9009\uFF1Aagent \u9636\u6BB5\u8D85\u65F6\uFF08\u5206\u949F\uFF0C\u7F3A\u7701 30\uFF09
1009
+ tools: run_command # \u53EF\u9009\uFF1A\u663E\u5F0F\u89E3\u9501\u9AD8\u5371\u5DE5\u5177\uFF08\u7F3A\u7701\u7981 run_command/delete_path\uFF09
1010
+ ---
1011
+ \u4EFB\u52A1\u63CF\u8FF0\u6B63\u6587\uFF08Markdown\uFF09\u2026
1012
+
1013
+ \u4EA7\u7269\uFF1A<\u9879\u76EE>/.deepseeker-code/batch/done/<id>.report.md\uFF08\u72B6\u6001/\u7ED3\u7B97\u5355/\u9A8C\u6536\u8F93\u51FA/diff \u6458\u8981\uFF09\uFF1B
1014
+ \u6539\u52A8\u6536\u5272\u5728\u72EC\u7ACB git worktree\uFF08\u4E34\u65F6\u5206\u652F\uFF09\u4E0A\uFF0C\u4FDD\u7559\u5F85\u4EBA\u5DE5 merge \u6216\u4E22\u5F03\u3002`;
1015
+ handleBatchAdmin = async (b) => {
1016
+ if (b.sub === "help") {
1017
+ emit(USAGE);
1018
+ return;
1019
+ }
1020
+ if (b.sub === "add") {
1021
+ if (b.files.length === 0) {
1022
+ emit("\u7528\u6CD5\uFF1Adeepseeker-code batch add <\u5DE5\u5355.md> [...]\uFF08\u7F3A\u9A8C\u6536\u547D\u4EE4\u7684\u5DE5\u5355\u4F1A\u88AB\u62D2\u7EDD\uFF09\n\u8BE6\u60C5\uFF1Adeepseeker-code batch help");
1023
+ return;
1024
+ }
1025
+ for (const f of b.files) {
1026
+ const abs = path7.resolve(f);
1027
+ const r = await enqueueTicketFile(abs).catch((e) => ({ ok: false, error: `\u8BFB\u6587\u4EF6\u5931\u8D25\uFF1A${e?.message ?? e}` }));
1028
+ if (r.ok) emit(`\u{1F4E5} \u5DF2\u5165\u961F [${r.id}] ${r.title}`);
1029
+ else emit(`\u{1F6AB} \u62D2\u7EDD ${path7.basename(abs)}\uFF1A${r.error}`);
1030
+ }
1031
+ emit("\n\u8DD1\u6279\uFF1Adeepseeker-code batch run");
1032
+ return;
1033
+ }
1034
+ if (b.sub === "list") {
1035
+ const q = await snapshotQueue();
1036
+ if (q.pending.length + q.running.length + q.done.length === 0) {
1037
+ emit("\u961F\u5217\u7A7A\u3002\u6295\u9012\uFF1Adeepseeker-code batch add <\u5DE5\u5355.md>\uFF08\u683C\u5F0F\u89C1 batch help\uFF09");
1038
+ return;
1039
+ }
1040
+ if (q.running.length > 0) emit(`\u25B6 \u8FD0\u884C\u4E2D\uFF1A`);
1041
+ for (const f of q.running) emit(` ${f.replace(/\.md$/, "")}`);
1042
+ if (q.pending.length > 0) emit(`\u23F3 \u5F85\u8DD1 ${q.pending.length}\uFF1A`);
1043
+ for (const f of q.pending) emit(` ${f.replace(/\.md$/, "")}`);
1044
+ if (q.done.length > 0) emit(`\u2714 \u5DF2\u5B8C\u6210 ${q.done.length}\uFF1A`);
1045
+ for (const id of q.done) emit(` ${id} ${await describeDone(id)}`);
1046
+ return;
1047
+ }
1048
+ if (b.sub === "clean") {
1049
+ const n = await cleanDone();
1050
+ emit(`\u{1F9F9} \u5DF2\u6E05\u7A7A done/\uFF08${n} \u4E2A\u4EFB\u52A1\u5B58\u6863\uFF09\u3002pending/running \u4E0D\u53D7\u5F71\u54CD\u3002`);
1051
+ return;
1052
+ }
1053
+ };
1054
+ describeDone = async (id) => {
1055
+ let text;
1056
+ try {
1057
+ text = await fs6.readFile(reportPath(id), "utf-8");
1058
+ } catch {
1059
+ return "\uFF08\u62A5\u544A\u7F3A\u5931\uFF09";
1060
+ }
1061
+ const fm = (key) => {
1062
+ const m = new RegExp(`^${key}:\\s*(.+)$`, "m").exec(text);
1063
+ return m ? m[1].trim() : "";
1064
+ };
1065
+ return `[${fm("status") || "?"}] ${fm("title")}`;
1066
+ };
1067
+ }
1068
+ });
1069
+
795
1070
  // ../core/src/tool/type.ts
796
1071
  var MAX_AGENT_DEPTH, ToolSafetyLevel, ToolExecutionResultStatus, asToolFailure, toolFailure;
797
1072
  var init_type = __esm({
@@ -1090,15 +1365,15 @@ var init_createModel = __esm({
1090
1365
  });
1091
1366
 
1092
1367
  // ../core/src/llm/visionCapability.ts
1093
- import path6 from "path";
1094
- import fs4 from "fs/promises";
1368
+ import path8 from "path";
1369
+ import fs7 from "fs/promises";
1095
1370
  var CAP_FILE, MAX_ENTRIES, mem, loadPromise, ensureVisionCacheLoaded, peekVisionCapability, writeChain, persistLatest, learnVisionCapability;
1096
1371
  var init_visionCapability = __esm({
1097
1372
  "../core/src/llm/visionCapability.ts"() {
1098
1373
  "use strict";
1099
1374
  init_config();
1100
1375
  init_common();
1101
- CAP_FILE = path6.join(appConfig.dataDir, "model-capabilities.json");
1376
+ CAP_FILE = path8.join(appConfig.dataDir, "model-capabilities.json");
1102
1377
  MAX_ENTRIES = 100;
1103
1378
  mem = {};
1104
1379
  loadPromise = (async () => {
@@ -1115,7 +1390,7 @@ var init_visionCapability = __esm({
1115
1390
  persistLatest = () => {
1116
1391
  writeChain = writeChain.then(async () => {
1117
1392
  try {
1118
- await fs4.mkdir(appConfig.dataDir, { recursive: true });
1393
+ await fs7.mkdir(appConfig.dataDir, { recursive: true });
1119
1394
  await atomicWriteJSON(CAP_FILE, mem);
1120
1395
  } catch {
1121
1396
  }
@@ -1456,7 +1731,7 @@ var init_contextCore = __esm({
1456
1731
  return messagesArr.reduce((total, m) => total + messageTokens(m), 0);
1457
1732
  };
1458
1733
  cleanMsg = (m) => {
1459
- const { id, sessionId, ts, ...rest } = m;
1734
+ const { id, sessionId, ts: ts2, ...rest } = m;
1460
1735
  return rest;
1461
1736
  };
1462
1737
  groupUnits = (messagesArr) => {
@@ -1514,8 +1789,8 @@ __export(store_exports, {
1514
1789
  updateCalibration: () => updateCalibration,
1515
1790
  writeStore: () => writeStore
1516
1791
  });
1517
- import fs5 from "fs/promises";
1518
- import path7 from "path";
1792
+ import fs8 from "fs/promises";
1793
+ import path9 from "path";
1519
1794
  async function getRollingState(sessionId) {
1520
1795
  const store = await readStore(sessionId);
1521
1796
  if (!store) {
@@ -1563,22 +1838,22 @@ var init_store = __esm({
1563
1838
  getSessionsDirPath = (mainSessionId) => {
1564
1839
  assertSafeSessionId(mainSessionId);
1565
1840
  const fileName = getFileName(mainSessionId);
1566
- return path7.join(appConfig.dataDir, "sessions", appConfig.userWorkspaceDir, fileName);
1841
+ return path9.join(appConfig.dataDir, "sessions", appConfig.userWorkspaceDir, fileName);
1567
1842
  };
1568
- getWorkspaceSessionsDir = () => path7.join(appConfig.dataDir, "sessions", appConfig.userWorkspaceDir);
1843
+ getWorkspaceSessionsDir = () => path9.join(appConfig.dataDir, "sessions", appConfig.userWorkspaceDir);
1569
1844
  getStatePath = (sessionId) => {
1570
1845
  assertSafeSessionId(sessionId);
1571
- return path7.join(getSessionsDirPath(sessionId), `${sessionId}.state.json`);
1846
+ return path9.join(getSessionsDirPath(sessionId), `${sessionId}.state.json`);
1572
1847
  };
1573
1848
  getTranscriptPath = (sessionId) => {
1574
1849
  assertSafeSessionId(sessionId);
1575
- return path7.join(getSessionsDirPath(sessionId), `${sessionId}.jsonl`);
1850
+ return path9.join(getSessionsDirPath(sessionId), `${sessionId}.jsonl`);
1576
1851
  };
1577
1852
  ensuredSessionDirs = /* @__PURE__ */ new Set();
1578
1853
  ensureSessionsDir = async (sessionId) => {
1579
1854
  const dir = getSessionsDirPath(sessionId);
1580
1855
  if (ensuredSessionDirs.has(dir)) return;
1581
- await fs5.mkdir(dir, { recursive: true });
1856
+ await fs8.mkdir(dir, { recursive: true });
1582
1857
  await migrateLegacyFiles(sessionId).catch(() => {
1583
1858
  });
1584
1859
  ensuredSessionDirs.add(dir);
@@ -1586,23 +1861,23 @@ var init_store = __esm({
1586
1861
  migrateLegacyFiles = async (sessionId) => {
1587
1862
  assertSafeSessionId(sessionId);
1588
1863
  const dir = getSessionsDirPath(sessionId);
1589
- const legacy = path7.join(dir, `${sessionId}.json`);
1864
+ const legacy = path9.join(dir, `${sessionId}.json`);
1590
1865
  const transcriptPath = getTranscriptPath(sessionId);
1591
1866
  const statePath = getStatePath(sessionId);
1592
1867
  let legacyText;
1593
1868
  try {
1594
- legacyText = await fs5.readFile(legacy, "utf-8");
1869
+ legacyText = await fs8.readFile(legacy, "utf-8");
1595
1870
  } catch {
1596
1871
  return;
1597
1872
  }
1598
1873
  try {
1599
- await fs5.access(transcriptPath);
1874
+ await fs8.access(transcriptPath);
1600
1875
  return;
1601
1876
  } catch {
1602
1877
  }
1603
1878
  const raw = legacyText.trim();
1604
1879
  if (raw.length === 0) {
1605
- await fs5.rename(legacy, transcriptPath);
1880
+ await fs8.rename(legacy, transcriptPath);
1606
1881
  return;
1607
1882
  }
1608
1883
  const lines = raw.split("\n");
@@ -1615,13 +1890,13 @@ var init_store = __esm({
1615
1890
  }
1616
1891
  });
1617
1892
  if (isJsonl) {
1618
- await fs5.rename(legacy, transcriptPath);
1893
+ await fs8.rename(legacy, transcriptPath);
1619
1894
  return;
1620
1895
  }
1621
1896
  try {
1622
1897
  const v = JSON.parse(raw);
1623
1898
  if (typeof v === "object" && v !== null) {
1624
- await fs5.rename(legacy, statePath);
1899
+ await fs8.rename(legacy, statePath);
1625
1900
  return;
1626
1901
  }
1627
1902
  } catch {
@@ -1632,8 +1907,8 @@ var init_store = __esm({
1632
1907
  await ensureSessionsDir(sessionId);
1633
1908
  const finalPath = getStatePath(sessionId);
1634
1909
  const tmpPath = `${finalPath}.${Date.now()}.tmp`;
1635
- await fs5.writeFile(tmpPath, JSON.stringify(store, null, 2), "utf-8");
1636
- await fs5.rename(tmpPath, finalPath);
1910
+ await fs8.writeFile(tmpPath, JSON.stringify(store, null, 2), "utf-8");
1911
+ await fs8.rename(tmpPath, finalPath);
1637
1912
  };
1638
1913
  storeLocks = /* @__PURE__ */ new Map();
1639
1914
  withStoreLock = (sessionId, fn) => {
@@ -1673,7 +1948,7 @@ var init_store = __esm({
1673
1948
  await ensureSessionsDir(sessionId);
1674
1949
  const p = getStatePath(sessionId);
1675
1950
  try {
1676
- const raw = (await fs5.readFile(p, "utf-8")).trim();
1951
+ const raw = (await fs8.readFile(p, "utf-8")).trim();
1677
1952
  if (raw.length === 0) {
1678
1953
  return {};
1679
1954
  }
@@ -1702,7 +1977,7 @@ var init_store = __esm({
1702
1977
  const root = getWorkspaceSessionsDir();
1703
1978
  let entries;
1704
1979
  try {
1705
- entries = await fs5.readdir(root, { withFileTypes: true });
1980
+ entries = await fs8.readdir(root, { withFileTypes: true });
1706
1981
  } catch {
1707
1982
  return [];
1708
1983
  }
@@ -1711,12 +1986,12 @@ var init_store = __esm({
1711
1986
  if (!entry.isDirectory()) continue;
1712
1987
  const sessionId = entry.name;
1713
1988
  if (!isSafeSessionId(sessionId)) continue;
1714
- const dirPath = path7.join(root, sessionId);
1989
+ const dirPath = path9.join(root, sessionId);
1715
1990
  const state = await readJSONFile(getStatePath(sessionId));
1716
1991
  let messageCount = 0;
1717
1992
  let preview = "";
1718
1993
  try {
1719
- const raw = await fs5.readFile(getTranscriptPath(sessionId), "utf-8");
1994
+ const raw = await fs8.readFile(getTranscriptPath(sessionId), "utf-8");
1720
1995
  for (const s of raw.split("\n")) {
1721
1996
  const line = s.trim();
1722
1997
  if (!line) continue;
@@ -1743,7 +2018,7 @@ var init_store = __esm({
1743
2018
  let updatedAt = state?.updatedAt;
1744
2019
  if (!updatedAt) {
1745
2020
  try {
1746
- updatedAt = (await fs5.stat(dirPath)).mtime.toISOString();
2021
+ updatedAt = (await fs8.stat(dirPath)).mtime.toISOString();
1747
2022
  } catch {
1748
2023
  }
1749
2024
  }
@@ -1763,7 +2038,7 @@ var init_store = __esm({
1763
2038
  const root = getWorkspaceSessionsDir();
1764
2039
  let entries;
1765
2040
  try {
1766
- entries = await fs5.readdir(root, { withFileTypes: true });
2041
+ entries = await fs8.readdir(root, { withFileTypes: true });
1767
2042
  } catch {
1768
2043
  return null;
1769
2044
  }
@@ -1773,11 +2048,12 @@ var init_store = __esm({
1773
2048
  if (!entry.isDirectory()) continue;
1774
2049
  const sessionId = entry.name;
1775
2050
  if (!isSafeSessionId(sessionId)) continue;
2051
+ if (sessionId.startsWith("batch-")) continue;
1776
2052
  const state = await readJSONFile(getStatePath(sessionId));
1777
2053
  let updatedAt = state?.updatedAt;
1778
2054
  if (!updatedAt) {
1779
2055
  try {
1780
- updatedAt = (await fs5.stat(path7.join(root, sessionId))).mtime.toISOString();
2056
+ updatedAt = (await fs8.stat(path9.join(root, sessionId))).mtime.toISOString();
1781
2057
  } catch {
1782
2058
  }
1783
2059
  }
@@ -1802,14 +2078,14 @@ var init_store = __esm({
1802
2078
  deleteSession = async (sessionId) => {
1803
2079
  assertSafeSessionId(sessionId);
1804
2080
  const dir = getSessionsDirPath(sessionId);
1805
- await fs5.rm(dir, { recursive: true, force: true });
2081
+ await fs8.rm(dir, { recursive: true, force: true });
1806
2082
  ensuredSessionDirs.delete(dir);
1807
2083
  };
1808
2084
  }
1809
2085
  });
1810
2086
 
1811
2087
  // ../core/src/session/transcript.ts
1812
- import fs6 from "fs/promises";
2088
+ import fs9 from "fs/promises";
1813
2089
  var isEventLine, readTranscriptLines, appendSizeCache, appendLineWithRetry, appendMessage, appendMessages, appendEvent;
1814
2090
  var init_transcript = __esm({
1815
2091
  "../core/src/session/transcript.ts"() {
@@ -1822,7 +2098,7 @@ var init_transcript = __esm({
1822
2098
  await ensureSessionsDir(sessionId);
1823
2099
  const p = getTranscriptPath(sessionId);
1824
2100
  try {
1825
- const text = await fs6.readFile(p, "utf-8");
2101
+ const text = await fs9.readFile(p, "utf-8");
1826
2102
  const lines = [];
1827
2103
  for (const s of text.split("\n")) {
1828
2104
  const line = s.trim();
@@ -1848,18 +2124,18 @@ var init_transcript = __esm({
1848
2124
  if (beforeSize === void 0) {
1849
2125
  beforeSize = 0;
1850
2126
  try {
1851
- beforeSize = (await fs6.stat(p)).size;
2127
+ beforeSize = (await fs9.stat(p)).size;
1852
2128
  } catch {
1853
2129
  }
1854
2130
  }
1855
2131
  try {
1856
2132
  if (handle) await handle.appendFile(payload, "utf-8");
1857
- else await fs6.appendFile(p, payload, "utf-8");
2133
+ else await fs9.appendFile(p, payload, "utf-8");
1858
2134
  appendSizeCache.set(p, beforeSize + payloadBytes);
1859
2135
  return;
1860
2136
  } catch (e) {
1861
2137
  try {
1862
- await fs6.truncate(p, beforeSize);
2138
+ await fs9.truncate(p, beforeSize);
1863
2139
  } catch {
1864
2140
  }
1865
2141
  appendSizeCache.set(p, beforeSize);
@@ -1900,7 +2176,7 @@ var init_transcript = __esm({
1900
2176
  let handle = null;
1901
2177
  let i = 0;
1902
2178
  try {
1903
- handle = await fs6.open(p, "a");
2179
+ handle = await fs9.open(p, "a");
1904
2180
  for (; i < payloads.length; i++) await appendLineWithRetry(p, payloads[i], handle);
1905
2181
  } catch (e) {
1906
2182
  console.warn(`[transcript] \u6279\u91CF\u843D\u76D8\u7B2C ${i + 1}/${payloads.length} \u6761\u5931\u8D25\uFF0C\u8BE5\u6761\u8D77\u56DE\u843D\u9010\u6761\u65E7\u8DEF\u5F84:`, e instanceof Error ? e.message : e);
@@ -2070,17 +2346,118 @@ var init_content = __esm({
2070
2346
  const archivedMessageCount = recovery.compaction.archivedMessageCount;
2071
2347
  const messageAll = all.slice(archivedMessageCount);
2072
2348
  if (messageAll.length === 0) {
2073
- result.push(currentUserMsg);
2349
+ if (currentUserMsg) result.push(currentUserMsg);
2074
2350
  return enforceVisionGate(result, modelId);
2075
2351
  }
2076
2352
  const repair = repairOrphanToolCalls(messageAll, recovery.interruption.kind === "crashed");
2077
2353
  result.push(...decayOldToolResults(repair.msgs));
2078
- result.push(currentUserMsg);
2354
+ if (currentUserMsg) result.push(currentUserMsg);
2079
2355
  return enforceVisionGate(result, modelId);
2080
2356
  };
2081
2357
  }
2082
2358
  });
2083
2359
 
2360
+ // ../core/src/agent/planMode.ts
2361
+ function filterToolsForPlanMode(tools) {
2362
+ const allowed = tools.filter((t) => t.function.planAllowed === true);
2363
+ return [...allowed, exitPlanModeToolSchema];
2364
+ }
2365
+ function appendPlanControlTools(tools) {
2366
+ return [
2367
+ ...tools,
2368
+ enterPlanModeToolSchema,
2369
+ exitPlanModeToolSchema
2370
+ ];
2371
+ }
2372
+ var exitPlanModeToolSchema, enterPlanModeToolSchema, PLAN_MODE_AUTO_ENTER_HINT;
2373
+ var init_planMode = __esm({
2374
+ "../core/src/agent/planMode.ts"() {
2375
+ "use strict";
2376
+ exitPlanModeToolSchema = {
2377
+ type: "function",
2378
+ function: {
2379
+ name: "exit_plan_mode",
2380
+ description: "\u8BA1\u5212\u6A21\u5F0F\u4E13\u7528\uFF1A\u5B8C\u6210\u53EA\u8BFB\u8C03\u7814\u3001\u5F62\u6210\u660E\u786E\u5B9E\u73B0\u65B9\u6848\u540E\u8C03\u7528\u672C\u5DE5\u5177\u63D0\u4EA4\u65B9\u6848\u3002\u63D0\u4EA4\u540E\u65B9\u6848\u4F1A\u5448\u73B0\u7ED9\u7528\u6237\u5BA1\u6279\uFF1B\u5BA1\u6279\u901A\u8FC7\u540E\u624D\u8FDB\u5165\u5B9E\u73B0\u9636\u6BB5\uFF08\u5C4A\u65F6\u624D\u5141\u8BB8\u4FEE\u6539\u6587\u4EF6/\u6267\u884C\u547D\u4EE4\uFF09\u3002\u5728\u8BA1\u5212\u6A21\u5F0F\u4E0B\u4F60\u53EA\u80FD\u8BFB\u53D6\u4E0E\u641C\u7D22\uFF0C\u4E0D\u80FD\u505A\u4EFB\u4F55\u4FEE\u6539\u3002",
2381
+ parameters: {
2382
+ type: "object",
2383
+ properties: {
2384
+ plan: { type: "string", description: "\u5B8C\u6574\u7684\u5B9E\u73B0\u65B9\u6848\uFF1A\u8981\u6539\u54EA\u4E9B\u6587\u4EF6\u3001\u5177\u4F53\u600E\u4E48\u6539\u3001\u4E3A\u4EC0\u4E48\u8FD9\u4E48\u505A\u3001\u6709\u4EC0\u4E48\u98CE\u9669\u4E0E\u53D6\u820D" }
2385
+ },
2386
+ required: ["plan"]
2387
+ }
2388
+ }
2389
+ };
2390
+ enterPlanModeToolSchema = {
2391
+ type: "function",
2392
+ function: {
2393
+ name: "enter_plan_mode",
2394
+ description: "\u81EA\u4E3B\u8FDB\u5165\u8BA1\u5212\u6A21\u5F0F\uFF1A\u5F53\u4EFB\u52A1\u662F\u975E\u5E73\u51E1\u7684\u5B9E\u73B0\u4EFB\u52A1\uFF08\u591A\u6587\u4EF6\u6539\u52A8\u3001\u67B6\u6784\u51B3\u7B56\u3001\u4E0D\u786E\u5B9A\u8DEF\u5F84\u3001\u9AD8\u98CE\u9669\u64CD\u4F5C\uFF09\u65F6\u8C03\u7528\u3002\u8C03\u7528\u540E\u672C\u8F6E\u7ED3\u675F\u5E76\u8FDB\u5165\u53EA\u8BFB\u8C03\u7814\u9636\u6BB5\u2014\u2014\u4F60\u53EA\u80FD\u8BFB\u53D6\u4E0E\u641C\u7D22\uFF0C\u4EA7\u51FA\u5B8C\u6574\u5B9E\u73B0\u65B9\u6848\uFF08\u8981\u6539\u54EA\u4E9B\u6587\u4EF6\u3001\u600E\u4E48\u6539\u3001\u4E3A\u4F55\u3001\u98CE\u9669\uFF09\u7ECF\u7528\u6237\u5BA1\u6279\u540E\u518D\u5B9E\u73B0\u3002\u7B80\u5355\u4EFB\u52A1\u65E0\u9700\u8C03\u7528\uFF0C\u76F4\u63A5\u5B9E\u73B0\u3002",
2395
+ parameters: {
2396
+ type: "object",
2397
+ properties: {
2398
+ reason: { type: "string", description: "\u4E3A\u4F55\u8981\u8FDB\u5165\u8BA1\u5212\u6A21\u5F0F\uFF08\u4EFB\u52A1\u7684\u590D\u6742\u70B9\u3001\u9700\u5148\u5398\u6E05\u7684\u5173\u952E\u95EE\u9898\uFF09" }
2399
+ },
2400
+ required: ["reason"]
2401
+ }
2402
+ }
2403
+ };
2404
+ PLAN_MODE_AUTO_ENTER_HINT = `\u3010\u4EFB\u52A1\u5206\u7C7B\uFF08\u6536\u5230\u5B9E\u73B0\u7C7B\u8BF7\u6C42\u65F6\u7684\u9996\u4E2A\u52A8\u4F5C\uFF09\u3011\u5148\u5224\u65AD\u590D\u6742\u5EA6\uFF0C\u518D\u51B3\u5B9A\u662F\u5426\u5148\u89C4\u5212\uFF1A
2405
+ - **\u975E\u5E73\u51E1\u4EFB\u52A1**\uFF08\u6EE1\u8DB3\u4EFB\u4E00\u5373\u7B97\uFF1A\u6D89\u53CA\u591A\u4E2A\u6587\u4EF6\u6539\u52A8 / \u9700\u8981\u67B6\u6784\u51B3\u7B56 / \u5B9E\u73B0\u8DEF\u5F84\u4E0D\u786E\u5B9A / \u9AD8\u98CE\u9669\u64CD\u4F5C / \u9884\u4F30 \u22653 \u4E2A\u6B65\u9AA4\uFF09\u2192 **\u9ED8\u8BA4\u5148\u8C03\u7528 enter_plan_mode \u8FDB\u5165\u8BA1\u5212\u6A21\u5F0F**\uFF1A\u4EE5\u53EA\u8BFB\u65B9\u5F0F\u4E13\u6CE8\u8C03\u7814\u3001\u7406\u6E05\u73B0\u72B6\u4E0E\u6539\u9020\u70B9\uFF0C\u518D\u8C03\u7528 exit_plan_mode \u63D0\u4EA4\u5B8C\u6574\u5B9E\u73B0\u65B9\u6848\uFF08\u8981\u6539\u54EA\u4E9B\u6587\u4EF6\u3001\u5177\u4F53\u600E\u4E48\u6539\u3001\u4E3A\u4F55\u8FD9\u4E48\u505A\u3001\u6709\u4EC0\u4E48\u98CE\u9669\u4E0E\u53D6\u820D\uFF09\uFF0C\u65B9\u6848\u7ECF\u7528\u6237\u5BA1\u6279\u540E\u624D\u8FDB\u5165\u5B9E\u73B0\u9636\u6BB5\u3002
2406
+ - **\u7B80\u5355\u4EFB\u52A1**\uFF08\u5355\u6587\u4EF6\u3001\u5355\u884C\u4FEE\u590D\u3001\u660E\u786E\u7684\u5C0F\u8C03\u6574\u3001\u7EAF\u67E5\u8BE2\u6216\u89E3\u91CA\uFF09\u2192 \u65E0\u9700\u89C4\u5212\uFF0C\u76F4\u63A5\u5B9E\u73B0\u6216\u4F5C\u7B54\u3002
2407
+ - \u5224\u636E\u793A\u4F8B\uFF1A\u300C\u65B0\u589E/\u5B9E\u73B0\u4E00\u4E2A\u529F\u80FD\u6A21\u5757\u300D\u300C\u91CD\u6784/\u6539\u9020 XX \u5B50\u7CFB\u7EDF\u300D\u300C\u628A A \u8FC1\u79FB\u5230 B\u300D\u300C\u8C03\u6574\u6574\u4F53\u6570\u636E\u6D41\u300D\u2192 \u975E\u5E73\u51E1\uFF0C\u5148\u89C4\u5212\uFF1B\u300C\u6539\u4E00\u4E0B\u7B2C N \u884C\u7684\u53D8\u91CF\u540D\u300D\u300C\u89E3\u91CA\u8FD9\u6BB5\u4EE3\u7801\u300D\u300C\u8DD1\u4E00\u4E0B\u6D4B\u8BD5\u300D\u2192 \u7B80\u5355\uFF0C\u76F4\u63A5\u505A\u3002`;
2408
+ }
2409
+ });
2410
+
2411
+ // ../core/src/agent/systemPrompt.ts
2412
+ var buildSystemPrompt;
2413
+ var init_systemPrompt = __esm({
2414
+ "../core/src/agent/systemPrompt.ts"() {
2415
+ "use strict";
2416
+ init_planMode();
2417
+ buildSystemPrompt = (p) => `\u4F60\u662F ${p.displayName}\u2014\u2014\u4E00\u4E2A\u57FA\u4E8E ${p.modelLabel} \u5927\u6A21\u578B\u7684\u7EC8\u7AEF AI \u7F16\u7A0B\u52A9\u624B\u3002\u4F60\u8FD0\u884C\u5728\u7528\u6237\u7684\u7EC8\u7AEF\u4E2D\uFF0C\u80FD\u8C03\u7528\u4E00\u7CFB\u5217\u5DE5\u5177\uFF08\u8BFB\u5199\u6587\u4EF6\u3001\u641C\u7D22\u4EE3\u7801\u3001\u6267\u884C\u547D\u4EE4\u3001\u8054\u7F51\u68C0\u7D22\u3001\u4EFB\u52A1\u7BA1\u7406\u7B49\uFF09\u76F4\u63A5\u5728\u7528\u6237\u5DE5\u4F5C\u533A\u5B8C\u6210\u5F00\u53D1\u4EFB\u52A1\u3002
2418
+
2419
+ \u3010\u8EAB\u4EFD\u3011
2420
+ - \u4F60\u7684\u540D\u5B57\u662F ${p.displayName}\uFF0C\u7531 ${p.modelLabel} \u6A21\u578B\u9A71\u52A8\u3002
2421
+ - \u88AB\u95EE"\u4F60\u662F\u8C01"\u65F6\u636E\u5B9E\u56DE\u7B54\uFF1A\u4F60\u662F ${p.displayName}\u3002\u5207\u52FF\u81EA\u79F0 ChatGPT\u3001GPT \u6216\u4EFB\u4F55\u5176\u4ED6\u516C\u53F8\u7684\u5927\u6A21\u578B/AI \u4EA7\u54C1\u3002
2422
+
2423
+ \u3010\u56DE\u7B54\u51C6\u5219 / \u5B8C\u6210\u5224\u5B9A\u3011
2424
+ - \u4EFB\u52A1\u5B8C\u6210\u540E\u76F4\u63A5\u7528\u81EA\u7136\u8BED\u8A00\u7ED9\u51FA\u6700\u7EC8\u7B54\u6848\uFF0C\u4E0D\u8981\u518D\u8C03\u7528\u5DE5\u5177\u3002**\u5B8C\u6210\u5224\u636E = \u7528\u6237\u7684\u6BCF\u4E2A\u5B50\u76EE\u6807\u90FD\u6709\u843D\u5730\u4EA7\u7269**\uFF08\u6240\u9700\u4FE1\u606F\u5DF2\u5230\u624B / \u8BE5\u6539\u7684\u6587\u4EF6\u5DF2\u6539\u5B8C / \u5DF2\u9A8C\u8BC1\u901A\u8FC7\uFF09\uFF0C\u800C\u975E"\u8C03\u7528\u8FC7\u5DE5\u5177"\u3002\u6BCF\u8F6E\u5DE5\u5177\u8FD4\u56DE\u540E\u5BF9\u7167\u539F\u59CB\u8BF7\u6C42\u4E0E todo \u6E05\u5355\uFF08\u82E5\u6709\uFF09\u9010\u9879\u6838\u5BF9\uFF1A\u8FD8\u6709\u672A\u843D\u5730\u9879\u5C31\u7EE7\u7EED\u63A8\u8FDB\uFF0C\u4E0D\u8981\u62FF\u90E8\u5206\u68C0\u7D22/\u8BFB\u53D6\u7ED3\u679C\u603B\u7ED3\u6536\u5C3E\u3002\u590D\u6742\u4EFB\u52A1\u7528 todo_write \u62C6\u89E3\u5E76\u9010\u9879\u52FE\u9009\uFF0C\u6BCF\u8F6E\u5BF9\u7167\u6E05\u5355\u6838\u5BF9\u8FDB\u5EA6\u3002
2425
+ - \u5DE5\u5177**\u6267\u884C\u5931\u8D25\u6216\u88AB\u7528\u6237\u62D2\u7EDD**\u65F6\uFF0C\u8BFB\u8FD4\u56DE\u7ED3\u679C\u5B9A\u4F4D\u539F\u56E0\uFF0C\u4FEE\u6B63\u53C2\u6570\u6216\u6362\u7B49\u6548\u65B9\u6848\u7EE7\u7EED\uFF0C\u4E0D\u8981\u9053\u6B49\u4E00\u4E24\u53E5\u5C31\u505C\u4E0B\uFF1B\u786E\u5B9E\u53D7\u963B\u9700\u8981\u7528\u6237\u51B3\u7B56\u65F6\uFF0C\u7528 ask_question \u8BF4\u660E**\u5177\u4F53**\u963B\u585E\u70B9\u3002**\u4E25\u7981**\u5728\u672A\u771F\u6B63\u6267\u884C\u6216\u672A\u9A8C\u8BC1\u7684\u60C5\u51B5\u4E0B\u58F0\u79F0"\u5DF2\u5B8C\u6210/\u5DF2\u4FEE\u6539/\u5DF2\u4FEE\u590D"\u2014\u2014\u6539\u52A8\u82E5\u53EF\u9A8C\u8BC1\uFF08\u91CD\u8BFB\u786E\u8BA4\u3001\u8DD1\u6D4B\u8BD5\u3001\u7C7B\u578B\u68C0\u67E5\uFF09\uFF0C\u5148\u9A8C\u8BC1\u518D\u6536\u5C3E\u3002
2426
+
2427
+ \u3010\u56DE\u7B54\u5F62\u5F0F\u3011
2428
+ - **\u5148\u7ED3\u8BBA\u540E\u7EC6\u8282**\uFF1A\u5148\u76F4\u63A5\u56DE\u7B54\u6216\u6C47\u62A5\u7ED3\u679C\uFF0C\u518D\u5C55\u5F00\u5FC5\u8981\u7684\u89E3\u91CA\uFF1B\u6536\u5C3E\u603B\u7ED3\u7B80\u77ED\uFF08\u51E0\u884C\u4EE5\u5185\uFF09\uFF0C\u4E0D\u9010\u6587\u4EF6\u6D41\u6C34\u8D26\u3002
2429
+ - **\u4E0D\u56DE\u8D34\u5927\u6BB5\u4EE3\u7801**\uFF1A\u6539\u52A8\u5185\u5BB9\u7528\u6237\u5728\u7F16\u8F91\u5668/diff \u91CC\u770B\u5F97\u5230\uFF0C\u6B63\u6587\u53EA\u9700\u4E00\u53E5\u8BDD\u8BF4\u660E\u6539\u4E86\u4EC0\u4E48\u3001\u4E3A\u4EC0\u4E48\uFF0C\u6216\u5F15\u7528\u5173\u952E\u51E0\u884C\u3002
2430
+
2431
+ \u3010\u5DE5\u5177\u4F7F\u7528\u51C6\u5219\u3011
2432
+ - \u4FEE\u6539\u6587\u4EF6**\u53EA\u80FD**\u7528 edit_file / create_file / write_file\u3002**\u4E25\u7981**\u7528 run_command \u901A\u8FC7 python/node/sed/awk/perl \u7B49\u811A\u672C\u8BFB\u5199\u6216\u4FEE\u6539\u6587\u4EF6\u2014\u2014\u811A\u672C\u8F6C\u4E49\u6781\u6613\u51FA\u9519\u3001\u6BCF\u6761\u547D\u4EE4\u90FD\u8981\u7528\u6237\u5BA1\u6279\u3001\u6548\u7387\u6781\u4F4E\uFF0C\u662F\u88AB\u660E\u786E\u7981\u6B62\u7684\u9000\u8DEF\u3002
2433
+ - edit_file \u5931\u8D25\u65F6**\u4E0D\u8981\u9000\u56DE shell**\uFF1A\u7528 read_file \u91CD\u65B0\u6838\u5BF9\u76EE\u6807\u7247\u6BB5\uFF08\u53BB\u6389\u300C<\u884C\u53F7>: \u300D\u524D\u7F00\u3001\u4FDD\u7559\u539F\u59CB Tab/\u7A7A\u683C\u7F29\u8FDB\u4E0E\u6362\u884C\uFF09\u540E\u518D\u6B21\u8C03\u7528 edit_file\uFF1B\u5B9A\u4F4D\u4E0D\u51C6\u5C31\u591A\u8BFB\u51E0\u884C\u4E0A\u4E0B\u6587\u5305\u88F9\u8FDB\u53BB\u3002\u672C\u5DE5\u5177\u5DF2\u6709\u591A\u7EA7\u7A7A\u767D/\u7F29\u8FDB\u5BB9\u9519\uFF0C\u591A\u6570\u5931\u914D\u53EA\u9700\u7CBE\u786E\u91CD\u8BFB\u5373\u53EF\u89E3\u51B3\u3002
2434
+ - \u4FEE\u6539\u65E2\u6709\u6587\u4EF6**\u4E00\u5F8B\u4F18\u5148 edit_file**\uFF08\u7CBE\u51C6\u5C40\u90E8\u66FF\u6362\u3001\u4FDD\u7559\u539F\u7F29\u8FDB\u3001\u6700\u5C0F diff\uFF09\uFF1Bwrite_file / create_file \u4EC5\u7528\u4E8E\u65B0\u5EFA\u6587\u4EF6\u6216\u5F7B\u5E95\u91CD\u5199\u6574\u4E2A\u6587\u4EF6\u3002\u2605 \u7528 write_file \u5168\u91CF\u8986\u76D6\u65E2\u6709\u6587\u4EF6\u4F1A\u4E22\u5931\u539F\u6709\u7F29\u8FDB\u4E0E\u683C\u5F0F\u3001\u4EA7\u751F\u5927\u91CF\u65E0\u5173 diff\uFF0C\u662F\u7528\u6237\u660E\u786E\u53CD\u611F\u7684\u53CD\u6A21\u5F0F\u2014\u2014\u5373\u4FBF\u8981\u6539\u7684\u5730\u65B9\u5F88\u591A\uFF0C\u4E5F\u7528\u591A\u6B21 edit_file \u800C\u975E\u4E00\u6B21 write_file \u8986\u76D6\u3002
2435
+ - \u8C03\u7528\u5DE5\u5177\u524D\u5148\u81EA\u95EE\uFF1A\u5DF2\u6709\u7684\u4FE1\u606F\u662F\u5426\u8DB3\u4EE5\u56DE\u7B54\u7528\u6237\uFF1F\u591F\u5C31\u4E0D\u518D\u8C03\u5DE5\u5177\uFF0C\u76F4\u63A5\u4F5C\u7B54\u3002
2436
+ - **\u5148\u8BFB\u5168\u518D\u52A8\u624B\uFF0C\u522B\u628A\u641C\u7D22\u5F53\u5B57\u5178\u67E5\uFF08\u53CD\u788E\u6B65\xB7\u91CD\u8981\uFF09**\uFF1A\u8981\u6539\u67D0\u4E2A\u6587\u4EF6/\u6A21\u5757\u524D\uFF0C\u5148\u7528 read_file \u628A\u76F8\u5173\u6587\u4EF6\u4E00\u6B21\u6027\u8BFB\u5168\uFF08\u7ED3\u6784\u3001\u5B57\u6BB5\u3001\u7528\u6CD5\u90FD\u5728\u6587\u4EF6\u91CC\uFF09\uFF0C\u4E0D\u8981\u9760 search_grep \u4E00\u4E2A\u5B57\u6BB5\u3001\u4E00\u4E2A\u7528\u6CD5\u5730\u8BD5\u63A2\u3002search_grep \u662F\u5B9A\u4F4D\u5DE5\u5177\u2014\u2014\u7528\u6765\u627E\u67D0\u7B26\u53F7\u5728\u54EA\u5B9A\u4E49/\u88AB\u8C01\u8C03\u7528\uFF0C\u627E\u5230\u540E\u7ACB\u5373\u8BFB\u5B8C\u6574\u6587\u4EF6\u7406\u89E3\u4E0A\u4E0B\u6587\uFF1B\u7EDD\u4E0D\u7528\u8FD1\u4E49\u5173\u952E\u8BCD\u53CD\u590D\u641C\u540C\u4E00\u4E2A\u610F\u56FE\u3002
2437
+ - **\u6279\u91CF\u89C4\u5212\u6539\u52A8\uFF0C\u4E00\u6B21\u6210\u578B\uFF08\u53CD\u788E\u6B65\xB7\u91CD\u8981\uFF09**\uFF1A\u52A8\u624B\u524D\u5148\u628A\u6240\u6709\u8981\u6539\u7684\u70B9\u60F3\u6E05\u695A\u3001\u5217\u51FA\u6765\uFF0C\u518D\u7528\u591A\u6B21 edit_file \u4E00\u53E3\u6C14\u6539\u5B8C\u3002\u4E0D\u8981"\u6539\u4E00\u5904 \u2192 \u770B\u4E00\u773C \u2192 \u53C8\u53D1\u73B0\u4E00\u5904 \u2192 \u518D\u6539"\u6765\u56DE\u4E03\u516B\u8D9F\u2014\u2014\u65E2\u70E7 token \u53C8\u6613\u9057\u6F0F\u3002\u6B63\u786E\u8282\u594F\uFF1A\u5148\u8BFB\u5168 \u2192 \u89C4\u5212 \u2192 \u6279\u91CF\u6539 \u2192 \u6700\u540E\u7EDF\u4E00\u9A8C\u8BC1\u3002
2438
+ - **\u6539\u5B8C\u52FF\u7ACB\u523B\u91CD\u8BFB\uFF08\u53CD\u788E\u6B65\xB7\u91CD\u8981\uFF09**\uFF1Aedit_file / write_file \u6210\u529F\u8FD4\u56DE\u540E\uFF0C\u5DE5\u5177\u7ED3\u679C\u5DF2\u8BF4\u660E\u6539\u4E86\u4EC0\u4E48\uFF0C\u4E0D\u8981\u9A6C\u4E0A read_file \u628A\u6574\u4E2A\u6587\u4EF6\u91CD\u8BFB\u4E00\u904D\u6765"\u786E\u8BA4"\u3002\u786E\u9700\u6838\u9A8C\u65F6\uFF0C\u53EA\u8BFB\u6539\u52A8\u9644\u8FD1\u51E0\u884C\u6216\u8DD1\u7C7B\u578B\u68C0\u67E5/\u6D4B\u8BD5\uFF0C\u800C\u975E\u6574\u6587\u4EF6\u91CD\u8BFB\u3002
2439
+ - \u4E0D\u91CD\u590D\u6293\u53D6\u5DF2\u6293\u53D6\u8FC7\u7684 URL\uFF1B\u4E0D\u7528\u8FD1\u4E49\u5173\u952E\u8BCD\u53CD\u590D\u641C\u7D22\u540C\u4E00\u4E2A\u610F\u56FE\u3002
2440
+ - \u8054\u7F51/\u641C\u7D22\u7C7B\u8C03\u7814\u4EFB\u52A1\uFF0C\u901A\u5E38 1~3 \u4E2A\u6765\u6E90\u5DF2\u8DB3\u591F\u652F\u6491\u56DE\u7B54\u2014\u2014\u62FF\u5230\u5373\u7EFC\u5408\u4F5C\u7B54\uFF0C\u4E0D\u8981\u4E3A\u8FFD\u6C42"\u66F4\u5168\u9762"\u800C\u65E0\u9650\u8FFD\u52A0\u68C0\u7D22\u8F6E\u6B21\u3002
2441
+ - **\u72EC\u7ACB\u8BFB\u64CD\u4F5C\u5E76\u884C\u6253\u5305\uFF08\u91CD\u8981\uFF09**\uFF1A\u591A\u4E2A\u4E92\u4E0D\u4F9D\u8D56\u7684\u53EA\u8BFB\u8C03\u7528\uFF08\u8BFB\u591A\u4E2A\u6587\u4EF6\u3001\u591A\u4E2A\u68C0\u7D22\u3001\u591A\u4E2A\u5B9A\u4E49\u67E5\u8BE2\uFF09\u5E94\u5728\u540C\u4E00\u6761\u6D88\u606F\u91CC\u4E00\u6B21\u6027\u5168\u90E8\u53D1\u51FA\uFF0C\u6267\u884C\u5C42\u4F1A\u81EA\u52A8\u5E76\u53D1\u6267\u884C\uFF0C\u4E00\u8F6E\u9876\u591A\u8F6E\uFF1B\u6709\u4F9D\u8D56\uFF08\u540E\u4E00\u6B65\u8981\u7528\u524D\u4E00\u6B65\u7ED3\u679C\uFF09\u6216\u4F1A\u6539\u72B6\u6001\u7684\u64CD\u4F5C\uFF0C\u5FC5\u987B\u7B49\u524D\u5E8F\u7ED3\u679C\u8FD4\u56DE\u518D\u53D1\u3002
2442
+ - \u591A\u6B65\u9AA4\u7684\u590D\u6742\u4EFB\u52A1\uFF08\u22653 \u6B65\u3001\u8DE8\u591A\u6587\u4EF6\u6216\u591A\u9636\u6BB5\uFF09\u5148\u8C03\u7528 todo_write \u628A\u8BA1\u5212\u62C6\u6210\u53EF\u52FE\u9009\u7684\u4EFB\u52A1\u6E05\u5355\uFF0C\u518D\u9010\u6B65\u63A8\u8FDB\u5E76\u5373\u65F6\u66F4\u65B0\u72B6\u6001\u2014\u2014\u8BA9\u4F60\u548C\u7528\u6237\u90FD\u770B\u6E05\u8FDB\u5EA6\u3001\u4E0D\u9057\u6F0F\u6B65\u9AA4\uFF1B\u7B80\u5355 1-2 \u6B65\u7684\u4EFB\u52A1\u65E0\u9700\u5EFA\u6E05\u5355\u3002
2443
+
2444
+ \u3010\u64CD\u4F5C\u786E\u8BA4\u7EA6\u5B9A\u3011
2445
+ - \u9047\u5230\u4F1A\u6539\u53D8\u72B6\u6001\u6216\u5177\u98CE\u9669\u7684\u5DE5\u5177\uFF08\u5199\u6587\u4EF6\u3001\u7F16\u8F91\u3001\u5220\u9664\u3001\u79FB\u52A8\u3001\u6267\u884C\u547D\u4EE4\u3001\u5BF9\u5916\u7F51\u7EDC\u8BF7\u6C42\u7B49\uFF09\uFF0C\u76F4\u63A5\u8C03\u7528\u8BE5\u5DE5\u5177\u5373\u53EF\uFF0C\u4E0D\u8981\u5148\u7528\u81EA\u7136\u8BED\u8A00\u5F81\u6C42\u786E\u8BA4\uFF08\u5982"\u6211\u53EF\u4EE5\u6267\u884C\u5417\uFF1F""\u662F\u5426\u7EE7\u7EED\uFF1F"\uFF09\u3002\u8FD9\u7C7B\u5DE5\u5177\u7531\u7CFB\u7EDF\u7EDF\u4E00\u62E6\u622A\u5E76\u5F39\u51FA\u5BA1\u6279\u754C\u9762\uFF0C\u7528\u6237\u4F1A\u4E00\u952E\u540C\u610F\u6216\u62D2\u7EDD\u2014\u2014\u4F60\u65E0\u9700\u4EE3\u66FF\u7CFB\u7EDF\u53D1\u95EE\uFF0C\u66F4\u4E0D\u8981\u505C\u4E0B\u7B49\u7528\u6237\u6253\u5B57\u786E\u8BA4\u3002
2446
+ - \u4EC5\u5F53\u5B58\u5728\u591A\u79CD\u660E\u663E\u4E0D\u540C\u7684\u5B9E\u73B0\u65B9\u6848\u3001\u9700\u8981\u7528\u6237\u5728\u65B9\u5411\u4E0A\u62CD\u677F\u65F6\uFF0C\u8C03\u7528 ask_question \u5DE5\u5177\u63D0\u51FA 2-4 \u4E2A\u7ED3\u6784\u5316\u9009\u9879\u8BA9\u7528\u6237\u9009\u62E9\uFF08\u7EC8\u7AEF\u4F1A\u5F39\u51FA\u591A\u9009\u6846\uFF0C\u6BD4\u7EAF\u6587\u5B57\u66F4\u6E05\u6670\u9AD8\u6548\uFF0C\u7528\u6237\u9009\u62E9\u4F1A\u81EA\u52A8\u56DE\u4F20\u7ED9\u4F60\uFF1B\u63D0\u95EE\u6846\u6052\u6709\u300COther\u300D\u81EA\u7531\u8F93\u5165\u6863\uFF0C\u9700\u8981\u7528\u6237\u63D0\u4F9B\u9009\u9879\u4E4B\u5916\u7684\u8D44\u6599\u2014\u2014\u5982\u767B\u5F55 token\u3001\u6587\u4EF6\u8DEF\u5F84\u2014\u2014\u4E5F\u7528 ask_question \u63D0\u51FA\uFF0C\u7528\u6237\u4F1A\u7ECF Other \u7C98\u8D34\u539F\u6587\u56DE\u4F20\uFF09\uFF1B\u5BF9"\u67D0\u4E2A\u5177\u4F53\u64CD\u4F5C\u662F\u5426\u6267\u884C"\u4E00\u5F8B\u76F4\u63A5\u8C03\u7528\u5DE5\u5177\u8D70\u5BA1\u6279\uFF0C\u4E0D\u8981\u7528 ask_question \u53BB\u95EE\u80FD\u5426\u6267\u884C\u67D0\u4E2A\u64CD\u4F5C\u3002
2447
+
2448
+ \u3010\u8BA1\u5212\u6A21\u5F0F\u3011
2449
+ ${PLAN_MODE_AUTO_ENTER_HINT}
2450
+ - **\u8BA1\u5212\u6A21\u5F0F\u7684\u8BC6\u522B**\uFF1A\u5F53\u4F60\u53D1\u73B0\u5F53\u524D\u53EF\u7528\u5DE5\u5177\u4EC5\u5305\u542B\u8BFB\u53D6\u4E0E\u68C0\u7D22\u7C7B\uFF08read_file/search_grep/glob/git \u53EA\u8BFB/web \u7B49\uFF09\u3001\u4E0D\u542B\u4EFB\u4F55\u5199\u6587\u4EF6/\u6267\u884C\u547D\u4EE4/\u540E\u53F0\u4EFB\u52A1\u7C7B\u5DE5\u5177\u65F6\uFF0C\u8BF4\u660E\u5DF2\u8FDB\u5165\u8BA1\u5212\u6A21\u5F0F\u2014\u2014\u6B64\u65F6\u4E25\u7981\u4FEE\u6539\u4EFB\u4F55\u6587\u4EF6\u6216\u6267\u884C\u547D\u4EE4\uFF0C\u53EA\u80FD\u8C03\u7814\uFF0C\u5B8C\u6210\u540E\u5FC5\u987B\u8C03\u7528 exit_plan_mode \u63D0\u4EA4\u65B9\u6848\u3002
2451
+ - **\u63D0\u4EA4\u65B9\u6848\u5FC5\u987B\u7528\u5DE5\u5177**\uFF1A\u8FDB\u5165\u8BA1\u5212\u6A21\u5F0F\u540E\u7528 exit_plan_mode \u63D0\u4EA4\uFF1B\u82E5\u4F60\u5728\u6B63\u5E38\u8F6E\u5DF2\u81EA\u884C\u7528\u53EA\u8BFB\u5DE5\u5177\u5B8C\u6210\u8C03\u7814\uFF0C\u4E5F\u53EF\u76F4\u63A5\u8C03 exit_plan_mode \u63D0\u4EA4\u3002\u7EDD\u4E0D\u8981\u4EE5\u7EAF\u6587\u672C\u9648\u8FF0\u65B9\u6848\u7136\u540E\u505C\u4E0B\u7B49\u5F85\u5BA1\u6279\u2014\u2014\u7EAF\u6587\u672C\u65B9\u6848\u4E0D\u4F1A\u89E6\u53D1\u5BA1\u6279\u754C\u9762\uFF0C\u7528\u6237\u65E0\u6CD5\u4E00\u952E\u6279\u51C6/\u7F16\u8F91\uFF0C\u6D41\u7A0B\u4F1A\u5361\u6B7B\u3002
2452
+
2453
+ \u3010\u6301\u4E45\u8BB0\u5FC6\u3011
2454
+ - \u4F60\u62E5\u6709\u8DE8\u4F1A\u8BDD\u7684\u6301\u4E45\u8BB0\u5FC6\uFF1A\u7CFB\u7EDF\u63D0\u793A\u8BCD\u4E2D\u4EE5\u3010\u8BB0\u5FC6\u7D22\u5F15\u3011\u5217\u51FA\u5DF2\u5B58\u8BB0\u5FC6\uFF08\u4E00\u884C/\u6761\uFF1A\u540D\u79F0\u3001\u7C7B\u522B\u3001\u63CF\u8FF0\uFF09\u3002\u5F53\u7D22\u5F15\u4E2D\u67D0\u6761\u4E0E\u5F53\u524D\u4EFB\u52A1\u76F8\u5173\u3001\u9700\u8981\u7EC6\u8282\u65F6\uFF0C\u8C03\u7528 memory_read \u6309\u9700\u53EC\u56DE\u5168\u6587\uFF1B\u4E0D\u8981\u65E0\u5DEE\u522B\u5730\u5168\u91CF\u8BFB\u53D6\u3002
2455
+ - \u9047\u5230\u503C\u5F97\u8DE8\u4F1A\u8BDD\u4FDD\u7559\u7684\u4FE1\u606F\u65F6\uFF0C\u4E3B\u52A8\u7528 memory_save \u5B58\u6210\u8BB0\u5FC6\uFF0C\u4F8B\u5982\uFF1A\u7528\u6237\u7684\u957F\u671F\u504F\u597D\u4E0E\u89D2\u8272\u753B\u50CF\u3001\u7528\u6237\u7ED9\u51FA\u7684\u5DE5\u4F5C\u65B9\u5F0F\u53CD\u9988\uFF08\u542B\u539F\u56E0\u4E0E\u505A\u6CD5\uFF09\u3001\u9879\u76EE\u76EE\u6807\u4E0E\u9690\u542B\u7EA6\u675F\u3001\u5916\u90E8\u8D44\u6E90\u6307\u9488\uFF08URL/\u770B\u677F/\u5DE5\u5355\uFF09\u3002\u5373\u90A3\u4E9B\u300C\u4E0B\u6B21\u4E0D\u8BE5\u91CD\u65B0\u53D1\u73B0\u300D\u300C\u4EE3\u7801\u4E0E git \u4E0D\u4F1A\u76F4\u63A5\u544A\u8BC9\u4F60\u300D\u7684\u975E\u663E\u7136\u4E8B\u5B9E\u3002
2456
+ - \u4E0D\u8981\u4FDD\u5B58\uFF1A\u4EE3\u7801\u7ED3\u6784\u3001\u8FC7\u5F80\u4FEE\u590D\u3001git \u5386\u53F2\u7B49\u4ED3\u5E93\u672C\u8EAB\u5DF2\u8BB0\u5F55\u7684\u5185\u5BB9\uFF1B\u53EA\u5BF9\u672C\u6B21\u5BF9\u8BDD\u6709\u610F\u4E49\u3001\u4E0B\u4E0D\u4E3A\u4F8B\u7684\u4E34\u65F6\u4FE1\u606F\u3002\u82E5\u4E0D\u786E\u5B9A\u67D0\u6761\u4FE1\u606F\u662F\u5426\u503C\u5F97\u5B58\uFF0C\u5148\u95EE\u6E05\u5176\u975E\u663E\u7136\u4E4B\u5904\uFF0C\u5B58\u90A3\u4E00\u70B9\u800C\u975E\u6574\u6BB5\u6D41\u6C34\u3002
2457
+ - \u8BB0\u5FC6\u4F1A\u91CD\u590D\u51FA\u73B0\uFF0C\u53D1\u73B0\u5DF2\u5931\u6548\u6216\u6709\u8BEF\u7684\u8BB0\u5FC6\u7528 memory_delete \u6E05\u7406\u3002\u7C7B\u522B\u6309\u8BED\u4E49\u9009\uFF1Auser\uFF08\u7528\u6237\u753B\u50CF/\u504F\u597D\uFF09/ feedback\uFF08\u5DE5\u4F5C\u65B9\u5F0F\u53CD\u9988\uFF09/ project\uFF08\u9879\u76EE\u76EE\u6807/\u7EA6\u675F\uFF09/ reference\uFF08\u5916\u90E8\u8D44\u6E90\u6307\u9488\uFF09\u3002`;
2458
+ }
2459
+ });
2460
+
2084
2461
  // ../core/src/hooks/types.ts
2085
2462
  var INTERCEPTABLE_EVENTS, TOOL_EVENTS, ALL_EVENTS, DEFAULT_TIMEOUT_BY_EVENT;
2086
2463
  var init_types = __esm({
@@ -2107,7 +2484,7 @@ var init_types = __esm({
2107
2484
 
2108
2485
  // ../core/src/hooks/shellExecutor.ts
2109
2486
  import { spawn } from "child_process";
2110
- import path8 from "path";
2487
+ import path10 from "path";
2111
2488
  var MAX_OUTPUT, DEFAULT_TIMEOUT_MS, HARD_TIMEOUT_CAP_MS, ENV_WHITELIST, truncate, MAX_STDIN_FIELD, capFieldStrings, extractFilePath, executeHookCommand;
2112
2489
  var init_shellExecutor = __esm({
2113
2490
  "../core/src/hooks/shellExecutor.ts"() {
@@ -2153,7 +2530,7 @@ var init_shellExecutor = __esm({
2153
2530
  if (typeof rel !== "string" || !rel.trim()) return void 0;
2154
2531
  const base = typeof p.cwd === "string" && p.cwd || process.env.WORKSPACE_ROOT || process.cwd();
2155
2532
  try {
2156
- return path8.resolve(base, rel);
2533
+ return path10.resolve(base, rel);
2157
2534
  } catch {
2158
2535
  return void 0;
2159
2536
  }
@@ -2370,7 +2747,7 @@ var init_hooks = __esm({
2370
2747
  });
2371
2748
 
2372
2749
  // ../core/src/agent/truncate.ts
2373
- import path9 from "path";
2750
+ import path11 from "path";
2374
2751
  function stripAnsi(text) {
2375
2752
  if (!text || !text.includes(ANSI_ESC_CHAR)) return text;
2376
2753
  return text.replace(ANSI_ESCAPE, "");
@@ -2390,6 +2767,8 @@ var init_truncate = __esm({
2390
2767
  init_contextCore();
2391
2768
  init_contentParts();
2392
2769
  init_content();
2770
+ init_systemPrompt();
2771
+ init_model();
2393
2772
  init_store();
2394
2773
  init_transcript();
2395
2774
  init_hooks();
@@ -2409,10 +2788,10 @@ var init_truncate = __esm({
2409
2788
  if (!text) return text;
2410
2789
  const roots = /* @__PURE__ */ new Set();
2411
2790
  try {
2412
- roots.add(path9.resolve(appConfig.userWorkspaceDir));
2791
+ roots.add(path11.resolve(appConfig.userWorkspaceDir));
2413
2792
  for (const r of getFileAccessRoots()) {
2414
2793
  try {
2415
- roots.add(path9.resolve(r));
2794
+ roots.add(path11.resolve(r));
2416
2795
  } catch {
2417
2796
  }
2418
2797
  }
@@ -2710,14 +3089,14 @@ ${lines}
2710
3089
  const hitRate = event.lastRealPromptTokens && event.lastCachedTokens != null && event.lastRealPromptTokens > 0 ? event.lastCachedTokens / event.lastRealPromptTokens : null;
2711
3090
  const cacheFactor = hitRate == null ? 1 : Math.min(1.1, Math.max(0.9, 0.9 + hitRate * 0.2));
2712
3091
  const effectiveRatio = Math.min(event.compactRatio * cacheFactor, 0.82);
2713
- if (estReal(event.messageArr) <= event.modelWindow * effectiveRatio) return;
3092
+ if (!event.forceCompact && estReal(event.messageArr) <= event.modelWindow * effectiveRatio) return;
2714
3093
  const preDecaySize = estReal(event.messageArr);
2715
3094
  const decayedArr = decayOldToolResults(event.messageArr);
2716
3095
  if (decayedArr !== event.messageArr) {
2717
3096
  event.messageArr.length = 0;
2718
3097
  event.messageArr.push(...decayedArr);
2719
3098
  }
2720
- if (estReal(event.messageArr) <= event.modelWindow * effectiveRatio) {
3099
+ if (!event.forceCompact && estReal(event.messageArr) <= event.modelWindow * effectiveRatio) {
2721
3100
  console.log(`\u{1F4C9} [\u7A97\u53E3\u6CBB\u7406] \u514D\u8D39\u8870\u51CF\uFF08\u65E7\u5DE5\u5177\u7ED3\u679C\u6298\u53E0\uFF09\u540E\u56DE\u5230\u9608\u503C\u5185\uFF08${Math.round(preDecaySize)} \u2192 ${Math.round(estReal(event.messageArr))} token\uFF09\uFF0C\u8DF3\u8FC7 LLM \u538B\u7F29`);
2722
3101
  return;
2723
3102
  }
@@ -2730,7 +3109,9 @@ ${lines}
2730
3109
  const preCompactSize = Math.round(lastSize);
2731
3110
  const startTime = performance.now();
2732
3111
  let round = 0;
2733
- while (lastSize > event.modelWindow * effectiveRatio) {
3112
+ let forcedPass = event.forceCompact === true;
3113
+ while (forcedPass || lastSize > event.modelWindow * effectiveRatio) {
3114
+ forcedPass = false;
2734
3115
  if (event.signal?.aborted) {
2735
3116
  return;
2736
3117
  }
@@ -2838,7 +3219,7 @@ ${lines}
2838
3219
  tokensBefore: preCompactSize,
2839
3220
  tokensAfter: afterSize,
2840
3221
  durationMs: Math.round(performance.now() - startTime),
2841
- trigger: "auto",
3222
+ trigger: event.compactTrigger ?? "auto",
2842
3223
  summary
2843
3224
  });
2844
3225
  }
@@ -2853,8 +3234,8 @@ ${lines}
2853
3234
  });
2854
3235
 
2855
3236
  // ../core/src/tool/permissions.ts
2856
- import fs7 from "fs/promises";
2857
- import path10 from "path";
3237
+ import fs10 from "fs/promises";
3238
+ import path12 from "path";
2858
3239
  var rules2, trustedProject, globCache, globToRegex, DANGER_COMMAND_TOOLS, compileRule, readPermissionConfig, toolNameMatches, ruleMatches, initPermissions, checkPermission, listPermissionRules, buildScopedAllowRule, resolveSettingsPath, addPermissionRule;
2859
3240
  var init_permissions = __esm({
2860
3241
  "../core/src/tool/permissions.ts"() {
@@ -2900,15 +3281,15 @@ var init_permissions = __esm({
2900
3281
  readPermissionConfig = async (includeProject) => {
2901
3282
  const merged = { allow: [], deny: [], ask: [] };
2902
3283
  const paths = [
2903
- path10.join(appConfig.dataDir, "settings.json"),
3284
+ path12.join(appConfig.dataDir, "settings.json"),
2904
3285
  // 全局用户级
2905
- ...includeProject ? [path10.join(process.cwd(), ".deepseeker-code", "settings.json")] : []
3286
+ ...includeProject ? [path12.join(process.cwd(), ".deepseeker-code", "settings.json")] : []
2906
3287
  // 项目级(叠加);未信任时省略
2907
3288
  ];
2908
3289
  for (const configPath of paths) {
2909
3290
  let raw;
2910
3291
  try {
2911
- raw = await fs7.readFile(configPath, "utf-8");
3292
+ raw = await fs10.readFile(configPath, "utf-8");
2912
3293
  } catch {
2913
3294
  continue;
2914
3295
  }
@@ -2992,7 +3373,7 @@ var init_permissions = __esm({
2992
3373
  }
2993
3374
  return `${toolName}(${val})`;
2994
3375
  };
2995
- resolveSettingsPath = (scope) => scope === "global" ? path10.join(appConfig.dataDir, "settings.json") : path10.join(process.cwd(), ".deepseeker-code", "settings.json");
3376
+ resolveSettingsPath = (scope) => scope === "global" ? path12.join(appConfig.dataDir, "settings.json") : path12.join(process.cwd(), ".deepseeker-code", "settings.json");
2996
3377
  addPermissionRule = async (scope, kind, ruleStr) => {
2997
3378
  if (scope === "project" && !trustedProject) return false;
2998
3379
  const compiled2 = compileRule(ruleStr, `runtime:addPermissionRule(${scope})`, kind);
@@ -3004,7 +3385,7 @@ var init_permissions = __esm({
3004
3385
  const arr = Array.isArray(cfg.permissions[kind]) ? cfg.permissions[kind] : cfg.permissions[kind] = [];
3005
3386
  if (!arr.includes(ruleStr)) {
3006
3387
  arr.push(ruleStr);
3007
- await fs7.mkdir(path10.dirname(file), { recursive: true });
3388
+ await fs10.mkdir(path12.dirname(file), { recursive: true });
3008
3389
  await atomicWriteJSON(file, cfg);
3009
3390
  }
3010
3391
  if (!rules2[kind].some((r) => r.raw === compiled2.raw)) rules2[kind].push(compiled2);
@@ -3042,9 +3423,9 @@ var init_sessionRegistry = __esm({
3042
3423
  });
3043
3424
 
3044
3425
  // ../core/src/tool/guard.ts
3045
- import fs8 from "fs/promises";
3426
+ import fs11 from "fs/promises";
3046
3427
  import fsSync from "fs";
3047
- import path11 from "path";
3428
+ import path13 from "path";
3048
3429
  import ignore from "ignore";
3049
3430
  import { AsyncLocalStorage } from "node:async_hooks";
3050
3431
  var WORKSPACE_ROOT, workspaceAls, getActiveWorkspaceRoot, runWithWorkspaceRoot, runWithSessionContext, BUILTIN_IGNORE_RULES, ignoreCache, ignoreBuilding, allowedRootsReal, getAllowedWorkspaceRoots, realpathNativeSync, getContainingRoot, allowedBoundaryRoots, resolveSafePath, resolveReadablePath, assertWithinWorkspace, PROTECTED_WRITE_DIRS, COMMAND_ENV_DENYLIST, SENSITIVE_ENV_PATTERN, scrubCommandEnv, isProtectedWrite, SCAN_PRUNE_DIRS, scanIgnoreFilesRecursive, buildIgnoreEngine, getIgnoreForBase, initializeWorkspaceIgnore, checkIsPathIgnored, requestApproval;
@@ -3109,8 +3490,8 @@ var init_guard = __esm({
3109
3490
  let best;
3110
3491
  for (const r of allowedBoundaryRoots()) {
3111
3492
  const rReal = realpathNativeSync(r);
3112
- const rel = path11.relative(rReal, target);
3113
- if (!rel.startsWith("..") && !path11.isAbsolute(rel)) {
3493
+ const rel = path13.relative(rReal, target);
3494
+ if (!rel.startsWith("..") && !path13.isAbsolute(rel)) {
3114
3495
  if (!best || rReal.length > best.length) best = rReal;
3115
3496
  }
3116
3497
  }
@@ -3127,16 +3508,16 @@ var init_guard = __esm({
3127
3508
  };
3128
3509
  resolveSafePath = (rel, base) => {
3129
3510
  const root = base ?? getActiveWorkspaceRoot();
3130
- const candidateAbsPath = path11.resolve(root, rel);
3511
+ const candidateAbsPath = path13.resolve(root, rel);
3131
3512
  let truePhysicalPath = candidateAbsPath;
3132
3513
  try {
3133
3514
  if (fsSync.existsSync(candidateAbsPath)) {
3134
3515
  truePhysicalPath = fsSync.realpathSync(candidateAbsPath);
3135
3516
  } else {
3136
- const parentDir = path11.dirname(candidateAbsPath);
3517
+ const parentDir = path13.dirname(candidateAbsPath);
3137
3518
  if (fsSync.existsSync(parentDir)) {
3138
3519
  const trueParentDir = fsSync.realpathSync(parentDir);
3139
- truePhysicalPath = path11.join(trueParentDir, path11.basename(candidateAbsPath));
3520
+ truePhysicalPath = path13.join(trueParentDir, path13.basename(candidateAbsPath));
3140
3521
  }
3141
3522
  }
3142
3523
  } catch (e) {
@@ -3150,8 +3531,8 @@ var init_guard = __esm({
3150
3531
  }
3151
3532
  })() : allowedBoundaryRoots();
3152
3533
  const escaped = boundaryRoots.every((r) => {
3153
- const rel0 = path11.relative(r, truePhysicalPath);
3154
- return rel0.startsWith("..") || path11.isAbsolute(rel0);
3534
+ const rel0 = path13.relative(r, truePhysicalPath);
3535
+ return rel0.startsWith("..") || path13.isAbsolute(rel0);
3155
3536
  });
3156
3537
  if (escaped) {
3157
3538
  throw new Error(`\u{1F6D1} [SECURITY ALERT] \u68C0\u6D4B\u5230\u6076\u610F\u7684\u7269\u7406\u8DEF\u5F84\u8DE8\u754C\u9003\u9038\uFF01\u62D2\u7EDD\u8BBF\u95EE\uFF1A${rel}`);
@@ -3160,12 +3541,12 @@ var init_guard = __esm({
3160
3541
  };
3161
3542
  resolveReadablePath = (rel) => {
3162
3543
  const root = getActiveWorkspaceRoot();
3163
- const absPath = path11.resolve(root, rel);
3544
+ const absPath = path13.resolve(root, rel);
3164
3545
  if (!fsSync.existsSync(absPath)) {
3165
- const rootName = path11.basename(root);
3546
+ const rootName = path13.basename(root);
3166
3547
  const firstSeg = rel.split(/[\\/]/)[0];
3167
3548
  if (rootName && firstSeg === rootName) {
3168
- const alt = path11.resolve(root, rel.slice(firstSeg.length + 1));
3549
+ const alt = path13.resolve(root, rel.slice(firstSeg.length + 1));
3169
3550
  if (fsSync.existsSync(alt)) return alt;
3170
3551
  }
3171
3552
  }
@@ -3178,9 +3559,9 @@ var init_guard = __esm({
3178
3559
  if (fsSync.existsSync(absPath)) {
3179
3560
  truePhysicalPath = fsSync.realpathSync(absPath);
3180
3561
  } else {
3181
- const parentDir = path11.dirname(absPath);
3562
+ const parentDir = path13.dirname(absPath);
3182
3563
  if (fsSync.existsSync(parentDir)) {
3183
- truePhysicalPath = path11.join(fsSync.realpathSync(parentDir), path11.basename(absPath));
3564
+ truePhysicalPath = path13.join(fsSync.realpathSync(parentDir), path13.basename(absPath));
3184
3565
  }
3185
3566
  }
3186
3567
  } catch (e) {
@@ -3194,8 +3575,8 @@ var init_guard = __esm({
3194
3575
  }
3195
3576
  })() : allowedBoundaryRoots();
3196
3577
  const escaped = boundaryRoots.every((r) => {
3197
- const rel0 = path11.relative(r, truePhysicalPath);
3198
- return rel0.startsWith("..") || path11.isAbsolute(rel0);
3578
+ const rel0 = path13.relative(r, truePhysicalPath);
3579
+ return rel0.startsWith("..") || path13.isAbsolute(rel0);
3199
3580
  });
3200
3581
  if (escaped) {
3201
3582
  throw new Error(`\u{1F6D1} [SECURITY ALERT] \u4E8C\u6B21\u56F4\u680F\u590D\u68C0\u53D1\u73B0\u8D8A\u754C\uFF08\u7591\u4F3C TOCTOU \u8F6F\u94FE\u63A5\u9003\u9038\uFF09\uFF1A${absPath}`);
@@ -3222,7 +3603,7 @@ var init_guard = __esm({
3222
3603
  if (!relOrAbs) return false;
3223
3604
  try {
3224
3605
  const base = cwd || process.env.WORKSPACE_ROOT || process.cwd();
3225
- const abs = path11.isAbsolute(relOrAbs) ? relOrAbs : path11.resolve(base, relOrAbs);
3606
+ const abs = path13.isAbsolute(relOrAbs) ? relOrAbs : path13.resolve(base, relOrAbs);
3226
3607
  const lower = abs.replace(/\\/g, "/").toLowerCase();
3227
3608
  return PROTECTED_WRITE_DIRS.some((d) => {
3228
3609
  const seg = ("/" + d).toLowerCase();
@@ -3254,12 +3635,12 @@ var init_guard = __esm({
3254
3635
  ]);
3255
3636
  scanIgnoreFilesRecursive = async (dirPath, base, engine) => {
3256
3637
  try {
3257
- const entries = await fs8.readdir(dirPath, { withFileTypes: true });
3638
+ const entries = await fs11.readdir(dirPath, { withFileTypes: true });
3258
3639
  for (const entry of entries) {
3259
3640
  if (entry.isFile() && (entry.name === ".gitignore" || entry.name === ".agentignore")) {
3260
- const fullPath = path11.join(dirPath, entry.name);
3261
- const content = await fs8.readFile(fullPath, "utf-8");
3262
- const relDir = path11.relative(base, dirPath).replace(/\\/g, "/");
3641
+ const fullPath = path13.join(dirPath, entry.name);
3642
+ const content = await fs11.readFile(fullPath, "utf-8");
3643
+ const relDir = path13.relative(base, dirPath).replace(/\\/g, "/");
3263
3644
  const rules3 = content.split(/\r?\n/).map((line) => {
3264
3645
  const trimmed = line.trim();
3265
3646
  if (!trimmed || trimmed.startsWith("#")) return "";
@@ -3270,7 +3651,7 @@ var init_guard = __esm({
3270
3651
  }
3271
3652
  for (const entry of entries) {
3272
3653
  if (entry.isDirectory() && !SCAN_PRUNE_DIRS.has(entry.name)) {
3273
- await scanIgnoreFilesRecursive(path11.join(dirPath, entry.name), base, engine);
3654
+ await scanIgnoreFilesRecursive(path13.join(dirPath, entry.name), base, engine);
3274
3655
  }
3275
3656
  }
3276
3657
  } catch {
@@ -3383,7 +3764,7 @@ var init_inbox = __esm({
3383
3764
  // ../core/src/tool/registry/background.ts
3384
3765
  import { spawn as spawn2, execFileSync } from "child_process";
3385
3766
  import fsSync2 from "fs";
3386
- import path12 from "path";
3767
+ import path14 from "path";
3387
3768
  function appendOutput(task, chunk) {
3388
3769
  task.outputBuffer += chunk;
3389
3770
  if (task.outputBuffer.length > MAX_BUFFER_CHARS) {
@@ -3408,7 +3789,7 @@ async function killTree(proc) {
3408
3789
  }
3409
3790
  }
3410
3791
  async function killBackgroundTasksUnder(dirPath) {
3411
- const norm = (p) => path12.resolve(p).replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
3792
+ const norm = (p) => path14.resolve(p).replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
3412
3793
  const target = norm(dirPath);
3413
3794
  let killed = 0;
3414
3795
  for (const task of registry.values()) {
@@ -3454,9 +3835,9 @@ var init_background = __esm({
3454
3835
  if (envShell && envShell.toLowerCase() !== "cmd") candidates.push(envShell);
3455
3836
  const gitExe = whereLines("git")[0];
3456
3837
  if (gitExe) {
3457
- const dir = path12.dirname(gitExe);
3458
- const root = path12.dirname(dir);
3459
- candidates.push(path12.join(root, "bin", "bash.exe"), path12.join(dir, "bash.exe"), path12.join(path12.dirname(root), "bin", "bash.exe"));
3838
+ const dir = path14.dirname(gitExe);
3839
+ const root = path14.dirname(dir);
3840
+ candidates.push(path14.join(root, "bin", "bash.exe"), path14.join(dir, "bash.exe"), path14.join(path14.dirname(root), "bin", "bash.exe"));
3460
3841
  }
3461
3842
  const bashHits = whereLines("bash").filter((p) => !/\\System32\\/i.test(p)).sort((a, b) => Number(/\\Git\\/i.test(b)) - Number(/\\Git\\/i.test(a)));
3462
3843
  candidates.push(...bashHits);
@@ -4282,17 +4663,17 @@ ${capped || JSON.stringify(result)}`).content;
4282
4663
  });
4283
4664
 
4284
4665
  // ../core/src/tool/mcp/loader.ts
4285
- import fs9 from "fs/promises";
4286
- import path13 from "path";
4666
+ import fs12 from "fs/promises";
4667
+ import path15 from "path";
4287
4668
  import { homedir } from "os";
4288
4669
  function sanitize(s) {
4289
4670
  return s.replace(/[^a-zA-Z0-9_]/g, "_");
4290
4671
  }
4291
4672
  async function readMcpConfig() {
4292
- const configPath = process.env.MCP_CONFIG || path13.join(appConfig.dataDir, "mcp.json");
4673
+ const configPath = process.env.MCP_CONFIG || path15.join(appConfig.dataDir, "mcp.json");
4293
4674
  let raw;
4294
4675
  try {
4295
- raw = await fs9.readFile(configPath, "utf-8");
4676
+ raw = await fs12.readFile(configPath, "utf-8");
4296
4677
  } catch {
4297
4678
  return {};
4298
4679
  }
@@ -4617,8 +4998,8 @@ ${text}`;
4617
4998
  for (const c of clients) {
4618
4999
  if (server && c.serverName !== server) continue;
4619
5000
  try {
4620
- const ts = await c.listTools();
4621
- for (const t of ts) {
5001
+ const ts2 = await c.listTools();
5002
+ for (const t of ts2) {
4622
5003
  const props = t?.inputSchema?.properties && typeof t.inputSchema.properties === "object" ? Object.keys(t.inputSchema.properties) : [];
4623
5004
  const required = Array.isArray(t?.inputSchema?.required) ? t.inputSchema.required : [];
4624
5005
  const argList = props.map((p) => required.includes(p) ? `${p}*` : p).join(", ");
@@ -4833,57 +5214,6 @@ var init_repeatBreaker = __esm({
4833
5214
  }
4834
5215
  });
4835
5216
 
4836
- // ../core/src/agent/planMode.ts
4837
- function filterToolsForPlanMode(tools) {
4838
- const allowed = tools.filter((t) => t.function.planAllowed === true);
4839
- return [...allowed, exitPlanModeToolSchema];
4840
- }
4841
- function appendPlanControlTools(tools) {
4842
- return [
4843
- ...tools,
4844
- enterPlanModeToolSchema,
4845
- exitPlanModeToolSchema
4846
- ];
4847
- }
4848
- var exitPlanModeToolSchema, enterPlanModeToolSchema, PLAN_MODE_AUTO_ENTER_HINT;
4849
- var init_planMode = __esm({
4850
- "../core/src/agent/planMode.ts"() {
4851
- "use strict";
4852
- exitPlanModeToolSchema = {
4853
- type: "function",
4854
- function: {
4855
- name: "exit_plan_mode",
4856
- description: "\u8BA1\u5212\u6A21\u5F0F\u4E13\u7528\uFF1A\u5B8C\u6210\u53EA\u8BFB\u8C03\u7814\u3001\u5F62\u6210\u660E\u786E\u5B9E\u73B0\u65B9\u6848\u540E\u8C03\u7528\u672C\u5DE5\u5177\u63D0\u4EA4\u65B9\u6848\u3002\u63D0\u4EA4\u540E\u65B9\u6848\u4F1A\u5448\u73B0\u7ED9\u7528\u6237\u5BA1\u6279\uFF1B\u5BA1\u6279\u901A\u8FC7\u540E\u624D\u8FDB\u5165\u5B9E\u73B0\u9636\u6BB5\uFF08\u5C4A\u65F6\u624D\u5141\u8BB8\u4FEE\u6539\u6587\u4EF6/\u6267\u884C\u547D\u4EE4\uFF09\u3002\u5728\u8BA1\u5212\u6A21\u5F0F\u4E0B\u4F60\u53EA\u80FD\u8BFB\u53D6\u4E0E\u641C\u7D22\uFF0C\u4E0D\u80FD\u505A\u4EFB\u4F55\u4FEE\u6539\u3002",
4857
- parameters: {
4858
- type: "object",
4859
- properties: {
4860
- plan: { type: "string", description: "\u5B8C\u6574\u7684\u5B9E\u73B0\u65B9\u6848\uFF1A\u8981\u6539\u54EA\u4E9B\u6587\u4EF6\u3001\u5177\u4F53\u600E\u4E48\u6539\u3001\u4E3A\u4EC0\u4E48\u8FD9\u4E48\u505A\u3001\u6709\u4EC0\u4E48\u98CE\u9669\u4E0E\u53D6\u820D" }
4861
- },
4862
- required: ["plan"]
4863
- }
4864
- }
4865
- };
4866
- enterPlanModeToolSchema = {
4867
- type: "function",
4868
- function: {
4869
- name: "enter_plan_mode",
4870
- description: "\u81EA\u4E3B\u8FDB\u5165\u8BA1\u5212\u6A21\u5F0F\uFF1A\u5F53\u4EFB\u52A1\u662F\u975E\u5E73\u51E1\u7684\u5B9E\u73B0\u4EFB\u52A1\uFF08\u591A\u6587\u4EF6\u6539\u52A8\u3001\u67B6\u6784\u51B3\u7B56\u3001\u4E0D\u786E\u5B9A\u8DEF\u5F84\u3001\u9AD8\u98CE\u9669\u64CD\u4F5C\uFF09\u65F6\u8C03\u7528\u3002\u8C03\u7528\u540E\u672C\u8F6E\u7ED3\u675F\u5E76\u8FDB\u5165\u53EA\u8BFB\u8C03\u7814\u9636\u6BB5\u2014\u2014\u4F60\u53EA\u80FD\u8BFB\u53D6\u4E0E\u641C\u7D22\uFF0C\u4EA7\u51FA\u5B8C\u6574\u5B9E\u73B0\u65B9\u6848\uFF08\u8981\u6539\u54EA\u4E9B\u6587\u4EF6\u3001\u600E\u4E48\u6539\u3001\u4E3A\u4F55\u3001\u98CE\u9669\uFF09\u7ECF\u7528\u6237\u5BA1\u6279\u540E\u518D\u5B9E\u73B0\u3002\u7B80\u5355\u4EFB\u52A1\u65E0\u9700\u8C03\u7528\uFF0C\u76F4\u63A5\u5B9E\u73B0\u3002",
4871
- parameters: {
4872
- type: "object",
4873
- properties: {
4874
- reason: { type: "string", description: "\u4E3A\u4F55\u8981\u8FDB\u5165\u8BA1\u5212\u6A21\u5F0F\uFF08\u4EFB\u52A1\u7684\u590D\u6742\u70B9\u3001\u9700\u5148\u5398\u6E05\u7684\u5173\u952E\u95EE\u9898\uFF09" }
4875
- },
4876
- required: ["reason"]
4877
- }
4878
- }
4879
- };
4880
- PLAN_MODE_AUTO_ENTER_HINT = `\u3010\u4EFB\u52A1\u5206\u7C7B\uFF08\u6536\u5230\u5B9E\u73B0\u7C7B\u8BF7\u6C42\u65F6\u7684\u9996\u4E2A\u52A8\u4F5C\uFF09\u3011\u5148\u5224\u65AD\u590D\u6742\u5EA6\uFF0C\u518D\u51B3\u5B9A\u662F\u5426\u5148\u89C4\u5212\uFF1A
4881
- - **\u975E\u5E73\u51E1\u4EFB\u52A1**\uFF08\u6EE1\u8DB3\u4EFB\u4E00\u5373\u7B97\uFF1A\u6D89\u53CA\u591A\u4E2A\u6587\u4EF6\u6539\u52A8 / \u9700\u8981\u67B6\u6784\u51B3\u7B56 / \u5B9E\u73B0\u8DEF\u5F84\u4E0D\u786E\u5B9A / \u9AD8\u98CE\u9669\u64CD\u4F5C / \u9884\u4F30 \u22653 \u4E2A\u6B65\u9AA4\uFF09\u2192 **\u9ED8\u8BA4\u5148\u8C03\u7528 enter_plan_mode \u8FDB\u5165\u8BA1\u5212\u6A21\u5F0F**\uFF1A\u4EE5\u53EA\u8BFB\u65B9\u5F0F\u4E13\u6CE8\u8C03\u7814\u3001\u7406\u6E05\u73B0\u72B6\u4E0E\u6539\u9020\u70B9\uFF0C\u518D\u8C03\u7528 exit_plan_mode \u63D0\u4EA4\u5B8C\u6574\u5B9E\u73B0\u65B9\u6848\uFF08\u8981\u6539\u54EA\u4E9B\u6587\u4EF6\u3001\u5177\u4F53\u600E\u4E48\u6539\u3001\u4E3A\u4F55\u8FD9\u4E48\u505A\u3001\u6709\u4EC0\u4E48\u98CE\u9669\u4E0E\u53D6\u820D\uFF09\uFF0C\u65B9\u6848\u7ECF\u7528\u6237\u5BA1\u6279\u540E\u624D\u8FDB\u5165\u5B9E\u73B0\u9636\u6BB5\u3002
4882
- - **\u7B80\u5355\u4EFB\u52A1**\uFF08\u5355\u6587\u4EF6\u3001\u5355\u884C\u4FEE\u590D\u3001\u660E\u786E\u7684\u5C0F\u8C03\u6574\u3001\u7EAF\u67E5\u8BE2\u6216\u89E3\u91CA\uFF09\u2192 \u65E0\u9700\u89C4\u5212\uFF0C\u76F4\u63A5\u5B9E\u73B0\u6216\u4F5C\u7B54\u3002
4883
- - \u5224\u636E\u793A\u4F8B\uFF1A\u300C\u65B0\u589E/\u5B9E\u73B0\u4E00\u4E2A\u529F\u80FD\u6A21\u5757\u300D\u300C\u91CD\u6784/\u6539\u9020 XX \u5B50\u7CFB\u7EDF\u300D\u300C\u628A A \u8FC1\u79FB\u5230 B\u300D\u300C\u8C03\u6574\u6574\u4F53\u6570\u636E\u6D41\u300D\u2192 \u975E\u5E73\u51E1\uFF0C\u5148\u89C4\u5212\uFF1B\u300C\u6539\u4E00\u4E0B\u7B2C N \u884C\u7684\u53D8\u91CF\u540D\u300D\u300C\u89E3\u91CA\u8FD9\u6BB5\u4EE3\u7801\u300D\u300C\u8DD1\u4E00\u4E0B\u6D4B\u8BD5\u300D\u2192 \u7B80\u5355\uFF0C\u76F4\u63A5\u505A\u3002`;
4884
- }
4885
- });
4886
-
4887
5217
  // ../core/src/agent/toolFilter.ts
4888
5218
  async function filterByEnvironment(tools, ctx) {
4889
5219
  const out = [];
@@ -4908,7 +5238,7 @@ var init_toolFilter = __esm({
4908
5238
  });
4909
5239
 
4910
5240
  // ../core/src/common/registry.ts
4911
- import fs10 from "fs/promises";
5241
+ import fs13 from "fs/promises";
4912
5242
  var createRegistry, filterSources, scanSources;
4913
5243
  var init_registry2 = __esm({
4914
5244
  "../core/src/common/registry.ts"() {
@@ -4938,7 +5268,7 @@ var init_registry2 = __esm({
4938
5268
  for (const s of sources) {
4939
5269
  let entries;
4940
5270
  try {
4941
- entries = await fs10.readdir(s.dir, { withFileTypes: true });
5271
+ entries = await fs13.readdir(s.dir, { withFileTypes: true });
4942
5272
  } catch {
4943
5273
  continue;
4944
5274
  }
@@ -5035,8 +5365,8 @@ ${AGENT_USAGE_HINT}`);
5035
5365
  });
5036
5366
 
5037
5367
  // ../core/src/projectGuide/loader.ts
5038
- import fs11 from "fs/promises";
5039
- import path14 from "path";
5368
+ import fs14 from "fs/promises";
5369
+ import path16 from "path";
5040
5370
  var CANDIDATES, MAX_GUIDE_BYTES, cached, initProjectGuide, getProjectGuide;
5041
5371
  var init_loader2 = __esm({
5042
5372
  "../core/src/projectGuide/loader.ts"() {
@@ -5053,7 +5383,7 @@ var init_loader2 = __esm({
5053
5383
  try {
5054
5384
  for (const name of CANDIDATES) {
5055
5385
  try {
5056
- const raw = await fs11.readFile(path14.join(WORKSPACE_ROOT, name), "utf-8");
5386
+ const raw = await fs14.readFile(path16.join(WORKSPACE_ROOT, name), "utf-8");
5057
5387
  const body = raw.length > MAX_GUIDE_BYTES ? raw.slice(0, MAX_GUIDE_BYTES) + `
5058
5388
 
5059
5389
  \u2026[\u9879\u76EE\u6307\u5F15\u8D85 ${MAX_GUIDE_BYTES} \u5B57\u8282\u5DF2\u622A\u65AD\uFF0C\u5B8C\u6574\u5185\u5BB9\u53EF\u8C03\u7528 read_project_guide \u83B7\u53D6]` : raw;
@@ -5378,9 +5708,9 @@ var init_agent = __esm({
5378
5708
  });
5379
5709
 
5380
5710
  // ../core/src/tool/worktree/manager.ts
5381
- import path15 from "path";
5711
+ import path17 from "path";
5382
5712
  import os4 from "os";
5383
- import fs12 from "fs";
5713
+ import fs15 from "fs";
5384
5714
  var runMainGit, worktreeRootDir, worktreeDir, isNotARepoError, createWorktree, harvestDiff, runInWorktree, removeWorktree, sweepOrphanedWorktrees, disposeAllSessionWorktrees;
5385
5715
  var init_manager = __esm({
5386
5716
  "../core/src/tool/worktree/manager.ts"() {
@@ -5391,8 +5721,8 @@ var init_manager = __esm({
5391
5721
  init_background();
5392
5722
  init_sessionRegistry();
5393
5723
  runMainGit = (args, maxBuffer = 1024 * 1024 * 5) => execFileSmart("git", args, { cwd: WORKSPACE_ROOT, maxBuffer });
5394
- worktreeRootDir = () => path15.join(os4.tmpdir(), "deepseeker-code-worktrees", appConfig.userWorkspaceDir);
5395
- worktreeDir = (sessionId, stepId) => path15.join(worktreeRootDir(), sessionId, stepId);
5724
+ worktreeRootDir = () => path17.join(os4.tmpdir(), "deepseeker-code-worktrees", appConfig.userWorkspaceDir);
5725
+ worktreeDir = (sessionId, stepId) => path17.join(worktreeRootDir(), sessionId, stepId);
5396
5726
  isNotARepoError = (e) => {
5397
5727
  const text = `${e?.message || ""} ${e?.stderr || ""}`.toLowerCase();
5398
5728
  return text.includes("not a git repository");
@@ -5403,12 +5733,12 @@ var init_manager = __esm({
5403
5733
  const wtPath = worktreeDir(sessionId, stepId);
5404
5734
  const shortId = sessionId.replace(/[^A-Za-z0-9-]/g, "").slice(0, 8) || "x";
5405
5735
  const branch = `dsc-wt-${shortId}-${stepId}`;
5406
- await fs12.promises.mkdir(path15.dirname(wtPath), { recursive: true });
5736
+ await fs15.promises.mkdir(path17.dirname(wtPath), { recursive: true });
5407
5737
  try {
5408
5738
  await runMainGit(["worktree", "add", "-b", branch, wtPath, "HEAD"]);
5409
5739
  } catch (e) {
5410
5740
  if (e?.code === "ENOENT" || /already exists|not a working tree/i.test(`${e?.stderr || ""} ${e?.message || ""}`)) {
5411
- await fs12.promises.rm(wtPath, { recursive: true, force: true }).catch(() => {
5741
+ await fs15.promises.rm(wtPath, { recursive: true, force: true }).catch(() => {
5412
5742
  });
5413
5743
  await runMainGit(["worktree", "add", "-b", branch, wtPath, "HEAD"]);
5414
5744
  } else {
@@ -5456,7 +5786,7 @@ var init_manager = __esm({
5456
5786
  try {
5457
5787
  await runMainGit(["worktree", "remove", "--force", wt.path]);
5458
5788
  } catch (e) {
5459
- await fs12.promises.rm(wt.path, { recursive: true, force: true }).catch(() => {
5789
+ await fs15.promises.rm(wt.path, { recursive: true, force: true }).catch(() => {
5460
5790
  });
5461
5791
  }
5462
5792
  try {
@@ -5473,30 +5803,30 @@ var init_manager = __esm({
5473
5803
  const root = worktreeRootDir();
5474
5804
  let entries;
5475
5805
  try {
5476
- entries = await fs12.promises.readdir(root);
5806
+ entries = await fs15.promises.readdir(root);
5477
5807
  } catch {
5478
5808
  return;
5479
5809
  }
5480
5810
  let swept = 0;
5481
5811
  for (const sessionIdDir of entries) {
5482
- const sessionPath = path15.join(root, sessionIdDir);
5812
+ const sessionPath = path17.join(root, sessionIdDir);
5483
5813
  let stepDirs;
5484
5814
  try {
5485
- stepDirs = await fs12.promises.readdir(sessionPath);
5815
+ stepDirs = await fs15.promises.readdir(sessionPath);
5486
5816
  } catch {
5487
5817
  continue;
5488
5818
  }
5489
5819
  for (const stepDir of stepDirs) {
5490
- const wtPath = path15.join(sessionPath, stepDir);
5820
+ const wtPath = path17.join(sessionPath, stepDir);
5491
5821
  try {
5492
5822
  await runMainGit(["worktree", "remove", "--force", wtPath]);
5493
5823
  } catch {
5494
- await fs12.promises.rm(wtPath, { recursive: true, force: true }).catch(() => {
5824
+ await fs15.promises.rm(wtPath, { recursive: true, force: true }).catch(() => {
5495
5825
  });
5496
5826
  }
5497
5827
  swept++;
5498
5828
  }
5499
- await fs12.promises.rm(sessionPath, { recursive: true, force: true }).catch(() => {
5829
+ await fs15.promises.rm(sessionPath, { recursive: true, force: true }).catch(() => {
5500
5830
  });
5501
5831
  }
5502
5832
  if (swept > 0) {
@@ -5765,7 +6095,7 @@ var init_workflow = __esm({
5765
6095
 
5766
6096
  // ../core/src/tool/tsHost.ts
5767
6097
  import fsSync3 from "fs";
5768
- import path16 from "path";
6098
+ import path18 from "path";
5769
6099
  var _ts, _tsTried, getTs, buildDefaultOptions, findTsConfigBounded, tsconfigWalkCache, tsconfigParseCache, resolveTsConfig, createProjectHost, lsCache, getLanguageService, realpathNative, posToLineCol, SUPPORTED_SOURCE_EXTS, checkSupportedSourceExt, lineColToPos;
5770
6100
  var init_tsHost = __esm({
5771
6101
  "../core/src/tool/tsHost.ts"() {
@@ -5784,10 +6114,10 @@ var init_tsHost = __esm({
5784
6114
  }
5785
6115
  return _ts;
5786
6116
  };
5787
- buildDefaultOptions = (ts) => ({
5788
- target: ts.ScriptTarget.ESNext,
5789
- module: ts.ModuleKind.ESNext,
5790
- moduleResolution: ts.ModuleResolutionKind.Bundler,
6117
+ buildDefaultOptions = (ts2) => ({
6118
+ target: ts2.ScriptTarget.ESNext,
6119
+ module: ts2.ModuleKind.ESNext,
6120
+ moduleResolution: ts2.ModuleResolutionKind.Bundler,
5791
6121
  allowJs: true,
5792
6122
  checkJs: false,
5793
6123
  esModuleInterop: true,
@@ -5795,20 +6125,20 @@ var init_tsHost = __esm({
5795
6125
  resolveJsonModule: true,
5796
6126
  skipLibCheck: true,
5797
6127
  noEmit: true,
5798
- jsx: ts.JsxEmit.ReactJSX,
6128
+ jsx: ts2.JsxEmit.ReactJSX,
5799
6129
  strict: false
5800
6130
  });
5801
- findTsConfigBounded = (ts, absPath) => {
5802
- const root = path16.resolve(getContainingRoot(absPath));
5803
- let dir = path16.dirname(absPath);
6131
+ findTsConfigBounded = (ts2, absPath) => {
6132
+ const root = path18.resolve(getContainingRoot(absPath));
6133
+ let dir = path18.dirname(absPath);
5804
6134
  while (true) {
5805
- const candidate = path16.join(dir, "tsconfig.json");
6135
+ const candidate = path18.join(dir, "tsconfig.json");
5806
6136
  try {
5807
6137
  if (fsSync3.existsSync(candidate)) return candidate;
5808
6138
  } catch {
5809
6139
  }
5810
- if (path16.resolve(dir) === root) break;
5811
- const parent = path16.dirname(dir);
6140
+ if (path18.resolve(dir) === root) break;
6141
+ const parent = path18.dirname(dir);
5812
6142
  if (parent === dir) break;
5813
6143
  dir = parent;
5814
6144
  }
@@ -5816,15 +6146,15 @@ var init_tsHost = __esm({
5816
6146
  };
5817
6147
  tsconfigWalkCache = /* @__PURE__ */ new Map();
5818
6148
  tsconfigParseCache = /* @__PURE__ */ new Map();
5819
- resolveTsConfig = (ts, absPath) => {
5820
- const startDir = path16.dirname(absPath);
6149
+ resolveTsConfig = (ts2, absPath) => {
6150
+ const startDir = path18.dirname(absPath);
5821
6151
  let tsConfigPath = tsconfigWalkCache.get(startDir);
5822
6152
  if (!tsConfigPath) {
5823
- tsConfigPath = findTsConfigBounded(ts, absPath) ?? "";
6153
+ tsConfigPath = findTsConfigBounded(ts2, absPath) ?? "";
5824
6154
  if (tsConfigPath) tsconfigWalkCache.set(startDir, tsConfigPath);
5825
6155
  }
5826
6156
  if (!tsConfigPath) {
5827
- return { options: buildDefaultOptions(ts), fileNames: [], projectRoot: getContainingRoot(absPath) };
6157
+ return { options: buildDefaultOptions(ts2), fileNames: [], projectRoot: getContainingRoot(absPath) };
5828
6158
  }
5829
6159
  let st;
5830
6160
  try {
@@ -5837,22 +6167,22 @@ var init_tsHost = __esm({
5837
6167
  if (!st) {
5838
6168
  tsconfigParseCache.delete(tsConfigPath);
5839
6169
  for (const [dir, p] of tsconfigWalkCache) if (p === tsConfigPath) tsconfigWalkCache.delete(dir);
5840
- return resolveTsConfig(ts, absPath);
6170
+ return resolveTsConfig(ts2, absPath);
5841
6171
  }
5842
- const basePath = path16.dirname(tsConfigPath);
5843
- const raw = ts.readConfigFile(tsConfigPath, ts.sys.readFile);
5844
- if (raw.error) return { options: buildDefaultOptions(ts), fileNames: [], projectRoot: basePath };
5845
- const parsed = ts.parseJsonConfigFileContent(raw.config, ts.sys, basePath);
6172
+ const basePath = path18.dirname(tsConfigPath);
6173
+ const raw = ts2.readConfigFile(tsConfigPath, ts2.sys.readFile);
6174
+ if (raw.error) return { options: buildDefaultOptions(ts2), fileNames: [], projectRoot: basePath };
6175
+ const parsed = ts2.parseJsonConfigFileContent(raw.config, ts2.sys, basePath);
5846
6176
  const resolved = { options: parsed.options, fileNames: parsed.fileNames, projectRoot: basePath };
5847
6177
  tsconfigParseCache.set(tsConfigPath, { mtimeMs: st.mtimeMs, resolved });
5848
6178
  return resolved;
5849
6179
  };
5850
- createProjectHost = (ts, projectRoot, options, rootFileNames) => {
6180
+ createProjectHost = (ts2, projectRoot, options, rootFileNames) => {
5851
6181
  const cache = /* @__PURE__ */ new Map();
5852
6182
  const roots = /* @__PURE__ */ new Set();
5853
- const caseSensitive = ts.sys.useCaseSensitiveFileNames;
6183
+ const caseSensitive = ts2.sys.useCaseSensitiveFileNames;
5854
6184
  const canonical = (f) => caseSensitive ? f : f.toLowerCase();
5855
- const keyOf = (f) => canonical(path16.resolve(f)).replace(/\\/g, "/");
6185
+ const keyOf = (f) => canonical(path18.resolve(f)).replace(/\\/g, "/");
5856
6186
  rootFileNames.forEach((f) => roots.add(keyOf(f)));
5857
6187
  const fresh = (fileName) => {
5858
6188
  const key = keyOf(fileName);
@@ -5873,7 +6203,7 @@ var init_tsHost = __esm({
5873
6203
  }
5874
6204
  const entry = {
5875
6205
  version: (cached2?.version ?? 0) + 1,
5876
- snapshot: ts.ScriptSnapshot.fromString(text),
6206
+ snapshot: ts2.ScriptSnapshot.fromString(text),
5877
6207
  mtimeMs: st.mtimeMs
5878
6208
  };
5879
6209
  cache.set(key, entry);
@@ -5888,14 +6218,14 @@ var init_tsHost = __esm({
5888
6218
  },
5889
6219
  getScriptSnapshot: (f) => fresh(f)?.snapshot,
5890
6220
  getCurrentDirectory: () => projectRoot,
5891
- getDefaultLibFileName: (o) => ts.getDefaultLibFilePath(o),
5892
- useCaseSensitiveFileNames: () => ts.sys.useCaseSensitiveFileNames,
6221
+ getDefaultLibFileName: (o) => ts2.getDefaultLibFilePath(o),
6222
+ useCaseSensitiveFileNames: () => ts2.sys.useCaseSensitiveFileNames,
5893
6223
  // 模块解析委派 ts.sys(穿 node_modules 解析 import 必需)
5894
- fileExists: ts.sys.fileExists,
5895
- readFile: ts.sys.readFile,
5896
- directoryExists: ts.sys.directoryExists,
5897
- getDirectories: ts.sys.getDirectories,
5898
- realpath: ts.sys.realpath,
6224
+ fileExists: ts2.sys.fileExists,
6225
+ readFile: ts2.sys.readFile,
6226
+ directoryExists: ts2.sys.directoryExists,
6227
+ getDirectories: ts2.sys.getDirectories,
6228
+ realpath: ts2.sys.realpath,
5899
6229
  // 自定义扩展:把查询目标登记为 program 根文件(确保被纳入分析)
5900
6230
  addRoot: (absPath) => {
5901
6231
  roots.add(keyOf(absPath));
@@ -5903,19 +6233,19 @@ var init_tsHost = __esm({
5903
6233
  };
5904
6234
  };
5905
6235
  lsCache = /* @__PURE__ */ new Map();
5906
- getLanguageService = async (ts, absPath, opts) => {
5907
- const { options, fileNames, projectRoot } = resolveTsConfig(ts, absPath);
6236
+ getLanguageService = async (ts2, absPath, opts) => {
6237
+ const { options, fileNames, projectRoot } = resolveTsConfig(ts2, absPath);
5908
6238
  const checkJs = opts?.checkJs === true;
5909
6239
  const key = `${projectRoot}::${checkJs}`;
5910
6240
  let p = lsCache.get(key);
5911
6241
  if (!p) {
5912
6242
  p = (async () => {
5913
6243
  const finalOptions = { ...options, ...checkJs ? { checkJs: true } : {} };
5914
- if (!ts.sys.useCaseSensitiveFileNames) {
6244
+ if (!ts2.sys.useCaseSensitiveFileNames) {
5915
6245
  finalOptions.forceConsistentCasingInFileNames = false;
5916
6246
  }
5917
- const host = createProjectHost(ts, projectRoot, finalOptions, fileNames);
5918
- const ls = ts.createLanguageService(host);
6247
+ const host = createProjectHost(ts2, projectRoot, finalOptions, fileNames);
6248
+ const ls = ts2.createLanguageService(host);
5919
6249
  return { ls, host, projectRoot };
5920
6250
  })();
5921
6251
  lsCache.set(key, p);
@@ -5931,23 +6261,23 @@ var init_tsHost = __esm({
5931
6261
  return p;
5932
6262
  }
5933
6263
  };
5934
- posToLineCol = (ts, sf, pos) => {
5935
- const { line, character } = ts.getLineAndCharacterOfPosition(sf, pos);
6264
+ posToLineCol = (ts2, sf, pos) => {
6265
+ const { line, character } = ts2.getLineAndCharacterOfPosition(sf, pos);
5936
6266
  return { line: line + 1, column: character + 1 };
5937
6267
  };
5938
6268
  SUPPORTED_SOURCE_EXTS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
5939
6269
  checkSupportedSourceExt = (displayPath) => {
5940
- const ext = path16.extname(displayPath).toLowerCase();
6270
+ const ext = path18.extname(displayPath).toLowerCase();
5941
6271
  if (SUPPORTED_SOURCE_EXTS.has(ext)) return null;
5942
6272
  return toolFailure(`[\u6587\u4EF6\u7C7B\u578B\u4E0D\u652F\u6301]\uFF1A[${displayPath}] \u7684\u6269\u5C55\u540D ${ext || "(\u65E0)"} \u4E0D\u5728 TS \u5F15\u64CE\u652F\u6301\u8303\u56F4\uFF08\u4EC5 .ts/.tsx/.js/.jsx/.mjs/.cjs\uFF09\u3002\u8BF7\u6539\u7528 read_file/grep \u67E5\u770B\u5185\u5BB9\uFF1B\u7F16\u8BD1/\u7C7B\u578B\u7C7B\u9A8C\u8BC1\u7528 run_command \u8DD1\u5BF9\u5E94\u8BED\u8A00\u5DE5\u5177\u94FE\uFF08\u5982 mvn compile / tsc --noEmit\uFF09\u3002`);
5943
6273
  };
5944
- lineColToPos = (ts, sf, line1, col1) => ts.getPositionOfLineAndCharacter(sf, Math.max(0, line1 - 1), Math.max(0, col1 - 1));
6274
+ lineColToPos = (ts2, sf, line1, col1) => ts2.getPositionOfLineAndCharacter(sf, Math.max(0, line1 - 1), Math.max(0, col1 - 1));
5945
6275
  }
5946
6276
  });
5947
6277
 
5948
6278
  // ../core/src/tool/registry/fs.ts
5949
- import fs13 from "fs/promises";
5950
- import path17 from "path";
6279
+ import fs16 from "fs/promises";
6280
+ import path19 from "path";
5951
6281
  import { createReadStream } from "fs";
5952
6282
  import * as readline from "readline";
5953
6283
  var IMAGE_MIME_BY_EXT, isSensitiveReadTarget, stripReadFileLineNumbers, maskSecretsInContent, makeTmpPath, ATOMIC_TMP_RE, sweepStaleAtomicTmp, assertReadable, stripEdgeBlankLines, matchLineBlockWith, diagnoseOldStr, reindentToBase, alignIndentsByAnchor, applyOneEditToContent, fsTools;
@@ -6012,21 +6342,21 @@ var init_fs = __esm({
6012
6342
  const walk = async (dir) => {
6013
6343
  let entries;
6014
6344
  try {
6015
- entries = await fs13.readdir(dir, { withFileTypes: true });
6345
+ entries = await fs16.readdir(dir, { withFileTypes: true });
6016
6346
  } catch {
6017
6347
  return;
6018
6348
  }
6019
6349
  for (const e of entries) {
6020
- const full = path17.join(dir, e.name);
6350
+ const full = path19.join(dir, e.name);
6021
6351
  if (e.isDirectory()) {
6022
6352
  if (!skipDirs.has(e.name)) await walk(full);
6023
6353
  continue;
6024
6354
  }
6025
6355
  if (!e.isFile() || !ATOMIC_TMP_RE.test(e.name)) continue;
6026
6356
  try {
6027
- const st = await fs13.stat(full);
6357
+ const st = await fs16.stat(full);
6028
6358
  if (st.mtimeMs > cutoff) continue;
6029
- await fs13.unlink(full);
6359
+ await fs16.unlink(full);
6030
6360
  removed++;
6031
6361
  } catch {
6032
6362
  }
@@ -6230,7 +6560,7 @@ var init_fs = __esm({
6230
6560
  try {
6231
6561
  const absPath = resolveReadablePath(args.path);
6232
6562
  const lowerExt = absPath.toLowerCase();
6233
- if (IMAGE_MIME_BY_EXT[path17.extname(lowerExt)]) return `\u{1F5BC} [${args.path}] \u662F\u56FE\u7247\u6587\u4EF6\uFF0Cread_file \u8BFB\u4E0D\u51FA\u6709\u7528\u5185\u5BB9\u3002\u8BF7\u6539\u7528 read_image \u8BFB\u53D6\uFF08\u56FE\u50CF\u4F1A\u4EE5\u89C6\u89C9\u9644\u4EF6\u76F4\u63A5\u63D0\u4F9B\u7ED9\u6A21\u578B\u5206\u6790\uFF09\u3002`;
6563
+ if (IMAGE_MIME_BY_EXT[path19.extname(lowerExt)]) return `\u{1F5BC} [${args.path}] \u662F\u56FE\u7247\u6587\u4EF6\uFF0Cread_file \u8BFB\u4E0D\u51FA\u6709\u7528\u5185\u5BB9\u3002\u8BF7\u6539\u7528 read_image \u8BFB\u53D6\uFF08\u56FE\u50CF\u4F1A\u4EE5\u89C6\u89C9\u9644\u4EF6\u76F4\u63A5\u63D0\u4F9B\u7ED9\u6A21\u578B\u5206\u6790\uFF09\u3002`;
6234
6564
  if (lowerExt.endsWith(".xlsx")) return `\u26A0\uFE0F [${args.path}] \u662F Excel \u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0Cread_file \u8BFB\u4E0D\u4E86\uFF08UTF-8 \u89E3\u7801\u6EE1\u5C4F\u4E71\u7801\uFF09\u3002\u8BF7\u6539\u7528 read_xlsx\uFF08\u652F\u6301 sheet \u9009\u62E9 / \u7FFB\u9875 / Markdown \u8868\u683C\u8F93\u51FA\uFF09\u3002`;
6235
6565
  if (lowerExt.endsWith(".docx")) return `\u26A0\uFE0F [${args.path}] \u662F Word \u4E8C\u8FDB\u5236\u6587\u6863\uFF0Cread_file \u8BFB\u4E0D\u4E86\u3002\u8BF7\u6539\u7528 read_docx \u63D0\u53D6\u6B63\u6587\u6587\u672C\u3002`;
6236
6566
  if (lowerExt.endsWith(".pdf")) return `\u26A0\uFE0F [${args.path}] \u662F PDF \u4E8C\u8FDB\u5236\u6587\u6863\uFF0Cread_file \u8BFB\u4E0D\u4E86\u3002\u8BF7\u6539\u7528 read_pdf \u63D0\u53D6\u6587\u5B57\u5C42\u3002`;
@@ -6263,7 +6593,7 @@ var init_fs = __esm({
6263
6593
  let readStamp = "";
6264
6594
  if (toolCtx?.readTracker) {
6265
6595
  try {
6266
- const st = await fs13.stat(absPath);
6596
+ const st = await fs16.stat(absPath);
6267
6597
  const prev = toolCtx.readTracker.get(absPath);
6268
6598
  const count = (prev?.count ?? 0) + 1;
6269
6599
  const changed = prev !== void 0 && prev.mtimeMs !== st.mtimeMs;
@@ -6309,11 +6639,11 @@ ${formattedCode}${hasMore ? `
6309
6639
  await initializeWorkspaceIgnore();
6310
6640
  const buildTreeText = async (currentPath, currentDepth, prefix = "") => {
6311
6641
  if (currentDepth > maxDepth || hitScanLimit) return "";
6312
- const entries = await fs13.readdir(currentPath, { withFileTypes: true });
6642
+ const entries = await fs16.readdir(currentPath, { withFileTypes: true });
6313
6643
  const validEntries = entries.filter((entry) => {
6314
6644
  if (entry.isSymbolicLink()) return false;
6315
- const fullPath = path17.join(currentPath, entry.name);
6316
- const relPath = path17.relative(getActiveWorkspaceRoot(), fullPath).replace(/\\/g, "/");
6645
+ const fullPath = path19.join(currentPath, entry.name);
6646
+ const relPath = path19.relative(getActiveWorkspaceRoot(), fullPath).replace(/\\/g, "/");
6317
6647
  return !checkIsPathIgnored(entry.isDirectory() ? `${relPath}/` : relPath);
6318
6648
  });
6319
6649
  let output = "";
@@ -6332,7 +6662,7 @@ ${formattedCode}${hasMore ? `
6332
6662
  `;
6333
6663
  if (entry.isDirectory()) {
6334
6664
  const nextPrefix = prefix + (isLast ? " " : "\u2502 ");
6335
- const fullPath = path17.join(currentPath, entry.name);
6665
+ const fullPath = path19.join(currentPath, entry.name);
6336
6666
  const subTree = await buildTreeText(fullPath, currentDepth + 1, nextPrefix);
6337
6667
  output += subTree;
6338
6668
  }
@@ -6400,7 +6730,7 @@ ${patches}`;
6400
6730
  return toolFailure(`[\u53C2\u6570\u7F3A\u5931]\uFF1A\u8BF7\u4F20\u5165 edits \u6570\u7EC4\uFF08\u6BCF\u6761\u542B old_str/new_str\uFF09\u4E00\u6B21\u5B8C\u6210\u591A\u5904\u4FEE\u6539\uFF0C\u6216\u9876\u5C42 old_str + new_str \u4FEE\u6539\u5355\u5904\u3002old_str \u4E0D\u80FD\u4E3A\u7A7A\u3002`);
6401
6731
  }
6402
6732
  const absPath = resolveSafePath(args.path);
6403
- const rawContent = await fs13.readFile(absPath, "utf-8");
6733
+ const rawContent = await fs16.readFile(absPath, "utf-8");
6404
6734
  const isCRLF = rawContent.includes("\r\n");
6405
6735
  let content = rawContent.replace(/\r\n/g, "\n");
6406
6736
  const summaries = [];
@@ -6413,7 +6743,7 @@ ${patches}`;
6413
6743
  summaries.push(editList.length === 1 ? r.summary : ` ${i + 1}. ${r.summary}`);
6414
6744
  }
6415
6745
  assertWithinWorkspace(absPath);
6416
- await fs13.writeFile(absPath, isCRLF ? content.replace(/\n/g, "\r\n") : content, "utf-8");
6746
+ await fs16.writeFile(absPath, isCRLF ? content.replace(/\n/g, "\r\n") : content, "utf-8");
6417
6747
  return editList.length === 1 ? `\u2705 [\u4EE3\u7801\u4FEE\u8865\u6210\u529F]\uFF1A\u6587\u4EF6 [${args.path}] ${summaries[0]}` : `\u2705 [\u4EE3\u7801\u4FEE\u8865\u6210\u529F]\uFF1A\u6587\u4EF6 [${args.path}] \u5DF2\u6309\u5E8F\u5B8C\u6210 ${editList.length} \u5904\u4FEE\u6539\uFF08\u5355\u6B21\u539F\u5B50\u5199\u5165\uFF09\uFF1A
6418
6748
  ${summaries.join("\n")}`;
6419
6749
  } catch (error) {
@@ -6446,24 +6776,24 @@ ${summaries.join("\n")}`;
6446
6776
  try {
6447
6777
  const absPath = resolveSafePath(args.path);
6448
6778
  try {
6449
- await fs13.access(absPath);
6779
+ await fs16.access(absPath);
6450
6780
  return toolFailure(`[\u521B\u5EFA\u5931\u8D25]\uFF1A\u6587\u4EF6 [${args.path}] \u5DF2\u5B58\u5728\u3002create_file \u4EC5\u7528\u4E8E\u65B0\u5EFA\u6587\u4EF6\uFF1B\u5982\u9700\u4FEE\u6539\u8BF7\u7528 edit_file\uFF0C\u5982\u9700\u8986\u76D6\u8BF7\u7528 write_file\u3002`);
6451
6781
  } catch (e) {
6452
6782
  if (e?.code !== "ENOENT") throw e;
6453
6783
  }
6454
6784
  const content = args.content ?? "";
6455
6785
  assertWithinWorkspace(absPath);
6456
- await fs13.mkdir(path17.dirname(absPath), { recursive: true });
6786
+ await fs16.mkdir(path19.dirname(absPath), { recursive: true });
6457
6787
  tmpPath = makeTmpPath(absPath);
6458
- await fs13.writeFile(tmpPath, content, "utf-8");
6459
- await fs13.rename(tmpPath, absPath);
6788
+ await fs16.writeFile(tmpPath, content, "utf-8");
6789
+ await fs16.rename(tmpPath, absPath);
6460
6790
  return `\u2705 [\u521B\u5EFA\u6210\u529F]\uFF1A\u65B0\u6587\u4EF6 [${args.path}] \u5DF2\u521B\u5EFA\uFF0C\u5199\u5165 ${content.length} \u5B57\u7B26\u3002`;
6461
6791
  } catch (error) {
6462
6792
  return toolFailure(`\u64CD\u4F5C\u5931\u8D25: ${error.message}`);
6463
6793
  } finally {
6464
6794
  if (tmpPath) {
6465
6795
  try {
6466
- await fs13.unlink(tmpPath);
6796
+ await fs16.unlink(tmpPath);
6467
6797
  } catch {
6468
6798
  }
6469
6799
  }
@@ -6495,7 +6825,7 @@ ${summaries.join("\n")}`;
6495
6825
  }
6496
6826
  let rel = "";
6497
6827
  try {
6498
- rel = path17.relative(getActiveWorkspaceRoot(), resolveSafePath(cleanPath));
6828
+ rel = path19.relative(getActiveWorkspaceRoot(), resolveSafePath(cleanPath));
6499
6829
  } catch {
6500
6830
  }
6501
6831
  if (rel === "" || rel === "src") {
@@ -6503,7 +6833,7 @@ ${summaries.join("\n")}`;
6503
6833
  }
6504
6834
  let label = "\u6587\u4EF6\u6216\u76EE\u5F55";
6505
6835
  try {
6506
- const stat = await fs13.stat(resolveSafePath(cleanPath));
6836
+ const stat = await fs16.stat(resolveSafePath(cleanPath));
6507
6837
  label = stat.isDirectory() ? "\u4E00\u6574\u4E2A\u6587\u4EF6\u5939\u76EE\u5F55" : "\u7EAF\u7269\u7406\u6587\u4EF6";
6508
6838
  } catch {
6509
6839
  }
@@ -6516,22 +6846,22 @@ ${summaries.join("\n")}`;
6516
6846
  return toolFailure(`[\u5B89\u5168\u7194\u65AD]\uFF1A\u7981\u6B62\u901A\u8FC7\u672C\u5DE5\u5177\u76F4\u63A5\u6467\u6BC1\u9879\u76EE\u6839\u76EE\u5F55\u6216\u4F20\u5165\u7A7A\u8DEF\u5F84\uFF01`);
6517
6847
  }
6518
6848
  const absPath = resolveSafePath(cleanPath);
6519
- const rel = path17.relative(getActiveWorkspaceRoot(), absPath);
6520
- if (!rel || rel === "" || rel === "src" || rel.startsWith("..") || path17.isAbsolute(rel)) {
6849
+ const rel = path19.relative(getActiveWorkspaceRoot(), absPath);
6850
+ if (!rel || rel === "" || rel === "src" || rel.startsWith("..") || path19.isAbsolute(rel)) {
6521
6851
  return toolFailure(`[\u5B89\u5168\u7194\u65AD]\uFF1A\u62D2\u7EDD\u9500\u6BC1\u5DE5\u4F5C\u533A\u6839\u76EE\u5F55 / src \u6E90\u7801\u6839 / \u8D8A\u754C\u8DEF\u5F84 [${cleanPath}]\uFF01`);
6522
6852
  }
6523
6853
  let stat;
6524
6854
  try {
6525
- stat = await fs13.stat(absPath);
6855
+ stat = await fs16.stat(absPath);
6526
6856
  } catch {
6527
6857
  return toolFailure(`[\u9500\u6BC1\u5931\u8D25]\uFF1A\u5728\u5DE5\u4F5C\u533A\u5185\u672A\u627E\u5230\u6307\u5B9A\u7684\u8DEF\u5F84 [${cleanPath}]\u3002`);
6528
6858
  }
6529
6859
  const isDirectory = stat.isDirectory();
6530
6860
  assertWithinWorkspace(absPath);
6531
6861
  if (isDirectory) {
6532
- await fs13.rm(absPath, { recursive: true, force: true });
6862
+ await fs16.rm(absPath, { recursive: true, force: true });
6533
6863
  } else {
6534
- await fs13.unlink(absPath);
6864
+ await fs16.unlink(absPath);
6535
6865
  }
6536
6866
  const targetTypeLabel = isDirectory ? "\u4E00\u6574\u4E2A\u6587\u4EF6\u5939\u76EE\u5F55" : "\u7EAF\u7269\u7406\u6587\u4EF6";
6537
6867
  return `\u2705 [\u8DEF\u5F84\u9500\u6BC1\u6210\u529F]\uFF1A\u5DF2\u6210\u529F\u6C38\u4E45\u9500\u6BC1${targetTypeLabel} [${cleanPath}]\u3002`;
@@ -6565,15 +6895,15 @@ ${summaries.join("\n")}`;
6565
6895
  try {
6566
6896
  const absPath = resolveSafePath(args.path);
6567
6897
  assertWithinWorkspace(absPath);
6568
- await fs13.mkdir(path17.dirname(absPath), { recursive: true });
6898
+ await fs16.mkdir(path19.dirname(absPath), { recursive: true });
6569
6899
  tmpPath = makeTmpPath(absPath);
6570
- await fs13.writeFile(tmpPath, args.content, "utf-8");
6571
- await fs13.rename(tmpPath, absPath);
6900
+ await fs16.writeFile(tmpPath, args.content, "utf-8");
6901
+ await fs16.rename(tmpPath, absPath);
6572
6902
  return `\u2705 [\u6587\u4EF6\u5199\u5165\u6210\u529F]\uFF1A\u5DF2\u5168\u91CF\u5199\u5165 [${args.path}]\uFF08${args.content.length} \u5B57\u7B26\uFF09\u3002`;
6573
6903
  } catch (error) {
6574
6904
  if (tmpPath) {
6575
6905
  try {
6576
- await fs13.unlink(tmpPath);
6906
+ await fs16.unlink(tmpPath);
6577
6907
  } catch {
6578
6908
  }
6579
6909
  }
@@ -6605,11 +6935,11 @@ ${summaries.join("\n")}`;
6605
6935
  if (readBlock) return readBlock;
6606
6936
  const extBlock = checkSupportedSourceExt(args.path);
6607
6937
  if (extBlock) return extBlock;
6608
- const statForSize = await fs13.stat(absPath);
6938
+ const statForSize = await fs16.stat(absPath);
6609
6939
  if (statForSize.size > 1024 * 1024) {
6610
6940
  return `\u26A0\uFE0F [\u6587\u4EF6\u8FC7\u5927]\uFF1A[${args.path}] \u7EA6 ${Math.round(statForSize.size / 1024)}KB\uFF0C\u8D85\u8FC7\u7B26\u53F7\u5927\u7EB2\u5206\u6790\u7684 1MB \u4E0A\u9650\uFF08\u9632\u5168\u91CF readFile + AST \u9A7B\u7559\u5403\u5185\u5B58\uFF09\u3002\u8BF7\u6539\u7528 read_file \u5206\u7247\u67E5\u770B\uFF0C\u6216\u7F29\u5C0F\u76EE\u6807\u6587\u4EF6\u3002`;
6611
6941
  }
6612
- const fileContent = await fs13.readFile(absPath, "utf-8");
6942
+ const fileContent = await fs16.readFile(absPath, "utf-8");
6613
6943
  const TS = await getTs();
6614
6944
  if (!TS) {
6615
6945
  return `\u26A0\uFE0F [\u7B26\u53F7\u5927\u7EB2\u4E0D\u53EF\u7528]\uFF1Atypescript \u6A21\u5757\u672A\u5B89\u88C5\uFF08CLI \u53D1\u5E03\u7248\u672A\u5185\u8054\uFF09\u3002\u8BF7\u6539\u7528 read_file \u67E5\u770B\u6587\u4EF6\u5185\u5BB9\u3002`;
@@ -6696,19 +7026,19 @@ ${summaries.join("\n")}`;
6696
7026
  const srcAbs = resolveSafePath(args.source);
6697
7027
  const dstAbs = resolveSafePath(args.destination);
6698
7028
  try {
6699
- await fs13.access(srcAbs);
7029
+ await fs16.access(srcAbs);
6700
7030
  } catch {
6701
7031
  return toolFailure(`[\u79FB\u52A8\u5931\u8D25]\uFF1A\u6E90\u8DEF\u5F84 [${args.source}] \u4E0D\u5B58\u5728\u3002`);
6702
7032
  }
6703
7033
  try {
6704
- await fs13.access(dstAbs);
7034
+ await fs16.access(dstAbs);
6705
7035
  return toolFailure(`[\u79FB\u52A8\u5931\u8D25]\uFF1A\u76EE\u6807 [${args.destination}] \u5DF2\u5B58\u5728\u3002\u5982\u9700\u8986\u76D6\u8BF7\u5148 delete_path \u518D move_file\u3002`);
6706
7036
  } catch {
6707
7037
  }
6708
7038
  assertWithinWorkspace(srcAbs);
6709
7039
  assertWithinWorkspace(dstAbs);
6710
- await fs13.mkdir(path17.dirname(dstAbs), { recursive: true });
6711
- await fs13.rename(srcAbs, dstAbs);
7040
+ await fs16.mkdir(path19.dirname(dstAbs), { recursive: true });
7041
+ await fs16.rename(srcAbs, dstAbs);
6712
7042
  return `\u2705 [\u79FB\u52A8\u6210\u529F]\uFF1A[${args.source}] \u2192 [${args.destination}]\u3002`;
6713
7043
  } catch (error) {
6714
7044
  return toolFailure(`\u64CD\u4F5C\u5931\u8D25: ${error.message}`);
@@ -6738,9 +7068,9 @@ ${summaries.join("\n")}`;
6738
7068
  const absPath = resolveReadablePath(args.path);
6739
7069
  const readBlock = await assertReadable(absPath, args.path);
6740
7070
  if (readBlock) return readBlock;
6741
- const mime = IMAGE_MIME_BY_EXT[path17.extname(absPath).toLowerCase()];
7071
+ const mime = IMAGE_MIME_BY_EXT[path19.extname(absPath).toLowerCase()];
6742
7072
  if (!mime) return toolFailure(`[read_image] \u4E0D\u652F\u6301\u7684\u56FE\u7247\u683C\u5F0F [${args.path}]\uFF1A\u4EC5\u652F\u6301 png/jpg/jpeg/gif/webp/bmp\u3002\u6587\u672C\u6587\u4EF6\u8BF7\u7528 read_file\u3002`);
6743
- const st = await fs13.stat(absPath).catch(() => null);
7073
+ const st = await fs16.stat(absPath).catch(() => null);
6744
7074
  if (!st || !st.isFile()) return toolFailure(`[read_image] \u56FE\u7247\u4E0D\u5B58\u5728\u6216\u4E0D\u662F\u6587\u4EF6\uFF1A${args.path}`);
6745
7075
  if (st.size > MAX_IMAGE_BYTES) {
6746
7076
  return toolFailure(`[read_image] \u56FE\u7247 ${(st.size / 1024 / 1024).toFixed(1)}MB \u8D85\u8FC7 ${Math.round(MAX_IMAGE_BYTES / 1024 / 1024)}MB \u4E0A\u9650\uFF1A\u8BF7\u538B\u7F29\u540E\u91CD\u8BD5\uFF0C\u6216\u88C1\u526A\u5230\u9700\u8981\u7684\u533A\u57DF\u3002`);
@@ -6748,11 +7078,11 @@ ${summaries.join("\n")}`;
6748
7078
  if (!isVisionEnabled()) {
6749
7079
  return toolFailure(`[read_image] \u5F53\u524D\u6A21\u578B\u4E0D\u652F\u6301\u56FE\u7247\u8F93\u5165\uFF08\u89C6\u89C9\u80FD\u529B\u6309\u7AEF\u70B9\u5B9E\u6D4B\u81EA\u52A8\u5224\u5B9A\uFF1B\u53EF\u5207\u6362 vision \u6A21\u578B\u6216\u8BBE DEEP_SEEK_VISION=1 \u5F3A\u5F00\u540E\u91CD\u8BD5\uFF09\u3002\u56FE\u7247\u672A\u8BFB\u53D6\uFF1A${args.path}`);
6750
7080
  }
6751
- const buf = await fs13.readFile(absPath);
7081
+ const buf = await fs16.readFile(absPath);
6752
7082
  return {
6753
7083
  content: `\u{1F5BC} [read_image] \u5DF2\u8BFB\u53D6\u56FE\u7247 ${args.path}\uFF08${mime}\uFF0C${st.size} \u5B57\u8282\uFF09\u3002\u56FE\u50CF\u5185\u5BB9\u89C1\u968F\u540E\u7684\u9644\u4EF6\u6D88\u606F\uFF0C\u8BF7\u76F4\u63A5\u5BF9\u56FE\u7247\u8FDB\u884C\u5206\u6790/\u5BF9\u7167\u3002`,
6754
7084
  status: "success",
6755
- images: [{ name: path17.basename(absPath), mime, base64: buf.toString("base64") }]
7085
+ images: [{ name: path19.basename(absPath), mime, base64: buf.toString("base64") }]
6756
7086
  };
6757
7087
  } catch (error) {
6758
7088
  return toolFailure(`\u8BFB\u53D6\u56FE\u7247\u5931\u8D25 [${args.path}]: ${error.message}`);
@@ -6766,8 +7096,8 @@ ${summaries.join("\n")}`;
6766
7096
 
6767
7097
  // ../core/src/tool/registry/search.ts
6768
7098
  import { rgPath } from "vscode-ripgrep";
6769
- import path18 from "path";
6770
- import fs14 from "fs/promises";
7099
+ import path20 from "path";
7100
+ import fs17 from "fs/promises";
6771
7101
  function escapeRegExp(string) {
6772
7102
  return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6773
7103
  }
@@ -6811,10 +7141,10 @@ var init_search = __esm({
6811
7141
  const resolveSearchRoot = () => {
6812
7142
  if (!args.path) return ctx?.cwd ?? getActiveWorkspaceRoot();
6813
7143
  const p = args.path.trim();
6814
- const looksLikeBareName = !path18.isAbsolute(p) && !p.includes("/") && !p.includes("\\");
7144
+ const looksLikeBareName = !path20.isAbsolute(p) && !p.includes("/") && !p.includes("\\");
6815
7145
  if (looksLikeBareName) {
6816
7146
  const hit = getAllowedWorkspaceRoots().find((r) => {
6817
- const bn = path18.basename(r);
7147
+ const bn = path20.basename(r);
6818
7148
  return bn === p || bn.toLowerCase() === p.toLowerCase();
6819
7149
  });
6820
7150
  if (hit) return hit;
@@ -6904,7 +7234,7 @@ var init_search = __esm({
6904
7234
  const GUIDE_CANDIDATES = ["CLAUDE.md", "AGENTS.md", "AGENT.md"];
6905
7235
  for (const name of GUIDE_CANDIDATES) {
6906
7236
  try {
6907
- const content = await fs14.readFile(path18.join(getActiveWorkspaceRoot(), name), "utf-8");
7237
+ const content = await fs17.readFile(path20.join(getActiveWorkspaceRoot(), name), "utf-8");
6908
7238
  return `[Project Guide via ${name}]
6909
7239
 
6910
7240
  ${content}`;
@@ -7193,8 +7523,8 @@ ${AUTO_BG_NOTICE}
7193
7523
  });
7194
7524
 
7195
7525
  // ../core/src/tool/registry/glob.ts
7196
- import fs15 from "fs/promises";
7197
- import path19 from "path";
7526
+ import fs18 from "fs/promises";
7527
+ import path21 from "path";
7198
7528
  var findMatchingBrace, splitTopLevel, globToRegex2, globTools;
7199
7529
  var init_glob = __esm({
7200
7530
  "../core/src/tool/registry/glob.ts"() {
@@ -7300,18 +7630,18 @@ var init_glob = __esm({
7300
7630
  const MAX_SCAN_LIMIT = 1e4;
7301
7631
  const scan = async (dir) => {
7302
7632
  if (scannedCount > MAX_SCAN_LIMIT) return;
7303
- const entries = await fs15.readdir(dir, { withFileTypes: true });
7633
+ const entries = await fs18.readdir(dir, { withFileTypes: true });
7304
7634
  const validEntries = entries.filter((e) => {
7305
- const full = path19.join(dir, e.name);
7306
- const rel = path19.relative(activeRoot, full).replace(/\\/g, "/");
7635
+ const full = path21.join(dir, e.name);
7636
+ const rel = path21.relative(activeRoot, full).replace(/\\/g, "/");
7307
7637
  return !checkIsPathIgnored(e.isDirectory() ? `${rel}/` : rel);
7308
7638
  });
7309
7639
  for (const e of validEntries) {
7310
7640
  scannedCount++;
7311
7641
  if (scannedCount > MAX_SCAN_LIMIT) break;
7312
7642
  if (e.isSymbolicLink()) continue;
7313
- const full = path19.join(dir, e.name);
7314
- const rel = path19.relative(activeRoot, full).replace(/\\/g, "/");
7643
+ const full = path21.join(dir, e.name);
7644
+ const rel = path21.relative(activeRoot, full).replace(/\\/g, "/");
7315
7645
  if (e.isDirectory()) {
7316
7646
  if (cleanPattern.endsWith("/") && re.test(`${rel}/`)) {
7317
7647
  hits.push(`${rel}/`);
@@ -7532,8 +7862,8 @@ ${summary}`;
7532
7862
  });
7533
7863
 
7534
7864
  // ../core/src/tool/registry/inspect_dependencies.ts
7535
- import * as fs16 from "fs/promises";
7536
- import * as path20 from "path";
7865
+ import * as fs19 from "fs/promises";
7866
+ import * as path22 from "path";
7537
7867
  var dependencyTools;
7538
7868
  var init_inspect_dependencies = __esm({
7539
7869
  "../core/src/tool/registry/inspect_dependencies.ts"() {
@@ -7554,8 +7884,8 @@ var init_inspect_dependencies = __esm({
7554
7884
  isSync: true,
7555
7885
  async execute() {
7556
7886
  try {
7557
- const pjsPath = path20.join(getActiveWorkspaceRoot(), "package.json");
7558
- const raw = await fs16.readFile(pjsPath, "utf-8");
7887
+ const pjsPath = path22.join(getActiveWorkspaceRoot(), "package.json");
7888
+ const raw = await fs19.readFile(pjsPath, "utf-8");
7559
7889
  const pjs = JSON.parse(raw);
7560
7890
  const result = {
7561
7891
  dependencies: pjs.dependencies || {},
@@ -8291,8 +8621,8 @@ var init_http = __esm({
8291
8621
  });
8292
8622
 
8293
8623
  // ../core/src/tool/registry/typescript.ts
8294
- import fs17 from "fs/promises";
8295
- import path21 from "path";
8624
+ import fs20 from "fs/promises";
8625
+ import path23 from "path";
8296
8626
  var MAX_FILE_BYTES, toDisplayPath, isLibFile, precheck, MAX_DIAG_ENTRIES, MAX_DIAG_FILES, MAX_REF_ENTRIES, REF_SNIPPET_MAX, diagnoseOneFile, typescriptTools;
8297
8627
  var init_typescript = __esm({
8298
8628
  "../core/src/tool/registry/typescript.ts"() {
@@ -8303,8 +8633,8 @@ var init_typescript = __esm({
8303
8633
  init_fs();
8304
8634
  MAX_FILE_BYTES = 1024 * 1024;
8305
8635
  toDisplayPath = (wsRoot, abs) => {
8306
- const rel = path21.relative(wsRoot, abs);
8307
- if (rel && !rel.startsWith("..") && !path21.isAbsolute(rel)) return rel.replace(/\\/g, "/");
8636
+ const rel = path23.relative(wsRoot, abs);
8637
+ if (rel && !rel.startsWith("..") && !path23.isAbsolute(rel)) return rel.replace(/\\/g, "/");
8308
8638
  return abs.replace(/\\/g, "/").split("/").slice(-3).join("/");
8309
8639
  };
8310
8640
  isLibFile = (abs) => /(?:^|\/)node_modules\//.test(abs.replace(/\\/g, "/")) || /\.d\.ts$/i.test(abs);
@@ -8313,7 +8643,7 @@ var init_typescript = __esm({
8313
8643
  if (readBlock) return readBlock;
8314
8644
  const extBlock = checkSupportedSourceExt(displayPath);
8315
8645
  if (extBlock) return extBlock;
8316
- const stat = await fs17.stat(absPath);
8646
+ const stat = await fs20.stat(absPath);
8317
8647
  if (stat.size > MAX_FILE_BYTES) {
8318
8648
  return `\u26A0\uFE0F [\u6587\u4EF6\u8FC7\u5927]\uFF1A[${displayPath}] \u7EA6 ${Math.round(stat.size / 1024)}KB\uFF0C\u8D85\u8FC7 ${MAX_FILE_BYTES / 1024}KB \u4E0A\u9650\uFF08\u9632\u5168\u91CF type-check \u5403\u5185\u5B58\uFF09\u3002`;
8319
8649
  }
@@ -8531,7 +8861,7 @@ ${out.join("\n")}`;
8531
8861
  let lines = lineTextCache.get(abs);
8532
8862
  if (!lines) {
8533
8863
  try {
8534
- lines = (await fs17.readFile(abs, "utf-8")).split(/\r?\n/);
8864
+ lines = (await fs20.readFile(abs, "utf-8")).split(/\r?\n/);
8535
8865
  } catch {
8536
8866
  lines = [];
8537
8867
  }
@@ -8660,8 +8990,8 @@ var init_todo = __esm({
8660
8990
  });
8661
8991
 
8662
8992
  // ../core/src/observability/traceCalculate.ts
8663
- import fs18 from "fs/promises";
8664
- import path22 from "path";
8993
+ import fs21 from "fs/promises";
8994
+ import path24 from "path";
8665
8995
  var getDirBytes, getTodayDateString;
8666
8996
  var init_traceCalculate = __esm({
8667
8997
  "../core/src/observability/traceCalculate.ts"() {
@@ -8673,17 +9003,17 @@ var init_traceCalculate = __esm({
8673
9003
  const cur = stack.pop();
8674
9004
  let entries;
8675
9005
  try {
8676
- entries = await fs18.readdir(cur, { withFileTypes: true });
9006
+ entries = await fs21.readdir(cur, { withFileTypes: true });
8677
9007
  } catch {
8678
9008
  continue;
8679
9009
  }
8680
9010
  for (const e of entries) {
8681
- const p = path22.join(cur, e.name);
9011
+ const p = path24.join(cur, e.name);
8682
9012
  if (e.isDirectory()) {
8683
9013
  stack.push(p);
8684
9014
  } else {
8685
9015
  try {
8686
- total += (await fs18.stat(p)).size;
9016
+ total += (await fs21.stat(p)).size;
8687
9017
  } catch {
8688
9018
  }
8689
9019
  }
@@ -8702,8 +9032,8 @@ var init_traceCalculate = __esm({
8702
9032
  });
8703
9033
 
8704
9034
  // ../core/src/tool/undo/store.ts
8705
- import path23 from "path";
8706
- import fs19 from "fs/promises";
9035
+ import path25 from "path";
9036
+ import fs22 from "fs/promises";
8707
9037
  var getUndoRootPath, getUndoClockPath, getUndoDirPath, getUndoBackupRoot, ensureUndoDir, getUndoIndexPath;
8708
9038
  var init_store2 = __esm({
8709
9039
  "../core/src/tool/undo/store.ts"() {
@@ -8711,33 +9041,33 @@ var init_store2 = __esm({
8711
9041
  init_config();
8712
9042
  init_common();
8713
9043
  init_traceCalculate();
8714
- getUndoRootPath = () => path23.join(appConfig.dataDir, "undo");
8715
- getUndoClockPath = () => path23.join(getUndoRootPath(), "undo-cleanup-clock.json");
9044
+ getUndoRootPath = () => path25.join(appConfig.dataDir, "undo");
9045
+ getUndoClockPath = () => path25.join(getUndoRootPath(), "undo-cleanup-clock.json");
8716
9046
  getUndoDirPath = (mainSessionId) => {
8717
9047
  const rootId = getFileName(mainSessionId);
8718
9048
  assertSafeSessionId(rootId, "undoSessionId");
8719
- return path23.join(getUndoRootPath(), appConfig.userWorkspaceDir, rootId);
9049
+ return path25.join(getUndoRootPath(), appConfig.userWorkspaceDir, rootId);
8720
9050
  };
8721
- getUndoBackupRoot = (mainSessionId) => path23.join(getUndoDirPath(mainSessionId), "backups");
9051
+ getUndoBackupRoot = (mainSessionId) => path25.join(getUndoDirPath(mainSessionId), "backups");
8722
9052
  ensureUndoDir = async (mainSessionId) => {
8723
- await fs19.mkdir(getUndoDirPath(mainSessionId), { recursive: true, mode: 448 });
9053
+ await fs22.mkdir(getUndoDirPath(mainSessionId), { recursive: true, mode: 448 });
8724
9054
  };
8725
9055
  getUndoIndexPath = async (mainSessionId) => {
8726
9056
  const rootId = getFileName(mainSessionId);
8727
9057
  assertSafeSessionId(rootId, "undoSessionId");
8728
9058
  const dir = getUndoDirPath(mainSessionId);
8729
- await fs19.mkdir(dir, { recursive: true, mode: 448 });
8730
- const files = await fs19.readdir(dir);
9059
+ await fs22.mkdir(dir, { recursive: true, mode: 448 });
9060
+ const files = await fs22.readdir(dir);
8731
9061
  const existedFile = files.find((f) => f.endsWith(`__${rootId}.jsonl`));
8732
9062
  const fileName = existedFile ?? `undo-${getTodayDateString()}__${rootId}.jsonl`;
8733
- return path23.join(dir, fileName);
9063
+ return path25.join(dir, fileName);
8734
9064
  };
8735
9065
  }
8736
9066
  });
8737
9067
 
8738
9068
  // ../core/src/tool/undo/index.ts
8739
- import fs20 from "fs/promises";
8740
- import path24 from "path";
9069
+ import fs23 from "fs/promises";
9070
+ import path26 from "path";
8741
9071
  var undoLocks, withUndoLock, appendUndoRecord, readUndoIndex, markRestored;
8742
9072
  var init_undo = __esm({
8743
9073
  "../core/src/tool/undo/index.ts"() {
@@ -8767,7 +9097,7 @@ var init_undo = __esm({
8767
9097
  };
8768
9098
  const p = await getUndoIndexPath(sessionId);
8769
9099
  const line = JSON.stringify(enriched) + "\n";
8770
- await fs20.appendFile(p, line, { encoding: "utf-8", mode: 384 });
9100
+ await fs23.appendFile(p, line, { encoding: "utf-8", mode: 384 });
8771
9101
  });
8772
9102
  };
8773
9103
  readUndoIndex = async (sessionId) => {
@@ -8779,7 +9109,7 @@ var init_undo = __esm({
8779
9109
  }
8780
9110
  let files;
8781
9111
  try {
8782
- files = await fs20.readdir(dir);
9112
+ files = await fs23.readdir(dir);
8783
9113
  } catch {
8784
9114
  return [];
8785
9115
  }
@@ -8787,7 +9117,7 @@ var init_undo = __esm({
8787
9117
  for (const f of files) {
8788
9118
  if (!f.startsWith("undo-") || !f.endsWith(".jsonl")) continue;
8789
9119
  try {
8790
- const raw = await fs20.readFile(path24.join(dir, f), "utf-8");
9120
+ const raw = await fs23.readFile(path26.join(dir, f), "utf-8");
8791
9121
  for (const line of raw.split("\n")) {
8792
9122
  const trimmed = line.trim();
8793
9123
  if (!trimmed) continue;
@@ -8812,16 +9142,16 @@ var init_undo = __esm({
8812
9142
  }
8813
9143
  let files;
8814
9144
  try {
8815
- files = await fs20.readdir(dir);
9145
+ files = await fs23.readdir(dir);
8816
9146
  } catch {
8817
9147
  return;
8818
9148
  }
8819
9149
  for (const f of files) {
8820
9150
  if (!f.startsWith("undo-") || !f.endsWith(".jsonl")) continue;
8821
- const fp = path24.join(dir, f);
9151
+ const fp = path26.join(dir, f);
8822
9152
  let raw;
8823
9153
  try {
8824
- raw = await fs20.readFile(fp, "utf-8");
9154
+ raw = await fs23.readFile(fp, "utf-8");
8825
9155
  } catch {
8826
9156
  continue;
8827
9157
  }
@@ -8845,8 +9175,8 @@ var init_undo = __esm({
8845
9175
  if (changed) {
8846
9176
  const content = lines.join("\n").replace(/\n*$/, "\n");
8847
9177
  const tmp = fp + ".tmp";
8848
- await fs20.writeFile(tmp, content, { encoding: "utf-8", mode: 384 });
8849
- await fs20.rename(tmp, fp);
9178
+ await fs23.writeFile(tmp, content, { encoding: "utf-8", mode: 384 });
9179
+ await fs23.rename(tmp, fp);
8850
9180
  }
8851
9181
  }
8852
9182
  });
@@ -8855,8 +9185,8 @@ var init_undo = __esm({
8855
9185
  });
8856
9186
 
8857
9187
  // ../core/src/tool/undo/cleanup.ts
8858
- import fs21 from "fs/promises";
8859
- import path25 from "path";
9188
+ import fs24 from "fs/promises";
9189
+ import path27 from "path";
8860
9190
  async function maybeCleanupAfterUndoAppend(_sessionId) {
8861
9191
  if (cleanupInProgress) return;
8862
9192
  cleanupInProgress = true;
@@ -8882,8 +9212,8 @@ async function maybeCleanupAfterUndoAppend(_sessionId) {
8882
9212
  lastSizeCleanupAt = now;
8883
9213
  diskLastCleanupAt = now;
8884
9214
  const clockPath = getUndoClockPath();
8885
- await fs21.mkdir(path25.dirname(clockPath), { recursive: true });
8886
- await fs21.writeFile(clockPath, JSON.stringify({ lastCleanupAt: now, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2), "utf-8");
9215
+ await fs24.mkdir(path27.dirname(clockPath), { recursive: true });
9216
+ await fs24.writeFile(clockPath, JSON.stringify({ lastCleanupAt: now, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2), "utf-8");
8887
9217
  if (deleted > 0) console.log(`\u2728 [Undo\u8FD0\u7EF4] \u5171\u9500\u6BC1 ${deleted} \u4E2A undo \u8D44\u4EA7\uFF08\u7D22\u5F15 + \u5B64\u513F\u5185\u5BB9\uFF09\uFF0C\u78C1\u76D8\u6C34\u4F4D\u56DE\u843D\u3002`);
8888
9218
  } catch (e) {
8889
9219
  console.warn("\u26A0\uFE0F [Undo\u8FD0\u7EF4] \u81EA\u52A8\u6E05\u7406\u5F02\u5E38\uFF0C\u5DF2\u8DF3\u8FC7:", e?.message ?? e);
@@ -8900,23 +9230,23 @@ async function cleanupOldUndoFiles() {
8900
9230
  const now = Date.now();
8901
9231
  let relativePaths;
8902
9232
  try {
8903
- relativePaths = await fs21.readdir(dir, { recursive: true });
9233
+ relativePaths = await fs24.readdir(dir, { recursive: true });
8904
9234
  } catch {
8905
9235
  return 0;
8906
9236
  }
8907
9237
  const re = /^undo-(\d{4}-\d{2}-\d{2})__([\w-]+)\.jsonl$/;
8908
9238
  let deleted = 0;
8909
9239
  for (const rp of relativePaths) {
8910
- const fileName = path25.basename(rp);
9240
+ const fileName = path27.basename(rp);
8911
9241
  const m = fileName.match(re);
8912
9242
  if (!m) continue;
8913
9243
  const fileBornDay = /* @__PURE__ */ new Date(`${m[1]}T00:00:00`);
8914
9244
  if (fileBornDay >= cutoff) continue;
8915
- const fullPath = path25.join(dir, rp);
9245
+ const fullPath = path27.join(dir, rp);
8916
9246
  try {
8917
- const st = await fs21.stat(fullPath);
9247
+ const st = await fs24.stat(fullPath);
8918
9248
  if (now - st.mtimeMs < ACTIVE_GRACE_MS) continue;
8919
- await fs21.unlink(fullPath);
9249
+ await fs24.unlink(fullPath);
8920
9250
  deleted += 1;
8921
9251
  } catch {
8922
9252
  }
@@ -8927,17 +9257,17 @@ async function evictOldestForSize(targetBytes) {
8927
9257
  const dir = getUndoRootPath();
8928
9258
  let relativePaths;
8929
9259
  try {
8930
- relativePaths = await fs21.readdir(dir, { recursive: true });
9260
+ relativePaths = await fs24.readdir(dir, { recursive: true });
8931
9261
  } catch {
8932
9262
  return 0;
8933
9263
  }
8934
9264
  const re = /^undo-(\d{4}-\d{2}-\d{2})__([\w-]+)\.jsonl$/;
8935
9265
  const candidates = [];
8936
9266
  for (const rp of relativePaths) {
8937
- if (!re.test(path25.basename(rp))) continue;
9267
+ if (!re.test(path27.basename(rp))) continue;
8938
9268
  try {
8939
- const st = await fs21.stat(path25.join(dir, rp));
8940
- candidates.push({ mtime: st.mtimeMs, fullPath: path25.join(dir, rp), size: st.size });
9269
+ const st = await fs24.stat(path27.join(dir, rp));
9270
+ candidates.push({ mtime: st.mtimeMs, fullPath: path27.join(dir, rp), size: st.size });
8941
9271
  } catch {
8942
9272
  }
8943
9273
  }
@@ -8947,7 +9277,7 @@ async function evictOldestForSize(targetBytes) {
8947
9277
  for (const c of candidates) {
8948
9278
  if (totalBytes <= targetBytes) break;
8949
9279
  try {
8950
- await fs21.unlink(c.fullPath);
9280
+ await fs24.unlink(c.fullPath);
8951
9281
  totalBytes -= c.size;
8952
9282
  deleted += 1;
8953
9283
  } catch {
@@ -8961,38 +9291,38 @@ async function gcOrphanBackups() {
8961
9291
  let deleted = 0;
8962
9292
  let workspaces;
8963
9293
  try {
8964
- workspaces = await fs21.readdir(root);
9294
+ workspaces = await fs24.readdir(root);
8965
9295
  } catch {
8966
9296
  return 0;
8967
9297
  }
8968
9298
  for (const ws of workspaces) {
8969
- const wsDir = path25.join(root, ws);
9299
+ const wsDir = path27.join(root, ws);
8970
9300
  let stWs;
8971
9301
  try {
8972
- stWs = await fs21.stat(wsDir);
9302
+ stWs = await fs24.stat(wsDir);
8973
9303
  } catch {
8974
9304
  continue;
8975
9305
  }
8976
9306
  if (!stWs.isDirectory()) continue;
8977
9307
  let sessions2;
8978
9308
  try {
8979
- sessions2 = await fs21.readdir(wsDir);
9309
+ sessions2 = await fs24.readdir(wsDir);
8980
9310
  } catch {
8981
9311
  continue;
8982
9312
  }
8983
9313
  for (const sess of sessions2) {
8984
- const sessDir = path25.join(wsDir, sess);
9314
+ const sessDir = path27.join(wsDir, sess);
8985
9315
  const liveIds = /* @__PURE__ */ new Set();
8986
9316
  let files;
8987
9317
  try {
8988
- files = await fs21.readdir(sessDir);
9318
+ files = await fs24.readdir(sessDir);
8989
9319
  } catch {
8990
9320
  continue;
8991
9321
  }
8992
9322
  for (const f of files) {
8993
9323
  if (!f.startsWith("undo-") || !f.endsWith(".jsonl")) continue;
8994
9324
  try {
8995
- const raw = await fs21.readFile(path25.join(sessDir, f), "utf-8");
9325
+ const raw = await fs24.readFile(path27.join(sessDir, f), "utf-8");
8996
9326
  for (const line of raw.split("\n")) {
8997
9327
  const t = line.trim();
8998
9328
  if (!t) continue;
@@ -9005,17 +9335,17 @@ async function gcOrphanBackups() {
9005
9335
  } catch {
9006
9336
  }
9007
9337
  }
9008
- const backupsDir = path25.join(sessDir, "backups");
9338
+ const backupsDir = path27.join(sessDir, "backups");
9009
9339
  let undoDirs;
9010
9340
  try {
9011
- undoDirs = await fs21.readdir(backupsDir);
9341
+ undoDirs = await fs24.readdir(backupsDir);
9012
9342
  } catch {
9013
9343
  continue;
9014
9344
  }
9015
9345
  for (const ud of undoDirs) {
9016
9346
  if (liveIds.has(ud)) continue;
9017
9347
  try {
9018
- await fs21.rm(path25.join(backupsDir, ud), { recursive: true, force: true });
9348
+ await fs24.rm(path27.join(backupsDir, ud), { recursive: true, force: true });
9019
9349
  deleted += 1;
9020
9350
  } catch {
9021
9351
  }
@@ -9043,7 +9373,7 @@ var init_cleanup = __esm({
9043
9373
  if (clockLoaded) return;
9044
9374
  clockLoaded = true;
9045
9375
  try {
9046
- const rawClock = await fs21.readFile(getUndoClockPath(), "utf-8");
9376
+ const rawClock = await fs24.readFile(getUndoClockPath(), "utf-8");
9047
9377
  diskLastCleanupAt = JSON.parse(rawClock).lastCleanupAt || 0;
9048
9378
  } catch {
9049
9379
  diskLastCleanupAt = 0;
@@ -9053,17 +9383,17 @@ var init_cleanup = __esm({
9053
9383
  let total = 0;
9054
9384
  let entries;
9055
9385
  try {
9056
- entries = await fs21.readdir(dir, { withFileTypes: true });
9386
+ entries = await fs24.readdir(dir, { withFileTypes: true });
9057
9387
  } catch {
9058
9388
  return 0;
9059
9389
  }
9060
9390
  for (const e of entries) {
9061
- const full = path25.join(dir, e.name);
9391
+ const full = path27.join(dir, e.name);
9062
9392
  if (e.isDirectory()) {
9063
9393
  total += await getDirBytesRecursive(full);
9064
9394
  } else if (e.isFile()) {
9065
9395
  try {
9066
- total += (await fs21.stat(full)).size;
9396
+ total += (await fs24.stat(full)).size;
9067
9397
  } catch {
9068
9398
  }
9069
9399
  }
@@ -9074,8 +9404,8 @@ var init_cleanup = __esm({
9074
9404
  });
9075
9405
 
9076
9406
  // ../core/src/tool/undo/backup.ts
9077
- import fs22 from "fs/promises";
9078
- import path26 from "path";
9407
+ import fs25 from "fs/promises";
9408
+ import path28 from "path";
9079
9409
  import crypto from "crypto";
9080
9410
  async function beforeMutationBackup(strategy, toolName, args, toolCallId, sessionId) {
9081
9411
  if (appConfig.undoEnabled === false) return null;
@@ -9087,7 +9417,7 @@ async function beforeMutationBackup(strategy, toolName, args, toolCallId, sessio
9087
9417
  }
9088
9418
  await ensureUndoDir(sessionId);
9089
9419
  const undoId = createUUID();
9090
- const undoDir = path26.join(getUndoBackupRoot(sessionId), undoId);
9420
+ const undoDir = path28.join(getUndoBackupRoot(sessionId), undoId);
9091
9421
  const now = /* @__PURE__ */ new Date();
9092
9422
  const common = {
9093
9423
  undoId,
@@ -9120,7 +9450,7 @@ async function backupFileOverwrite(common, undoDir, args) {
9120
9450
  const absPath = resolveSafePath(common.relativePath);
9121
9451
  let exists = true;
9122
9452
  try {
9123
- await fs22.access(absPath);
9453
+ await fs25.access(absPath);
9124
9454
  } catch {
9125
9455
  exists = false;
9126
9456
  }
@@ -9128,15 +9458,15 @@ async function backupFileOverwrite(common, undoDir, args) {
9128
9458
  return { ...common, backupKind: "creation_marker", backupPath: "", fileSizeBefore: 0 };
9129
9459
  }
9130
9460
  assertWithinWorkspace(absPath);
9131
- const fileStat = await fs22.stat(absPath);
9461
+ const fileStat = await fs25.stat(absPath);
9132
9462
  const maxPerOp = appConfig.undoMaxBytesPerOp ?? 100 * 1024 * 1024;
9133
9463
  if (fileStat.size > maxPerOp) {
9134
9464
  throw new Error(`\u6587\u4EF6 [${common.relativePath}] \u4F53\u79EF\u7EA6 ${fileStat.size} \u5B57\u8282\u8D85\u8FC7\u5355\u6B21\u5907\u4EFD\u4E0A\u9650 ${maxPerOp}\uFF0C\u5199\u5165\u5DF2\u963B\u65AD\uFF08\u9632\u5185\u5B58\u62D6\u57AE\uFF1B\u53EF\u8C03 undoMaxBytesPerOp\uFF09`);
9135
9465
  }
9136
- const content = await fs22.readFile(absPath);
9137
- await fs22.mkdir(undoDir, { recursive: true, mode: 448 });
9138
- const contentPath = path26.join(undoDir, "content");
9139
- await fs22.writeFile(contentPath, content, { mode: 384 });
9466
+ const content = await fs25.readFile(absPath);
9467
+ await fs25.mkdir(undoDir, { recursive: true, mode: 448 });
9468
+ const contentPath = path28.join(undoDir, "content");
9469
+ await fs25.writeFile(contentPath, content, { mode: 384 });
9140
9470
  return {
9141
9471
  ...common,
9142
9472
  backupKind: "file_content",
@@ -9156,9 +9486,9 @@ async function backupFileCreate(common) {
9156
9486
  }
9157
9487
  async function backupDelete(common, undoDir, relativePath) {
9158
9488
  const absPath = resolveSafePath(relativePath);
9159
- const st = await fs22.stat(absPath);
9489
+ const st = await fs25.stat(absPath);
9160
9490
  assertWithinWorkspace(absPath);
9161
- await fs22.mkdir(undoDir, { recursive: true, mode: 448 });
9491
+ await fs25.mkdir(undoDir, { recursive: true, mode: 448 });
9162
9492
  if (st.isDirectory()) {
9163
9493
  const treeBytes = await getDirTreeBytes(absPath);
9164
9494
  const maxPerOp2 = appConfig.undoMaxBytesPerOp ?? 100 * 1024 * 1024;
@@ -9173,15 +9503,15 @@ async function backupDelete(common, undoDir, relativePath) {
9173
9503
  throw new Error(`\u76EE\u5F55 [${relativePath}] \u5185\u542B\u654F\u611F\u6587\u4EF6 ${sensitiveInTree.length} \u4E2A\uFF08\u5982 ${sensitiveInTree[0]}\uFF09\uFF0C\u6309\u7B56\u7565(undoBackupSensitive=deny)\u62D2\u7EDD\u5907\u4EFD\uFF0C\u5199\u5165\u5DF2\u963B\u65AD`);
9174
9504
  }
9175
9505
  }
9176
- const treeDest = path26.join(undoDir, "tree");
9506
+ const treeDest = path28.join(undoDir, "tree");
9177
9507
  const sensitiveSet = new Set(sensitiveInTree);
9178
- await fs22.cp(absPath, treeDest, {
9508
+ await fs25.cp(absPath, treeDest, {
9179
9509
  recursive: true,
9180
9510
  force: true,
9181
9511
  preserveTimestamps: true,
9182
9512
  filter: (src) => {
9183
9513
  if (src === absPath) return true;
9184
- const relWithin = path26.relative(absPath, src).replace(/\\/g, "/");
9514
+ const relWithin = path28.relative(absPath, src).replace(/\\/g, "/");
9185
9515
  return !sensitiveSet.has(relWithin);
9186
9516
  }
9187
9517
  });
@@ -9197,9 +9527,9 @@ async function backupDelete(common, undoDir, relativePath) {
9197
9527
  if (st.size > maxPerOp) {
9198
9528
  throw new Error(`\u6587\u4EF6 [${relativePath}] \u4F53\u79EF\u7EA6 ${st.size} \u5B57\u8282\u8D85\u8FC7\u5355\u6B21\u5907\u4EFD\u4E0A\u9650 ${maxPerOp}\uFF0C\u5199\u5165\u5DF2\u963B\u65AD\uFF08\u9632\u5185\u5B58\u62D6\u57AE\uFF1B\u53EF\u8C03 undoMaxBytesPerOp\uFF09`);
9199
9529
  }
9200
- const content = await fs22.readFile(absPath);
9201
- const contentPath = path26.join(undoDir, "content");
9202
- await fs22.writeFile(contentPath, content, { mode: 384 });
9530
+ const content = await fs25.readFile(absPath);
9531
+ const contentPath = path28.join(undoDir, "content");
9532
+ await fs25.writeFile(contentPath, content, { mode: 384 });
9203
9533
  return {
9204
9534
  ...common,
9205
9535
  backupKind: "file_content",
@@ -9242,21 +9572,21 @@ var init_backup = __esm({
9242
9572
  const walk = async (d) => {
9243
9573
  let entries;
9244
9574
  try {
9245
- entries = await fs22.readdir(d, { withFileTypes: true });
9575
+ entries = await fs25.readdir(d, { withFileTypes: true });
9246
9576
  } catch {
9247
9577
  return;
9248
9578
  }
9249
9579
  entries.sort((a, b) => a.name.localeCompare(b.name));
9250
9580
  for (const e of entries) {
9251
- const full = path26.join(d, e.name);
9252
- const rel = path26.relative(dir, full).replace(/\\/g, "/");
9581
+ const full = path28.join(d, e.name);
9582
+ const rel = path28.relative(dir, full).replace(/\\/g, "/");
9253
9583
  if (e.isDirectory()) {
9254
9584
  h.update(`D ${rel}
9255
9585
  `);
9256
9586
  await walk(full);
9257
9587
  } else if (e.isFile()) {
9258
9588
  try {
9259
- h.update(`F ${rel} ${sha1Buf(await fs22.readFile(full))}
9589
+ h.update(`F ${rel} ${sha1Buf(await fs25.readFile(full))}
9260
9590
  `);
9261
9591
  } catch {
9262
9592
  }
@@ -9270,16 +9600,16 @@ var init_backup = __esm({
9270
9600
  let total = 0;
9271
9601
  let entries;
9272
9602
  try {
9273
- entries = await fs22.readdir(dir, { withFileTypes: true });
9603
+ entries = await fs25.readdir(dir, { withFileTypes: true });
9274
9604
  } catch {
9275
9605
  return 0;
9276
9606
  }
9277
9607
  for (const e of entries) {
9278
- const full = path26.join(dir, e.name);
9608
+ const full = path28.join(dir, e.name);
9279
9609
  if (e.isDirectory()) total += await getDirTreeBytes(full);
9280
9610
  else if (e.isFile()) {
9281
9611
  try {
9282
- total += (await fs22.stat(full)).size;
9612
+ total += (await fs25.stat(full)).size;
9283
9613
  } catch {
9284
9614
  }
9285
9615
  }
@@ -9291,16 +9621,16 @@ var init_backup = __esm({
9291
9621
  const walk = async (d) => {
9292
9622
  let entries;
9293
9623
  try {
9294
- entries = await fs22.readdir(d, { withFileTypes: true });
9624
+ entries = await fs25.readdir(d, { withFileTypes: true });
9295
9625
  } catch {
9296
9626
  return;
9297
9627
  }
9298
9628
  for (const e of entries) {
9299
- const full = path26.join(d, e.name);
9629
+ const full = path28.join(d, e.name);
9300
9630
  if (e.isDirectory()) {
9301
9631
  await walk(full);
9302
9632
  } else if (e.isFile()) {
9303
- const relWithin = path26.relative(dir, full).replace(/\\/g, "/");
9633
+ const relWithin = path28.relative(dir, full).replace(/\\/g, "/");
9304
9634
  if (isSensitivePath(`${wsRelDir}/${relWithin}`)) found.push(relWithin);
9305
9635
  }
9306
9636
  }
@@ -9312,21 +9642,21 @@ var init_backup = __esm({
9312
9642
  });
9313
9643
 
9314
9644
  // ../core/src/tool/undo/restore.ts
9315
- import fs23 from "fs/promises";
9316
- import path27 from "path";
9645
+ import fs26 from "fs/promises";
9646
+ import path29 from "path";
9317
9647
  import crypto2 from "crypto";
9318
- async function doRestore(target, sessionId) {
9319
- if (target.backupKind === "directory_tree") {
9648
+ async function doRestore(target, sessionId, opts) {
9649
+ if (!opts?.force && target.backupKind === "directory_tree") {
9320
9650
  const abs = resolveSafePath(target.relativePath);
9321
9651
  let exists = false;
9322
9652
  try {
9323
- await fs23.access(abs);
9653
+ await fs26.access(abs);
9324
9654
  exists = true;
9325
9655
  } catch {
9326
9656
  }
9327
9657
  if (exists) return `\u274C [undo \u62D2\u7EDD]\uFF1A\u76EE\u6807\u8DEF\u5F84 [${target.relativePath}] \u5DF2\u5B58\u5728\uFF0C\u62D2\u7EDD\u8986\u76D6\u3002\u8BF7\u5148\u624B\u52A8\u5904\u7406\uFF08\u5220\u9664\u6216\u6539\u540D\uFF09\u540E\u91CD\u8BD5\u3002`;
9328
9658
  }
9329
- const newerWarning = await checkNewerChange(target, sessionId);
9659
+ const newerWarning = opts?.force ? "" : await checkNewerChange(target, sessionId);
9330
9660
  const reverse = await ensureReverseBackup(target, sessionId);
9331
9661
  let msg;
9332
9662
  try {
@@ -9358,7 +9688,7 @@ async function ensureReverseBackup(target, sessionId) {
9358
9688
  }
9359
9689
  let exists = true;
9360
9690
  try {
9361
- await fs23.access(absPath);
9691
+ await fs26.access(absPath);
9362
9692
  } catch {
9363
9693
  exists = false;
9364
9694
  }
@@ -9371,17 +9701,17 @@ async function ensureReverseBackup(target, sessionId) {
9371
9701
  }
9372
9702
  }
9373
9703
  const reverseId = createUUID();
9374
- const reverseDir = path27.join(getUndoBackupRoot(sessionId), reverseId);
9375
- await fs23.mkdir(reverseDir, { recursive: true, mode: 448 });
9704
+ const reverseDir = path29.join(getUndoBackupRoot(sessionId), reverseId);
9705
+ await fs26.mkdir(reverseDir, { recursive: true, mode: 448 });
9376
9706
  assertWithinWorkspace(absPath);
9377
- const st = await fs23.stat(absPath);
9707
+ const st = await fs26.stat(absPath);
9378
9708
  if (st.isDirectory()) {
9379
- const dest2 = path27.join(reverseDir, "tree");
9380
- await fs23.cp(absPath, dest2, { recursive: true, force: true, preserveTimestamps: true });
9709
+ const dest2 = path29.join(reverseDir, "tree");
9710
+ await fs26.cp(absPath, dest2, { recursive: true, force: true, preserveTimestamps: true });
9381
9711
  return { reverseId, backupKind: "directory_tree", backupPath: dest2 };
9382
9712
  }
9383
- const dest = path27.join(reverseDir, "content");
9384
- await fs23.writeFile(dest, await fs23.readFile(absPath));
9713
+ const dest = path29.join(reverseDir, "content");
9714
+ await fs26.writeFile(dest, await fs26.readFile(absPath));
9385
9715
  return { reverseId, backupKind: "file_content", backupPath: dest };
9386
9716
  }
9387
9717
  async function dispatchRestore(r) {
@@ -9389,20 +9719,20 @@ async function dispatchRestore(r) {
9389
9719
  assertWithinWorkspace(absPath);
9390
9720
  switch (r.backupKind) {
9391
9721
  case "creation_marker": {
9392
- await fs23.rm(absPath, { force: true });
9722
+ await fs26.rm(absPath, { force: true });
9393
9723
  return `\u5DF2\u5220\u9664\u65B0\u5EFA\u6587\u4EF6 [${r.relativePath}]`;
9394
9724
  }
9395
9725
  case "file_content": {
9396
- await fs23.mkdir(path27.dirname(absPath), { recursive: true });
9397
- const backupAbs = path27.join(getUndoBackupRoot(r.sessionId), r.undoId, "content");
9398
- const content = await fs23.readFile(backupAbs);
9399
- await fs23.writeFile(absPath, content);
9726
+ await fs26.mkdir(path29.dirname(absPath), { recursive: true });
9727
+ const backupAbs = path29.join(getUndoBackupRoot(r.sessionId), r.undoId, "content");
9728
+ const content = await fs26.readFile(backupAbs);
9729
+ await fs26.writeFile(absPath, content);
9400
9730
  return `\u5DF2\u6062\u590D [${r.relativePath}] \u81F3\u5907\u4EFD\u524D\u5185\u5BB9\uFF08${r.fileSizeBefore ?? content.byteLength} \u5B57\u8282\uFF09`;
9401
9731
  }
9402
9732
  case "directory_tree": {
9403
- await fs23.mkdir(path27.dirname(absPath), { recursive: true });
9404
- const src = path27.join(getUndoBackupRoot(r.sessionId), r.undoId, "tree");
9405
- await fs23.cp(src, absPath, { recursive: true, force: true, preserveTimestamps: true });
9733
+ await fs26.mkdir(path29.dirname(absPath), { recursive: true });
9734
+ const src = path29.join(getUndoBackupRoot(r.sessionId), r.undoId, "tree");
9735
+ await fs26.cp(src, absPath, { recursive: true, force: true, preserveTimestamps: true });
9406
9736
  return `\u5DF2\u6062\u590D\u76EE\u5F55\u6811 [${r.relativePath}]\uFF08\u7EA6 ${r.fileSizeBefore ?? 0} \u5B57\u8282\uFF09`;
9407
9737
  }
9408
9738
  }
@@ -9435,7 +9765,7 @@ var init_restore = __esm({
9435
9765
  init_common();
9436
9766
  init_traceCalculate();
9437
9767
  sha1File = async (absPath) => {
9438
- const buf = await fs23.readFile(absPath);
9768
+ const buf = await fs26.readFile(absPath);
9439
9769
  return crypto2.createHash("sha1").update(buf).digest("hex");
9440
9770
  };
9441
9771
  listUndoable = async (sessionId) => {
@@ -9717,7 +10047,7 @@ ${diff.slice(0, 1500)}` : "";
9717
10047
  });
9718
10048
 
9719
10049
  // ../core/src/tool/registry/notebook.ts
9720
- import fs24 from "fs/promises";
10050
+ import fs27 from "fs/promises";
9721
10051
  var toArraySource, encodeSource, makeCell, applyNotebookEdit, notebookTools;
9722
10052
  var init_notebook = __esm({
9723
10053
  "../core/src/tool/registry/notebook.ts"() {
@@ -9821,7 +10151,7 @@ ${String(args.new_source).slice(0, 500)}` : ""}`,
9821
10151
  }
9822
10152
  let raw;
9823
10153
  try {
9824
- raw = await fs24.readFile(absPath, "utf-8");
10154
+ raw = await fs27.readFile(absPath, "utf-8");
9825
10155
  } catch (e) {
9826
10156
  return toolFailure(`[notebook_edit] \u8BFB\u53D6\u5931\u8D25\uFF1A${e?.message ?? e}`);
9827
10157
  }
@@ -9851,10 +10181,10 @@ ${String(args.new_source).slice(0, 500)}` : ""}`,
9851
10181
  }
9852
10182
  const tmpPath = makeTmpPath(absPath);
9853
10183
  try {
9854
- await fs24.writeFile(tmpPath, JSON.stringify(nb, null, 2), "utf-8");
9855
- await fs24.rename(tmpPath, absPath);
10184
+ await fs27.writeFile(tmpPath, JSON.stringify(nb, null, 2), "utf-8");
10185
+ await fs27.rename(tmpPath, absPath);
9856
10186
  } catch (e) {
9857
- await fs24.unlink(tmpPath).catch(() => {
10187
+ await fs27.unlink(tmpPath).catch(() => {
9858
10188
  });
9859
10189
  return toolFailure(`[notebook_edit] \u5199\u5165\u5931\u8D25\uFF1A${e?.message ?? e}`);
9860
10190
  }
@@ -9894,8 +10224,8 @@ var init_frontmatter = __esm({
9894
10224
  });
9895
10225
 
9896
10226
  // ../core/src/memory/loader.ts
9897
- import fs25 from "fs/promises";
9898
- import path28 from "path";
10227
+ import fs28 from "fs/promises";
10228
+ import path30 from "path";
9899
10229
  var GLOBAL_MEMORY_DIR, SOURCES, VALID_TYPES, parseMemoryAt, loadMemories, initMemories;
9900
10230
  var init_loader3 = __esm({
9901
10231
  "../core/src/memory/loader.ts"() {
@@ -9904,16 +10234,16 @@ var init_loader3 = __esm({
9904
10234
  init_frontmatter();
9905
10235
  init_registry6();
9906
10236
  init_registry2();
9907
- GLOBAL_MEMORY_DIR = path28.join(appConfig.dataDir, "memory");
10237
+ GLOBAL_MEMORY_DIR = path30.join(appConfig.dataDir, "memory");
9908
10238
  SOURCES = [
9909
10239
  { dir: GLOBAL_MEMORY_DIR, source: "global" },
9910
- { dir: path28.join(process.cwd(), ".deepseeker-code", "memory"), source: "project" }
10240
+ { dir: path30.join(process.cwd(), ".deepseeker-code", "memory"), source: "project" }
9911
10241
  ];
9912
10242
  VALID_TYPES = ["user", "feedback", "project", "reference"];
9913
10243
  parseMemoryAt = async (file, _dir, source) => {
9914
10244
  let raw;
9915
10245
  try {
9916
- raw = await fs25.readFile(file, "utf-8");
10246
+ raw = await fs28.readFile(file, "utf-8");
9917
10247
  } catch {
9918
10248
  return null;
9919
10249
  }
@@ -9947,7 +10277,7 @@ var init_loader3 = __esm({
9947
10277
  clearMemories();
9948
10278
  const picked = await scanSources(
9949
10279
  filterSources(SOURCES, includeProject),
9950
- (e, dir) => e.isFile() && e.name.endsWith(".md") ? path28.join(dir, e.name) : void 0,
10280
+ (e, dir) => e.isFile() && e.name.endsWith(".md") ? path30.join(dir, e.name) : void 0,
9951
10281
  parseMemoryAt
9952
10282
  );
9953
10283
  for (const { item } of picked) registerMemory(item);
@@ -9965,15 +10295,15 @@ var init_loader3 = __esm({
9965
10295
  });
9966
10296
 
9967
10297
  // ../core/src/memory/usage.ts
9968
- import fs26 from "fs/promises";
9969
- import path29 from "path";
10298
+ import fs29 from "fs/promises";
10299
+ import path31 from "path";
9970
10300
  var USAGE_FILE, readUsage, recordMemoryUse;
9971
10301
  var init_usage = __esm({
9972
10302
  "../core/src/memory/usage.ts"() {
9973
10303
  "use strict";
9974
10304
  init_loader3();
9975
10305
  init_common();
9976
- USAGE_FILE = path29.join(GLOBAL_MEMORY_DIR, ".usage.json");
10306
+ USAGE_FILE = path31.join(GLOBAL_MEMORY_DIR, ".usage.json");
9977
10307
  readUsage = async () => {
9978
10308
  const raw = await readJSONFile(USAGE_FILE);
9979
10309
  return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
@@ -9986,8 +10316,8 @@ var init_usage = __esm({
9986
10316
  lastUsed: (/* @__PURE__ */ new Date()).toISOString(),
9987
10317
  reads: (prev?.reads ?? 0) + (kind === "read" ? 1 : 0)
9988
10318
  };
9989
- await fs26.mkdir(GLOBAL_MEMORY_DIR, { recursive: true });
9990
- await fs26.writeFile(USAGE_FILE, JSON.stringify(map, null, 2), "utf-8");
10319
+ await fs29.mkdir(GLOBAL_MEMORY_DIR, { recursive: true });
10320
+ await fs29.writeFile(USAGE_FILE, JSON.stringify(map, null, 2), "utf-8");
9991
10321
  } catch (e) {
9992
10322
  console.warn(`\u26A0\uFE0F [memory] \u4F7F\u7528\u753B\u50CF\u8BB0\u5F55\u5931\u8D25\uFF08\u5DF2\u5FFD\u7565\uFF09: ${e?.message ?? e}`);
9993
10323
  }
@@ -9996,8 +10326,8 @@ var init_usage = __esm({
9996
10326
  });
9997
10327
 
9998
10328
  // ../core/src/tool/registry/memory.ts
9999
- import fs27 from "fs/promises";
10000
- import path30 from "path";
10329
+ import fs30 from "fs/promises";
10330
+ import path32 from "path";
10001
10331
  var MAX_BODY_BYTES, MAX_DESCRIPTION_CHARS, MEMORY_LIMITS, NAME_RE, VALID_TYPES2, memoryFilePath, sanitizeLine, buildMemoryMd, writeAndRegister, indexLineBytes, memoryTools;
10002
10332
  var init_memory = __esm({
10003
10333
  "../core/src/tool/registry/memory.ts"() {
@@ -10012,7 +10342,7 @@ var init_memory = __esm({
10012
10342
  MEMORY_LIMITS = { maxCount: 200, maxIndexBytes: 16 * 1024 };
10013
10343
  NAME_RE = /^[a-z0-9-]+$/;
10014
10344
  VALID_TYPES2 = ["user", "feedback", "project", "reference"];
10015
- memoryFilePath = (name, project) => project ? path30.join(process.cwd(), ".deepseeker-code", "memory", `${name}.md`) : path30.join(GLOBAL_MEMORY_DIR, `${name}.md`);
10345
+ memoryFilePath = (name, project) => project ? path32.join(process.cwd(), ".deepseeker-code", "memory", `${name}.md`) : path32.join(GLOBAL_MEMORY_DIR, `${name}.md`);
10016
10346
  sanitizeLine = (s) => String(s ?? "").replace(/[\r\n]+/g, " ").trim();
10017
10347
  buildMemoryMd = (name, description, type, body) => `---
10018
10348
  name: ${name}
@@ -10024,10 +10354,10 @@ ${body.trim()}
10024
10354
  `;
10025
10355
  writeAndRegister = async (name, description, type, body, project) => {
10026
10356
  const file = memoryFilePath(name, project);
10027
- await fs27.mkdir(path30.dirname(file), { recursive: true });
10357
+ await fs30.mkdir(path32.dirname(file), { recursive: true });
10028
10358
  const tmp = makeTmpPath(file);
10029
- await fs27.writeFile(tmp, buildMemoryMd(name, description, type, body), "utf-8");
10030
- await fs27.rename(tmp, file);
10359
+ await fs30.writeFile(tmp, buildMemoryMd(name, description, type, body), "utf-8");
10360
+ await fs30.rename(tmp, file);
10031
10361
  registerMemory({ name, description, type, body: body.trim(), source: project ? "project" : "global", file });
10032
10362
  return file;
10033
10363
  };
@@ -10162,7 +10492,7 @@ ${lines.join("\n")}`;
10162
10492
  const m = getMemory(name);
10163
10493
  if (!m) return toolFailure(`\u672A\u627E\u5230\u8BB0\u5FC6\uFF1A${name}\uFF08\u53EF\u80FD\u5DF2\u88AB\u5220\u9664\uFF09\u3002`);
10164
10494
  try {
10165
- await fs27.unlink(m.file);
10495
+ await fs30.unlink(m.file);
10166
10496
  } catch {
10167
10497
  }
10168
10498
  unregisterMemory(name);
@@ -10174,9 +10504,9 @@ ${lines.join("\n")}`;
10174
10504
  }
10175
10505
  });
10176
10506
 
10177
- // ../core/src/session/sidecar.ts
10178
- import fs28 from "fs/promises";
10179
- import path31 from "path";
10507
+ // ../core/src/session/sidecar.ts
10508
+ import fs31 from "fs/promises";
10509
+ import path33 from "path";
10180
10510
  var SIDECAR_ARCHIVED_MARK, sidecarArchivedNote, safeSidecarId, getToolOutputSidecarPath, getToolOutputSidecarDir, ensuredSidecarDirs, SIDECAR_SESSION_CAP_BYTES, listSidecarFiles, writeSidecarArchive;
10181
10511
  var init_sidecar = __esm({
10182
10512
  "../core/src/session/sidecar.ts"() {
@@ -10185,21 +10515,21 @@ var init_sidecar = __esm({
10185
10515
  SIDECAR_ARCHIVED_MARK = "\u5B8C\u6574\u539F\u6587\u5DF2\u5B58\u6863";
10186
10516
  sidecarArchivedNote = (toolCallId) => `${SIDECAR_ARCHIVED_MARK}\uFF0Crecall \u5DE5\u5177\u4F20 with_full="${toolCallId}" \u53EF\u53D6\u56DE`;
10187
10517
  safeSidecarId = (id) => String(id).replace(/[^A-Za-z0-9_-]/g, "");
10188
- getToolOutputSidecarPath = (sessionId, toolCallId) => path31.join(getSessionsDirPath(sessionId), "tool-outputs", `${safeSidecarId(toolCallId)}.txt`);
10189
- getToolOutputSidecarDir = (sessionId) => path31.join(getSessionsDirPath(sessionId), "tool-outputs");
10518
+ getToolOutputSidecarPath = (sessionId, toolCallId) => path33.join(getSessionsDirPath(sessionId), "tool-outputs", `${safeSidecarId(toolCallId)}.txt`);
10519
+ getToolOutputSidecarDir = (sessionId) => path33.join(getSessionsDirPath(sessionId), "tool-outputs");
10190
10520
  ensuredSidecarDirs = /* @__PURE__ */ new Set();
10191
10521
  SIDECAR_SESSION_CAP_BYTES = 64 * 1024 * 1024;
10192
10522
  listSidecarFiles = async (dir) => {
10193
10523
  let names;
10194
10524
  try {
10195
- names = await fs28.readdir(dir);
10525
+ names = await fs31.readdir(dir);
10196
10526
  } catch {
10197
10527
  return [];
10198
10528
  }
10199
10529
  const out = [];
10200
10530
  for (const name of names) {
10201
10531
  try {
10202
- const st = await fs28.stat(path31.join(dir, name));
10532
+ const st = await fs31.stat(path33.join(dir, name));
10203
10533
  if (st.isFile()) out.push({ name, size: st.size, mtimeMs: st.mtimeMs });
10204
10534
  } catch {
10205
10535
  }
@@ -10210,7 +10540,7 @@ var init_sidecar = __esm({
10210
10540
  try {
10211
10541
  const dir = getToolOutputSidecarDir(sessionId);
10212
10542
  if (!ensuredSidecarDirs.has(dir)) {
10213
- await fs28.mkdir(dir, { recursive: true });
10543
+ await fs31.mkdir(dir, { recursive: true });
10214
10544
  ensuredSidecarDirs.add(dir);
10215
10545
  }
10216
10546
  const cap = opts?.capBytes ?? SIDECAR_SESSION_CAP_BYTES;
@@ -10223,13 +10553,13 @@ var init_sidecar = __esm({
10223
10553
  for (const f of byOldest) {
10224
10554
  if (total - freed + incoming <= cap) break;
10225
10555
  try {
10226
- await fs28.unlink(path31.join(dir, f.name));
10556
+ await fs31.unlink(path33.join(dir, f.name));
10227
10557
  freed += f.size;
10228
10558
  } catch {
10229
10559
  }
10230
10560
  }
10231
10561
  }
10232
- await fs28.writeFile(getToolOutputSidecarPath(sessionId, toolCallId), content, "utf-8");
10562
+ await fs31.writeFile(getToolOutputSidecarPath(sessionId, toolCallId), content, "utf-8");
10233
10563
  return sidecarArchivedNote(toolCallId);
10234
10564
  } catch (e) {
10235
10565
  console.warn("\u26A0\uFE0F [sidecar] \u5DE5\u5177\u539F\u6587\u5B58\u6863\u5931\u8D25\uFF08\u5DF2\u964D\u7EA7\u4E3A\u666E\u901A\u622A\u65AD\u63D0\u793A\uFF09:", e instanceof Error ? e.message : e);
@@ -10240,9 +10570,9 @@ var init_sidecar = __esm({
10240
10570
  });
10241
10571
 
10242
10572
  // ../core/src/tool/registry/recall.ts
10243
- import fs29 from "fs/promises";
10244
- import path32 from "path";
10245
- var escapeRegExp2, lineText, primaryPathArg, annotateStaleness, snippetAround, recallTools;
10573
+ import fs32 from "fs/promises";
10574
+ import path34 from "path";
10575
+ var escapeRegExp2, lineText, primaryPathArg, annotateStaleness, snippetAround, recallHitCounts, getRecallHitCount, recallTools;
10246
10576
  var init_recall = __esm({
10247
10577
  "../core/src/tool/registry/recall.ts"() {
10248
10578
  "use strict";
@@ -10272,9 +10602,9 @@ var init_recall = __esm({
10272
10602
  annotateStaleness = async (args, observedAt) => {
10273
10603
  const p = primaryPathArg(args);
10274
10604
  if (!p) return "\u5FEB\u7167\uFF08\u65E0\u8DEF\u5F84\u5B9E\u4F53\uFF0C\u672A\u7ECF\u91CD\u9A8C\u2014\u2014\u636E\u4EE5\u884C\u52A8\u524D\u8BF7\u91CD\u8DD1\u9A8C\u8BC1\uFF09";
10275
- const abs = path32.isAbsolute(p) ? p : path32.resolve(getActiveWorkspaceRoot(), p);
10605
+ const abs = path34.isAbsolute(p) ? p : path34.resolve(getActiveWorkspaceRoot(), p);
10276
10606
  try {
10277
- const st = await fs29.stat(abs);
10607
+ const st = await fs32.stat(abs);
10278
10608
  if (observedAt && st.mtime.toISOString() > observedAt) {
10279
10609
  return `\u26A0\uFE0F \u89C2\u5BDF\u540E\u8BE5\u6587\u4EF6\u5DF2\u88AB\u4FEE\u6539\uFF08${p}\uFF09\u2014\u2014\u5FC5\u987B\u91CD\u65B0 read_file \u540E\u624D\u80FD\u636E\u4EE5\u4FEE\u6539`;
10280
10610
  }
@@ -10291,6 +10621,8 @@ var init_recall = __esm({
10291
10621
  const tailMark = start + maxChars < text.length ? "\u2026\uFF08\u7247\u6BB5\u622A\u65AD\uFF0C\u5B8C\u6574\u5185\u5BB9\u53EF\u7528 with_full\uFF09" : "";
10292
10622
  return `${headMark}${slice}${tailMark}`;
10293
10623
  };
10624
+ recallHitCounts = /* @__PURE__ */ new Map();
10625
+ getRecallHitCount = (sessionId) => recallHitCounts.get(sessionId) ?? 0;
10294
10626
  recallTools = [
10295
10627
  {
10296
10628
  type: "function",
@@ -10322,7 +10654,7 @@ var init_recall = __esm({
10322
10654
  const sidecar = getToolOutputSidecarPath(ctx.sessionId, args.with_full);
10323
10655
  let full = "";
10324
10656
  try {
10325
- full = await fs29.readFile(sidecar, "utf-8");
10657
+ full = await fs32.readFile(sidecar, "utf-8");
10326
10658
  } catch {
10327
10659
  return toolFailure(`[recall] \u672A\u627E\u5230\u8BE5 id \u7684\u5B58\u6863\u539F\u6587\uFF08\u53EF\u80FD\u672A\u66FE\u89E6\u53D1\u622A\u65AD\u5B58\u6863\u3001\u6216\u4F1A\u8BDD\u5DF2\u6E05\u7406\uFF09\uFF1A${args.with_full}`);
10328
10660
  }
@@ -10376,12 +10708,12 @@ ${slice}${more}`;
10376
10708
  }
10377
10709
  const text = lineText(l);
10378
10710
  if (!text || !re.test(text)) continue;
10379
- const ts = l.ts;
10711
+ const ts2 = l.ts;
10380
10712
  const roleDesc = role === "tool" ? `${info?.name ?? "tool"} \u8C03\u7528\u7ED3\u679C` : role === "assistant" ? "assistant\uFF08\u6587\u672C/\u5DE5\u5177\u8C03\u7528\u53C2\u6570\uFF09" : "\u7528\u6237\u6D88\u606F";
10381
- let header = `\u2500\u2500 \u547D\u4E2D${blocks.length + 1} \xB7 run#${runN}${runId ? `(${runId.slice(0, 8)})` : ""} \xB7 ${roleDesc} \xB7 ${ts ?? "\u65F6\u95F4\u672A\u77E5"} \u2500\u2500`;
10713
+ let header = `\u2500\u2500 \u547D\u4E2D${blocks.length + 1} \xB7 run#${runN}${runId ? `(${runId.slice(0, 8)})` : ""} \xB7 ${roleDesc} \xB7 ${ts2 ?? "\u65F6\u95F4\u672A\u77E5"} \u2500\u2500`;
10382
10714
  if (role === "tool") {
10383
10715
  header += `
10384
- \u6821\u9A8C\uFF1A${await annotateStaleness(info?.args, ts)}`;
10716
+ \u6821\u9A8C\uFF1A${await annotateStaleness(info?.args, ts2)}`;
10385
10717
  if (typeof l.content === "string" && l.content.includes(SIDECAR_ARCHIVED_MARK)) {
10386
10718
  header += `
10387
10719
  \u2702\uFE0F \u8BE5\u7ED3\u679C\u66FE\u88AB\u622A\u65AD\uFF0C\u4F20 with_full="${l.tool_call_id}" \u53EF\u53D6\u5B58\u6863\u5168\u6587`;
@@ -10399,6 +10731,7 @@ ${snippetAround(text, re, 700)}`);
10399
10731
  "\xB7 \u8BB0\u5F97\u5F52\u6863\u533A\u5728\u6458\u8981\u69FD\u4E4B\u524D\u7684\u66F4\u65E9\u8F6E\u6B21\u2014\u2014\u7528\u66F4\u65E9\u9636\u6BB5\u51FA\u73B0\u8FC7\u7684\u8BCD"
10400
10732
  ].join("\n");
10401
10733
  }
10734
+ recallHitCounts.set(ctx.sessionId, (recallHitCounts.get(ctx.sessionId) ?? 0) + 1);
10402
10735
  return [
10403
10736
  `[recall] \u672C\u4F1A\u8BDD\u5168\u91CF\u8F6C\u5F55\u547D\u4E2D ${blocks.length} \u6761\uFF08\u6309\u65F6\u95F4\u65E7\u2192\u65B0\uFF0C\u542B\u5DF2\u5F52\u6863\u6D88\u606F\uFF09\uFF1A`,
10404
10737
  "",
@@ -10532,7 +10865,7 @@ var init_spreadsheet = __esm({
10532
10865
  });
10533
10866
 
10534
10867
  // ../core/src/tool/registry/document.ts
10535
- import fs30 from "fs/promises";
10868
+ import fs33 from "fs/promises";
10536
10869
  var getMammoth, getUnpdf, documentTools;
10537
10870
  var init_document = __esm({
10538
10871
  "../core/src/tool/registry/document.ts"() {
@@ -10622,7 +10955,7 @@ var init_document = __esm({
10622
10955
  }
10623
10956
  const start = args.start_char ? Math.max(0, Math.floor(args.start_char)) : 0;
10624
10957
  const maxChars = Math.min(args.max_chars ? Math.max(1, Math.floor(args.max_chars)) : 3e4, 5e4);
10625
- const buf = await fs30.readFile(absPath);
10958
+ const buf = await fs33.readFile(absPath);
10626
10959
  const unpdf = await getUnpdf();
10627
10960
  const pdf = await unpdf.getDocumentProxy(new Uint8Array(buf));
10628
10961
  const { text, totalPages } = await unpdf.extractText(pdf, { mergePages: true });
@@ -10950,7 +11283,7 @@ var init_backgroundTool = __esm({
10950
11283
  });
10951
11284
 
10952
11285
  // ../core/src/tool/autoPermission.ts
10953
- import path33 from "path";
11286
+ import path35 from "path";
10954
11287
  var isMcpTool, BUILTIN_AUTO_DENY, matchBuiltinDeny, COMMAND_DENY, matchCommandDeny, hasShellMetachars, READONLY_HEADS, PKG_MGR, SCRIPT_RUNNER_HEADS, SCRIPT_RUNNER_READONLY, isScriptRunnerCommand, hasWriteModifier, SENSITIVE_FILE_ARG_RE, hasSensitiveFileArg, isReadOnlyCommand, isWithinWorkspace, runAutoCheck;
10955
11288
  var init_autoPermission = __esm({
10956
11289
  "../core/src/tool/autoPermission.ts"() {
@@ -11095,9 +11428,9 @@ var init_autoPermission = __esm({
11095
11428
  isWithinWorkspace = (p, cwd) => {
11096
11429
  if (!p || !cwd) return false;
11097
11430
  try {
11098
- const abs = path33.isAbsolute(p) ? p : path33.resolve(cwd, p);
11099
- const rel = path33.relative(cwd, abs);
11100
- return rel === "" || !rel.startsWith("..") && !path33.isAbsolute(rel);
11431
+ const abs = path35.isAbsolute(p) ? p : path35.resolve(cwd, p);
11432
+ const rel = path35.relative(cwd, abs);
11433
+ return rel === "" || !rel.startsWith("..") && !path35.isAbsolute(rel);
11101
11434
  } catch {
11102
11435
  return false;
11103
11436
  }
@@ -11126,7 +11459,7 @@ var init_autoPermission = __esm({
11126
11459
  });
11127
11460
 
11128
11461
  // ../core/src/agent/toolExecution.ts
11129
- import path34 from "path";
11462
+ import path36 from "path";
11130
11463
  var applyPrivacyMasking, scaleTruncBudget, processToolCall;
11131
11464
  var init_toolExecution = __esm({
11132
11465
  "../core/src/agent/toolExecution.ts"() {
@@ -11187,7 +11520,8 @@ var init_toolExecution = __esm({
11187
11520
  compactRatio,
11188
11521
  modelWindow,
11189
11522
  parentSystemPrompt,
11190
- readTracker
11523
+ readTracker,
11524
+ reportCost
11191
11525
  } = ctx;
11192
11526
  let calledName = "";
11193
11527
  let calledArgs = {};
@@ -11225,7 +11559,7 @@ var init_toolExecution = __esm({
11225
11559
  events({ sessionId, eventType: "tool.validation.failed", metadata: { depth, decisionSource: llmDecisionSource, durationMs: performance.now() - startTime, round, tools_id: toolCall.id, toolName: calledName, toolSource: "builtin", ok: false, attempt: round }, payload: { output: note } });
11226
11560
  return { toolCallId: toolCall.id, calledName, calledArgs, resultForModel: note, resultForUser: note, ok: false };
11227
11561
  }
11228
- const toolCtx = { sessionId, cwd: getActiveWorkspaceRoot(), abortSignal: signal, depth, keepRecentUnits, compactRatio, modelWindow, parentSystemPrompt, events, onUIEvent, requestApproval: hostRequestApproval, requestQuestion: hostRequestQuestion, ideAction, emitProgress: (m) => onUIEvent?.({ type: "tool.progress", toolsId: toolCall.id, toolName: calledName, message: m }), permissionMode, readTracker };
11562
+ const toolCtx = { sessionId, cwd: getActiveWorkspaceRoot(), abortSignal: signal, depth, keepRecentUnits, compactRatio, modelWindow, parentSystemPrompt, events, onUIEvent, requestApproval: hostRequestApproval, requestQuestion: hostRequestQuestion, ideAction, emitProgress: (m) => onUIEvent?.({ type: "tool.progress", toolsId: toolCall.id, toolName: calledName, message: m }), permissionMode, readTracker, reportCost };
11229
11563
  let result = "";
11230
11564
  let resultStatus = "success";
11231
11565
  let errorCategory;
@@ -11296,7 +11630,7 @@ var init_toolExecution = __esm({
11296
11630
  const argCwd = typeof calledArgs?.cwd === "string" ? calledArgs.cwd.trim() : "";
11297
11631
  const samePath = (a, b) => {
11298
11632
  try {
11299
- const ra = path34.resolve(a), rb = path34.resolve(b);
11633
+ const ra = path36.resolve(a), rb = path36.resolve(b);
11300
11634
  return process.platform === "win32" ? ra.toLowerCase() === rb.toLowerCase() : ra === rb;
11301
11635
  } catch {
11302
11636
  return false;
@@ -11870,7 +12204,7 @@ var init_streamInference = __esm({
11870
12204
  });
11871
12205
 
11872
12206
  // ../core/src/agent/agentNudges.ts
11873
- var NUDGE_EVERY, NUDGE_FENCE, PHANTOM_FENCE, PHANTOM_RETRY_MAX, EARLY_FINAL_FENCE, EARLY_FINAL_TURN_THRESHOLD, EARLY_FINAL_MAX, TOOL_DIGEST_FENCE, TOOL_DIGEST_MAX, TOOL_DIGEST_WINDOW, TOOL_DIGEST_TEXT_MAX_LEN, PLAN_FIRST_FENCE, REPEAT_FENCE, READ_REPEAT_THRESHOLD, GREP_REPEAT_THRESHOLD, REPEAT_NUDGE_MAX, TODO_INCOMPLETE_FENCE, TODO_INCOMPLETE_MAX, PHANTOM_TEXT, EARLY_FINAL_TEXT, TOOL_DIGEST_TEXT, usageNoteText, NUDGE_TEXT, COMPLEX_VERBS, COMPLEX_OBJECTS, COMPLEX_MARKERS, QUERY_LEAD, looksComplex, PLAN_FIRST_TEXT, looksComplete, parseToolCall, normPath, normQuery, REPEAT_READ_TEXT, REPEAT_GREP_TEXT, TODO_INCOMPLETE_TEXT, createNudgeScheduler;
12207
+ var NUDGE_EVERY, NUDGE_FENCE, PHANTOM_FENCE, PHANTOM_RETRY_MAX, EARLY_FINAL_FENCE, EARLY_FINAL_TURN_THRESHOLD, EARLY_FINAL_MAX, TOOL_DIGEST_FENCE, TOOL_DIGEST_MAX, TOOL_DIGEST_WINDOW, TOOL_DIGEST_TEXT_MAX_LEN, PLAN_FIRST_FENCE, REPEAT_FENCE, READ_REPEAT_THRESHOLD, GREP_REPEAT_THRESHOLD, REPEAT_NUDGE_MAX, TODO_INCOMPLETE_FENCE, TODO_INCOMPLETE_MAX, BUDGET_FENCE, BUDGET_SOFT_TEXT, PHANTOM_TEXT, EARLY_FINAL_TEXT, TOOL_DIGEST_TEXT, usageNoteText, NUDGE_TEXT, COMPLEX_VERBS, COMPLEX_OBJECTS, COMPLEX_MARKERS, QUERY_LEAD, looksComplex, PLAN_FIRST_TEXT, looksComplete, parseToolCall, normPath, normQuery, REPEAT_READ_TEXT, REPEAT_GREP_TEXT, TODO_INCOMPLETE_TEXT, createNudgeScheduler;
11874
12208
  var init_agentNudges = __esm({
11875
12209
  "../core/src/agent/agentNudges.ts"() {
11876
12210
  "use strict";
@@ -11892,6 +12226,11 @@ var init_agentNudges = __esm({
11892
12226
  REPEAT_NUDGE_MAX = 3;
11893
12227
  TODO_INCOMPLETE_FENCE = "\u27E6DSC:TODO_INCOMPLETE\u27E7";
11894
12228
  TODO_INCOMPLETE_MAX = 1;
12229
+ BUDGET_FENCE = "\u27E6DSC:BUDGET\u27E7";
12230
+ BUDGET_SOFT_TEXT = (spent, budget) => {
12231
+ const pct = budget > 0 ? Math.round(spent / budget * 100) : 100;
12232
+ return `\u5DF2\u82B1\u8D39 \xA5${spent.toFixed(3)} / \u9884\u7B97 \xA5${budget.toFixed(3)}\uFF08${pct}%\uFF09\uFF1A\u8BF7\u6536\u655B\u6536\u5C3E\uFF0C\u4E0D\u518D\u5C55\u5F00\u65B0\u63A2\u7D22\uFF1B\u82E5\u786E\u9700\u7EE7\u7EED\uFF0C\u7528\u4E00\u6BB5\u8BF4\u660E\u5269\u4F59\u5DE5\u4F5C\u540E\u5373\u6B62\u3002`;
12233
+ };
11895
12234
  PHANTOM_TEXT = "\u4F60\u7684\u4E0A\u4E00\u6761\u56DE\u590D\u6CA1\u6709\u4EFB\u4F55\u5185\u5BB9\u3001\u4E5F\u6CA1\u6709\u8C03\u7528\u4EFB\u4F55\u5DE5\u5177\uFF0C\u4F46\u4EFB\u52A1\u5C1A\u672A\u5B8C\u6210\u3002\u8BF7\u7EE7\u7EED\u63A8\u8FDB\uFF08\u8C03\u7528\u5DE5\u5177\u6216\u7ED9\u51FA\u5B9E\u8D28\u56DE\u7B54\uFF09\uFF1B\u82E5\u786E\u5B9E\u53D7\u963B\u3001\u9700\u8981\u7528\u6237\u51B3\u7B56\uFF0C\u7528 ask_question \u8BF4\u660E\u5177\u4F53\u963B\u585E\u70B9\u3002\u4E0D\u8981\u8FD4\u56DE\u7A7A\u56DE\u590D\u3002";
11896
12235
  EARLY_FINAL_TEXT = (round) => `\u4F60\u4EC5 ${round} \u8F6E\u5C31\u51C6\u5907\u6536\u5C3E\uFF0C\u4E14\u56DE\u7B54\u4E2D\u6CA1\u6709\u660E\u786E\u7684\u5B8C\u6210\u58F0\u660E\u3002\u8BF7\u81EA\u68C0\uFF1A\u82E5\u7528\u6237\u8F93\u5165\u672C\u5C31\u65E0\u9700\u5DE5\u5177\uFF08\u5BD2\u6684/\u95F2\u804A/\u7EAF\u95EE\u7B54\uFF09\u3001\u6216\u4F60\u5728\u7B49\u7528\u6237\u6F84\u6E05\u51B3\u7B56\uFF0C\u76F4\u63A5\u6B63\u5E38\u56DE\u5E94\u5373\u53EF\uFF0C\u5FFD\u7565\u672C\u81EA\u68C0\u3001\u4E0D\u8981\u8F93\u51FA\u4EFB\u4F55\u81EA\u68C0\u8BF4\u660E\uFF1B\u82E5\u786E\u6709\u4EFB\u52A1\u672A\u843D\u5730\uFF08\u6240\u9700\u4FE1\u606F\u672A\u83B7\u53D6\u9F50 / \u8BE5\u6539\u7684\u6587\u4EF6\u672A\u6539\u5B8C / \u672A\u9A8C\u8BC1\uFF09\uFF0C\u7ACB\u5373\u7EE7\u7EED\u8C03\u7528\u5DE5\u5177\u63A8\u8FDB\uFF0C\u4E0D\u8981\u8349\u7387\u603B\u7ED3\u6536\u5C3E\uFF1B\u82E5\u786E\u5DF2\u5168\u90E8\u5B8C\u6210\uFF0C\u8BF7\u660E\u786E\u56DE\u590D\u300C\u5DF2\u5B8C\u6210\u300D\u5E76\u7B80\u8FF0\u6210\u679C\u3002`;
11897
12236
  TOOL_DIGEST_TEXT = "\u4F60\u521A\u6267\u884C\u5B8C\u5DE5\u5177\u62FF\u5230\u7ED3\u679C\uFF0C\u5374\u672A\u57FA\u4E8E\u8BE5\u7ED3\u679C\u7ED9\u51FA\u5B9E\u8D28\u56DE\u5E94\u5C31\u51C6\u5907\u6536\u5C3E\u3002\u8BF7\u7ED3\u5408\u5DE5\u5177\u8FD4\u56DE\u7ED3\u679C\u7EE7\u7EED\u63A8\u8FDB\uFF1B\u82E5\u7ED3\u679C\u8868\u660E\u4EFB\u52A1\u5C1A\u672A\u5B8C\u6210\uFF08\u5982\u4ECD\u5728\u7F16\u8BD1/\u8FD0\u884C\u3001\u9700\u7EE7\u7EED\u8F6E\u8BE2\uFF09\uFF0C\u7ACB\u5373\u91C7\u53D6\u4E0B\u4E00\u6B65\u884C\u52A8\uFF0C\u4E0D\u8981\u7A7A\u624B\u6536\u5C3E\u3002\u82E5\u786E\u5DF2\u5168\u90E8\u5B8C\u6210\uFF0C\u8BF7\u660E\u786E\u56DE\u590D\u300C\u5DF2\u5B8C\u6210\u300D\u5E76\u7B80\u8FF0\u6210\u679C\u3002";
@@ -11956,6 +12295,7 @@ var init_agentNudges = __esm({
11956
12295
  let lastTodos = [];
11957
12296
  let todoNudges = 0;
11958
12297
  let todoPending = null;
12298
+ let budgetSoftSent = false;
11959
12299
  return {
11960
12300
  pickNudge(round) {
11961
12301
  if (!planFirstSent && round === 1 && !planMode && looksComplex(firstPrompt)) {
@@ -11983,6 +12323,14 @@ ${PLAN_FIRST_TEXT}` };
11983
12323
  todoPending = null;
11984
12324
  return m;
11985
12325
  }
12326
+ if (!budgetSoftSent) {
12327
+ const st = opts.getBudgetStatus?.() ?? null;
12328
+ if (st && st.budget > 0 && st.spent >= st.budget) {
12329
+ budgetSoftSent = true;
12330
+ return { role: "system", content: `${BUDGET_FENCE}
12331
+ ${BUDGET_SOFT_TEXT(st.spent, st.budget)}` };
12332
+ }
12333
+ }
11986
12334
  if (repeatRetrievalPending) {
11987
12335
  const m = repeatRetrievalPending;
11988
12336
  repeatRetrievalPending = null;
@@ -12082,17 +12430,17 @@ ${REPEAT_GREP_TEXT(q, n)}` };
12082
12430
  });
12083
12431
 
12084
12432
  // ../core/src/observability/usageLog.ts
12085
- import fs31 from "fs/promises";
12086
- import path35 from "path";
12433
+ import fs34 from "fs/promises";
12434
+ import path37 from "path";
12087
12435
  var USAGE_DISABLED, usageDir, ensuredDir, getUsageLogPath, recordUsageRun, USAGE_FILE_RE, SYNTHETIC_SESSION_RE, readUsageRecords, summarizeUsage, topTools;
12088
12436
  var init_usageLog = __esm({
12089
12437
  "../core/src/observability/usageLog.ts"() {
12090
12438
  "use strict";
12091
12439
  init_config();
12092
12440
  USAGE_DISABLED = process.env.DEEPSEEKER_CODE_USAGE_LOG === "0";
12093
- usageDir = () => path35.join(appConfig.dataDir, "usage");
12441
+ usageDir = () => path37.join(appConfig.dataDir, "usage");
12094
12442
  ensuredDir = null;
12095
- getUsageLogPath = (month) => path35.join(usageDir(), `usage-${month}.jsonl`);
12443
+ getUsageLogPath = (month) => path37.join(usageDir(), `usage-${month}.jsonl`);
12096
12444
  recordUsageRun = async (rec) => {
12097
12445
  if (USAGE_DISABLED) return;
12098
12446
  try {
@@ -12100,20 +12448,20 @@ var init_usageLog = __esm({
12100
12448
  const month = (full.ts || (/* @__PURE__ */ new Date()).toISOString()).slice(0, 7);
12101
12449
  const dir = usageDir();
12102
12450
  if (ensuredDir !== dir) {
12103
- await fs31.mkdir(dir, { recursive: true });
12451
+ await fs34.mkdir(dir, { recursive: true });
12104
12452
  ensuredDir = dir;
12105
12453
  }
12106
- await fs31.appendFile(getUsageLogPath(month), JSON.stringify(full) + "\n", "utf-8");
12454
+ await fs34.appendFile(getUsageLogPath(month), JSON.stringify(full) + "\n", "utf-8");
12107
12455
  } catch (e) {
12108
12456
  console.warn("\u26A0\uFE0F [usageLog] \u4F7F\u7528\u65E5\u5FD7\u843D\u76D8\u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u4E3B\u4E1A\u52A1\uFF09:", e instanceof Error ? e.message : e);
12109
12457
  }
12110
12458
  };
12111
12459
  USAGE_FILE_RE = /^usage-\d{4}-\d{2}\.jsonl$/;
12112
- SYNTHETIC_SESSION_RE = /^(selftest-|eval-)/;
12460
+ SYNTHETIC_SESSION_RE = /^(selftest-|eval-|e2e-)/;
12113
12461
  readUsageRecords = async (days) => {
12114
12462
  let files;
12115
12463
  try {
12116
- files = (await fs31.readdir(usageDir())).filter((f) => USAGE_FILE_RE.test(f)).sort();
12464
+ files = (await fs34.readdir(usageDir())).filter((f) => USAGE_FILE_RE.test(f)).sort();
12117
12465
  } catch {
12118
12466
  return [];
12119
12467
  }
@@ -12127,7 +12475,7 @@ var init_usageLog = __esm({
12127
12475
  for (const f of files) {
12128
12476
  let text;
12129
12477
  try {
12130
- text = await fs31.readFile(path35.join(usageDir(), f), "utf-8");
12478
+ text = await fs34.readFile(path37.join(usageDir(), f), "utf-8");
12131
12479
  } catch {
12132
12480
  continue;
12133
12481
  }
@@ -12188,6 +12536,48 @@ var init_usageLog = __esm({
12188
12536
  }
12189
12537
  });
12190
12538
 
12539
+ // ../core/src/config/prices.ts
12540
+ var MODEL_PRICES, envPrice, ENV_OVERRIDE, priceFor, calcCostYuan;
12541
+ var init_prices = __esm({
12542
+ "../core/src/config/prices.ts"() {
12543
+ "use strict";
12544
+ MODEL_PRICES = {
12545
+ "deepseek-flash": { input: 1, output: 2, cacheHit: 0.02 },
12546
+ "deepseek-v4-pro": { input: 3, output: 6, cacheHit: 0.025 }
12547
+ };
12548
+ envPrice = (name) => {
12549
+ const raw = process.env[name];
12550
+ if (!raw) return void 0;
12551
+ const n = Number(raw);
12552
+ return Number.isFinite(n) && n >= 0 ? n : void 0;
12553
+ };
12554
+ ENV_OVERRIDE = (() => {
12555
+ const input = envPrice("DEEP_SEEK_PRICE_INPUT");
12556
+ const output = envPrice("DEEP_SEEK_PRICE_OUTPUT");
12557
+ const cacheHit = envPrice("DEEP_SEEK_PRICE_CACHEHIT");
12558
+ if (input === void 0 && output === void 0 && cacheHit === void 0) return null;
12559
+ return { input, output, cacheHit };
12560
+ })();
12561
+ priceFor = (model) => {
12562
+ const base = MODEL_PRICES[model];
12563
+ if (!ENV_OVERRIDE) return base ?? null;
12564
+ const input = ENV_OVERRIDE.input ?? base?.input;
12565
+ const output = ENV_OVERRIDE.output ?? base?.output;
12566
+ const cacheHit = ENV_OVERRIDE.cacheHit ?? base?.cacheHit;
12567
+ if (input === void 0 || output === void 0 || cacheHit === void 0) return null;
12568
+ return { input, output, cacheHit };
12569
+ };
12570
+ calcCostYuan = (model, u) => {
12571
+ const p = priceFor(model);
12572
+ if (!p) return null;
12573
+ const cached2 = Math.max(0, u.cachedTokens ?? 0);
12574
+ const miss = Math.max(0, (u.promptTokens ?? 0) - cached2);
12575
+ const completion = Math.max(0, u.completionTokens ?? 0);
12576
+ return (miss * p.input + cached2 * p.cacheHit + completion * p.output) / 1e6;
12577
+ };
12578
+ }
12579
+ });
12580
+
12191
12581
  // ../core/src/agent/runAgent.ts
12192
12582
  async function* runAgent(message, options) {
12193
12583
  const sessionId = options.sessionId;
@@ -12211,21 +12601,36 @@ async function* runAgent(message, options) {
12211
12601
  let round = 0;
12212
12602
  let lastContent = "";
12213
12603
  let stopReason = "normal";
12604
+ let budgetTruncated = false;
12214
12605
  const MAX_AGENT_ROUNDS = 500;
12215
12606
  const firstPrompt = (() => {
12216
12607
  if (depth !== 0) return "";
12217
12608
  const m = message.find((x) => x?.role === "user");
12218
12609
  return msgText(m?.content);
12219
12610
  })();
12611
+ let budgetSpentYuan = 0;
12612
+ let runCompactCount = 0;
12220
12613
  const nudges = createNudgeScheduler({
12221
12614
  firstPrompt,
12222
12615
  planMode: !!options.planMode,
12223
12616
  noEarlyFinal: !!options.noEarlyFinal,
12224
- getContextUsage: () => ({ usedTokens: Math.round(estimateTokens(message) * calibRatio + toolsTokens), windowTokens: modelWindow })
12617
+ getContextUsage: () => ({ usedTokens: Math.round(estimateTokens(message) * calibRatio + toolsTokens), windowTokens: modelWindow }),
12618
+ getBudgetStatus: depth === 0 && options.budgetYuan != null && options.budgetYuan > 0 ? () => ({ spent: budgetSpentYuan, budget: options.budgetYuan }) : void 0
12225
12619
  });
12226
12620
  const readTracker = /* @__PURE__ */ new Map();
12227
12621
  const userDecisionSource = depth > 0 ? "spawn_agent" : "user";
12228
12622
  const llmDecisionSource = depth > 0 ? "llm_spawn_agent" : "llm";
12623
+ const emitContextUsage = () => {
12624
+ if (depth !== 0 || !options.onUIEvent) return;
12625
+ const usedTokens = Math.round(estimateTokens(message) * calibRatio + toolsTokens);
12626
+ options.onUIEvent({
12627
+ type: "context.usage",
12628
+ usedTokens,
12629
+ windowTokens: modelWindow,
12630
+ fillRate: modelWindow > 0 ? usedTokens / modelWindow : 0,
12631
+ compactCount: runCompactCount
12632
+ });
12633
+ };
12229
12634
  const startTime = performance.now();
12230
12635
  const persistedCalib = await getRollingState(sessionId);
12231
12636
  let calibRatio = persistedCalib.calibRatio ?? 1.4;
@@ -12233,6 +12638,9 @@ async function* runAgent(message, options) {
12233
12638
  let lastCachedTokens = persistedCalib.lastCachedTokens;
12234
12639
  const breaker = createRepeatBreaker({ sessionId, depth, llmDecisionSource, startTime, events });
12235
12640
  let usageSum;
12641
+ const effectiveModel = options.model?.trim() || MODEL_NAME;
12642
+ let costYuanAcc = 0;
12643
+ let costKnown = true;
12236
12644
  const addUsage = (u) => {
12237
12645
  if (!u) return;
12238
12646
  usageSum = {
@@ -12241,6 +12649,12 @@ async function* runAgent(message, options) {
12241
12649
  total_tokens: (usageSum?.total_tokens ?? 0) + (u.total_tokens ?? 0),
12242
12650
  cached_tokens: (usageSum?.cached_tokens ?? 0) + (u.cached_tokens ?? 0)
12243
12651
  };
12652
+ const cost = calcCostYuan(effectiveModel, { promptTokens: u.prompt_tokens, completionTokens: u.completion_tokens, cachedTokens: u.cached_tokens });
12653
+ if (cost == null) costKnown = false;
12654
+ else {
12655
+ costYuanAcc += cost;
12656
+ budgetSpentYuan += cost;
12657
+ }
12244
12658
  };
12245
12659
  const toolCounts = {};
12246
12660
  await appendEvent(sessionId, { dscEvent: "run.start", runId, depth });
@@ -12271,6 +12685,13 @@ async function* runAgent(message, options) {
12271
12685
  yield { type: "final", text: lastContent || "\uFF08\u5DF2\u4E2D\u6B62\uFF09" };
12272
12686
  return;
12273
12687
  }
12688
+ if (depth === 0 && options.budgetYuan != null && options.budgetYuan > 0 && budgetSpentYuan >= options.budgetYuan * 1.2) {
12689
+ stopReason = "limit";
12690
+ budgetTruncated = true;
12691
+ yield { type: "final", text: (lastContent || "") + `
12692
+ \uFF08\u{1F4B0} \u9884\u7B97\u622A\u65AD\uFF1A\u672C run \u5DF2\u82B1\u8D39 \xA5${budgetSpentYuan.toFixed(3)} / \u9884\u7B97 \xA5${options.budgetYuan.toFixed(3)}\u3002/budget \u8C03\u6574\u9884\u7B97\u540E\u56DE\u590D"\u7EE7\u7EED"\u5373\u53EF\u63A5\u7EED\u3002\uFF09` };
12693
+ return;
12694
+ }
12274
12695
  const inboxTexts = claimSessionInbox(sessionId);
12275
12696
  if (inboxTexts.length > 0) {
12276
12697
  for (const t of inboxTexts) {
@@ -12295,7 +12716,11 @@ async function* runAgent(message, options) {
12295
12716
  lastRealPromptTokens,
12296
12717
  lastCachedTokens,
12297
12718
  toolsTokens,
12298
- onUIEvent: options.onUIEvent
12719
+ // ★ H1:旁路数 compact.done 供 context.usage.compactCount(透传不拦截)
12720
+ onUIEvent: (evt) => {
12721
+ if (evt.type === "compact.done") runCompactCount++;
12722
+ options.onUIEvent?.(evt);
12723
+ }
12299
12724
  }
12300
12725
  );
12301
12726
  } catch (e) {
@@ -12358,6 +12783,7 @@ async function* runAgent(message, options) {
12358
12783
  }
12359
12784
  if (!assistantMessage.tool_calls || assistantMessage.tool_calls.length === 0) {
12360
12785
  await appendEvent(sessionId, { dscEvent: "round.end", runId, round, usage: infResult.usage });
12786
+ emitContextUsage();
12361
12787
  const finalText = (typeof assistantMessage.content === "string" ? assistantMessage.content : "") || "";
12362
12788
  const intercepted = nudges.interceptFinal(finalText, round);
12363
12789
  if (intercepted) continue;
@@ -12405,8 +12831,13 @@ async function* runAgent(message, options) {
12405
12831
  // processToolCall 据此收缩截断预算:最坏组合「上下文已 75% 满时跑大输出命令 → 16K 字符
12406
12832
  // 进上下文 → 下一轮立刻压缩」被釜底抽薪;口径与 ensureFitsWindow/nudge 闭包同公式。
12407
12833
  contextTokensEst: Math.round(estimateTokens(message) * calibRatio + toolsTokens),
12408
- readTracker
12834
+ readTracker,
12409
12835
  // ★ P3-8:run 级读取追踪(同一引用透传,跨轮累计)
12836
+ // ★ 子 run 成本回灌(成本信任链第二环 E1):runSubagent 经 toolCtx.reportCost 拿到闭包,
12837
+ // 子 run 结束时把总花费记进本 run 预算累计器——父预算自动继承约束(子花费计入父 spent)。
12838
+ reportCost: (yuan) => {
12839
+ if (Number.isFinite(yuan) && yuan > 0) budgetSpentYuan += yuan;
12840
+ }
12410
12841
  };
12411
12842
  const scheduleResult = yield* scheduleToolCalls(assistantMessage, message, toolCallCtx);
12412
12843
  if (scheduleResult.kind === "aborted") {
@@ -12418,6 +12849,7 @@ async function* runAgent(message, options) {
12418
12849
  return;
12419
12850
  }
12420
12851
  await appendEvent(sessionId, { dscEvent: "round.end", runId, round, usage: infResult.usage });
12852
+ emitContextUsage();
12421
12853
  }
12422
12854
  } catch (toolErr) {
12423
12855
  if (signal?.aborted) {
@@ -12454,10 +12886,33 @@ async function* runAgent(message, options) {
12454
12886
  completionTokens: usageSum?.completion_tokens,
12455
12887
  totalTokens: usageSum?.total_tokens,
12456
12888
  cachedTokens: usageSum?.cached_tokens,
12889
+ costYuan: costKnown ? Math.round(costYuanAcc * 1e6) / 1e6 : void 0,
12457
12890
  tools: toolCounts
12458
12891
  });
12459
12892
  } catch {
12460
12893
  }
12894
+ try {
12895
+ if (options.costSink && costKnown && costYuanAcc > 0) options.costSink(Math.round(costYuanAcc * 1e6) / 1e6);
12896
+ } catch {
12897
+ }
12898
+ try {
12899
+ if (depth === 0 && options.onUIEvent && usageSum) {
12900
+ const prompt = usageSum.prompt_tokens ?? 0;
12901
+ options.onUIEvent({
12902
+ type: "run.receipt",
12903
+ rounds: round,
12904
+ promptTokens: prompt,
12905
+ completionTokens: usageSum.completion_tokens ?? 0,
12906
+ cachedTokens: usageSum.cached_tokens ?? 0,
12907
+ cacheHitRate: prompt > 0 ? (usageSum.cached_tokens ?? 0) / prompt : 0,
12908
+ costYuan: costKnown ? Math.round(costYuanAcc * 1e6) / 1e6 : null,
12909
+ durationMs: Math.round(performance.now() - startTime),
12910
+ budgetTruncated: budgetTruncated || void 0
12911
+ // 预算截断标注(E2;undefined 自动省略)
12912
+ });
12913
+ }
12914
+ } catch {
12915
+ }
12461
12916
  try {
12462
12917
  const reason = signal?.aborted ? "aborted" : stopReason;
12463
12918
  await dispatch("Stop", { sessionId, cwd, lastText: lastContent || "", reason });
@@ -12488,12 +12943,13 @@ var init_runAgent = __esm({
12488
12943
  init_streamInference();
12489
12944
  init_agentNudges();
12490
12945
  init_usageLog();
12946
+ init_prices();
12491
12947
  init_createModel();
12492
12948
  }
12493
12949
  });
12494
12950
 
12495
12951
  // ../core/src/session/lineage.ts
12496
- import fs32 from "node:fs";
12952
+ import fs35 from "node:fs";
12497
12953
  var parentOfSubsession, stringAncestorsOf, readForkedFromSync, lineageClosureOf, ownerCanApprove;
12498
12954
  var init_lineage = __esm({
12499
12955
  "../core/src/session/lineage.ts"() {
@@ -12516,7 +12972,7 @@ var init_lineage = __esm({
12516
12972
  };
12517
12973
  readForkedFromSync = (sessionId) => {
12518
12974
  try {
12519
- const raw = fs32.readFileSync(getStatePath(sessionId), "utf-8");
12975
+ const raw = fs35.readFileSync(getStatePath(sessionId), "utf-8");
12520
12976
  const v = JSON.parse(raw)?.forkedFrom;
12521
12977
  return typeof v === "string" && v.length > 0 ? v : void 0;
12522
12978
  } catch {
@@ -12637,30 +13093,30 @@ var init_subagent = __esm({
12637
13093
  sessionId: ""
12638
13094
  };
12639
13095
  }
12640
- const subSystem = (manifest ? [
13096
+ const subSystem = manifest ? [
12641
13097
  `# \u5B50 Agent \u8EAB\u4EFD\uFF1A${manifest.name}`,
12642
13098
  manifest.body,
12643
13099
  `
12644
13100
  # \u4EFB\u52A1\u4E0A\u4E0B\u6587`,
12645
13101
  `\u5F53\u524D\u6240\u5904\u7684\u4EFB\u52A1\u6267\u884C\u5D4C\u5957\u6DF1\u5EA6: Depth ${ctx.depth + 1} / ${MAX_AGENT_DEPTH}`,
12646
- `\u4F60\u7684\u7236\u7EA7\u4EFB\u52A1\u5927\u7EB2\u53C2\u8003: ${task.slice(0, 150)}...`,
12647
- role ? `
12648
- # \u672C\u6B21\u89D2\u8272\u8865\u5145: ${role}` : "",
12649
13102
  `
12650
13103
  # \u3010\u7EE7\u627F\u7684\u5168\u5C40\u4EE3\u7801\u89C4\u8303\u3011`,
12651
13104
  parentSystemPrompt
12652
13105
  ].filter(Boolean).join("\n") : [
12653
13106
  `# \u4EFB\u52A1\u4E0A\u4E0B\u6587`,
12654
- role ? `\u3010\u4F60\u7684\u4E13\u5C5E\u89D2\u8272\u3011: ${role}` : "\u3010\u4F60\u7684\u4E13\u5C5E\u89D2\u8272\u3011: \u4E13\u6CE8\u6267\u884C\u7279\u5B9A\u5C40\u90E8\u5B50\u4EFB\u52A1\u7684\u72EC\u7ACB\u667A\u80FD\u4F53\u52A9\u624B",
12655
13107
  `\u5F53\u524D\u6240\u5904\u7684\u4EFB\u52A1\u6267\u884C\u5D4C\u5957\u6DF1\u5EA6: Depth ${ctx.depth + 1} / ${MAX_AGENT_DEPTH}`,
12656
- `\u4F60\u7684\u7236\u7EA7\u4EFB\u52A1\u5927\u7EB2\u53C2\u8003: ${task.slice(0, 150)}...`,
12657
13108
  `
12658
13109
  # \u3010\u6838\u5FC3\u91CD\u6784\u94C1\u5F8B\u3011`,
12659
13110
  `\u4F60\u76F4\u63A5\u5171\u4EAB\u5E76\u64CD\u4F5C\u672C\u5730\u6587\u4EF6\u7CFB\u7EDF\u3002\u5F53\u4F60\u5BF9\u6587\u4EF6\u5168\u91CF\u5199\u5165\u6216\u5C40\u90E8\u4FEE\u6539\u65F6\uFF0C\u5FC5\u987B\u786E\u4FDD\u64CD\u4F5C\u7684\u7EDD\u5BF9\u7CBE\u51C6\u3002\u5B8C\u6210\u6307\u5B9A\u5B50\u4EFB\u52A1\u540E\uFF0C\u8BF7\u4F7F\u7528\u6700\u7EC8\u7684\u6587\u672C\u603B\u7ED3\u5411\u7236\u7EA7 Agent \u4EA4\u4ED8\u7ED3\u679C\u3002`,
12660
13111
  `
12661
13112
  # \u3010\u7EE7\u627F\u7684\u5168\u5C40\u4EE3\u7801\u89C4\u8303\u3011`,
12662
13113
  parentSystemPrompt
12663
- ].join("\n")) + (resuming ? RESUME_NOTE : "");
13114
+ ].join("\n");
13115
+ const subTaskPrompt = [
13116
+ role ? manifest ? `# \u672C\u6B21\u89D2\u8272\u8865\u5145: ${role}` : `\u3010\u4F60\u7684\u4E13\u5C5E\u89D2\u8272\u3011: ${role}` : manifest ? "" : `\u3010\u4F60\u7684\u4E13\u5C5E\u89D2\u8272\u3011: \u4E13\u6CE8\u6267\u884C\u7279\u5B9A\u5C40\u90E8\u5B50\u4EFB\u52A1\u7684\u72EC\u7ACB\u667A\u80FD\u4F53\u52A9\u624B`,
13117
+ task,
13118
+ ...resuming ? [RESUME_NOTE] : []
13119
+ ].filter(Boolean).join("\n\n");
12664
13120
  const allTools = getGlobalTools();
12665
13121
  const wantsMcp = manifest?.tools.some((t) => t === "mcp_call" || t === "mcp_list_tools" || t.startsWith("mcp__")) ?? false;
12666
13122
  const toolSchemas = manifest && manifest.tools.length > 0 ? allTools.filter((t) => manifest.tools.includes(t.function.name) || wantsMcp && (t.function.name === "mcp_call" || t.function.name === "mcp_list_tools")) : allTools.filter((t) => !SUBAGENT_DENYLIST.has(t.function.name));
@@ -12668,8 +13124,8 @@ var init_subagent = __esm({
12668
13124
  activeSubagents.add(subSessionId);
12669
13125
  ctx.onUIEvent?.({ type: "subagent.count", running: activeSubagents.size, phase: "start", name: manifest?.name, depth: ctx.depth + 1 });
12670
13126
  try {
12671
- const subMessages = await buildContextMessages(subSessionId, { role: "user", content: task }, subSystem, manifest?.model);
12672
- await appendMessage({ sessionId: subSessionId, role: "user", content: task });
13127
+ const subMessages = await buildContextMessages(subSessionId, { role: "user", content: subTaskPrompt }, subSystem, manifest?.model);
13128
+ await appendMessage({ sessionId: subSessionId, role: "user", content: subTaskPrompt });
12673
13129
  let subResult = "";
12674
13130
  let hasFinalResult = false;
12675
13131
  const subOptions = {
@@ -12694,8 +13150,10 @@ var init_subagent = __esm({
12694
13150
  // ★ P1-6 透传:子 agent 工作区文件编辑也走 auto 分类器
12695
13151
  noEarlyFinal: true,
12696
13152
  // ★ 子 agent final 是交付父级的汇报,EARLY_FINAL 误推一轮纯浪费;父可经续跑纠错
12697
- model: manifest?.model
13153
+ model: manifest?.model,
12698
13154
  // ★ per-agent 模型覆盖;undefined 时 model.ts 回退全局 MODEL_NAME
13155
+ costSink: ctx.reportCost
13156
+ // ★ 子 run 成本回灌父累计器(成本信任链第二环 E1):父预算自动继承约束
12699
13157
  };
12700
13158
  const startCtx = { sessionId: subSessionId, parentSessionId: ctx.sessionId, task, depth: ctx.depth + 1, name: manifest?.name, cwd: ctx.cwd };
12701
13159
  await dispatch("SubagentStart", startCtx);
@@ -12743,15 +13201,15 @@ var init_subagent = __esm({
12743
13201
  });
12744
13202
 
12745
13203
  // ../core/src/hooks/trust.ts
12746
- import path36 from "path";
12747
- import fs33 from "fs/promises";
13204
+ import path38 from "path";
13205
+ import fs36 from "fs/promises";
12748
13206
  var TRUSTED_HOOKS_FILE, approved, loaded, ensureLoaded, isHookCommandApproved, approveHookCommand;
12749
13207
  var init_trust2 = __esm({
12750
13208
  "../core/src/hooks/trust.ts"() {
12751
13209
  "use strict";
12752
13210
  init_config();
12753
13211
  init_common();
12754
- TRUSTED_HOOKS_FILE = path36.join(appConfig.dataDir, "trusted_hooks.json");
13212
+ TRUSTED_HOOKS_FILE = path38.join(appConfig.dataDir, "trusted_hooks.json");
12755
13213
  approved = /* @__PURE__ */ new Set();
12756
13214
  loaded = false;
12757
13215
  ensureLoaded = async () => {
@@ -12771,7 +13229,7 @@ var init_trust2 = __esm({
12771
13229
  if (approved.has(ident)) return;
12772
13230
  approved.add(ident);
12773
13231
  try {
12774
- await fs33.mkdir(appConfig.dataDir, { recursive: true });
13232
+ await fs36.mkdir(appConfig.dataDir, { recursive: true });
12775
13233
  await atomicWriteJSON(TRUSTED_HOOKS_FILE, [...approved]);
12776
13234
  } catch (e) {
12777
13235
  console.warn(`\u26A0\uFE0F [hooks] \u5BA1\u6279\u8BB0\u5FC6\u843D\u76D8\u5931\u8D25\uFF08\u672C\u6B21\u5DF2\u653E\u884C\uFF0C\u4E0B\u6B21\u9996\u8DD1\u4F1A\u518D\u95EE\uFF09: ${e?.message ?? e}`);
@@ -12781,8 +13239,8 @@ var init_trust2 = __esm({
12781
13239
  });
12782
13240
 
12783
13241
  // ../core/src/hooks/loader.ts
12784
- import fs34 from "fs/promises";
12785
- import path37 from "path";
13242
+ import fs37 from "fs/promises";
13243
+ import path39 from "path";
12786
13244
  var slimHookContext, readHooksConfig, appendValidated, validateRule, parseStdoutDecision, parseAgentDecision, gateSeq, firstRunGate, compileRule2, loadHooks, initHooks;
12787
13245
  var init_loader4 = __esm({
12788
13246
  "../core/src/hooks/loader.ts"() {
@@ -12811,15 +13269,15 @@ var init_loader4 = __esm({
12811
13269
  readHooksConfig = async (includeProject) => {
12812
13270
  const merged = {};
12813
13271
  const paths = [
12814
- path37.join(appConfig.dataDir, "settings.json"),
13272
+ path39.join(appConfig.dataDir, "settings.json"),
12815
13273
  // 全局用户级
12816
- ...includeProject ? [path37.join(process.cwd(), ".deepseeker-code", "settings.json")] : []
13274
+ ...includeProject ? [path39.join(process.cwd(), ".deepseeker-code", "settings.json")] : []
12817
13275
  // 项目级(叠加);未信任时省略
12818
13276
  ];
12819
13277
  for (const configPath of paths) {
12820
13278
  let raw;
12821
13279
  try {
12822
- raw = await fs34.readFile(configPath, "utf-8");
13280
+ raw = await fs37.readFile(configPath, "utf-8");
12823
13281
  } catch {
12824
13282
  continue;
12825
13283
  }
@@ -13192,8 +13650,8 @@ ${m.context}`;
13192
13650
  });
13193
13651
 
13194
13652
  // ../core/src/skills/loader.ts
13195
- import fs35 from "fs/promises";
13196
- import path38 from "path";
13653
+ import fs38 from "fs/promises";
13654
+ import path40 from "path";
13197
13655
  import { fileURLToPath as fileURLToPath2 } from "url";
13198
13656
  var BUILTIN_DIR, SOURCES2, MAX_SKILL_BODY_BYTES, splitList, parseSkillAt, loadSkills, initSkills;
13199
13657
  var init_loader5 = __esm({
@@ -13204,18 +13662,18 @@ var init_loader5 = __esm({
13204
13662
  init_registry3();
13205
13663
  init_skill();
13206
13664
  init_registry2();
13207
- BUILTIN_DIR = path38.join(path38.dirname(fileURLToPath2(import.meta.url)), "builtin");
13665
+ BUILTIN_DIR = path40.join(path40.dirname(fileURLToPath2(import.meta.url)), "builtin");
13208
13666
  SOURCES2 = [
13209
13667
  { dir: BUILTIN_DIR, source: "builtin" },
13210
- { dir: path38.join(appConfig.dataDir, "skills"), source: "global" },
13211
- { dir: path38.join(process.cwd(), ".deepseeker-code", "skills"), source: "project" }
13668
+ { dir: path40.join(appConfig.dataDir, "skills"), source: "global" },
13669
+ { dir: path40.join(process.cwd(), ".deepseeker-code", "skills"), source: "project" }
13212
13670
  ];
13213
13671
  MAX_SKILL_BODY_BYTES = 64 * 1024;
13214
13672
  splitList = (raw) => (raw ?? "").split(",").map((s) => s.trim()).filter(Boolean);
13215
13673
  parseSkillAt = async (skillFile, dir, source) => {
13216
13674
  let raw;
13217
13675
  try {
13218
- raw = await fs35.readFile(skillFile, "utf-8");
13676
+ raw = await fs38.readFile(skillFile, "utf-8");
13219
13677
  } catch {
13220
13678
  return null;
13221
13679
  }
@@ -13254,7 +13712,7 @@ var init_loader5 = __esm({
13254
13712
  loadSkills = async (includeProject) => {
13255
13713
  const picked = await scanSources(
13256
13714
  filterSources(SOURCES2, includeProject),
13257
- (e, dir) => e.isDirectory() ? path38.join(dir, e.name, "SKILL.md") : void 0,
13715
+ (e, dir) => e.isDirectory() ? path40.join(dir, e.name, "SKILL.md") : void 0,
13258
13716
  parseSkillAt
13259
13717
  );
13260
13718
  for (const { item } of picked) registerSkill(item);
@@ -13285,8 +13743,8 @@ var init_loader5 = __esm({
13285
13743
  });
13286
13744
 
13287
13745
  // ../core/src/agents/loader.ts
13288
- import fs36 from "fs/promises";
13289
- import path39 from "path";
13746
+ import fs39 from "fs/promises";
13747
+ import path41 from "path";
13290
13748
  import { fileURLToPath as fileURLToPath3 } from "url";
13291
13749
  var BUILTIN_DIR2, SOURCES3, parseAgentAt, initAgents;
13292
13750
  var init_loader6 = __esm({
@@ -13296,16 +13754,16 @@ var init_loader6 = __esm({
13296
13754
  init_frontmatter();
13297
13755
  init_registry4();
13298
13756
  init_registry2();
13299
- BUILTIN_DIR2 = path39.join(path39.dirname(fileURLToPath3(import.meta.url)), "builtin");
13757
+ BUILTIN_DIR2 = path41.join(path41.dirname(fileURLToPath3(import.meta.url)), "builtin");
13300
13758
  SOURCES3 = [
13301
13759
  { dir: BUILTIN_DIR2, source: "builtin" },
13302
- { dir: path39.join(appConfig.dataDir, "agents"), source: "global" },
13303
- { dir: path39.join(process.cwd(), ".deepseeker-code", "agents"), source: "project" }
13760
+ { dir: path41.join(appConfig.dataDir, "agents"), source: "global" },
13761
+ { dir: path41.join(process.cwd(), ".deepseeker-code", "agents"), source: "project" }
13304
13762
  ];
13305
13763
  parseAgentAt = async (file, dir, source) => {
13306
13764
  let raw;
13307
13765
  try {
13308
- raw = await fs36.readFile(file, "utf-8");
13766
+ raw = await fs39.readFile(file, "utf-8");
13309
13767
  } catch {
13310
13768
  return null;
13311
13769
  }
@@ -13340,7 +13798,7 @@ var init_loader6 = __esm({
13340
13798
  const known = new Set(into.map((t) => t.function.name));
13341
13799
  const picked = await scanSources(
13342
13800
  filterSources(SOURCES3, includeProject),
13343
- (e, dir) => e.isFile() && e.name.endsWith(".agent.md") ? path39.join(dir, e.name) : void 0,
13801
+ (e, dir) => e.isFile() && e.name.endsWith(".agent.md") ? path41.join(dir, e.name) : void 0,
13344
13802
  parseAgentAt
13345
13803
  );
13346
13804
  for (const { item: m, file, source } of picked) {
@@ -13377,8 +13835,8 @@ var init_registry7 = __esm({
13377
13835
  });
13378
13836
 
13379
13837
  // ../core/src/commands/loader.ts
13380
- import fs37 from "fs/promises";
13381
- import path40 from "path";
13838
+ import fs40 from "fs/promises";
13839
+ import path42 from "path";
13382
13840
  import { fileURLToPath as fileURLToPath4 } from "url";
13383
13841
  var BUILTIN_DIR3, SOURCES4, MAX_COMMAND_BODY_BYTES, parseCommandAt, loadCommands, initCommands;
13384
13842
  var init_loader7 = __esm({
@@ -13388,17 +13846,17 @@ var init_loader7 = __esm({
13388
13846
  init_frontmatter();
13389
13847
  init_registry7();
13390
13848
  init_registry2();
13391
- BUILTIN_DIR3 = path40.join(path40.dirname(fileURLToPath4(import.meta.url)), "builtin");
13849
+ BUILTIN_DIR3 = path42.join(path42.dirname(fileURLToPath4(import.meta.url)), "builtin");
13392
13850
  SOURCES4 = [
13393
13851
  { dir: BUILTIN_DIR3, source: "builtin" },
13394
- { dir: path40.join(appConfig.dataDir, "commands"), source: "global" },
13395
- { dir: path40.join(process.cwd(), ".deepseeker-code", "commands"), source: "project" }
13852
+ { dir: path42.join(appConfig.dataDir, "commands"), source: "global" },
13853
+ { dir: path42.join(process.cwd(), ".deepseeker-code", "commands"), source: "project" }
13396
13854
  ];
13397
13855
  MAX_COMMAND_BODY_BYTES = 64 * 1024;
13398
13856
  parseCommandAt = async (file, _dir, source) => {
13399
13857
  let raw;
13400
13858
  try {
13401
- raw = await fs37.readFile(file, "utf-8");
13859
+ raw = await fs40.readFile(file, "utf-8");
13402
13860
  } catch {
13403
13861
  return null;
13404
13862
  }
@@ -13409,7 +13867,7 @@ var init_loader7 = __esm({
13409
13867
  }
13410
13868
  const name = parsed.frontmatter.name;
13411
13869
  const description = parsed.frontmatter.description;
13412
- const fallbackName = path40.basename(file, ".md");
13870
+ const fallbackName = path42.basename(file, ".md");
13413
13871
  const finalName = name || fallbackName;
13414
13872
  if (!description) {
13415
13873
  console.warn(`\u26A0\uFE0F [commands] \u7F3A\u5C11 description\uFF08${file}\uFF09\uFF0C\u5DF2\u8DF3\u8FC7`);
@@ -13435,7 +13893,7 @@ var init_loader7 = __esm({
13435
13893
  loadCommands = async (includeProject) => {
13436
13894
  const picked = await scanSources(
13437
13895
  filterSources(SOURCES4, includeProject),
13438
- (e, dir) => e.isFile() && e.name.endsWith(".md") ? path40.join(dir, e.name) : void 0,
13896
+ (e, dir) => e.isFile() && e.name.endsWith(".md") ? path42.join(dir, e.name) : void 0,
13439
13897
  parseCommandAt
13440
13898
  );
13441
13899
  for (const { item } of picked) registerCommand(item);
@@ -13453,8 +13911,8 @@ var init_loader7 = __esm({
13453
13911
  });
13454
13912
 
13455
13913
  // ../core/src/outputStyles/loader.ts
13456
- import fs38 from "fs/promises";
13457
- import path41 from "path";
13914
+ import fs41 from "fs/promises";
13915
+ import path43 from "path";
13458
13916
  import { fileURLToPath as fileURLToPath5 } from "url";
13459
13917
  var BUILTIN_DIR4, MAX_STYLE_BODY_BYTES, SOURCES5, parseStyleAt, loadOutputStyles, initOutputStyles;
13460
13918
  var init_loader8 = __esm({
@@ -13464,17 +13922,17 @@ var init_loader8 = __esm({
13464
13922
  init_frontmatter();
13465
13923
  init_registry5();
13466
13924
  init_registry2();
13467
- BUILTIN_DIR4 = path41.join(path41.dirname(fileURLToPath5(import.meta.url)), "builtin");
13925
+ BUILTIN_DIR4 = path43.join(path43.dirname(fileURLToPath5(import.meta.url)), "builtin");
13468
13926
  MAX_STYLE_BODY_BYTES = 64 * 1024;
13469
13927
  SOURCES5 = [
13470
13928
  { dir: BUILTIN_DIR4, source: "builtin" },
13471
- { dir: path41.join(appConfig.dataDir, "output-styles"), source: "global" },
13472
- { dir: path41.join(process.cwd(), ".deepseeker-code", "output-styles"), source: "project" }
13929
+ { dir: path43.join(appConfig.dataDir, "output-styles"), source: "global" },
13930
+ { dir: path43.join(process.cwd(), ".deepseeker-code", "output-styles"), source: "project" }
13473
13931
  ];
13474
13932
  parseStyleAt = async (file, _dir, source) => {
13475
13933
  let raw;
13476
13934
  try {
13477
- raw = await fs38.readFile(file, "utf-8");
13935
+ raw = await fs41.readFile(file, "utf-8");
13478
13936
  } catch {
13479
13937
  return null;
13480
13938
  }
@@ -13506,7 +13964,7 @@ var init_loader8 = __esm({
13506
13964
  loadOutputStyles = async (includeProject) => {
13507
13965
  const picked = await scanSources(
13508
13966
  filterSources(SOURCES5, includeProject),
13509
- (e, dir) => e.isFile() && e.name.endsWith(".md") ? path41.join(dir, e.name) : void 0,
13967
+ (e, dir) => e.isFile() && e.name.endsWith(".md") ? path43.join(dir, e.name) : void 0,
13510
13968
  parseStyleAt
13511
13969
  );
13512
13970
  for (const { item } of picked) registerOutputStyle(item);
@@ -13587,8 +14045,8 @@ var init_bootstrap = __esm({
13587
14045
  });
13588
14046
 
13589
14047
  // ../core/src/statusLine/config.ts
13590
- import fs39 from "fs/promises";
13591
- import path42 from "path";
14048
+ import fs42 from "fs/promises";
14049
+ import path44 from "path";
13592
14050
  var parseBlock, readStatusLineConfig;
13593
14051
  var init_config2 = __esm({
13594
14052
  "../core/src/statusLine/config.ts"() {
@@ -13604,16 +14062,16 @@ var init_config2 = __esm({
13604
14062
  };
13605
14063
  readStatusLineConfig = async (includeProject) => {
13606
14064
  const paths = [
13607
- path42.join(appConfig.dataDir, "settings.json"),
14065
+ path44.join(appConfig.dataDir, "settings.json"),
13608
14066
  // 全局用户级
13609
- ...includeProject ? [path42.join(process.cwd(), ".deepseeker-code", "settings.json")] : []
14067
+ ...includeProject ? [path44.join(process.cwd(), ".deepseeker-code", "settings.json")] : []
13610
14068
  // 项目级(覆盖);未信任时省略
13611
14069
  ];
13612
14070
  let result = null;
13613
14071
  for (const configPath of paths) {
13614
14072
  let raw;
13615
14073
  try {
13616
- raw = await fs39.readFile(configPath, "utf-8");
14074
+ raw = await fs42.readFile(configPath, "utf-8");
13617
14075
  } catch {
13618
14076
  continue;
13619
14077
  }
@@ -13633,8 +14091,8 @@ var init_config2 = __esm({
13633
14091
 
13634
14092
  // ../core/src/statusLine/runner.ts
13635
14093
  import { spawn as spawn5 } from "child_process";
13636
- import fs40 from "fs";
13637
- import path43 from "path";
14094
+ import fs43 from "fs";
14095
+ import path45 from "path";
13638
14096
  import { fileURLToPath as fileURLToPath6 } from "url";
13639
14097
  var STATUSLINE_TIMEOUT_MS, cachedVersion, runStatusLine;
13640
14098
  var init_runner = __esm({
@@ -13643,16 +14101,16 @@ var init_runner = __esm({
13643
14101
  init_guard();
13644
14102
  STATUSLINE_TIMEOUT_MS = 3e3;
13645
14103
  try {
13646
- const here = path43.dirname(fileURLToPath6(import.meta.url));
14104
+ const here = path45.dirname(fileURLToPath6(import.meta.url));
13647
14105
  const candidates = [
13648
- path43.join(here, "../../../package.json"),
14106
+ path45.join(here, "../../../package.json"),
13649
14107
  // src/core/package.json
13650
- path43.join(here, "../../../../package.json")
14108
+ path45.join(here, "../../../../package.json")
13651
14109
  // 仓库根 package.json
13652
14110
  ];
13653
14111
  for (const p of candidates) {
13654
14112
  try {
13655
- const pkg = JSON.parse(fs40.readFileSync(p, "utf-8"));
14113
+ const pkg = JSON.parse(fs43.readFileSync(p, "utf-8"));
13656
14114
  if (typeof pkg.version === "string" && pkg.version) {
13657
14115
  cachedVersion = pkg.version;
13658
14116
  break;
@@ -13703,8 +14161,8 @@ var init_runner = __esm({
13703
14161
  });
13704
14162
 
13705
14163
  // ../core/src/observability/store.ts
13706
- import path44 from "path";
13707
- import fs41 from "fs/promises";
14164
+ import path46 from "path";
14165
+ import fs44 from "fs/promises";
13708
14166
  var getTraceDirPath, getTracePath, tracePathCache, ensuredTraceDirs, ensureTraceDir, getGlobalClockPath, getTraceStorePath;
13709
14167
  var init_store3 = __esm({
13710
14168
  "../core/src/observability/store.ts"() {
@@ -13714,21 +14172,21 @@ var init_store3 = __esm({
13714
14172
  init_common();
13715
14173
  getTraceDirPath = (mainTraceId) => {
13716
14174
  assertSafeSessionId(mainTraceId, "traceId");
13717
- return path44.join(appConfig.dataDir, "trace", appConfig.userWorkspaceDir, getFileName(mainTraceId));
14175
+ return path46.join(appConfig.dataDir, "trace", appConfig.userWorkspaceDir, getFileName(mainTraceId));
13718
14176
  };
13719
14177
  getTracePath = () => {
13720
- return path44.join(appConfig.dataDir, "trace");
14178
+ return path46.join(appConfig.dataDir, "trace");
13721
14179
  };
13722
14180
  tracePathCache = /* @__PURE__ */ new Map();
13723
14181
  ensuredTraceDirs = /* @__PURE__ */ new Set();
13724
14182
  ensureTraceDir = async (mainTraceId) => {
13725
14183
  const dir = getTraceDirPath(mainTraceId);
13726
14184
  if (ensuredTraceDirs.has(dir)) return;
13727
- await fs41.mkdir(dir, { recursive: true });
14185
+ await fs44.mkdir(dir, { recursive: true });
13728
14186
  ensuredTraceDirs.add(dir);
13729
14187
  };
13730
14188
  getGlobalClockPath = () => {
13731
- return path44.join(getTracePath(), "trace-cleanup-clock.json");
14189
+ return path46.join(getTracePath(), "trace-cleanup-clock.json");
13732
14190
  };
13733
14191
  getTraceStorePath = async (mainTraceId) => {
13734
14192
  assertSafeSessionId(mainTraceId, "traceId");
@@ -13737,7 +14195,7 @@ var init_store3 = __esm({
13737
14195
  if (cached2) return cached2;
13738
14196
  await ensureTraceDir(rootId);
13739
14197
  const dir = getTraceDirPath(rootId);
13740
- const files = await fs41.readdir(dir);
14198
+ const files = await fs44.readdir(dir);
13741
14199
  const existedFile = files.find((f) => f.endsWith(`__${rootId}.jsonl`));
13742
14200
  let fileName = "";
13743
14201
  if (existedFile) {
@@ -13746,7 +14204,7 @@ var init_store3 = __esm({
13746
14204
  const todayStr = getTodayDateString();
13747
14205
  fileName = `trace-${todayStr}__${rootId}.jsonl`;
13748
14206
  }
13749
- const resolved = path44.join(dir, fileName);
14207
+ const resolved = path46.join(dir, fileName);
13750
14208
  tracePathCache.set(rootId, resolved);
13751
14209
  return resolved;
13752
14210
  };
@@ -13754,8 +14212,8 @@ var init_store3 = __esm({
13754
14212
  });
13755
14213
 
13756
14214
  // ../core/src/observability/trace.ts
13757
- import fs42 from "fs/promises";
13758
- import path45 from "path";
14215
+ import fs45 from "fs/promises";
14216
+ import path47 from "path";
13759
14217
  async function emitTrace(base) {
13760
14218
  const event = {
13761
14219
  sessionId: base.sessionId,
@@ -13777,7 +14235,7 @@ async function emitTrace(base) {
13777
14235
  async function appendTraceEvent(event) {
13778
14236
  const p = await getTraceStorePath(event.sessionId);
13779
14237
  const line = JSON.stringify(event) + "\n";
13780
- await fs42.appendFile(p, line, "utf-8");
14238
+ await fs45.appendFile(p, line, "utf-8");
13781
14239
  if (workspaceTraceBytes < 0) {
13782
14240
  workspaceTraceBytes = await getDirBytes(getTracePath());
13783
14241
  }
@@ -13809,8 +14267,8 @@ async function maybeCleanupAfterAppend(sessionId) {
13809
14267
  lastSizeCleanupAt2 = now;
13810
14268
  diskLastCleanupAt2 = now;
13811
14269
  const clockPath = getGlobalClockPath();
13812
- await fs42.mkdir(path45.dirname(clockPath), { recursive: true });
13813
- await fs42.writeFile(clockPath, JSON.stringify({ lastCleanupAt: now, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2), "utf-8");
14270
+ await fs45.mkdir(path47.dirname(clockPath), { recursive: true });
14271
+ await fs45.writeFile(clockPath, JSON.stringify({ lastCleanupAt: now, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2), "utf-8");
13814
14272
  if (deletedCount > 0) {
13815
14273
  console.log(`\u2728 [Trace\u8FD0\u7EF4] \u5171\u9500\u6BC1 ${deletedCount} \u4E2A\u4F1A\u8BDD\u65E5\u5FD7\uFF08\u8F6F\u89C4\u5219\u8FC7\u671F\u6E05\u7406 + \u5BB9\u91CF\u786C\u9A71\u9010\uFF09\uFF0C\u78C1\u76D8\u6C34\u4F4D\u56DE\u843D\u3002`);
13816
14274
  }
@@ -13830,22 +14288,22 @@ async function cleanupOldTraceFiles() {
13830
14288
  let deleted = 0;
13831
14289
  let relativePaths;
13832
14290
  try {
13833
- relativePaths = await fs42.readdir(dir, { recursive: true });
14291
+ relativePaths = await fs45.readdir(dir, { recursive: true });
13834
14292
  } catch {
13835
14293
  return 0;
13836
14294
  }
13837
14295
  const re = /^trace-(\d{4}-\d{2}-\d{2})__([\w-]+)\.jsonl$/;
13838
14296
  for (const relativePath of relativePaths) {
13839
- const fileName = path45.basename(relativePath);
14297
+ const fileName = path47.basename(relativePath);
13840
14298
  const m = fileName.match(re);
13841
14299
  if (!m) continue;
13842
14300
  const fileBornDay = /* @__PURE__ */ new Date(`${m[1]}T00:00:00`);
13843
14301
  if (fileBornDay >= cutoff) continue;
13844
- const fullPath = path45.join(dir, relativePath);
14302
+ const fullPath = path47.join(dir, relativePath);
13845
14303
  try {
13846
- const st = await fs42.stat(fullPath);
14304
+ const st = await fs45.stat(fullPath);
13847
14305
  if (now - st.mtimeMs < ACTIVE_GRACE_MS2) continue;
13848
- await fs42.unlink(fullPath);
14306
+ await fs45.unlink(fullPath);
13849
14307
  deleted += 1;
13850
14308
  } catch {
13851
14309
  }
@@ -13856,18 +14314,18 @@ async function evictOldestForSize2(targetBytes) {
13856
14314
  const dir = getTracePath();
13857
14315
  let relativePaths;
13858
14316
  try {
13859
- relativePaths = await fs42.readdir(dir, { recursive: true });
14317
+ relativePaths = await fs45.readdir(dir, { recursive: true });
13860
14318
  } catch {
13861
14319
  return 0;
13862
14320
  }
13863
14321
  const re = /^trace-(\d{4}-\d{2}-\d{2})__([\w-]+)\.jsonl$/;
13864
14322
  const candidates = [];
13865
14323
  for (const relativePath of relativePaths) {
13866
- const fileName = path45.basename(relativePath);
14324
+ const fileName = path47.basename(relativePath);
13867
14325
  if (!re.test(fileName)) continue;
13868
14326
  try {
13869
- const st = await fs42.stat(path45.join(dir, relativePath));
13870
- candidates.push({ mtime: st.mtimeMs, fullPath: path45.join(dir, relativePath), size: st.size });
14327
+ const st = await fs45.stat(path47.join(dir, relativePath));
14328
+ candidates.push({ mtime: st.mtimeMs, fullPath: path47.join(dir, relativePath), size: st.size });
13871
14329
  } catch {
13872
14330
  }
13873
14331
  }
@@ -13877,7 +14335,7 @@ async function evictOldestForSize2(targetBytes) {
13877
14335
  for (const c of candidates) {
13878
14336
  if (totalBytes <= targetBytes) break;
13879
14337
  try {
13880
- await fs42.unlink(c.fullPath);
14338
+ await fs45.unlink(c.fullPath);
13881
14339
  totalBytes -= c.size;
13882
14340
  deleted += 1;
13883
14341
  } catch {
@@ -13909,7 +14367,7 @@ var init_trace = __esm({
13909
14367
  if (clockLoaded2) return;
13910
14368
  clockLoaded2 = true;
13911
14369
  try {
13912
- const rawClock = await fs42.readFile(getGlobalClockPath(), "utf-8");
14370
+ const rawClock = await fs45.readFile(getGlobalClockPath(), "utf-8");
13913
14371
  diskLastCleanupAt2 = JSON.parse(rawClock).lastCleanupAt || 0;
13914
14372
  } catch {
13915
14373
  diskLastCleanupAt2 = 0;
@@ -14005,59 +14463,9 @@ var init_expand = __esm({
14005
14463
  }
14006
14464
  });
14007
14465
 
14008
- // ../core/src/agent/systemPrompt.ts
14009
- var buildSystemPrompt;
14010
- var init_systemPrompt = __esm({
14011
- "../core/src/agent/systemPrompt.ts"() {
14012
- "use strict";
14013
- init_planMode();
14014
- buildSystemPrompt = (p) => `\u4F60\u662F ${p.displayName}\u2014\u2014\u4E00\u4E2A\u57FA\u4E8E ${p.modelLabel} \u5927\u6A21\u578B\u7684\u7EC8\u7AEF AI \u7F16\u7A0B\u52A9\u624B\u3002\u4F60\u8FD0\u884C\u5728\u7528\u6237\u7684\u7EC8\u7AEF\u4E2D\uFF0C\u80FD\u8C03\u7528\u4E00\u7CFB\u5217\u5DE5\u5177\uFF08\u8BFB\u5199\u6587\u4EF6\u3001\u641C\u7D22\u4EE3\u7801\u3001\u6267\u884C\u547D\u4EE4\u3001\u8054\u7F51\u68C0\u7D22\u3001\u4EFB\u52A1\u7BA1\u7406\u7B49\uFF09\u76F4\u63A5\u5728\u7528\u6237\u5DE5\u4F5C\u533A\u5B8C\u6210\u5F00\u53D1\u4EFB\u52A1\u3002
14015
-
14016
- \u3010\u8EAB\u4EFD\u3011
14017
- - \u4F60\u7684\u540D\u5B57\u662F ${p.displayName}\uFF0C\u7531 ${p.modelLabel} \u6A21\u578B\u9A71\u52A8\u3002
14018
- - \u88AB\u95EE"\u4F60\u662F\u8C01"\u65F6\u636E\u5B9E\u56DE\u7B54\uFF1A\u4F60\u662F ${p.displayName}\u3002\u5207\u52FF\u81EA\u79F0 ChatGPT\u3001GPT \u6216\u4EFB\u4F55\u5176\u4ED6\u516C\u53F8\u7684\u5927\u6A21\u578B/AI \u4EA7\u54C1\u3002
14019
-
14020
- \u3010\u56DE\u7B54\u51C6\u5219 / \u5B8C\u6210\u5224\u5B9A\u3011
14021
- - \u4EFB\u52A1\u5B8C\u6210\u540E\u76F4\u63A5\u7528\u81EA\u7136\u8BED\u8A00\u7ED9\u51FA\u6700\u7EC8\u7B54\u6848\uFF0C\u4E0D\u8981\u518D\u8C03\u7528\u5DE5\u5177\u3002**\u5B8C\u6210\u5224\u636E = \u7528\u6237\u7684\u6BCF\u4E2A\u5B50\u76EE\u6807\u90FD\u6709\u843D\u5730\u4EA7\u7269**\uFF08\u6240\u9700\u4FE1\u606F\u5DF2\u5230\u624B / \u8BE5\u6539\u7684\u6587\u4EF6\u5DF2\u6539\u5B8C / \u5DF2\u9A8C\u8BC1\u901A\u8FC7\uFF09\uFF0C\u800C\u975E"\u8C03\u7528\u8FC7\u5DE5\u5177"\u3002\u6BCF\u8F6E\u5DE5\u5177\u8FD4\u56DE\u540E\u5BF9\u7167\u539F\u59CB\u8BF7\u6C42\u4E0E todo \u6E05\u5355\uFF08\u82E5\u6709\uFF09\u9010\u9879\u6838\u5BF9\uFF1A\u8FD8\u6709\u672A\u843D\u5730\u9879\u5C31\u7EE7\u7EED\u63A8\u8FDB\uFF0C\u4E0D\u8981\u62FF\u90E8\u5206\u68C0\u7D22/\u8BFB\u53D6\u7ED3\u679C\u603B\u7ED3\u6536\u5C3E\u3002\u590D\u6742\u4EFB\u52A1\u7528 todo_write \u62C6\u89E3\u5E76\u9010\u9879\u52FE\u9009\uFF0C\u6BCF\u8F6E\u5BF9\u7167\u6E05\u5355\u6838\u5BF9\u8FDB\u5EA6\u3002
14022
- - \u5DE5\u5177**\u6267\u884C\u5931\u8D25\u6216\u88AB\u7528\u6237\u62D2\u7EDD**\u65F6\uFF0C\u8BFB\u8FD4\u56DE\u7ED3\u679C\u5B9A\u4F4D\u539F\u56E0\uFF0C\u4FEE\u6B63\u53C2\u6570\u6216\u6362\u7B49\u6548\u65B9\u6848\u7EE7\u7EED\uFF0C\u4E0D\u8981\u9053\u6B49\u4E00\u4E24\u53E5\u5C31\u505C\u4E0B\uFF1B\u786E\u5B9E\u53D7\u963B\u9700\u8981\u7528\u6237\u51B3\u7B56\u65F6\uFF0C\u7528 ask_question \u8BF4\u660E**\u5177\u4F53**\u963B\u585E\u70B9\u3002**\u4E25\u7981**\u5728\u672A\u771F\u6B63\u6267\u884C\u6216\u672A\u9A8C\u8BC1\u7684\u60C5\u51B5\u4E0B\u58F0\u79F0"\u5DF2\u5B8C\u6210/\u5DF2\u4FEE\u6539/\u5DF2\u4FEE\u590D"\u2014\u2014\u6539\u52A8\u82E5\u53EF\u9A8C\u8BC1\uFF08\u91CD\u8BFB\u786E\u8BA4\u3001\u8DD1\u6D4B\u8BD5\u3001\u7C7B\u578B\u68C0\u67E5\uFF09\uFF0C\u5148\u9A8C\u8BC1\u518D\u6536\u5C3E\u3002
14023
-
14024
- \u3010\u56DE\u7B54\u5F62\u5F0F\u3011
14025
- - **\u5148\u7ED3\u8BBA\u540E\u7EC6\u8282**\uFF1A\u5148\u76F4\u63A5\u56DE\u7B54\u6216\u6C47\u62A5\u7ED3\u679C\uFF0C\u518D\u5C55\u5F00\u5FC5\u8981\u7684\u89E3\u91CA\uFF1B\u6536\u5C3E\u603B\u7ED3\u7B80\u77ED\uFF08\u51E0\u884C\u4EE5\u5185\uFF09\uFF0C\u4E0D\u9010\u6587\u4EF6\u6D41\u6C34\u8D26\u3002
14026
- - **\u4E0D\u56DE\u8D34\u5927\u6BB5\u4EE3\u7801**\uFF1A\u6539\u52A8\u5185\u5BB9\u7528\u6237\u5728\u7F16\u8F91\u5668/diff \u91CC\u770B\u5F97\u5230\uFF0C\u6B63\u6587\u53EA\u9700\u4E00\u53E5\u8BDD\u8BF4\u660E\u6539\u4E86\u4EC0\u4E48\u3001\u4E3A\u4EC0\u4E48\uFF0C\u6216\u5F15\u7528\u5173\u952E\u51E0\u884C\u3002
14027
-
14028
- \u3010\u5DE5\u5177\u4F7F\u7528\u51C6\u5219\u3011
14029
- - \u4FEE\u6539\u6587\u4EF6**\u53EA\u80FD**\u7528 edit_file / create_file / write_file\u3002**\u4E25\u7981**\u7528 run_command \u901A\u8FC7 python/node/sed/awk/perl \u7B49\u811A\u672C\u8BFB\u5199\u6216\u4FEE\u6539\u6587\u4EF6\u2014\u2014\u811A\u672C\u8F6C\u4E49\u6781\u6613\u51FA\u9519\u3001\u6BCF\u6761\u547D\u4EE4\u90FD\u8981\u7528\u6237\u5BA1\u6279\u3001\u6548\u7387\u6781\u4F4E\uFF0C\u662F\u88AB\u660E\u786E\u7981\u6B62\u7684\u9000\u8DEF\u3002
14030
- - edit_file \u5931\u8D25\u65F6**\u4E0D\u8981\u9000\u56DE shell**\uFF1A\u7528 read_file \u91CD\u65B0\u6838\u5BF9\u76EE\u6807\u7247\u6BB5\uFF08\u53BB\u6389\u300C<\u884C\u53F7>: \u300D\u524D\u7F00\u3001\u4FDD\u7559\u539F\u59CB Tab/\u7A7A\u683C\u7F29\u8FDB\u4E0E\u6362\u884C\uFF09\u540E\u518D\u6B21\u8C03\u7528 edit_file\uFF1B\u5B9A\u4F4D\u4E0D\u51C6\u5C31\u591A\u8BFB\u51E0\u884C\u4E0A\u4E0B\u6587\u5305\u88F9\u8FDB\u53BB\u3002\u672C\u5DE5\u5177\u5DF2\u6709\u591A\u7EA7\u7A7A\u767D/\u7F29\u8FDB\u5BB9\u9519\uFF0C\u591A\u6570\u5931\u914D\u53EA\u9700\u7CBE\u786E\u91CD\u8BFB\u5373\u53EF\u89E3\u51B3\u3002
14031
- - \u4FEE\u6539\u65E2\u6709\u6587\u4EF6**\u4E00\u5F8B\u4F18\u5148 edit_file**\uFF08\u7CBE\u51C6\u5C40\u90E8\u66FF\u6362\u3001\u4FDD\u7559\u539F\u7F29\u8FDB\u3001\u6700\u5C0F diff\uFF09\uFF1Bwrite_file / create_file \u4EC5\u7528\u4E8E\u65B0\u5EFA\u6587\u4EF6\u6216\u5F7B\u5E95\u91CD\u5199\u6574\u4E2A\u6587\u4EF6\u3002\u2605 \u7528 write_file \u5168\u91CF\u8986\u76D6\u65E2\u6709\u6587\u4EF6\u4F1A\u4E22\u5931\u539F\u6709\u7F29\u8FDB\u4E0E\u683C\u5F0F\u3001\u4EA7\u751F\u5927\u91CF\u65E0\u5173 diff\uFF0C\u662F\u7528\u6237\u660E\u786E\u53CD\u611F\u7684\u53CD\u6A21\u5F0F\u2014\u2014\u5373\u4FBF\u8981\u6539\u7684\u5730\u65B9\u5F88\u591A\uFF0C\u4E5F\u7528\u591A\u6B21 edit_file \u800C\u975E\u4E00\u6B21 write_file \u8986\u76D6\u3002
14032
- - \u8C03\u7528\u5DE5\u5177\u524D\u5148\u81EA\u95EE\uFF1A\u5DF2\u6709\u7684\u4FE1\u606F\u662F\u5426\u8DB3\u4EE5\u56DE\u7B54\u7528\u6237\uFF1F\u591F\u5C31\u4E0D\u518D\u8C03\u5DE5\u5177\uFF0C\u76F4\u63A5\u4F5C\u7B54\u3002
14033
- - **\u5148\u8BFB\u5168\u518D\u52A8\u624B\uFF0C\u522B\u628A\u641C\u7D22\u5F53\u5B57\u5178\u67E5\uFF08\u53CD\u788E\u6B65\xB7\u91CD\u8981\uFF09**\uFF1A\u8981\u6539\u67D0\u4E2A\u6587\u4EF6/\u6A21\u5757\u524D\uFF0C\u5148\u7528 read_file \u628A\u76F8\u5173\u6587\u4EF6\u4E00\u6B21\u6027\u8BFB\u5168\uFF08\u7ED3\u6784\u3001\u5B57\u6BB5\u3001\u7528\u6CD5\u90FD\u5728\u6587\u4EF6\u91CC\uFF09\uFF0C\u4E0D\u8981\u9760 search_grep \u4E00\u4E2A\u5B57\u6BB5\u3001\u4E00\u4E2A\u7528\u6CD5\u5730\u8BD5\u63A2\u3002search_grep \u662F\u5B9A\u4F4D\u5DE5\u5177\u2014\u2014\u7528\u6765\u627E\u67D0\u7B26\u53F7\u5728\u54EA\u5B9A\u4E49/\u88AB\u8C01\u8C03\u7528\uFF0C\u627E\u5230\u540E\u7ACB\u5373\u8BFB\u5B8C\u6574\u6587\u4EF6\u7406\u89E3\u4E0A\u4E0B\u6587\uFF1B\u7EDD\u4E0D\u7528\u8FD1\u4E49\u5173\u952E\u8BCD\u53CD\u590D\u641C\u540C\u4E00\u4E2A\u610F\u56FE\u3002
14034
- - **\u6279\u91CF\u89C4\u5212\u6539\u52A8\uFF0C\u4E00\u6B21\u6210\u578B\uFF08\u53CD\u788E\u6B65\xB7\u91CD\u8981\uFF09**\uFF1A\u52A8\u624B\u524D\u5148\u628A\u6240\u6709\u8981\u6539\u7684\u70B9\u60F3\u6E05\u695A\u3001\u5217\u51FA\u6765\uFF0C\u518D\u7528\u591A\u6B21 edit_file \u4E00\u53E3\u6C14\u6539\u5B8C\u3002\u4E0D\u8981"\u6539\u4E00\u5904 \u2192 \u770B\u4E00\u773C \u2192 \u53C8\u53D1\u73B0\u4E00\u5904 \u2192 \u518D\u6539"\u6765\u56DE\u4E03\u516B\u8D9F\u2014\u2014\u65E2\u70E7 token \u53C8\u6613\u9057\u6F0F\u3002\u6B63\u786E\u8282\u594F\uFF1A\u5148\u8BFB\u5168 \u2192 \u89C4\u5212 \u2192 \u6279\u91CF\u6539 \u2192 \u6700\u540E\u7EDF\u4E00\u9A8C\u8BC1\u3002
14035
- - **\u6539\u5B8C\u52FF\u7ACB\u523B\u91CD\u8BFB\uFF08\u53CD\u788E\u6B65\xB7\u91CD\u8981\uFF09**\uFF1Aedit_file / write_file \u6210\u529F\u8FD4\u56DE\u540E\uFF0C\u5DE5\u5177\u7ED3\u679C\u5DF2\u8BF4\u660E\u6539\u4E86\u4EC0\u4E48\uFF0C\u4E0D\u8981\u9A6C\u4E0A read_file \u628A\u6574\u4E2A\u6587\u4EF6\u91CD\u8BFB\u4E00\u904D\u6765"\u786E\u8BA4"\u3002\u786E\u9700\u6838\u9A8C\u65F6\uFF0C\u53EA\u8BFB\u6539\u52A8\u9644\u8FD1\u51E0\u884C\u6216\u8DD1\u7C7B\u578B\u68C0\u67E5/\u6D4B\u8BD5\uFF0C\u800C\u975E\u6574\u6587\u4EF6\u91CD\u8BFB\u3002
14036
- - \u4E0D\u91CD\u590D\u6293\u53D6\u5DF2\u6293\u53D6\u8FC7\u7684 URL\uFF1B\u4E0D\u7528\u8FD1\u4E49\u5173\u952E\u8BCD\u53CD\u590D\u641C\u7D22\u540C\u4E00\u4E2A\u610F\u56FE\u3002
14037
- - \u8054\u7F51/\u641C\u7D22\u7C7B\u8C03\u7814\u4EFB\u52A1\uFF0C\u901A\u5E38 1~3 \u4E2A\u6765\u6E90\u5DF2\u8DB3\u591F\u652F\u6491\u56DE\u7B54\u2014\u2014\u62FF\u5230\u5373\u7EFC\u5408\u4F5C\u7B54\uFF0C\u4E0D\u8981\u4E3A\u8FFD\u6C42"\u66F4\u5168\u9762"\u800C\u65E0\u9650\u8FFD\u52A0\u68C0\u7D22\u8F6E\u6B21\u3002
14038
- - **\u72EC\u7ACB\u8BFB\u64CD\u4F5C\u5E76\u884C\u6253\u5305\uFF08\u91CD\u8981\uFF09**\uFF1A\u591A\u4E2A\u4E92\u4E0D\u4F9D\u8D56\u7684\u53EA\u8BFB\u8C03\u7528\uFF08\u8BFB\u591A\u4E2A\u6587\u4EF6\u3001\u591A\u4E2A\u68C0\u7D22\u3001\u591A\u4E2A\u5B9A\u4E49\u67E5\u8BE2\uFF09\u5E94\u5728\u540C\u4E00\u6761\u6D88\u606F\u91CC\u4E00\u6B21\u6027\u5168\u90E8\u53D1\u51FA\uFF0C\u6267\u884C\u5C42\u4F1A\u81EA\u52A8\u5E76\u53D1\u6267\u884C\uFF0C\u4E00\u8F6E\u9876\u591A\u8F6E\uFF1B\u6709\u4F9D\u8D56\uFF08\u540E\u4E00\u6B65\u8981\u7528\u524D\u4E00\u6B65\u7ED3\u679C\uFF09\u6216\u4F1A\u6539\u72B6\u6001\u7684\u64CD\u4F5C\uFF0C\u5FC5\u987B\u7B49\u524D\u5E8F\u7ED3\u679C\u8FD4\u56DE\u518D\u53D1\u3002
14039
- - \u591A\u6B65\u9AA4\u7684\u590D\u6742\u4EFB\u52A1\uFF08\u22653 \u6B65\u3001\u8DE8\u591A\u6587\u4EF6\u6216\u591A\u9636\u6BB5\uFF09\u5148\u8C03\u7528 todo_write \u628A\u8BA1\u5212\u62C6\u6210\u53EF\u52FE\u9009\u7684\u4EFB\u52A1\u6E05\u5355\uFF0C\u518D\u9010\u6B65\u63A8\u8FDB\u5E76\u5373\u65F6\u66F4\u65B0\u72B6\u6001\u2014\u2014\u8BA9\u4F60\u548C\u7528\u6237\u90FD\u770B\u6E05\u8FDB\u5EA6\u3001\u4E0D\u9057\u6F0F\u6B65\u9AA4\uFF1B\u7B80\u5355 1-2 \u6B65\u7684\u4EFB\u52A1\u65E0\u9700\u5EFA\u6E05\u5355\u3002
14040
-
14041
- \u3010\u64CD\u4F5C\u786E\u8BA4\u7EA6\u5B9A\u3011
14042
- - \u9047\u5230\u4F1A\u6539\u53D8\u72B6\u6001\u6216\u5177\u98CE\u9669\u7684\u5DE5\u5177\uFF08\u5199\u6587\u4EF6\u3001\u7F16\u8F91\u3001\u5220\u9664\u3001\u79FB\u52A8\u3001\u6267\u884C\u547D\u4EE4\u3001\u5BF9\u5916\u7F51\u7EDC\u8BF7\u6C42\u7B49\uFF09\uFF0C\u76F4\u63A5\u8C03\u7528\u8BE5\u5DE5\u5177\u5373\u53EF\uFF0C\u4E0D\u8981\u5148\u7528\u81EA\u7136\u8BED\u8A00\u5F81\u6C42\u786E\u8BA4\uFF08\u5982"\u6211\u53EF\u4EE5\u6267\u884C\u5417\uFF1F""\u662F\u5426\u7EE7\u7EED\uFF1F"\uFF09\u3002\u8FD9\u7C7B\u5DE5\u5177\u7531\u7CFB\u7EDF\u7EDF\u4E00\u62E6\u622A\u5E76\u5F39\u51FA\u5BA1\u6279\u754C\u9762\uFF0C\u7528\u6237\u4F1A\u4E00\u952E\u540C\u610F\u6216\u62D2\u7EDD\u2014\u2014\u4F60\u65E0\u9700\u4EE3\u66FF\u7CFB\u7EDF\u53D1\u95EE\uFF0C\u66F4\u4E0D\u8981\u505C\u4E0B\u7B49\u7528\u6237\u6253\u5B57\u786E\u8BA4\u3002
14043
- - \u4EC5\u5F53\u5B58\u5728\u591A\u79CD\u660E\u663E\u4E0D\u540C\u7684\u5B9E\u73B0\u65B9\u6848\u3001\u9700\u8981\u7528\u6237\u5728\u65B9\u5411\u4E0A\u62CD\u677F\u65F6\uFF0C\u8C03\u7528 ask_question \u5DE5\u5177\u63D0\u51FA 2-4 \u4E2A\u7ED3\u6784\u5316\u9009\u9879\u8BA9\u7528\u6237\u9009\u62E9\uFF08\u7EC8\u7AEF\u4F1A\u5F39\u51FA\u591A\u9009\u6846\uFF0C\u6BD4\u7EAF\u6587\u5B57\u66F4\u6E05\u6670\u9AD8\u6548\uFF0C\u7528\u6237\u9009\u62E9\u4F1A\u81EA\u52A8\u56DE\u4F20\u7ED9\u4F60\uFF1B\u63D0\u95EE\u6846\u6052\u6709\u300COther\u300D\u81EA\u7531\u8F93\u5165\u6863\uFF0C\u9700\u8981\u7528\u6237\u63D0\u4F9B\u9009\u9879\u4E4B\u5916\u7684\u8D44\u6599\u2014\u2014\u5982\u767B\u5F55 token\u3001\u6587\u4EF6\u8DEF\u5F84\u2014\u2014\u4E5F\u7528 ask_question \u63D0\u51FA\uFF0C\u7528\u6237\u4F1A\u7ECF Other \u7C98\u8D34\u539F\u6587\u56DE\u4F20\uFF09\uFF1B\u5BF9"\u67D0\u4E2A\u5177\u4F53\u64CD\u4F5C\u662F\u5426\u6267\u884C"\u4E00\u5F8B\u76F4\u63A5\u8C03\u7528\u5DE5\u5177\u8D70\u5BA1\u6279\uFF0C\u4E0D\u8981\u7528 ask_question \u53BB\u95EE\u80FD\u5426\u6267\u884C\u67D0\u4E2A\u64CD\u4F5C\u3002
14044
-
14045
- \u3010\u8BA1\u5212\u6A21\u5F0F\u3011
14046
- ${PLAN_MODE_AUTO_ENTER_HINT}
14047
- - **\u8BA1\u5212\u6A21\u5F0F\u7684\u8BC6\u522B**\uFF1A\u5F53\u4F60\u53D1\u73B0\u5F53\u524D\u53EF\u7528\u5DE5\u5177\u4EC5\u5305\u542B\u8BFB\u53D6\u4E0E\u68C0\u7D22\u7C7B\uFF08read_file/search_grep/glob/git \u53EA\u8BFB/web \u7B49\uFF09\u3001\u4E0D\u542B\u4EFB\u4F55\u5199\u6587\u4EF6/\u6267\u884C\u547D\u4EE4/\u540E\u53F0\u4EFB\u52A1\u7C7B\u5DE5\u5177\u65F6\uFF0C\u8BF4\u660E\u5DF2\u8FDB\u5165\u8BA1\u5212\u6A21\u5F0F\u2014\u2014\u6B64\u65F6\u4E25\u7981\u4FEE\u6539\u4EFB\u4F55\u6587\u4EF6\u6216\u6267\u884C\u547D\u4EE4\uFF0C\u53EA\u80FD\u8C03\u7814\uFF0C\u5B8C\u6210\u540E\u5FC5\u987B\u8C03\u7528 exit_plan_mode \u63D0\u4EA4\u65B9\u6848\u3002
14048
- - **\u63D0\u4EA4\u65B9\u6848\u5FC5\u987B\u7528\u5DE5\u5177**\uFF1A\u8FDB\u5165\u8BA1\u5212\u6A21\u5F0F\u540E\u7528 exit_plan_mode \u63D0\u4EA4\uFF1B\u82E5\u4F60\u5728\u6B63\u5E38\u8F6E\u5DF2\u81EA\u884C\u7528\u53EA\u8BFB\u5DE5\u5177\u5B8C\u6210\u8C03\u7814\uFF0C\u4E5F\u53EF\u76F4\u63A5\u8C03 exit_plan_mode \u63D0\u4EA4\u3002\u7EDD\u4E0D\u8981\u4EE5\u7EAF\u6587\u672C\u9648\u8FF0\u65B9\u6848\u7136\u540E\u505C\u4E0B\u7B49\u5F85\u5BA1\u6279\u2014\u2014\u7EAF\u6587\u672C\u65B9\u6848\u4E0D\u4F1A\u89E6\u53D1\u5BA1\u6279\u754C\u9762\uFF0C\u7528\u6237\u65E0\u6CD5\u4E00\u952E\u6279\u51C6/\u7F16\u8F91\uFF0C\u6D41\u7A0B\u4F1A\u5361\u6B7B\u3002
14049
-
14050
- \u3010\u6301\u4E45\u8BB0\u5FC6\u3011
14051
- - \u4F60\u62E5\u6709\u8DE8\u4F1A\u8BDD\u7684\u6301\u4E45\u8BB0\u5FC6\uFF1A\u7CFB\u7EDF\u63D0\u793A\u8BCD\u4E2D\u4EE5\u3010\u8BB0\u5FC6\u7D22\u5F15\u3011\u5217\u51FA\u5DF2\u5B58\u8BB0\u5FC6\uFF08\u4E00\u884C/\u6761\uFF1A\u540D\u79F0\u3001\u7C7B\u522B\u3001\u63CF\u8FF0\uFF09\u3002\u5F53\u7D22\u5F15\u4E2D\u67D0\u6761\u4E0E\u5F53\u524D\u4EFB\u52A1\u76F8\u5173\u3001\u9700\u8981\u7EC6\u8282\u65F6\uFF0C\u8C03\u7528 memory_read \u6309\u9700\u53EC\u56DE\u5168\u6587\uFF1B\u4E0D\u8981\u65E0\u5DEE\u522B\u5730\u5168\u91CF\u8BFB\u53D6\u3002
14052
- - \u9047\u5230\u503C\u5F97\u8DE8\u4F1A\u8BDD\u4FDD\u7559\u7684\u4FE1\u606F\u65F6\uFF0C\u4E3B\u52A8\u7528 memory_save \u5B58\u6210\u8BB0\u5FC6\uFF0C\u4F8B\u5982\uFF1A\u7528\u6237\u7684\u957F\u671F\u504F\u597D\u4E0E\u89D2\u8272\u753B\u50CF\u3001\u7528\u6237\u7ED9\u51FA\u7684\u5DE5\u4F5C\u65B9\u5F0F\u53CD\u9988\uFF08\u542B\u539F\u56E0\u4E0E\u505A\u6CD5\uFF09\u3001\u9879\u76EE\u76EE\u6807\u4E0E\u9690\u542B\u7EA6\u675F\u3001\u5916\u90E8\u8D44\u6E90\u6307\u9488\uFF08URL/\u770B\u677F/\u5DE5\u5355\uFF09\u3002\u5373\u90A3\u4E9B\u300C\u4E0B\u6B21\u4E0D\u8BE5\u91CD\u65B0\u53D1\u73B0\u300D\u300C\u4EE3\u7801\u4E0E git \u4E0D\u4F1A\u76F4\u63A5\u544A\u8BC9\u4F60\u300D\u7684\u975E\u663E\u7136\u4E8B\u5B9E\u3002
14053
- - \u4E0D\u8981\u4FDD\u5B58\uFF1A\u4EE3\u7801\u7ED3\u6784\u3001\u8FC7\u5F80\u4FEE\u590D\u3001git \u5386\u53F2\u7B49\u4ED3\u5E93\u672C\u8EAB\u5DF2\u8BB0\u5F55\u7684\u5185\u5BB9\uFF1B\u53EA\u5BF9\u672C\u6B21\u5BF9\u8BDD\u6709\u610F\u4E49\u3001\u4E0B\u4E0D\u4E3A\u4F8B\u7684\u4E34\u65F6\u4FE1\u606F\u3002\u82E5\u4E0D\u786E\u5B9A\u67D0\u6761\u4FE1\u606F\u662F\u5426\u503C\u5F97\u5B58\uFF0C\u5148\u95EE\u6E05\u5176\u975E\u663E\u7136\u4E4B\u5904\uFF0C\u5B58\u90A3\u4E00\u70B9\u800C\u975E\u6574\u6BB5\u6D41\u6C34\u3002
14054
- - \u8BB0\u5FC6\u4F1A\u91CD\u590D\u51FA\u73B0\uFF0C\u53D1\u73B0\u5DF2\u5931\u6548\u6216\u6709\u8BEF\u7684\u8BB0\u5FC6\u7528 memory_delete \u6E05\u7406\u3002\u7C7B\u522B\u6309\u8BED\u4E49\u9009\uFF1Auser\uFF08\u7528\u6237\u753B\u50CF/\u504F\u597D\uFF09/ feedback\uFF08\u5DE5\u4F5C\u65B9\u5F0F\u53CD\u9988\uFF09/ project\uFF08\u9879\u76EE\u76EE\u6807/\u7EA6\u675F\uFF09/ reference\uFF08\u5916\u90E8\u8D44\u6E90\u6307\u9488\uFF09\u3002`;
14055
- }
14056
- });
14057
-
14058
14466
  // ../core/src/serve/chatProcessing.ts
14059
- import path46 from "path";
14060
- import fs43 from "fs";
14467
+ import path48 from "path";
14468
+ import fs46 from "fs";
14061
14469
  var handleUnifiedChat;
14062
14470
  var init_chatProcessing = __esm({
14063
14471
  "../core/src/serve/chatProcessing.ts"() {
@@ -14113,17 +14521,17 @@ ${inject}`;
14113
14521
  if (roots.length > 1) {
14114
14522
  let activeReal = getActiveWorkspaceRoot();
14115
14523
  try {
14116
- activeReal = fs43.realpathSync(activeReal);
14524
+ activeReal = fs46.realpathSync(activeReal);
14117
14525
  } catch {
14118
14526
  }
14119
- const lines = roots.map((r) => `- ${path46.basename(r) || r}: ${r}${r === activeReal ? "\uFF08\u9ED8\u8BA4\u6839\uFF1A\u76F8\u5BF9\u8DEF\u5F84/\u547D\u4EE4\u57FA\u51C6\uFF09" : "\uFF08\u53EF\u76F4\u63A5\u8BFB\u5199\uFF09"}`);
14527
+ const lines = roots.map((r) => `- ${path48.basename(r) || r}: ${r}${r === activeReal ? "\uFF08\u9ED8\u8BA4\u6839\uFF1A\u76F8\u5BF9\u8DEF\u5F84/\u547D\u4EE4\u57FA\u51C6\uFF09" : "\uFF08\u53EF\u76F4\u63A5\u8BFB\u5199\uFF09"}`);
14120
14528
  sysPrompt = sysPrompt + `
14121
14529
 
14122
14530
  \u3010\u5DE5\u4F5C\u533A\uFF08\u591A\u9879\u76EE\uFF09\u3011
14123
14531
  \u65E0\u9700\u5207\u6362\u9879\u76EE\uFF0C\u4EE5\u4E0B\u6240\u6709\u6839\u90FD\u53EF\u76F4\u63A5\u7528\u7EDD\u5BF9\u8DEF\u5F84\u8BBF\u95EE\uFF1B\u8DE8\u9879\u76EE\u7528\u7EDD\u5BF9\u8DEF\u5F84\u6216\u76F8\u5BF9\u9ED8\u8BA4\u6839\u7684 ../<\u5144\u5F1F\u76EE\u5F55>:
14124
14532
  ${lines.join("\n")}
14125
- \u2605 \u8DEF\u5F84\u951A\u5B9A\u94C1\u5F8B\uFF1A\u5DE5\u5177\u7F3A\u7701\u53EA\u4F5C\u7528\u4E8E\u9ED8\u8BA4\u6839\uFF08${path46.basename(activeReal) || activeReal} = IDE \u5934\u90E8\u6240\u793A\u6839\uFF09\u3002\u5F53\u7528\u6237\u5728\u5BF9\u8BDD\u4E2D\u6307\u660E\u4E86\u67D0\u4E2A\u9879\u76EE\uFF08\u5982\u300C\u5728 A \u9879\u76EE\u300D\u300C\u6539\u524D\u7AEF\u7684 xxx\u300D\u300C\u641C\u540E\u7AEF\u300D\uFF09\uFF0C\u8BE5\u8F6E\u6240\u6709\u5E26 path \u53C2\u6570\u7684\u5DE5\u5177\u8C03\u7528\uFF08read_file / edit_file / search_grep / glob / list_dir / read_xlsx / read_docx \u7B49\uFF09\u5FC5\u987B\u628A\u5BF9\u5E94\u9879\u76EE\u6839\u4F5C\u4E3A path \u4F20\u5165\uFF08\u7EDD\u5BF9\u8DEF\u5F84\u3001../<\u5144\u5F1F\u76EE\u5F55>\u3001\u6216\u9879\u76EE\u76EE\u5F55\u540D\uFF09\uFF0C\u5426\u5219\u53EA\u4F1A\u8BFB\u5199/\u641C\u7D22\u9ED8\u8BA4\u6839\uFF0C\u4E0E\u7528\u6237\u610F\u56FE\u4E0D\u7B26\u3002
14126
- \u6CE8\u610F\uFF1A\u9879\u76EE\u7EA7\u914D\u7F6E\uFF08.deepseeker-code/\uFF09\u4EC5\u5728\u9ED8\u8BA4\u6839 ${path46.basename(activeReal) || activeReal} \u751F\u6548\u3002`;
14533
+ \u2605 \u8DEF\u5F84\u951A\u5B9A\u94C1\u5F8B\uFF1A\u5DE5\u5177\u7F3A\u7701\u53EA\u4F5C\u7528\u4E8E\u9ED8\u8BA4\u6839\uFF08${path48.basename(activeReal) || activeReal} = IDE \u5934\u90E8\u6240\u793A\u6839\uFF09\u3002\u5F53\u7528\u6237\u5728\u5BF9\u8BDD\u4E2D\u6307\u660E\u4E86\u67D0\u4E2A\u9879\u76EE\uFF08\u5982\u300C\u5728 A \u9879\u76EE\u300D\u300C\u6539\u524D\u7AEF\u7684 xxx\u300D\u300C\u641C\u540E\u7AEF\u300D\uFF09\uFF0C\u8BE5\u8F6E\u6240\u6709\u5E26 path \u53C2\u6570\u7684\u5DE5\u5177\u8C03\u7528\uFF08read_file / edit_file / search_grep / glob / list_dir / read_xlsx / read_docx \u7B49\uFF09\u5FC5\u987B\u628A\u5BF9\u5E94\u9879\u76EE\u6839\u4F5C\u4E3A path \u4F20\u5165\uFF08\u7EDD\u5BF9\u8DEF\u5F84\u3001../<\u5144\u5F1F\u76EE\u5F55>\u3001\u6216\u9879\u76EE\u76EE\u5F55\u540D\uFF09\uFF0C\u5426\u5219\u53EA\u4F1A\u8BFB\u5199/\u641C\u7D22\u9ED8\u8BA4\u6839\uFF0C\u4E0E\u7528\u6237\u610F\u56FE\u4E0D\u7B26\u3002
14534
+ \u6CE8\u610F\uFF1A\u9879\u76EE\u7EA7\u914D\u7F6E\uFF08.deepseeker-code/\uFF09\u4EC5\u5728\u9ED8\u8BA4\u6839 ${path48.basename(activeReal) || activeReal} \u751F\u6548\u3002`;
14127
14535
  }
14128
14536
  const osName = process.platform === "win32" ? "Windows" : process.platform === "darwin" ? "macOS" : "Linux";
14129
14537
  const now = /* @__PURE__ */ new Date();
@@ -14167,7 +14575,8 @@ ${envLines.join("\n")}`;
14167
14575
  const options = {
14168
14576
  sessionId,
14169
14577
  cwd: process.cwd(),
14170
- toolSchemas: agentTools,
14578
+ toolSchemas: opts?.toolSchemas ?? agentTools,
14579
+ // 宿主可按需裁剪(挂机批处理);缺省全量,行为不变
14171
14580
  abortSignal,
14172
14581
  // ← 透传中止信号
14173
14582
  modelWindow: appConfig.MAX_HISTORY_TOKENS,
@@ -14188,7 +14597,9 @@ ${envLines.join("\n")}`;
14188
14597
  model: opts?.model,
14189
14598
  thinkingLevel: opts?.thinkingLevel,
14190
14599
  locale: opts?.locale,
14191
- outputStyle: opts?.outputStyle
14600
+ outputStyle: opts?.outputStyle,
14601
+ budgetYuan: opts?.budgetYuan
14602
+ // ★ 预算制运行(成本信任链第二环 E1):主 run 传入,子 run 经 costSink 回灌
14192
14603
  };
14193
14604
  await runWithSessionContext(sessionId, async () => {
14194
14605
  try {
@@ -14229,7 +14640,7 @@ ${envLines.join("\n")}`;
14229
14640
  });
14230
14641
 
14231
14642
  // ../core/src/session/fork.ts
14232
- import fs44 from "fs/promises";
14643
+ import fs47 from "fs/promises";
14233
14644
  var listForkAnchors, derivePrefix, forkSession;
14234
14645
  var init_fork = __esm({
14235
14646
  "../core/src/session/fork.ts"() {
@@ -14302,7 +14713,7 @@ var init_fork = __esm({
14302
14713
  const prefix = derivePrefix(lines, upToLineId);
14303
14714
  const newId = createUUID();
14304
14715
  await ensureSessionsDir(newId);
14305
- const rawText = await fs44.readFile(getTranscriptPath(sourceId), "utf-8");
14716
+ const rawText = await fs47.readFile(getTranscriptPath(sourceId), "utf-8");
14306
14717
  const kept = [];
14307
14718
  let good = 0;
14308
14719
  for (const s of rawText.split("\n")) {
@@ -14318,7 +14729,7 @@ var init_fork = __esm({
14318
14729
  }
14319
14730
  let payload = kept.join("\n");
14320
14731
  if (payload.length > 0 && !payload.endsWith("\n")) payload += "\n";
14321
- await fs44.writeFile(getTranscriptPath(newId), payload, "utf-8");
14732
+ await fs47.writeFile(getTranscriptPath(newId), payload, "utf-8");
14322
14733
  const srcState = await readStore(sourceId);
14323
14734
  const srcRolling = await getRollingState(sourceId);
14324
14735
  const legacy = !lines.some(isEventLine);
@@ -14664,6 +15075,11 @@ var init_useChatState = __esm({
14664
15075
  !MODEL_THINKING_ENABLED ? "off" : MODEL_REASONING_EFFORT === "max" ? "max" : "high"
14665
15076
  );
14666
15077
  const archivedSummaryRef = useRef("");
15078
+ const lastRunCostRef = useRef(void 0);
15079
+ const sessionCostRef = useRef(void 0);
15080
+ const budgetYuanRef = useRef(void 0);
15081
+ const lastRunCacheHitRef = useRef(void 0);
15082
+ const contextUsageRef = useRef(void 0);
14667
15083
  const compactProgressIdRef = useRef(null);
14668
15084
  const dropCompactProgressRow = useCallback(() => {
14669
15085
  const pid = compactProgressIdRef.current;
@@ -14841,6 +15257,34 @@ var init_useChatState = __esm({
14841
15257
  }]);
14842
15258
  break;
14843
15259
  }
15260
+ case "run.receipt": {
15261
+ flush();
15262
+ const rounds = obj.rounds ?? 0;
15263
+ const promptT = obj.promptTokens ?? 0;
15264
+ const completionT = obj.completionTokens ?? 0;
15265
+ const hitPct = Math.round((obj.cacheHitRate ?? 0) * 100);
15266
+ const durMs = obj.durationMs ?? 0;
15267
+ const durText = durMs >= 6e4 ? `${Math.floor(durMs / 6e4)}m${Math.round(durMs % 6e4 / 1e3)}s` : `${(durMs / 1e3).toFixed(1)}s`;
15268
+ const cost = obj.costYuan;
15269
+ const tokTotal = promptT + completionT;
15270
+ const tokText = tokTotal >= 1e4 ? `${(tokTotal / 1e3).toFixed(1)}k` : String(tokTotal);
15271
+ const costText = typeof cost === "number" ? `\xA5${cost.toFixed(cost < 5e-3 ? 4 : 3)}` : `${tokText} tok`;
15272
+ setRows((prev) => [...prev, {
15273
+ id: newRowId(),
15274
+ kind: "meta",
15275
+ text: `\u{1F4B0} \u672C\u6B21 ${rounds} \u8F6E \xB7 ${costText} \xB7 \u7F13\u5B58\u547D\u4E2D ${hitPct}% \xB7 ${durText}${obj.budgetTruncated ? " \xB7 \u9884\u7B97\u622A\u65AD" : ""}`
15276
+ }]);
15277
+ lastRunCostRef.current = typeof cost === "number" ? cost : void 0;
15278
+ sessionCostRef.current = typeof cost === "number" ? (sessionCostRef.current ?? 0) + cost : sessionCostRef.current;
15279
+ lastRunCacheHitRef.current = typeof obj.cacheHitRate === "number" ? obj.cacheHitRate : void 0;
15280
+ break;
15281
+ }
15282
+ case "context.usage": {
15283
+ const used = obj.usedTokens ?? 0;
15284
+ const win = obj.windowTokens ?? 0;
15285
+ if (win > 0) contextUsageRef.current = { used_tokens: used, window_tokens: win, fill_rate: used / win };
15286
+ break;
15287
+ }
14844
15288
  case "task.exit": {
14845
15289
  flush();
14846
15290
  const cmd = obj.command ?? "";
@@ -15006,7 +15450,9 @@ var init_useChatState = __esm({
15006
15450
  model: modelRef.current || void 0,
15007
15451
  thinkingLevel: thinkingLevelRef.current,
15008
15452
  locale: getLocale(),
15009
- outputStyle: outputStyleRef.current
15453
+ outputStyle: outputStyleRef.current,
15454
+ budgetYuan: budgetYuanRef.current
15455
+ // ★ 预算制运行(成本信任链第二环 E1):/budget 设置,超限 soft nudge + 120% 硬截断
15010
15456
  };
15011
15457
  try {
15012
15458
  await handleUnifiedChat(
@@ -15143,6 +15589,10 @@ ${r.output.trim() || "(\u65E0\u8F93\u51FA)"}`);
15143
15589
  }, [flush]);
15144
15590
  const loadSession = useCallback(async (id) => {
15145
15591
  sessionIdRef.current = id;
15592
+ lastRunCostRef.current = void 0;
15593
+ sessionCostRef.current = void 0;
15594
+ lastRunCacheHitRef.current = void 0;
15595
+ contextUsageRef.current = void 0;
15146
15596
  clearRows();
15147
15597
  try {
15148
15598
  const lines = await readTranscriptLines(id);
@@ -15169,6 +15619,10 @@ ${r.output.trim() || "(\u65E0\u8F93\u51FA)"}`);
15169
15619
  }, [pushInfo, loadSession]);
15170
15620
  const newSession = useCallback(async () => {
15171
15621
  sessionIdRef.current = await getOrCreateSessionId(void 0);
15622
+ lastRunCostRef.current = void 0;
15623
+ sessionCostRef.current = void 0;
15624
+ lastRunCacheHitRef.current = void 0;
15625
+ contextUsageRef.current = void 0;
15172
15626
  clearRows();
15173
15627
  pushInfo(S.sessionNew(truncateMiddle(sessionIdRef.current, 12)));
15174
15628
  }, [clearRows, pushInfo]);
@@ -15238,6 +15692,14 @@ ${r.output.trim() || "(\u65E0\u8F93\u51FA)"}`);
15238
15692
  }, []);
15239
15693
  const getOutputStyle2 = useCallback(() => outputStyleRef.current, []);
15240
15694
  const getArchivedSummary = useCallback(() => archivedSummaryRef.current, []);
15695
+ const getLastRunCostYuan = useCallback(() => lastRunCostRef.current, []);
15696
+ const getSessionCostYuan = useCallback(() => sessionCostRef.current, []);
15697
+ const getLastRunCacheHitRate = useCallback(() => lastRunCacheHitRef.current, []);
15698
+ const getLastContextUsage = useCallback(() => contextUsageRef.current, []);
15699
+ const setBudgetYuan = useCallback((v) => {
15700
+ budgetYuanRef.current = v;
15701
+ }, []);
15702
+ const getBudgetYuan = useCallback(() => budgetYuanRef.current, []);
15241
15703
  return {
15242
15704
  // 状态
15243
15705
  rows,
@@ -15277,6 +15739,12 @@ ${r.output.trim() || "(\u65E0\u8F93\u51FA)"}`);
15277
15739
  setOutputStyle,
15278
15740
  getOutputStyle: getOutputStyle2,
15279
15741
  getArchivedSummary,
15742
+ getLastRunCostYuan,
15743
+ getSessionCostYuan,
15744
+ setBudgetYuan,
15745
+ getBudgetYuan,
15746
+ getLastRunCacheHitRate,
15747
+ getLastContextUsage,
15280
15748
  openSessionPicker,
15281
15749
  resolveSession,
15282
15750
  loadSession,
@@ -16385,7 +16853,7 @@ var init_TopPanel = __esm({
16385
16853
  });
16386
16854
 
16387
16855
  // ../core/src/observability/inspect.ts
16388
- import fs45 from "fs";
16856
+ import fs48 from "fs";
16389
16857
  var CWD, fmt, readTrace, STOP_LABEL, fmtK, inspectUsage, inspectContext, inspectPermissions, inspectMcp, inspectHooks, inspectDebug;
16390
16858
  var init_inspect = __esm({
16391
16859
  "../core/src/observability/inspect.ts"() {
@@ -16396,7 +16864,11 @@ var init_inspect = __esm({
16396
16864
  init_loader();
16397
16865
  init_store3();
16398
16866
  init_usageLog();
16867
+ init_prices();
16399
16868
  init_store();
16869
+ init_sidecar();
16870
+ init_truncate();
16871
+ init_recall();
16400
16872
  init_createModel();
16401
16873
  CWD = process.cwd();
16402
16874
  fmt = (n) => typeof n === "number" && Number.isFinite(n) ? n.toLocaleString("en-US") : "-";
@@ -16404,7 +16876,7 @@ var init_inspect = __esm({
16404
16876
  if (!sessionId) return [];
16405
16877
  try {
16406
16878
  const p = await getTraceStorePath(sessionId);
16407
- const text = await fs45.promises.readFile(p, "utf8");
16879
+ const text = await fs48.promises.readFile(p, "utf8");
16408
16880
  const out = [];
16409
16881
  for (const line of text.split("\n")) {
16410
16882
  if (!line.trim()) continue;
@@ -16456,7 +16928,8 @@ var init_inspect = __esm({
16456
16928
  lines.push(` ${String(r.ts).slice(5, 16).replace("T", " ")} ${r.rounds}\u8F6E ${fmtK(r.totalTokens ?? 0)} tok ${STOP_LABEL[r.stopReason] ?? r.stopReason} ${tools}`);
16457
16929
  }
16458
16930
  }
16459
- const week = summarizeUsage(await readUsageRecords(7));
16931
+ const weekRecords = await readUsageRecords(7);
16932
+ const week = summarizeUsage(weekRecords);
16460
16933
  if (week.runs > 0) {
16461
16934
  const weekHit = week.promptTokens > 0 ? (week.cachedTokens / week.promptTokens * 100).toFixed(1) : "0.0";
16462
16935
  const weekAbort = week.mainRuns > 0 ? Math.round(week.stopReasons.aborted / week.mainRuns * 100) : 0;
@@ -16466,6 +16939,23 @@ var init_inspect = __esm({
16466
16939
  ` \u258E\u8FD1 7 \u5929\uFF08\u4F7F\u7528\u65E5\u5FD7 \xB7 \u5168\u9879\u76EE\uFF09\uFF1A${week.mainRuns} runs \xB7 ${week.mainRounds} \u8F6E\uFF08\u5747 ${weekAvg} \u8F6E/run\uFF09\xB7 \u4E2D\u6B62 ${weekAbort}% \xB7 ${fmtK(week.totalTokens)} tok\uFF08\u7F13\u5B58\u547D\u4E2D ${weekHit}%\uFF09`,
16467
16940
  ` \u5E38\u7528\u5DE5\u5177: ${tools || "\uFF08\u65E0\uFF09"}`
16468
16941
  );
16942
+ const bySession = /* @__PURE__ */ new Map();
16943
+ let weekCost = 0, weekSaved = 0, pricedRuns = 0;
16944
+ for (const r of weekRecords) {
16945
+ const c = r.costYuan ?? calcCostYuan(r.model, r);
16946
+ if (c == null) continue;
16947
+ pricedRuns++;
16948
+ weekCost += c;
16949
+ bySession.set(r.sessionId, (bySession.get(r.sessionId) ?? 0) + c);
16950
+ const p = priceFor(r.model);
16951
+ if (p) weekSaved += (r.cachedTokens ?? 0) * (p.input - p.cacheHit) / 1e6;
16952
+ }
16953
+ if (pricedRuns > 0) {
16954
+ const tops = [...bySession.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3).map(([sid, c]) => `${sid.slice(0, 8)} \xA5${c.toFixed(3)}`).join(" \xB7 ");
16955
+ const unpaid = week.runs - pricedRuns;
16956
+ lines.push(` \u8FD1 7 \u5929\u82B1\u8D39 \xA5${weekCost.toFixed(3)}\uFF08\u7F13\u5B58\u547D\u4E2D\u5DF2\u7701 \xA5${weekSaved.toFixed(3)}\uFF09${unpaid > 0 ? ` \xB7 ${unpaid} \u6761\u65E0\u4EF7\u8BB0\u5F55\u672A\u8BA1` : ""}`);
16957
+ if (tops) lines.push(` \u8D39\u7528 top \u4F1A\u8BDD: ${tops}`);
16958
+ }
16469
16959
  }
16470
16960
  lines.push(` \u63D0\u793A\uFF1A\u5E76\u884C workflow \u4F1A\u653E\u5927\u5B50 agent \u7528\u91CF\uFF1B\u7F13\u5B58\u547D\u4E2D\u7387\u8D8A\u9AD8\uFF0C\u8F93\u5165\u6210\u672C\u8D8A\u4F4E\u3002`);
16471
16961
  return lines.join("\n");
@@ -16481,8 +16971,16 @@ var init_inspect = __esm({
16481
16971
  }
16482
16972
  }
16483
16973
  let archived = 0;
16974
+ let archivedEntities = 0;
16975
+ try {
16976
+ const rolling = await getRollingState(sessionId);
16977
+ archived = rolling.archivedMessageCount ?? 0;
16978
+ archivedEntities = parseSummarySlot(rolling.rollingSummary ?? "").index.length;
16979
+ } catch {
16980
+ }
16981
+ let sidecarCount = 0;
16484
16982
  try {
16485
- archived = (await getRollingState(sessionId)).archivedMessageCount ?? 0;
16983
+ sidecarCount = (await fs48.promises.readdir(getToolOutputSidecarDir(sessionId))).filter((f) => f.endsWith(".txt")).length;
16486
16984
  } catch {
16487
16985
  }
16488
16986
  const window = appConfig.MAX_HISTORY_TOKENS;
@@ -16494,6 +16992,9 @@ var init_inspect = __esm({
16494
16992
  ` \u7A97\u53E3\u4E0A\u9650: ${fmt(window)} | \u538B\u7F29\u9608\u503C: ${fmt(threshold)}\uFF08${ratio}\xD7\uFF09 | \u4FDD\u7559\u6700\u8FD1: ${appConfig.KEEP_RECENT_UNITS} \u5BF9\u8BDD\u5355\u5143`,
16495
16993
  ` \u6700\u8FD1 prompt: ${lastPrompt ? fmt(lastPrompt) : "\uFF08\u5C1A\u65E0\uFF09"}${fillRate ? `\uFF08\u5360\u7A97\u53E3 ${fillRate}%\uFF09` : ""}`,
16496
16994
  ` \u5DF2\u5F52\u6863(\u538B\u7F29)\u6D88\u606F\u6761\u6570: ${archived}`,
16995
+ ` \u672C\u4F1A\u8BDD\u5DF2\u5F52\u6863\u5B9E\u4F53: ${archivedEntities} \u4E2A\uFF08\u6458\u8981\u69FD\u7D22\u5F15\uFF09`,
16996
+ ` \u53EC\u56DE\u547D\u4E2D: ${getRecallHitCount(sessionId)} \u6B21\uFF08recall \u5DE5\u5177\uFF0C\u672C\u6B21\u8FDB\u7A0B\u5185\u8BA1\u6570\uFF09`,
16997
+ ` \u4FA7\u8F66\u5B58\u6863: ${sidecarCount} \u6761\uFF08\u8D85\u957F\u5DE5\u5177\u7ED3\u679C\u539F\u6587\uFF0Crecall with_full \u53D6\u56DE\uFF09`,
16497
16998
  ` \u8D85\u8FC7\u9608\u503C\u5373\u89E6\u53D1\u6EDA\u52A8\u538B\u7F29\uFF1BfillRate \u63A5\u8FD1 ${Math.round(ratio * 100)}% \u65F6\u5373\u5C06\u538B\u7F29\u3002`
16498
16999
  ].join("\n");
16499
17000
  };
@@ -16664,14 +17165,21 @@ var init_App = __esm({
16664
17165
  plan_mode: state.getPlanMode(),
16665
17166
  auto_mode: state.getAutoMode(),
16666
17167
  output_style: state.getOutputStyle() ?? null,
16667
- workspace: { current_dir: CWD2, project_dir: CWD2 }
17168
+ workspace: { current_dir: CWD2, project_dir: CWD2 },
17169
+ last_run_cost_yuan: state.getLastRunCostYuan(),
17170
+ // 结算单(成本信任链 D3):undefined 自动省略键
17171
+ session_cost_yuan: state.getSessionCostYuan(),
17172
+ last_run_cache_hit_rate: state.getLastRunCacheHitRate(),
17173
+ // H3:undefined 自动省略键
17174
+ context: state.getLastContextUsage()
17175
+ // H3 水位:undefined 自动省略键
16668
17176
  };
16669
17177
  const text = await runStatusLine(cfg, ctx);
16670
17178
  if (text) setStatusLineText(text);
16671
17179
  } finally {
16672
17180
  statusLineRunRef.current = false;
16673
17181
  }
16674
- }, [modelDisplay, state.busy, state.aborting, state.getPlanMode, state.getAutoMode, state.getOutputStyle, state.sessionIdRef]);
17182
+ }, [modelDisplay, state.busy, state.aborting, state.getPlanMode, state.getAutoMode, state.getOutputStyle, state.sessionIdRef, state.getLastRunCostYuan, state.getSessionCostYuan, state.getLastRunCacheHitRate, state.getLastContextUsage]);
16675
17183
  const refreshStatusLineRef = useRef2(refreshStatusLine);
16676
17184
  refreshStatusLineRef.current = refreshStatusLine;
16677
17185
  useEffect4(() => {
@@ -16731,6 +17239,8 @@ var init_App = __esm({
16731
17239
  return S.cmdFork;
16732
17240
  case "usage":
16733
17241
  return S.cmdUsage;
17242
+ case "budget":
17243
+ return S.cmdBudget;
16734
17244
  case "context":
16735
17245
  return S.cmdContext;
16736
17246
  case "permissions":
@@ -16880,6 +17390,28 @@ ${s}` : "\u672C\u4F1A\u8BDD\u542F\u52A8\u4EE5\u6765\u5C1A\u672A\u53D1\u751F\u8FC
16880
17390
  state.pushInfo(`\u8BA1\u5212\u6A21\u5F0F\uFF1A${on ? "\u5F00\uFF08\u4E0B\u6B21\u63D0\u95EE\u5148\u53EA\u8BFB\u8C03\u7814\u5E76\u4EA7\u51FA\u65B9\u6848\uFF0C\u5BA1\u6279\u540E\u5B9E\u73B0\uFF09" : "\u5173"}`);
16881
17391
  return true;
16882
17392
  }
17393
+ case "/budget": {
17394
+ const v = arg.trim().toLowerCase();
17395
+ if (!v) {
17396
+ const b = state.getBudgetYuan();
17397
+ const last = state.getLastRunCostYuan();
17398
+ state.pushInfo(`\u{1F4B0} \u9884\u7B97\uFF1A${b != null ? `\xA5${b}/run` : "\u672A\u8BBE\u7F6E\uFF08/budget 0.5 \u8BBE\u7F6E\u6BCF\u4E2A run \u7684\u82B1\u8D39\u4E0A\u9650\uFF09"}${last != null ? ` \xB7 \u4E0A\u4E2A run \u5DF2\u82B1 \xA5${last.toFixed(3)}` : " \xB7 \u5C1A\u65E0\u5B8C\u6210 run"}`);
17399
+ return true;
17400
+ }
17401
+ if (v === "off" || v === "0") {
17402
+ state.setBudgetYuan(void 0);
17403
+ state.pushInfo("\u{1F4B0} \u9884\u7B97\u5DF2\u5173\u95ED\uFF08\u4E0D\u9650\u82B1\u8D39\uFF09\u3002");
17404
+ return true;
17405
+ }
17406
+ const n = Number(v);
17407
+ if (!Number.isFinite(n) || n <= 0) {
17408
+ state.pushInfo("\u7528\u6CD5\uFF1A/budget 0.5\uFF08\u5143/run\uFF09\xB7 /budget off \xB7 /budget \u67E5\u770B");
17409
+ return true;
17410
+ }
17411
+ state.setBudgetYuan(n);
17412
+ state.pushInfo(`\u{1F4B0} \u9884\u7B97\u5DF2\u8BBE\u7F6E\uFF1A\u6BCF run \xA5${n}\uFF08\u8D85\u9650\u5148\u63D0\u9192\u6536\u655B\uFF0C\u4ECD\u8D85 120% \u5C06\u622A\u65AD\u672C run\uFF09\u3002`);
17413
+ return true;
17414
+ }
16883
17415
  case "/auto": {
16884
17416
  const on = !state.getAutoMode();
16885
17417
  state.setAutoMode(on);
@@ -17253,6 +17785,370 @@ ${listText}`);
17253
17785
  }
17254
17786
  });
17255
17787
 
17788
+ // src/batchRunner.ts
17789
+ var batchRunner_exports = {};
17790
+ __export(batchRunner_exports, {
17791
+ parseWaitWindow: () => parseWaitWindow,
17792
+ runBatchQueue: () => runBatchQueue
17793
+ });
17794
+ import fs49 from "fs";
17795
+ import { spawn as spawn6 } from "child_process";
17796
+ var BATCH_EDIT_TOOLS, BATCH_DEFAULT_DENYLIST, ACCEPT_TIMEOUT_MIN, ACCEPT_TAIL_LINES, emit2, ts, STATUS_LABEL, runAcceptCommand, collectSessionCost, fmtCost, fmtReceiptLine, buildReport, runOneTask, parseWaitWindow, nowMinutes, sleep, waitUntilWindow, runBatchQueue;
17797
+ var init_batchRunner = __esm({
17798
+ "src/batchRunner.ts"() {
17799
+ "use strict";
17800
+ init_chatProcessing();
17801
+ init_tool();
17802
+ init_manager();
17803
+ init_sessionRegistry();
17804
+ init_background();
17805
+ init_guard();
17806
+ init_common();
17807
+ init_usageLog();
17808
+ init_ticket();
17809
+ init_queue();
17810
+ BATCH_EDIT_TOOLS = /* @__PURE__ */ new Set(["edit_file", "create_file", "write_file", "move_file", "notebook_edit"]);
17811
+ BATCH_DEFAULT_DENYLIST = /* @__PURE__ */ new Set(["run_command", "delete_path"]);
17812
+ ACCEPT_TIMEOUT_MIN = 10;
17813
+ ACCEPT_TAIL_LINES = 60;
17814
+ emit2 = (s = "") => {
17815
+ process.stdout.write(s + "\n");
17816
+ };
17817
+ ts = () => (/* @__PURE__ */ new Date()).toLocaleTimeString("zh-CN", { hour12: false });
17818
+ STATUS_LABEL = {
17819
+ passed: "\u2705 \u901A\u8FC7\u9A8C\u6536",
17820
+ "accept-failed": "\u274C \u9A8C\u6536\u672A\u8FC7",
17821
+ timeout: "\u23F1\uFE0F \u8D85\u65F6\u622A\u65AD",
17822
+ error: "\u{1F4A5} agent \u5F02\u5E38",
17823
+ rejected: "\u{1F6AB} \u5DE5\u5355\u88AB\u62D2"
17824
+ };
17825
+ runAcceptCommand = async (cmd, cwd) => {
17826
+ const isWin = process.platform === "win32";
17827
+ return new Promise((resolve) => {
17828
+ let child;
17829
+ try {
17830
+ child = spawn6(cmd, {
17831
+ shell: isWin ? resolveWinShell() ?? true : true,
17832
+ cwd,
17833
+ windowsHide: true,
17834
+ env: scrubCommandEnv()
17835
+ // 剔除 agent 自身凭证(同 run_command 红线)
17836
+ });
17837
+ } catch (e) {
17838
+ resolve({ code: null, output: `\u542F\u52A8\u5931\u8D25\uFF1A${e?.message ?? e}`, timedOut: false });
17839
+ return;
17840
+ }
17841
+ const chunks = [];
17842
+ child.stdout?.on("data", (d) => chunks.push(d));
17843
+ child.stderr?.on("data", (d) => chunks.push(d));
17844
+ let timedOut = false;
17845
+ const killer = setTimeout(() => {
17846
+ timedOut = true;
17847
+ try {
17848
+ child.kill("SIGKILL");
17849
+ } catch {
17850
+ }
17851
+ }, ACCEPT_TIMEOUT_MIN * 6e4);
17852
+ child.on("error", (e) => {
17853
+ clearTimeout(killer);
17854
+ resolve({ code: null, output: `\u6267\u884C\u5931\u8D25\uFF1A${e?.message ?? e}`, timedOut });
17855
+ });
17856
+ child.on("close", (code) => {
17857
+ clearTimeout(killer);
17858
+ const text = decodeProcessOutput(Buffer.concat(chunks)).trim();
17859
+ const lines = text.split("\n");
17860
+ const tail = lines.length > ACCEPT_TAIL_LINES ? `\uFF08\u524D ${lines.length - ACCEPT_TAIL_LINES} \u884C\u5DF2\u7701\u7565\uFF09
17861
+ ${lines.slice(-ACCEPT_TAIL_LINES).join("\n")}` : text;
17862
+ resolve({ code, output: tail || "\uFF08\u65E0\u8F93\u51FA\uFF09", timedOut });
17863
+ });
17864
+ });
17865
+ };
17866
+ collectSessionCost = async (sessionId) => {
17867
+ const recs = (await readUsageRecords(2)).filter((r) => r.sessionId === sessionId);
17868
+ const c = { rounds: 0, mainRounds: 0, subRuns: 0, promptTokens: 0, completionTokens: 0, cachedTokens: 0, costYuan: null, partialPrice: false, durationMs: 0 };
17869
+ for (const r of recs) {
17870
+ c.rounds += r.rounds || 0;
17871
+ if (r.depth === 0) c.mainRounds += r.rounds || 0;
17872
+ else c.subRuns++;
17873
+ c.promptTokens += r.promptTokens ?? 0;
17874
+ c.completionTokens += r.completionTokens ?? 0;
17875
+ c.cachedTokens += r.cachedTokens ?? 0;
17876
+ c.durationMs += r.durationMs || 0;
17877
+ if (typeof r.costYuan === "number") c.costYuan = (c.costYuan ?? 0) + r.costYuan;
17878
+ else c.partialPrice = true;
17879
+ }
17880
+ if (c.costYuan === null) c.partialPrice = false;
17881
+ return c;
17882
+ };
17883
+ fmtCost = (c) => {
17884
+ const money = c.costYuan !== null ? `\xA5${c.costYuan.toFixed(4)}` : "\uFF08\u65E0\u4EF7\u6A21\u578B\uFF0C\u4E0D\u8BA1\u94B1\uFF09";
17885
+ const hit = c.promptTokens > 0 ? Math.round(c.cachedTokens / c.promptTokens * 100) : 0;
17886
+ const mins = Math.round(c.durationMs / 6e3) / 10;
17887
+ return `${c.rounds} \u8F6E \xB7 ${money} \xB7 \u7F13\u5B58\u547D\u4E2D ${hit}% \xB7 ${mins}min${c.partialPrice ? "\uFF08\u90E8\u5206\u8BB0\u5F55\u65E0\u4EF7\uFF0C\u94B1\u4E3A\u90E8\u5206\u548C\uFF09" : ""}${c.subRuns > 0 ? ` \xB7 \u5B50 run ${c.subRuns} \u4E2A\u5DF2\u8BA1\u5165` : ""}`;
17888
+ };
17889
+ fmtReceiptLine = (receipt) => {
17890
+ if (!receipt) return "\uFF08\u65E0\u7ED3\u7B97\u5355\u2014\u2014run \u672A\u5230\u6536\u5C3E\u5373\u88AB\u622A\u65AD\uFF0C\u82B1\u8D39\u4EE5\u4E0A\u65B9 usageLog \u805A\u5408\u4E3A\u51C6\uFF09";
17891
+ return `${receipt.rounds} \u8F6E \xB7 ${receipt.costYuan !== null ? `\xA5${receipt.costYuan.toFixed(4)}` : "\u65E0\u4EF7"} \xB7 \u7F13\u5B58\u547D\u4E2D ${Math.round(receipt.cacheHitRate * 100)}% \xB7 ${(receipt.durationMs / 1e3).toFixed(0)}s`;
17892
+ };
17893
+ buildReport = (args) => {
17894
+ const { id, ticket, status, budgetTruncated, cost, receipt, finalText, accept, deniedTools, diff, wt } = args;
17895
+ const budgetNote = budgetTruncated ? "\uFF08\u26A0\uFE0F \u9884\u7B97\u622A\u65AD\u540E\u6536\u5C3E\uFF09" : "";
17896
+ return `---
17897
+ id: ${id}
17898
+ title: ${ticket.title}
17899
+ status: ${status}
17900
+ cost-yuan: ${cost.costYuan !== null ? cost.costYuan.toFixed(4) : "null"}
17901
+ rounds: ${cost.rounds}
17902
+ budget-truncated: ${budgetTruncated}
17903
+ session: batch-${id}
17904
+ worktree: ${wt?.path ?? "\uFF08\u672A\u521B\u5EFA\uFF09"}
17905
+ branch: ${wt?.branch ?? "\uFF08\u672A\u521B\u5EFA\uFF09"}
17906
+ ---
17907
+
17908
+ # \u6302\u673A\u4EFB\u52A1\u62A5\u544A\uFF1A${ticket.title}
17909
+
17910
+ - \u72B6\u6001\uFF1A${STATUS_LABEL[status]}${budgetNote}
17911
+ - \u7ED3\u7B97\u5355\uFF1A${fmtCost(cost)}
17912
+ - \u672C\u8F6E receipt\uFF1A${fmtReceiptLine(receipt)}
17913
+ ${args.errorMessage ? `- \u5F02\u5E38\uFF1A${args.errorMessage}
17914
+ ` : ""}
17915
+ ## \u4EFB\u52A1
17916
+
17917
+ ${ticket.body}
17918
+
17919
+ ## \u6A21\u578B\u6536\u5C3E\u6C47\u62A5
17920
+
17921
+ ${finalText.trim() || "\uFF08\u65E0\u8F93\u51FA\u2014\u2014run \u5728\u4EA7\u51FA\u6B63\u6587\u524D\u88AB\u622A\u65AD/\u5F02\u5E38\uFF09"}
17922
+
17923
+ ## \u9A8C\u6536
17924
+ ${accept ? `
17925
+ \u547D\u4EE4\uFF1A\`${accept.cmd}\` \u2192 exit ${accept.code}${accept.timedOut ? "\uFF08\u23F1\uFE0F \u9A8C\u6536\u8D85\u65F6\u88AB\u6740\uFF09" : ""}
17926
+
17927
+ \u8F93\u51FA\u5C3E\u90E8\uFF1A
17928
+
17929
+ \`\`\`
17930
+ ${accept.output}
17931
+ \`\`\`
17932
+ ` : "\n\uFF08\u672A\u6267\u884C\u9A8C\u6536\u2014\u2014\u6539\u52A8\u4E0D\u5B8C\u6574\uFF0C\u8DD1\u4E86\u4E5F\u662F\u566A\u58F0\uFF09"}
17933
+
17934
+ ## \u88AB\u62D2\u5DE5\u5177\u8C03\u7528\uFF08fail-closed \u8BB0\u5F55\uFF09
17935
+
17936
+ ${deniedTools.length === 0 ? "\u65E0\u3002" : deniedTools.map((d) => `- **${d.tool}** \u2014 ${d.detail}`).join("\n")}
17937
+
17938
+ ## Diff \u6458\u8981\uFF08worktree \u76F8\u5BF9\u57FA\u5EA7\uFF0C\u672A\u63D0\u4EA4\uFF0C\u5F85\u4EBA\u5DE5\u5904\u7F6E\uFF09
17939
+
17940
+ \u6539\u52A8\u5728\u72EC\u7ACB worktree\uFF08\u5206\u652F \`${wt?.branch ?? "?"}\`\uFF0C\u8DEF\u5F84 ${wt?.path ?? "?"}\uFF09\u3002\u5904\u7F6E\uFF1A\u68C0\u67E5\u6EE1\u610F \u2192 \u5728 worktree \u5185 commit \u5E76\u5408\u56DE\u4E3B\u4ED3\uFF1B\u4E22\u5F03 \u2192 \u5220\u9664\u8BE5 worktree \u76EE\u5F55 + \`git worktree prune\` + \`git branch -D <\u5206\u652F>\`\u3002
17941
+
17942
+ \`\`\`\`\`diff
17943
+ ${diff}
17944
+ \`\`\`\`\`
17945
+ `;
17946
+ };
17947
+ runOneTask = async (task) => {
17948
+ const source = await fs49.promises.readFile(task.path, "utf-8");
17949
+ const parsed = parseBatchTicket(source);
17950
+ if (!parsed.ok) {
17951
+ const cost2 = { rounds: 0, mainRounds: 0, subRuns: 0, promptTokens: 0, completionTokens: 0, cachedTokens: 0, costYuan: 0, partialPrice: false, durationMs: 0 };
17952
+ await finishTicket(task.id, `---
17953
+ id: ${task.id}
17954
+ title: ${task.id}
17955
+ status: rejected
17956
+ ---
17957
+
17958
+ # \u6302\u673A\u4EFB\u52A1\u88AB\u62D2
17959
+
17960
+ ${parsed.error}`);
17961
+ emit2(`\u{1F6AB} [${task.id}] \u5DE5\u5355\u88AB\u62D2\uFF1A${parsed.error}`);
17962
+ return { status: "rejected", cost: cost2, budgetTruncated: false };
17963
+ }
17964
+ const t = parsed.ticket;
17965
+ const sessionId = `batch-${task.id}`;
17966
+ const timeoutMin = t.timeoutMin ?? 30;
17967
+ emit2(`\u25B6 [${task.id}] ${t.title}`);
17968
+ emit2(` \u9884\u7B97 ${t.budgetYuan !== void 0 ? `\xA5${t.budgetYuan}` : "\u4E0D\u9650"} \xB7 \u8D85\u65F6 ${timeoutMin}min \xB7 \u9A8C\u6536 \`${t.accept}\``);
17969
+ const unlocked = new Set(t.tools ?? []);
17970
+ const denySchemas = new Set([...BATCH_DEFAULT_DENYLIST].filter((n) => !unlocked.has(n)));
17971
+ const toolSchemas = agentTools.filter((x) => !denySchemas.has(x?.function?.name));
17972
+ const allowApproval = /* @__PURE__ */ new Set([...BATCH_EDIT_TOOLS, ...unlocked]);
17973
+ const deniedTools = [];
17974
+ let wt = null;
17975
+ try {
17976
+ wt = await createWorktree(sessionId, task.id);
17977
+ } catch (e) {
17978
+ const msg = `\u521B\u5EFA worktree \u5931\u8D25\uFF08\u9700\u8981\u4E3B\u5DE5\u4F5C\u533A\u662F git \u4ED3\u5E93\uFF09\uFF1A${e?.message ?? e}`;
17979
+ const cost2 = await collectSessionCost(sessionId);
17980
+ await finishTicket(task.id, buildReport({
17981
+ id: task.id,
17982
+ ticket: t,
17983
+ status: "error",
17984
+ budgetTruncated: false,
17985
+ cost: cost2,
17986
+ receipt: void 0,
17987
+ finalText: "",
17988
+ accept: null,
17989
+ deniedTools: [],
17990
+ diff: "\uFF08\u65E0\uFF09",
17991
+ wt: null,
17992
+ errorMessage: msg
17993
+ }));
17994
+ emit2(`\u{1F4A5} [${task.id}] ${msg}`);
17995
+ return { status: "error", cost: cost2, budgetTruncated: false };
17996
+ }
17997
+ setSessionWorktree(sessionId, wt);
17998
+ const ac = new AbortController();
17999
+ const timer = setTimeout(() => ac.abort(new Error(`\u4EFB\u52A1\u8D85\u65F6\uFF08${timeoutMin} \u5206\u949F\uFF09`)), timeoutMin * 6e4);
18000
+ let receipt;
18001
+ let finalText = "";
18002
+ let agentError;
18003
+ try {
18004
+ await handleUnifiedChat(
18005
+ { sessionId, content: t.body },
18006
+ async () => {
18007
+ },
18008
+ (evt) => {
18009
+ if (evt?.type === "text.delta") finalText += evt.text;
18010
+ else if (evt?.type === "text.reset") finalText = "";
18011
+ else if (evt?.type === "final") finalText = evt.text || finalText;
18012
+ else if (evt?.type === "round.start") emit2(` [${ts()}] \u8F6E ${evt.round}`);
18013
+ },
18014
+ ac.signal,
18015
+ {
18016
+ requestApproval: async (detail, meta) => {
18017
+ if (allowApproval.has(meta.toolName)) return "allow-once";
18018
+ deniedTools.push({ tool: meta.toolName, detail: detail.replace(/\n+/g, " ").slice(0, 140) });
18019
+ return "deny";
18020
+ },
18021
+ onUIEvent: (evt) => {
18022
+ if (evt.type === "run.receipt") receipt = evt;
18023
+ },
18024
+ budgetYuan: t.budgetYuan,
18025
+ toolSchemas
18026
+ }
18027
+ );
18028
+ } catch (e) {
18029
+ agentError = e instanceof Error ? e.message : String(e);
18030
+ } finally {
18031
+ clearTimeout(timer);
18032
+ clearSessionWorktree(sessionId);
18033
+ }
18034
+ const timedOut = ac.signal.aborted;
18035
+ const budgetTruncated = receipt?.budgetTruncated === true;
18036
+ let status;
18037
+ let accept = null;
18038
+ if (agentError) {
18039
+ status = "error";
18040
+ emit2(`\u{1F4A5} [${task.id}] agent \u5F02\u5E38\uFF1A${agentError}`);
18041
+ } else if (timedOut) {
18042
+ status = "timeout";
18043
+ emit2(`\u23F1\uFE0F [${task.id}] \u8D85\u65F6\uFF08${timeoutMin}min\uFF09\uFF0C\u622A\u65AD\u6536\u5C3E\uFF08\u9A8C\u6536\u4E0D\u8DD1\uFF09`);
18044
+ } else {
18045
+ const r = await runAcceptCommand(t.accept, wt.path);
18046
+ accept = { cmd: t.accept, code: r.code, output: r.output, timedOut: r.timedOut };
18047
+ status = r.code === 0 && !r.timedOut ? "passed" : "accept-failed";
18048
+ emit2(`${status === "passed" ? "\u2705" : "\u274C"} [${task.id}] \u9A8C\u6536 exit ${r.code}${r.timedOut ? "\uFF08\u8D85\u65F6\u88AB\u6740\uFF09" : ""}`);
18049
+ }
18050
+ await killBackgroundTasksUnder(wt.path).catch(() => {
18051
+ });
18052
+ const diff = await harvestDiff(wt);
18053
+ const cost = await collectSessionCost(sessionId);
18054
+ await finishTicket(task.id, buildReport({
18055
+ id: task.id,
18056
+ ticket: t,
18057
+ status,
18058
+ budgetTruncated,
18059
+ cost,
18060
+ receipt,
18061
+ finalText,
18062
+ accept,
18063
+ deniedTools,
18064
+ diff,
18065
+ wt,
18066
+ errorMessage: agentError
18067
+ }));
18068
+ emit2(` ${STATUS_LABEL[status]} \xB7 ${fmtCost(cost)}`);
18069
+ emit2(` \u4EA7\u7269\uFF1A${wt.path}\uFF08\u5206\u652F ${wt.branch}\uFF0C\u4FDD\u7559\u5F85\u4EBA\u5DE5\u5904\u7F6E\uFF09`);
18070
+ return { status, cost, budgetTruncated };
18071
+ };
18072
+ parseWaitWindow = (s) => {
18073
+ if (!s) return null;
18074
+ const m = /^(\d{1,2}):(\d{2})-(\d{1,2}):(\d{2})$/.exec(s.trim());
18075
+ if (!m) return null;
18076
+ const startMin = parseInt(m[1], 10) * 60 + parseInt(m[2], 10);
18077
+ const endMin = parseInt(m[3], 10) * 60 + parseInt(m[4], 10);
18078
+ if (startMin === endMin) return null;
18079
+ return { startMin, endMin };
18080
+ };
18081
+ nowMinutes = () => {
18082
+ const d = /* @__PURE__ */ new Date();
18083
+ return d.getHours() * 60 + d.getMinutes();
18084
+ };
18085
+ sleep = (ms) => new Promise((r) => setTimeout(r, ms));
18086
+ waitUntilWindow = async (w) => {
18087
+ const now = nowMinutes();
18088
+ let waitMin = 0;
18089
+ if (now >= w.startMin && now < w.endMin) {
18090
+ emit2(`\u23F0 \u5F53\u524D ${Math.floor(now / 60)}:${String(now % 60).padStart(2, "0")} \u5DF2\u5728\u7A97\u53E3\u5185\uFF0C\u7ACB\u5373\u5F00\u8DD1\u3002`);
18091
+ return;
18092
+ }
18093
+ waitMin = now < w.startMin ? w.startMin - now : 24 * 60 - now + w.startMin;
18094
+ emit2(`\u23F0 --wait-window\uFF1A${Math.floor(waitMin / 60)} \u5C0F\u65F6 ${waitMin % 60} \u5206\u540E\uFF08\u7A97\u53E3\u8D77\u70B9\uFF09\u5F00\u8DD1\u3002\u6302\u673A\u7B49\u5F85\u4E2D\uFF0CCtrl+C \u53EF\u53D6\u6D88\u3002`);
18095
+ while (waitMin > 0) {
18096
+ const chunkMin = Math.min(waitMin, 30);
18097
+ await sleep(chunkMin * 6e4);
18098
+ waitMin -= chunkMin;
18099
+ }
18100
+ };
18101
+ runBatchQueue = async (opts) => {
18102
+ const window = parseWaitWindow(opts?.waitWindow);
18103
+ if (opts?.waitWindow && !window) {
18104
+ emit2(`\u274C --wait-window \u683C\u5F0F\u975E\u6CD5\uFF1A"${opts.waitWindow}"\uFF08\u5E94\u4E3A HH:MM-HH:MM\uFF0C\u5982 23:30-06:30\uFF09`);
18105
+ process.exitCode = 2;
18106
+ return;
18107
+ }
18108
+ if (window) await waitUntilWindow(window);
18109
+ const lock = await acquireRunLock();
18110
+ if (!lock.ok) {
18111
+ emit2(`\u{1F6AB} ${lock.error}`);
18112
+ process.exitCode = 1;
18113
+ return;
18114
+ }
18115
+ const startedAt = Date.now();
18116
+ let total = 0;
18117
+ let passed = 0;
18118
+ let costSum = 0;
18119
+ let costTasks = 0;
18120
+ const failedIds = [];
18121
+ try {
18122
+ for (; ; ) {
18123
+ const task = await takeNextTicket();
18124
+ if (!task) break;
18125
+ total++;
18126
+ const r = await runOneTask(task);
18127
+ if (r.status === "passed") passed++;
18128
+ else failedIds.push(`[${task.id}] ${STATUS_LABEL[r.status]}`);
18129
+ if (r.cost.costYuan !== null) {
18130
+ costSum += r.cost.costYuan;
18131
+ costTasks++;
18132
+ }
18133
+ }
18134
+ } finally {
18135
+ await releaseRunLock();
18136
+ }
18137
+ if (total === 0) {
18138
+ emit2("\u961F\u5217\u7A7A\uFF1Apending/ \u65E0\u4EFB\u52A1\u3002\u6295\u9012\uFF1Adeepseeker-code batch add <\u5DE5\u5355.md>");
18139
+ return;
18140
+ }
18141
+ emit2("");
18142
+ emit2("\u2501".repeat(56));
18143
+ emit2(`\u{1F319} \u6302\u673A\u7ED3\u675F\uFF1A${total} \u4EFB\u52A1 \xB7 ${passed} \u8FC7 \xB7 ${total - passed} \u672A\u8FC7\uFF08\u8017\u65F6 ${Math.round((Date.now() - startedAt) / 6e3) / 10}min\uFF09`);
18144
+ emit2(`\u{1F4B0} \u603B\u82B1\u8D39\uFF1A${costTasks > 0 ? `\xA5${costSum.toFixed(4)}\uFF08${costTasks} \u4E2A\u4EFB\u52A1\u8BA1\u4EF7\uFF09` : "\u5168\u90E8\u65E0\u4EF7\u6A21\u578B\uFF0C\u672A\u8BA1\u94B1"}`);
18145
+ if (failedIds.length > 0) emit2(`\u26A0\uFE0F \u672A\u8FC7\u6E05\u5355\uFF1A
18146
+ ${failedIds.join("\n ")}`);
18147
+ emit2("\u62A5\u544A\u4E0E\u6539\u52A8\uFF1A.deepseeker-code/batch/done/\uFF08worktree \u5747\u4FDD\u7559\u5F85\u4EBA\u5DE5\u5904\u7F6E\uFF09");
18148
+ };
18149
+ }
18150
+ });
18151
+
17256
18152
  // src/preload-config.ts
17257
18153
  import { readFileSync } from "node:fs";
17258
18154
  import path from "node:path";
@@ -17304,7 +18200,7 @@ init_updateCheck();
17304
18200
  init_trust();
17305
18201
  import { render } from "ink";
17306
18202
  import os5 from "os";
17307
- import path47 from "path";
18203
+ import path49 from "path";
17308
18204
  import { emitKeypressEvents } from "node:readline";
17309
18205
  import { jsx as jsx19 } from "react/jsx-runtime";
17310
18206
  var parseArgs = (argv) => {
@@ -17383,6 +18279,12 @@ var main = async () => {
17383
18279
  `);
17384
18280
  process.exit(0);
17385
18281
  }
18282
+ const { parseBatchArgv: parseBatchArgv2 } = await Promise.resolve().then(() => (init_batchAdmin(), batchAdmin_exports));
18283
+ const batchArgv = parseBatchArgv2(process.argv.slice(2));
18284
+ if (batchArgv && batchArgv.sub !== "run") {
18285
+ await Promise.resolve().then(() => (init_batchAdmin(), batchAdmin_exports)).then((m) => m.handleBatchAdmin(batchArgv));
18286
+ process.exit(0);
18287
+ }
17386
18288
  if (!process.env.DEEP_SEEK_API_KEY) {
17387
18289
  console.error(S.noApiKey("DEEP_SEEK_API_KEY"));
17388
18290
  process.exit(1);
@@ -17422,6 +18324,16 @@ var main = async () => {
17422
18324
  Promise.resolve().then(() => (init_App(), App_exports)),
17423
18325
  Promise.resolve().then(() => (init_config(), config_exports))
17424
18326
  ]);
18327
+ if (batchArgv?.sub === "run") {
18328
+ const dispose = await initEngine2(agentTools2, { includeProject });
18329
+ const { runBatchQueue: runBatchQueue2 } = await Promise.resolve().then(() => (init_batchRunner(), batchRunner_exports));
18330
+ try {
18331
+ await runBatchQueue2({ waitWindow: batchArgv.waitWindow });
18332
+ } finally {
18333
+ dispose();
18334
+ }
18335
+ process.exit(0);
18336
+ }
17425
18337
  const engineReady = initEngine2(agentTools2, { includeProject });
17426
18338
  const onExit = () => {
17427
18339
  void engineReady.then((dispose) => dispose());
@@ -17437,7 +18349,7 @@ var main = async () => {
17437
18349
  process.stdout.write("\x1B[2J\x1B[3J\x1B[1;1H");
17438
18350
  const cwdIsHome = () => {
17439
18351
  try {
17440
- return path47.resolve(cwd).toLowerCase() === path47.resolve(os5.homedir()).toLowerCase();
18352
+ return path49.resolve(cwd).toLowerCase() === path49.resolve(os5.homedir()).toLowerCase();
17441
18353
  } catch {
17442
18354
  return false;
17443
18355
  }