deepseeker-code 1.0.50 → 1.0.52

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 +7 -7
  2. package/dist/cli.mjs +556 -449
  3. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -130,6 +130,7 @@ var init_strings = __esm({
130
130
  approvalDeny: "\u62D2\u7EDD",
131
131
  errAborted: "\u5DF2\u4E2D\u6B62\u5F53\u524D\u8F6E\u3002",
132
132
  busyBlockSend: "\u23F3 \u6B63\u5728\u751F\u6210\uFF0C\u8BF7\u7B49\u5F85\u6216\u6309 Esc \u4E2D\u6B62\u540E\u518D\u53D1\u9001\u3002",
133
+ escInterrupt: "Esc \u4E2D\u6B62",
133
134
  inboxQueued: "\u{1F4EE} \u5DF2\u6392\u961F\uFF0C\u5C06\u5728\u56DE\u5408\u8FB9\u754C\u9001\u8FBE\u6A21\u578B\uFF08Esc \u4ECD\u53EF\u4E2D\u6B62\uFF09\u3002",
134
135
  inboxClaimed: (n) => `\u{1F4EC} \u5DF2\u9001\u8FBE\u6A21\u578B\uFF08${n} \u6761\u8865\u5145\u8F93\u5165\uFF09`,
135
136
  inboxCarryover: (n) => `\u{1F4EC} \u672C\u8F6E\u7ED3\u675F\u65F6 ${n} \u6761\u8865\u5145\u8F93\u5165\u672A\u5728\u56DE\u5408\u8FB9\u754C\u9001\u8FBE\uFF0C\u5DF2\u5199\u5165\u4F1A\u8BDD\u5386\u53F2\uFF0C\u4E0B\u8F6E\u5BF9\u8BDD\u81EA\u52A8\u5E26\u5165\u3002`,
@@ -206,7 +207,7 @@ ${dim} \u8FD0\u884C npm i -g deepseeker-code@latest \u66F4\u65B0${reset}
206
207
  return new Date(t).toLocaleDateString("zh-CN");
207
208
  },
208
209
  langCurrent: () => `\u5F53\u524D\u754C\u9762\u8BED\u8A00\uFF1A\u4E2D\u6587\uFF08/lang en \u5207\u6362\u82F1\u6587\uFF09`,
209
- langSet: (l) => `\u754C\u9762\u8BED\u8A00\u5DF2\u5207\u6362\uFF1A${l === "zh" ? "\u4E2D\u6587" : "English"}`,
210
+ langSet: (l) => `\u754C\u9762\u8BED\u8A00\u5DF2\u5207\u6362\uFF1A${l === "zh" ? "\u4E2D\u6587" : "English"}\uFF08AI \u56DE\u590D\u8BED\u8A00\u9ED8\u8BA4\u8DDF\u968F\u6BCF\u8F6E\u63D0\u95EE\u81EA\u52A8\u5224\u65AD\uFF1B\u7EAF\u4EE3\u7801/\u65E0\u6587\u5B57\u8F6E\u6B21\u4EE5\u6B64\u8BED\u8A00\u4E3A\u51C6\uFF09`,
210
211
  langInvalid: (arg) => `\u65E0\u6548\u8BED\u8A00\uFF1A${arg}\uFF08\u53EF\u9009\uFF1Azh \u4E2D\u6587 / en English\uFF09`,
211
212
  outputStyleNone: () => `\u672A\u52A0\u8F7D\u4EFB\u4F55\u8F93\u51FA\u98CE\u683C\uFF08\u5728 ~/.deepseeker-code/output-styles/ \u653E <name>.md\uFF09\u3002`,
212
213
  outputStyleCurrent: (cur) => `\u5F53\u524D\u8F93\u51FA\u98CE\u683C\uFF1A${cur ?? "\u9ED8\u8BA4\uFF08\u4E2D\u6027\uFF09"}\u3002\u53EF\u7528\uFF1A`,
@@ -220,10 +221,10 @@ ${cwd}
220
221
  DeepSeeker-Code \u5C06\u5728\u6B64\u76EE\u5F55\u8BFB\u53D6\u3001\u7F16\u8F91\u548C\u6267\u884C\u6587\u4EF6\u3002`,
221
222
  optTrust: "\u4FE1\u4EFB\u6B64\u76EE\u5F55",
222
223
  optExit: "\u9000\u51FA",
223
- helpText: (model2, thinking, locale2) => [
224
+ helpText: (model, thinking, locale2) => [
224
225
  "/help \xB7 /status \xB7 /clear \xB7 /exit",
225
226
  "/plan \u2014 \u5207\u6362\u8BA1\u5212\u6A21\u5F0F\uFF08\u53EA\u8BFB\u8C03\u7814 \u2192 \u65B9\u6848\u5BA1\u6279 \u2192 \u5B9E\u73B0\uFF09",
226
- `/model <\u6A21\u578Bid> \u2014 \u5207\u6362\u6A21\u578B\uFF08\u76F4\u8F93\uFF0C\u5F53\u524D ${model2}\uFF09`,
227
+ `/model <\u6A21\u578Bid> \u2014 \u5207\u6362\u6A21\u578B\uFF08\u76F4\u8F93\uFF0C\u5F53\u524D ${model}\uFF09`,
227
228
  "/switch \u2014 \u5F39\u51FA\u5019\u9009\u6A21\u578B\u9009\u62E9\u5668",
228
229
  `/thinking [off|high|max] \u2014 \u5207\u6362\u601D\u8003\u7B49\u7EA7\uFF08\u5F53\u524D ${thinking}\uFF09`,
229
230
  `/lang [zh|en] \u2014 \u5207\u6362\u754C\u9762\u8BED\u8A00\uFF08\u5F53\u524D ${locale2}\uFF09`,
@@ -232,8 +233,8 @@ DeepSeeker-Code \u5C06\u5728\u6B64\u76EE\u5F55\u8BFB\u53D6\u3001\u7F16\u8F91\u54
232
233
  "/trust \u2014 \u7BA1\u7406\u5DF2\u4FE1\u4EFB\u76EE\u5F55\uFF08\u9879\u76EE\u7EA7 hooks/skills \u7B49\u4EC5\u5728\u4FE1\u4EFB\u76EE\u5F55\u52A0\u8F7D\uFF1BCI \u7528 --trust \u663E\u5F0F\u4FE1\u4EFB\uFF09",
233
234
  "Ctrl+C \u9000\u51FA \xB7 Esc \u4E2D\u6B62/\u6E05\u8F93\u5165 \xB7 Ctrl+G \u4E2D\u6B62 \xB7 Ctrl+T \u5C55\u5F00/\u6536\u8D77\u601D\u8003"
234
235
  ].join("\n"),
235
- statusText: (model2, thinking, planOn, locale2, cwd) => [
236
- `\u6A21\u578B\uFF1A${model2}`,
236
+ statusText: (model, thinking, planOn, locale2, cwd) => [
237
+ `\u6A21\u578B\uFF1A${model}`,
237
238
  `\u601D\u8003\u7B49\u7EA7\uFF1A${thinking}`,
238
239
  `\u8BA1\u5212\u6A21\u5F0F\uFF1A${planOn ? "\u5F00" : "\u5173"}`,
239
240
  `\u754C\u9762\u8BED\u8A00\uFF1A${locale2}`,
@@ -278,6 +279,7 @@ DeepSeeker-Code \u5C06\u5728\u6B64\u76EE\u5F55\u8BFB\u53D6\u3001\u7F16\u8F91\u54
278
279
  approvalDeny: "Deny",
279
280
  errAborted: "Aborted current turn.",
280
281
  busyBlockSend: "\u23F3 Still generating\u2014wait or press Esc to abort before sending.",
282
+ escInterrupt: "esc to interrupt",
281
283
  inboxQueued: "\u{1F4EE} Queued\u2014will reach the model at the next round boundary (Esc still aborts).",
282
284
  inboxClaimed: (n) => `\u{1F4EC} Delivered to the model (${n} supplemental input${n > 1 ? "s" : ""})`,
283
285
  inboxCarryover: (n) => `\u{1F4EC} ${n} supplemental input${n > 1 ? "s" : ""} not claimed at a round boundary before this run ended; saved to session history and carried into the next turn.`,
@@ -354,7 +356,7 @@ Usage: /model <model-id> to switch directly, or /switch for the picker`,
354
356
  return new Date(t).toLocaleDateString("en-US");
355
357
  },
356
358
  langCurrent: () => `Interface language: English (/lang zh for \u4E2D\u6587)`,
357
- langSet: (l) => `Interface language: ${l === "zh" ? "\u4E2D\u6587" : "English"}`,
359
+ langSet: (l) => `Interface language: ${l === "zh" ? "\u4E2D\u6587" : "English"} (AI reply language follows each question's language automatically; this is the fallback for code-only / text-less turns)`,
358
360
  langInvalid: (arg) => `Invalid language: ${arg} (choose zh / en)`,
359
361
  outputStyleNone: () => `No output styles loaded (drop a <name>.md in ~/.deepseeker-code/output-styles/).`,
360
362
  outputStyleCurrent: (cur) => `Current output style: ${cur ?? "default (neutral)"}. Available:`,
@@ -368,10 +370,10 @@ ${cwd}
368
370
  DeepSeeker-Code will read, edit, and execute files here.`,
369
371
  optTrust: "Yes, I trust this folder",
370
372
  optExit: "No, exit",
371
- helpText: (model2, thinking, locale2) => [
373
+ helpText: (model, thinking, locale2) => [
372
374
  "/help \xB7 /status \xB7 /clear \xB7 /exit",
373
375
  "/plan \u2014 Toggle plan mode (read-only research \u2192 review \u2192 implement)",
374
- `/model <model-id> \u2014 Switch model (direct input; current ${model2})`,
376
+ `/model <model-id> \u2014 Switch model (direct input; current ${model})`,
375
377
  "/switch \u2014 Open the model picker",
376
378
  `/thinking [off|high|max] \u2014 Switch thinking level (current ${thinking})`,
377
379
  `/lang [zh|en] \u2014 Switch interface language (current ${locale2})`,
@@ -380,8 +382,8 @@ DeepSeeker-Code will read, edit, and execute files here.`,
380
382
  "/trust \u2014 Manage trusted dirs (project hooks/skills load only when trusted; CI uses --trust)",
381
383
  "Ctrl+C exit \xB7 Esc abort/clear input \xB7 Ctrl+G abort \xB7 Ctrl+T toggle thinking"
382
384
  ].join("\n"),
383
- statusText: (model2, thinking, planOn, locale2, cwd) => [
384
- `Model: ${model2}`,
385
+ statusText: (model, thinking, planOn, locale2, cwd) => [
386
+ `Model: ${model}`,
385
387
  `Thinking: ${thinking}`,
386
388
  `Plan mode: ${planOn ? "on" : "off"}`,
387
389
  `Language: ${locale2}`,
@@ -616,7 +618,7 @@ var init_common = __esm({
616
618
  }
617
619
  };
618
620
  detectTextLocale = (text) => {
619
- const stripped = (text || "").replace(/```[\s\S]*?```/g, " ").replace(/`[^`]*`/g, " ").replace(/\s+/g, " ");
621
+ const stripped = (text || "").replace(/```[\s\S]*?```/g, " ").replace(/`[^`]*`/g, " ").replace(/[A-Za-z]:[\\/][^\s"'`))\]},。;]*/g, " ").replace(/(?:^|[\s((【"'])\/(?:home|Users|root|var|tmp|mnt|opt|data|app)[^\s"'`))\]},。;]*/g, " ").replace(/https?:\/\/[^\s"'`))\]},。;]*/g, " ").replace(/\s+/g, " ");
620
622
  const cjk = (stripped.match(/[㐀-䶿一-鿿]/g) || []).length;
621
623
  const latin = (stripped.match(/[A-Za-z]/g) || []).length;
622
624
  if (cjk === 0 && latin === 0) return null;
@@ -718,8 +720,8 @@ var init_prefs = __esm({
718
720
  return p && typeof p === "object" ? p : {};
719
721
  };
720
722
  readModelPref = async () => {
721
- const { model: model2 } = await readPrefs();
722
- return typeof model2 === "string" && model2.trim() ? model2.trim() : null;
723
+ const { model } = await readPrefs();
724
+ return typeof model === "string" && model.trim() ? model.trim() : null;
723
725
  };
724
726
  readLocale = async () => {
725
727
  const { locale: locale2 } = await readPrefs();
@@ -804,11 +806,11 @@ var init_type = __esm({
804
806
 
805
807
  // ../core/src/llm/providers/deepseek/client.ts
806
808
  import OpenAI from "openai";
807
- var model, MODEL_NAME, AUX_MODEL_NAME, REASONING_EFFORTS, clampReasoningEffort, MODEL_REASONING_EFFORT, MODEL_THINKING_ENABLED;
809
+ var _model, getModel, MODEL_NAME, AUX_MODEL_NAME, REASONING_EFFORTS, clampReasoningEffort, MODEL_REASONING_EFFORT, MODEL_THINKING_ENABLED;
808
810
  var init_client = __esm({
809
811
  "../core/src/llm/providers/deepseek/client.ts"() {
810
812
  "use strict";
811
- model = new OpenAI({
813
+ getModel = () => _model ??= new OpenAI({
812
814
  baseURL: process.env.DEEP_SEEK_API_URL || "https://api.deepseek.com",
813
815
  apiKey: process.env.DEEP_SEEK_API_KEY,
814
816
  // ★ 瞬态错误自动指数退避重试(SDK 内置:408/409/429/500/502/503/504 + 连接错误),
@@ -819,8 +821,8 @@ var init_client = __esm({
819
821
  timeout: 12e4
820
822
  // 单次请求 120s 兜底(长上下文 / 长生成场景)
821
823
  });
822
- MODEL_NAME = process.env.DEEP_SEEK_MODEL || "deepseek-v4-flash";
823
- AUX_MODEL_NAME = process.env.DEEP_SEEK_AUX_MODEL || "deepseek-v4-flash";
824
+ MODEL_NAME = process.env.DEEP_SEEK_MODEL || "deepseek-flash";
825
+ AUX_MODEL_NAME = process.env.DEEP_SEEK_AUX_MODEL || "deepseek-flash";
824
826
  REASONING_EFFORTS = ["high", "max"];
825
827
  clampReasoningEffort = (raw) => raw && REASONING_EFFORTS.includes(raw) ? raw : "high";
826
828
  MODEL_REASONING_EFFORT = clampReasoningEffort(process.env.DEEP_SEEK_REASONING_EFFORT);
@@ -875,7 +877,7 @@ var init_stream = __esm({
875
877
  const idleAc = new AbortController();
876
878
  const extSignal = opts.signal;
877
879
  const combinedSignal = extSignal ? AbortSignal.any([idleAc.signal, extSignal]) : idleAc.signal;
878
- const stream = await model.chat.completions.create(requestBody, {
880
+ const stream = await getModel().chat.completions.create(requestBody, {
879
881
  signal: combinedSignal,
880
882
  maxRetries: 0
881
883
  });
@@ -935,7 +937,7 @@ var init_stream = __esm({
935
937
  });
936
938
 
937
939
  // ../core/src/llm/providers/deepseek/index.ts
938
- var summarize, classifyRisk, isContextLengthError, isTransientError, buildAssistantMessage, deepseekProvider;
940
+ var summarize, classifyRisk, isContextLengthError, isImageUnsupportedError, isTransientError, buildAssistantMessage, deepseekProvider;
939
941
  var init_deepseek = __esm({
940
942
  "../core/src/llm/providers/deepseek/index.ts"() {
941
943
  "use strict";
@@ -953,7 +955,7 @@ var init_deepseek = __esm({
953
955
  thinking: { type: "disabled" },
954
956
  stream: false
955
957
  };
956
- const completion = await model.chat.completions.create(requestBody, {
958
+ const completion = await getModel().chat.completions.create(requestBody, {
957
959
  signal: opts.signal
958
960
  });
959
961
  if (completion && "choices" in completion) return completion;
@@ -968,7 +970,7 @@ var init_deepseek = __esm({
968
970
  const timer = setTimeout(() => ac.abort(), 1e4);
969
971
  if (signal) signal.addEventListener("abort", () => ac.abort(), { once: true });
970
972
  try {
971
- const completion = await model.chat.completions.create({
973
+ const completion = await getModel().chat.completions.create({
972
974
  messages: [
973
975
  { role: "system", content: "\u4F60\u662F\u5DE5\u5177\u8C03\u7528\u98CE\u9669\u5206\u7C7B\u5668\u3002\u53EA\u56DE SAFE \u6216 RISKY\uFF0C\u4E0D\u8981\u4EFB\u4F55\u89E3\u91CA\u3002\u6309\u5DE5\u5177\u7C7B\u578B\u5224\u5B9A\uFF1A\u2460\u6587\u4EF6(edit/write/create/move_file/delete_path)\u2014\u2014\u5DE5\u4F5C\u533A\u5185\u5E38\u89C4\u6587\u4EF6\u64CD\u4F5C(\u542B\u79FB\u52A8/\u91CD\u547D\u540D)=SAFE\uFF0C\u8986\u76D6/\u5220\u9664/\u79FB\u52A8\u654F\u611F\u6587\u4EF6(.env/.git/.ssh/.aws/\u5BC6\u94A5/credentials/settings.json)\u6216\u5DE5\u4F5C\u533A\u5916=RISKY\uFF1B\u2461\u547D\u4EE4(run_command/run_in_background)\u2014\u2014\u53EA\u8BFB/\u6784\u5EFA/\u6D4B\u8BD5/\u67E5\u770B\u7C7B(ls/cat/git status/npm test/pnpm build/node -v/tsc/lint)=SAFE\uFF0C\u7834\u574F\u6027/\u5916\u5411/\u63D0\u6743(rm -rf\u3001\u683C\u5F0F\u5316\u3001curl|sh\u3001\u5916\u4F20\u6587\u4EF6\u3001chmod 777\u3001shutdown\u3001\u5199\u7CFB\u7EDF\u76EE\u5F55\u3001\u5B89\u88C5\u964C\u751F\u5305)=RISKY\uFF1B\u2462\u7F51\u7EDC(web_fetch/web_search)\u2014\u2014\u6293\u53D6\u516C\u5F00\u6587\u6863/\u5E38\u89C4 URL=SAFE\uFF0C\u5185\u7F51/\u53EF\u7591/\u672A\u77E5 URL=RISKY\uFF1B\u2463git_commit\u2014\u2014\u5E38\u89C4\u63D0\u4EA4=SAFE\uFF0C\u542B\u6076\u610F\u811A\u672C/\u5F02\u5E38\u6539\u52A8=RISKY\uFF1B\u2464MCP(mcp__*)\u2014\u2014\u9ED8\u8BA4 RISKY(\u9ED1\u76D2\u5DE5\u5177\u65E0\u6CD5\u5224\u5B9A\u5185\u90E8\u884C\u4E3A)\u3002\u4EFB\u4F55\u4E0D\u786E\u5B9A\u4E00\u5F8B RISKY\u3002" },
974
976
  { role: "user", content: `\u5DE5\u5177:${toolName}
@@ -995,6 +997,15 @@ var init_deepseek = __esm({
995
997
  const msg = typeof e.message === "string" ? e.message : "";
996
998
  return code === "context_length_exceeded" || /context_length|context length|maximum context|input length|too long|exceed/i.test(msg);
997
999
  };
1000
+ isImageUnsupportedError = (e) => {
1001
+ if (!e || isContextLengthError(e)) return false;
1002
+ const status = e.status ?? e.response?.status;
1003
+ if (status !== 400 && status !== 422) return false;
1004
+ const code = e.error?.code ?? e.code;
1005
+ const msg = typeof e.message === "string" ? e.message : "";
1006
+ const codeStr = typeof code === "string" ? code : "";
1007
+ return /image|multimodal|vision|image_url/i.test(msg) || /image/i.test(codeStr);
1008
+ };
998
1009
  isTransientError = (e) => {
999
1010
  if (!e) return false;
1000
1011
  const status = e.status ?? e.response?.status;
@@ -1017,7 +1028,8 @@ var init_deepseek = __esm({
1017
1028
  classifyRisk,
1018
1029
  buildAssistantMessage,
1019
1030
  isContextLengthError,
1020
- isTransientError
1031
+ isTransientError,
1032
+ isImageUnsupportedError
1021
1033
  };
1022
1034
  }
1023
1035
  });
@@ -1028,16 +1040,67 @@ var init_createModel = __esm({
1028
1040
  "../core/src/llm/createModel.ts"() {
1029
1041
  "use strict";
1030
1042
  init_client();
1031
- SELECTABLE_MODELS = ["deepseek-v4-flash", "deepseek-v4-pro", "deepseek-v4-flash-vision-exp"];
1043
+ SELECTABLE_MODELS = ["deepseek-flash", "deepseek-v4-pro", "deepseek-flash-vision-exp"];
1044
+ }
1045
+ });
1046
+
1047
+ // ../core/src/llm/visionCapability.ts
1048
+ import path6 from "path";
1049
+ import fs4 from "fs/promises";
1050
+ var CAP_FILE, MAX_ENTRIES, mem, loadPromise, ensureVisionCacheLoaded, peekVisionCapability, writeChain, persistLatest, learnVisionCapability;
1051
+ var init_visionCapability = __esm({
1052
+ "../core/src/llm/visionCapability.ts"() {
1053
+ "use strict";
1054
+ init_config();
1055
+ init_common();
1056
+ CAP_FILE = path6.join(appConfig.dataDir, "model-capabilities.json");
1057
+ MAX_ENTRIES = 100;
1058
+ mem = {};
1059
+ loadPromise = (async () => {
1060
+ const t = await readJSONFile(CAP_FILE);
1061
+ if (t && typeof t === "object") mem = t;
1062
+ })().catch(() => {
1063
+ });
1064
+ ensureVisionCacheLoaded = () => loadPromise;
1065
+ peekVisionCapability = (modelId) => {
1066
+ const e = mem[modelId?.trim()];
1067
+ return e && typeof e.vision === "boolean" ? e.vision : void 0;
1068
+ };
1069
+ writeChain = Promise.resolve();
1070
+ persistLatest = () => {
1071
+ writeChain = writeChain.then(async () => {
1072
+ try {
1073
+ await fs4.mkdir(appConfig.dataDir, { recursive: true });
1074
+ await atomicWriteJSON(CAP_FILE, mem);
1075
+ } catch {
1076
+ }
1077
+ });
1078
+ return writeChain;
1079
+ };
1080
+ learnVisionCapability = (modelId, vision) => {
1081
+ const id = modelId?.trim();
1082
+ if (!id) return;
1083
+ mem[id] = { vision, checkedAt: (/* @__PURE__ */ new Date()).toISOString() };
1084
+ while (Object.keys(mem).length > MAX_ENTRIES) {
1085
+ let oldestKey = "";
1086
+ for (const k of Object.keys(mem)) {
1087
+ if (!oldestKey || (mem[k]?.checkedAt ?? "") < (mem[oldestKey]?.checkedAt ?? "")) oldestKey = k;
1088
+ }
1089
+ if (!oldestKey) break;
1090
+ delete mem[oldestKey];
1091
+ }
1092
+ void persistLatest();
1093
+ };
1032
1094
  }
1033
1095
  });
1034
1096
 
1035
1097
  // ../core/src/session/contentParts.ts
1036
- var MAX_IMAGE_BYTES, msgText, imageUrlsOf, hasImagePart, modelSupportsVision, isVisionEnabled, estimateImageTokens, toWireUserContent, toIngestContents, replaceImageParts, collapseToText, degradeImagesForAux;
1098
+ var MAX_IMAGE_BYTES, msgText, imageUrlsOf, hasImagePart, VISION_DEGRADE_NOTE, isVisionEnabled, estimateImageTokens, toWireUserContent, toIngestContents, replaceImageParts, collapseToText, degradeImagesForAux;
1037
1099
  var init_contentParts = __esm({
1038
1100
  "../core/src/session/contentParts.ts"() {
1039
1101
  "use strict";
1040
1102
  init_createModel();
1103
+ init_visionCapability();
1041
1104
  MAX_IMAGE_BYTES = 8 * 1024 * 1024;
1042
1105
  msgText = (content) => {
1043
1106
  if (typeof content === "string") return content;
@@ -1051,13 +1114,13 @@ var init_contentParts = __esm({
1051
1114
  return content.filter((p) => p?.type === "image_url" && typeof p?.image_url?.url === "string").map((p) => p.image_url.url);
1052
1115
  };
1053
1116
  hasImagePart = (content) => imageUrlsOf(content).length > 0;
1054
- modelSupportsVision = (modelId) => /vision|vlm|(^|[-_.])vl([-_.0-9]|$)/i.test(modelId || "");
1117
+ VISION_DEGRADE_NOTE = "[\u56FE\u7247\u672A\u9001\u8FBE\uFF1A\u5F53\u524D\u6A21\u578B\u4E0D\u652F\u6301\u56FE\u7247\u8F93\u5165\uFF0C\u7CFB\u7EDF\u5DF2\u81EA\u52A8\u6539\u7528\u6587\u672C\u65B9\u5F0F\uFF1B\u539F\u56FE\u4ECD\u5728\u4F1A\u8BDD\u5F52\u6863\u4E2D\uFF0C\u5982\u9700\u5206\u6790\u56FE\u7247\u5185\u5BB9\u53EF\u914D\u7F6E\u56FE\u50CF\u8BC6\u522B\u5DE5\u5177\u8BFB\u53D6\u5B58\u6863\u8DEF\u5F84\uFF0C\u6216\u7531\u7528\u6237\u91CD\u65B0\u63D0\u4F9B]";
1055
1118
  isVisionEnabled = (modelId) => {
1056
1119
  const v = process.env.DEEP_SEEK_VISION;
1057
1120
  if (v === "1" || v === "true") return true;
1058
1121
  if (v === "0" || v === "false") return false;
1059
1122
  const effective = typeof modelId === "string" && modelId.trim() ? modelId.trim() : MODEL_NAME;
1060
- return modelSupportsVision(effective);
1123
+ return peekVisionCapability(effective) ?? true;
1061
1124
  };
1062
1125
  estimateImageTokens = () => {
1063
1126
  const n = Number(process.env.DEEP_SEEK_IMAGE_TOKENS);
@@ -1082,9 +1145,9 @@ var init_contentParts = __esm({
1082
1145
  skipped.push(`\u{1F5BC} \u56FE\u7247 ${name} \u5DF2\u5FFD\u7565\uFF1A\u8D85\u8FC7 ${Math.round(MAX_IMAGE_BYTES / 1024 / 1024)}MB \u4E0A\u9650`);
1083
1146
  continue;
1084
1147
  }
1085
- accepted.push({ name, url: `data:${a.mime};base64,${b64}` });
1148
+ accepted.push({ name, url: `data:${a.mime};base64,${b64}`, path: a.path });
1086
1149
  }
1087
- const labels = accepted.map((p) => `\u{1F5BC} [\u56FE\u7247: ${p.name}]`);
1150
+ const labels = accepted.map((p) => `\u{1F5BC} [\u56FE\u7247: ${p.name}${p.path ? ` | \u5B58\u6863: ${p.path}` : ""}]`);
1088
1151
  const footer = [...skipped, ...labels];
1089
1152
  const finalText = footer.length ? `${text}
1090
1153
 
@@ -1108,7 +1171,7 @@ ${paths.join("\n")}
1108
1171
  return {
1109
1172
  wire: `${text}
1110
1173
 
1111
- \u{1F5BC} \u6536\u5230\u56FE\u7247\u9644\u4EF6\uFF08${names}\uFF09\uFF1A\u5F53\u524D\u6A21\u578B\u65E0\u89C6\u89C9\u80FD\u529B\uFF0C\u65E0\u6CD5\u76F4\u63A5\u67E5\u770B\u56FE\u7247\u5185\u5BB9\uFF08\u53EF\u5207\u6362 vision \u6A21\u578B\u6216\u8BBE DEEP_SEEK_VISION=1 \u5F3A\u5F00\uFF09\uFF1B${relay}`,
1174
+ \u{1F5BC} \u6536\u5230\u56FE\u7247\u9644\u4EF6\uFF08${names}\uFF09\uFF1A\u5F53\u524D\u6A21\u578B\u4E0D\u652F\u6301\u56FE\u7247\u8F93\u5165\uFF08\u89C6\u89C9\u80FD\u529B\u5DF2\u6309\u7AEF\u70B9\u5B9E\u6D4B\u81EA\u52A8\u5224\u5B9A\uFF1B\u53EF\u5207\u6362 vision \u6A21\u578B\u6216\u8BBE DEEP_SEEK_VISION=1 \u5F3A\u5F00\uFF09\uFF1B${relay}`,
1112
1175
  archive
1113
1176
  };
1114
1177
  };
@@ -1149,10 +1212,11 @@ var init_replay = __esm({
1149
1212
  let attemptCounts = [];
1150
1213
  const calls = [];
1151
1214
  const makeFaultError = (fault) => {
1152
- const msg = fault.message ?? (fault.type === "idle" ? "stream_idle_timeout" : fault.type === "context_length" ? "context_length_exceeded\uFF08\u56DE\u653E\u6CE8\u5165\uFF09" : fault.type === "transient" ? "HTTP 429 rate limit\uFF08\u56DE\u653E\u6CE8\u5165\uFF09" : "\u56DE\u653E\u81F4\u547D\u9519\u8BEF\uFF08fatal\uFF09");
1215
+ const msg = fault.message ?? (fault.type === "idle" ? "stream_idle_timeout" : fault.type === "context_length" ? "context_length_exceeded\uFF08\u56DE\u653E\u6CE8\u5165\uFF09" : fault.type === "transient" ? "HTTP 429 rate limit\uFF08\u56DE\u653E\u6CE8\u5165\uFF09" : fault.type === "image_unsupported" ? "This model does not support image\uFF08\u56DE\u653E\u6CE8\u5165\uFF09" : "\u56DE\u653E\u81F4\u547D\u9519\u8BEF\uFF08fatal\uFF09");
1153
1216
  const e = new Error(msg);
1154
1217
  e.replayFault = fault.type;
1155
1218
  if (fault.type === "transient") e.status = 429;
1219
+ if (fault.type === "image_unsupported") e.status = 400;
1156
1220
  return e;
1157
1221
  };
1158
1222
  const streamChat2 = async function* (messages, tools, opts) {
@@ -1208,9 +1272,10 @@ var init_replay = __esm({
1208
1272
  if (parts.toolCalls?.length) m.tool_calls = parts.toolCalls;
1209
1273
  return m;
1210
1274
  },
1211
- // 自识别回放注入的故障(streamInference 经 activeProvider 调用这两个分类器驱动重试通道)
1275
+ // 自识别回放注入的故障(streamInference 经 activeProvider 调用这些分类器驱动重试通道)
1212
1276
  isContextLengthError: (e) => e?.replayFault === "context_length",
1213
1277
  isTransientError: (e) => e?.replayFault === "transient",
1278
+ isImageUnsupportedError: (e) => e?.replayFault === "image_unsupported",
1214
1279
  get calls() {
1215
1280
  return calls;
1216
1281
  },
@@ -1369,8 +1434,8 @@ __export(store_exports, {
1369
1434
  updateCalibration: () => updateCalibration,
1370
1435
  writeStore: () => writeStore
1371
1436
  });
1372
- import fs4 from "fs/promises";
1373
- import path6 from "path";
1437
+ import fs5 from "fs/promises";
1438
+ import path7 from "path";
1374
1439
  async function getRollingState(sessionId) {
1375
1440
  const store = await readStore(sessionId);
1376
1441
  if (!store) {
@@ -1418,42 +1483,42 @@ var init_store = __esm({
1418
1483
  getSessionsDirPath = (mainSessionId) => {
1419
1484
  assertSafeSessionId(mainSessionId);
1420
1485
  const fileName = getFileName(mainSessionId);
1421
- return path6.join(appConfig.dataDir, "sessions", appConfig.userWorkspaceDir, fileName);
1486
+ return path7.join(appConfig.dataDir, "sessions", appConfig.userWorkspaceDir, fileName);
1422
1487
  };
1423
- getWorkspaceSessionsDir = () => path6.join(appConfig.dataDir, "sessions", appConfig.userWorkspaceDir);
1488
+ getWorkspaceSessionsDir = () => path7.join(appConfig.dataDir, "sessions", appConfig.userWorkspaceDir);
1424
1489
  getStatePath = (sessionId) => {
1425
1490
  assertSafeSessionId(sessionId);
1426
- return path6.join(getSessionsDirPath(sessionId), `${sessionId}.state.json`);
1491
+ return path7.join(getSessionsDirPath(sessionId), `${sessionId}.state.json`);
1427
1492
  };
1428
1493
  getTranscriptPath = (sessionId) => {
1429
1494
  assertSafeSessionId(sessionId);
1430
- return path6.join(getSessionsDirPath(sessionId), `${sessionId}.jsonl`);
1495
+ return path7.join(getSessionsDirPath(sessionId), `${sessionId}.jsonl`);
1431
1496
  };
1432
1497
  ensureSessionsDir = async (sessionId) => {
1433
- await fs4.mkdir(getSessionsDirPath(sessionId), { recursive: true });
1498
+ await fs5.mkdir(getSessionsDirPath(sessionId), { recursive: true });
1434
1499
  await migrateLegacyFiles(sessionId).catch(() => {
1435
1500
  });
1436
1501
  };
1437
1502
  migrateLegacyFiles = async (sessionId) => {
1438
1503
  assertSafeSessionId(sessionId);
1439
1504
  const dir = getSessionsDirPath(sessionId);
1440
- const legacy = path6.join(dir, `${sessionId}.json`);
1505
+ const legacy = path7.join(dir, `${sessionId}.json`);
1441
1506
  const transcriptPath = getTranscriptPath(sessionId);
1442
1507
  const statePath = getStatePath(sessionId);
1443
1508
  let legacyText;
1444
1509
  try {
1445
- legacyText = await fs4.readFile(legacy, "utf-8");
1510
+ legacyText = await fs5.readFile(legacy, "utf-8");
1446
1511
  } catch {
1447
1512
  return;
1448
1513
  }
1449
1514
  try {
1450
- await fs4.access(transcriptPath);
1515
+ await fs5.access(transcriptPath);
1451
1516
  return;
1452
1517
  } catch {
1453
1518
  }
1454
1519
  const raw = legacyText.trim();
1455
1520
  if (raw.length === 0) {
1456
- await fs4.rename(legacy, transcriptPath);
1521
+ await fs5.rename(legacy, transcriptPath);
1457
1522
  return;
1458
1523
  }
1459
1524
  const lines = raw.split("\n");
@@ -1466,13 +1531,13 @@ var init_store = __esm({
1466
1531
  }
1467
1532
  });
1468
1533
  if (isJsonl) {
1469
- await fs4.rename(legacy, transcriptPath);
1534
+ await fs5.rename(legacy, transcriptPath);
1470
1535
  return;
1471
1536
  }
1472
1537
  try {
1473
1538
  const v = JSON.parse(raw);
1474
1539
  if (typeof v === "object" && v !== null) {
1475
- await fs4.rename(legacy, statePath);
1540
+ await fs5.rename(legacy, statePath);
1476
1541
  return;
1477
1542
  }
1478
1543
  } catch {
@@ -1483,8 +1548,8 @@ var init_store = __esm({
1483
1548
  await ensureSessionsDir(sessionId);
1484
1549
  const finalPath = getStatePath(sessionId);
1485
1550
  const tmpPath = `${finalPath}.${Date.now()}.tmp`;
1486
- await fs4.writeFile(tmpPath, JSON.stringify(store, null, 2), "utf-8");
1487
- await fs4.rename(tmpPath, finalPath);
1551
+ await fs5.writeFile(tmpPath, JSON.stringify(store, null, 2), "utf-8");
1552
+ await fs5.rename(tmpPath, finalPath);
1488
1553
  };
1489
1554
  storeLocks = /* @__PURE__ */ new Map();
1490
1555
  withStoreLock = (sessionId, fn) => {
@@ -1524,7 +1589,7 @@ var init_store = __esm({
1524
1589
  await ensureSessionsDir(sessionId);
1525
1590
  const p = getStatePath(sessionId);
1526
1591
  try {
1527
- const raw = (await fs4.readFile(p, "utf-8")).trim();
1592
+ const raw = (await fs5.readFile(p, "utf-8")).trim();
1528
1593
  if (raw.length === 0) {
1529
1594
  return {};
1530
1595
  }
@@ -1553,7 +1618,7 @@ var init_store = __esm({
1553
1618
  const root = getWorkspaceSessionsDir();
1554
1619
  let entries;
1555
1620
  try {
1556
- entries = await fs4.readdir(root, { withFileTypes: true });
1621
+ entries = await fs5.readdir(root, { withFileTypes: true });
1557
1622
  } catch {
1558
1623
  return [];
1559
1624
  }
@@ -1562,12 +1627,12 @@ var init_store = __esm({
1562
1627
  if (!entry.isDirectory()) continue;
1563
1628
  const sessionId = entry.name;
1564
1629
  if (!isSafeSessionId(sessionId)) continue;
1565
- const dirPath = path6.join(root, sessionId);
1630
+ const dirPath = path7.join(root, sessionId);
1566
1631
  const state = await readJSONFile(getStatePath(sessionId));
1567
1632
  let messageCount = 0;
1568
1633
  let preview = "";
1569
1634
  try {
1570
- const raw = await fs4.readFile(getTranscriptPath(sessionId), "utf-8");
1635
+ const raw = await fs5.readFile(getTranscriptPath(sessionId), "utf-8");
1571
1636
  for (const s of raw.split("\n")) {
1572
1637
  const line = s.trim();
1573
1638
  if (!line) continue;
@@ -1594,7 +1659,7 @@ var init_store = __esm({
1594
1659
  let updatedAt = state?.updatedAt;
1595
1660
  if (!updatedAt) {
1596
1661
  try {
1597
- updatedAt = (await fs4.stat(dirPath)).mtime.toISOString();
1662
+ updatedAt = (await fs5.stat(dirPath)).mtime.toISOString();
1598
1663
  } catch {
1599
1664
  }
1600
1665
  }
@@ -1627,13 +1692,13 @@ var init_store = __esm({
1627
1692
  deleteSession = async (sessionId) => {
1628
1693
  assertSafeSessionId(sessionId);
1629
1694
  const dir = getSessionsDirPath(sessionId);
1630
- await fs4.rm(dir, { recursive: true, force: true });
1695
+ await fs5.rm(dir, { recursive: true, force: true });
1631
1696
  };
1632
1697
  }
1633
1698
  });
1634
1699
 
1635
1700
  // ../core/src/session/transcript.ts
1636
- import fs5 from "fs/promises";
1701
+ import fs6 from "fs/promises";
1637
1702
  var isEventLine, readTranscriptLines, appendLineWithRetry, appendMessage, appendEvent;
1638
1703
  var init_transcript = __esm({
1639
1704
  "../core/src/session/transcript.ts"() {
@@ -1646,7 +1711,7 @@ var init_transcript = __esm({
1646
1711
  await ensureSessionsDir(sessionId);
1647
1712
  const p = getTranscriptPath(sessionId);
1648
1713
  try {
1649
- const text = await fs5.readFile(p, "utf-8");
1714
+ const text = await fs6.readFile(p, "utf-8");
1650
1715
  const lines = [];
1651
1716
  for (const s of text.split("\n")) {
1652
1717
  const line = s.trim();
@@ -1668,15 +1733,15 @@ var init_transcript = __esm({
1668
1733
  for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
1669
1734
  let beforeSize = 0;
1670
1735
  try {
1671
- beforeSize = (await fs5.stat(p)).size;
1736
+ beforeSize = (await fs6.stat(p)).size;
1672
1737
  } catch {
1673
1738
  }
1674
1739
  try {
1675
- await fs5.appendFile(p, payload, "utf-8");
1740
+ await fs6.appendFile(p, payload, "utf-8");
1676
1741
  return;
1677
1742
  } catch (e) {
1678
1743
  try {
1679
- await fs5.truncate(p, beforeSize);
1744
+ await fs6.truncate(p, beforeSize);
1680
1745
  } catch {
1681
1746
  }
1682
1747
  if (attempt === MAX_ATTEMPTS) throw e;
@@ -1739,7 +1804,7 @@ var init_types = __esm({
1739
1804
 
1740
1805
  // ../core/src/hooks/shellExecutor.ts
1741
1806
  import { spawn } from "child_process";
1742
- import path7 from "path";
1807
+ import path8 from "path";
1743
1808
  var MAX_OUTPUT, DEFAULT_TIMEOUT_MS, HARD_TIMEOUT_CAP_MS, ENV_WHITELIST, truncate, MAX_STDIN_FIELD, capFieldStrings, extractFilePath, executeHookCommand;
1744
1809
  var init_shellExecutor = __esm({
1745
1810
  "../core/src/hooks/shellExecutor.ts"() {
@@ -1785,7 +1850,7 @@ var init_shellExecutor = __esm({
1785
1850
  if (typeof rel !== "string" || !rel.trim()) return void 0;
1786
1851
  const base = typeof p.cwd === "string" && p.cwd || process.env.WORKSPACE_ROOT || process.cwd();
1787
1852
  try {
1788
- return path7.resolve(base, rel);
1853
+ return path8.resolve(base, rel);
1789
1854
  } catch {
1790
1855
  return void 0;
1791
1856
  }
@@ -2002,7 +2067,7 @@ var init_hooks = __esm({
2002
2067
  });
2003
2068
 
2004
2069
  // ../core/src/agent/truncate.ts
2005
- import path8 from "path";
2070
+ import path9 from "path";
2006
2071
  function stripAnsi(text) {
2007
2072
  return text.replace(ANSI_ESCAPE, "");
2008
2073
  }
@@ -2015,7 +2080,7 @@ function microcompactTextContent(raw) {
2015
2080
  function isAsyncGenerator(x) {
2016
2081
  return x != null && typeof x[Symbol.asyncIterator] === "function";
2017
2082
  }
2018
- var ANSI_ESCAPE, getFileAccessRoots, relativizeWorkspacePathsInText, truncateToolResult, truncateApprovalDetail, batchSummaryPrompt, compactBatch, ARCHIVE_INDEX_MAX_ENTRIES, ARCHIVE_INDEX_BATCH_CAP, extractArchiveEntities, parseSummarySlot, mergeSummarySlot, CHECKPOINT_MAX_CHARS, SLOT_PLACEHOLDER, CHECKPOINT_FORMAT, checkpointRules, checkpointPrompt, checkpointDirectPrompt, assembleSlot, parseSlotNarrativeState, synthesizeSlotNarrative, synthesizeSlotNarrativeFromBatch, compactSlotNarrative, splitIntoBatches, compactBatches, ensureSummarySlot, SUMMARY_SELF_COMPACT_THRESHOLD, ensureFitsWindow, collectToolResult;
2083
+ var ANSI_ESCAPE, getFileAccessRoots, relativizeWorkspacePathsInText, truncateToolResult, truncateApprovalDetail, batchSummaryPrompt, compactBatch, ARCHIVE_INDEX_MAX_ENTRIES, ARCHIVE_INDEX_BATCH_CAP, extractArchiveEntities, parseSummarySlot, mergeSummarySlot, CHECKPOINT_MAX_CHARS, SLOT_PLACEHOLDER, CHECKPOINT_FORMAT, checkpointRules, checkpointPrompt, checkpointDirectPrompt, assembleSlot, parseSlotNarrativeState, synthesizeSlotNarrative, synthesizeSlotNarrativeFromBatch, compactSlotNarrative, splitIntoBatches, compactBatches, ensureSummarySlot, SUMMARY_SELF_COMPACT_THRESHOLD, persistCompaction, ensureFitsWindow, collectToolResult;
2019
2084
  var init_truncate = __esm({
2020
2085
  "../core/src/agent/truncate.ts"() {
2021
2086
  "use strict";
@@ -2041,10 +2106,10 @@ var init_truncate = __esm({
2041
2106
  if (!text) return text;
2042
2107
  const roots = /* @__PURE__ */ new Set();
2043
2108
  try {
2044
- roots.add(path8.resolve(appConfig.userWorkspaceDir));
2109
+ roots.add(path9.resolve(appConfig.userWorkspaceDir));
2045
2110
  for (const r of getFileAccessRoots()) {
2046
2111
  try {
2047
- roots.add(path8.resolve(r));
2112
+ roots.add(path9.resolve(r));
2048
2113
  } catch {
2049
2114
  }
2050
2115
  }
@@ -2232,6 +2297,19 @@ ${lines}
2232
2297
  }
2233
2298
  };
2234
2299
  SUMMARY_SELF_COMPACT_THRESHOLD = 2e3;
2300
+ persistCompaction = async (sessionId, archivedMessageCount, summary) => {
2301
+ await setRollingState(sessionId, {
2302
+ archivedMessageCount,
2303
+ rollingSummary: summary,
2304
+ consecutiveFailures: 0,
2305
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2306
+ });
2307
+ await appendEvent(sessionId, {
2308
+ dscEvent: "compaction",
2309
+ archivedMessageCount,
2310
+ summary
2311
+ });
2312
+ };
2235
2313
  ensureFitsWindow = async (event) => {
2236
2314
  const correctionRatio = event.correctionRatio ?? 1.4;
2237
2315
  const toolsTokens = event.toolsTokens ?? 0;
@@ -2283,17 +2361,7 @@ ${lines}
2283
2361
  });
2284
2362
  const store = await getRollingState(event.sessionId);
2285
2363
  store.archivedMessageCount = (store.archivedMessageCount || 0) + toCompact.length;
2286
- await setRollingState(event.sessionId, {
2287
- archivedMessageCount: store.archivedMessageCount,
2288
- rollingSummary: summaryMsg.content,
2289
- consecutiveFailures: 0,
2290
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2291
- });
2292
- await appendEvent(event.sessionId, {
2293
- dscEvent: "compaction",
2294
- archivedMessageCount: store.archivedMessageCount,
2295
- summary: summaryMsg.content
2296
- });
2364
+ await persistCompaction(event.sessionId, store.archivedMessageCount, summaryMsg.content);
2297
2365
  } else if (keep > 1) {
2298
2366
  keep--;
2299
2367
  continue;
@@ -2302,17 +2370,7 @@ ${lines}
2302
2370
  event.messageArr.length = 0;
2303
2371
  event.messageArr.push(systemMsg, summaryMsg, ...keepRecent);
2304
2372
  const store = await getRollingState(event.sessionId);
2305
- await setRollingState(event.sessionId, {
2306
- archivedMessageCount: store.archivedMessageCount,
2307
- rollingSummary: summaryMsg.content,
2308
- consecutiveFailures: 0,
2309
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2310
- });
2311
- await appendEvent(event.sessionId, {
2312
- dscEvent: "compaction",
2313
- archivedMessageCount: store.archivedMessageCount,
2314
- summary: summaryMsg.content
2315
- });
2373
+ await persistCompaction(event.sessionId, store.archivedMessageCount, summaryMsg.content);
2316
2374
  } else {
2317
2375
  break;
2318
2376
  }
@@ -2419,8 +2477,8 @@ ${lines}
2419
2477
  });
2420
2478
 
2421
2479
  // ../core/src/tool/permissions.ts
2422
- import fs6 from "fs/promises";
2423
- import path9 from "path";
2480
+ import fs7 from "fs/promises";
2481
+ import path10 from "path";
2424
2482
  var PRIMARY_ARG, rules2, trustedProject, globCache, globToRegex, DANGER_COMMAND_TOOLS, compileRule, readPermissionConfig, toolNameMatches, ruleMatches, initPermissions, checkPermission, listPermissionRules, buildScopedAllowRule, resolveSettingsPath, addPermissionRule;
2425
2483
  var init_permissions = __esm({
2426
2484
  "../core/src/tool/permissions.ts"() {
@@ -2482,15 +2540,15 @@ var init_permissions = __esm({
2482
2540
  readPermissionConfig = async (includeProject) => {
2483
2541
  const merged = { allow: [], deny: [], ask: [] };
2484
2542
  const paths = [
2485
- path9.join(appConfig.dataDir, "settings.json"),
2543
+ path10.join(appConfig.dataDir, "settings.json"),
2486
2544
  // 全局用户级
2487
- ...includeProject ? [path9.join(process.cwd(), ".deepseeker-code", "settings.json")] : []
2545
+ ...includeProject ? [path10.join(process.cwd(), ".deepseeker-code", "settings.json")] : []
2488
2546
  // 项目级(叠加);未信任时省略
2489
2547
  ];
2490
2548
  for (const configPath of paths) {
2491
2549
  let raw;
2492
2550
  try {
2493
- raw = await fs6.readFile(configPath, "utf-8");
2551
+ raw = await fs7.readFile(configPath, "utf-8");
2494
2552
  } catch {
2495
2553
  continue;
2496
2554
  }
@@ -2575,7 +2633,7 @@ var init_permissions = __esm({
2575
2633
  }
2576
2634
  return `${toolName}(${val})`;
2577
2635
  };
2578
- resolveSettingsPath = (scope) => scope === "global" ? path9.join(appConfig.dataDir, "settings.json") : path9.join(process.cwd(), ".deepseeker-code", "settings.json");
2636
+ resolveSettingsPath = (scope) => scope === "global" ? path10.join(appConfig.dataDir, "settings.json") : path10.join(process.cwd(), ".deepseeker-code", "settings.json");
2579
2637
  addPermissionRule = async (scope, kind, ruleStr) => {
2580
2638
  if (scope === "project" && !trustedProject) return false;
2581
2639
  const compiled = compileRule(ruleStr, `runtime:addPermissionRule(${scope})`, kind);
@@ -2587,7 +2645,7 @@ var init_permissions = __esm({
2587
2645
  const arr = Array.isArray(cfg.permissions[kind]) ? cfg.permissions[kind] : cfg.permissions[kind] = [];
2588
2646
  if (!arr.includes(ruleStr)) {
2589
2647
  arr.push(ruleStr);
2590
- await fs6.mkdir(path9.dirname(file), { recursive: true });
2648
+ await fs7.mkdir(path10.dirname(file), { recursive: true });
2591
2649
  await atomicWriteJSON(file, cfg);
2592
2650
  }
2593
2651
  if (!rules2[kind].some((r) => r.raw === compiled.raw)) rules2[kind].push(compiled);
@@ -2625,9 +2683,9 @@ var init_sessionRegistry = __esm({
2625
2683
  });
2626
2684
 
2627
2685
  // ../core/src/tool/guard.ts
2628
- import fs7 from "fs/promises";
2686
+ import fs8 from "fs/promises";
2629
2687
  import fsSync from "fs";
2630
- import path10 from "path";
2688
+ import path11 from "path";
2631
2689
  import ignore from "ignore";
2632
2690
  import { AsyncLocalStorage } from "node:async_hooks";
2633
2691
  var WORKSPACE_ROOT, workspaceAls, getActiveWorkspaceRoot, runWithWorkspaceRoot, runWithSessionContext, BUILTIN_IGNORE_RULES, ignoreCache, ignoreBuilding, allowedRootsReal, getAllowedWorkspaceRoots, getContainingRoot, allowedBoundaryRoots, resolveSafePath, resolveReadablePath, assertWithinWorkspace, PROTECTED_WRITE_DIRS, COMMAND_ENV_DENYLIST, SENSITIVE_ENV_PATTERN, scrubCommandEnv, isProtectedWrite, scanIgnoreFilesRecursive, buildIgnoreEngine, getIgnoreForBase, initializeWorkspaceIgnore, checkIsPathIgnored, requestApproval;
@@ -2683,8 +2741,8 @@ var init_guard = __esm({
2683
2741
  getContainingRoot = (absPath) => {
2684
2742
  let best;
2685
2743
  for (const r of allowedBoundaryRoots()) {
2686
- const rel = path10.relative(r, absPath);
2687
- if (!rel.startsWith("..") && !path10.isAbsolute(rel)) {
2744
+ const rel = path11.relative(r, absPath);
2745
+ if (!rel.startsWith("..") && !path11.isAbsolute(rel)) {
2688
2746
  if (!best || r.length > best.length) best = r;
2689
2747
  }
2690
2748
  }
@@ -2701,16 +2759,16 @@ var init_guard = __esm({
2701
2759
  };
2702
2760
  resolveSafePath = (rel, base) => {
2703
2761
  const root = base ?? getActiveWorkspaceRoot();
2704
- const candidateAbsPath = path10.resolve(root, rel);
2762
+ const candidateAbsPath = path11.resolve(root, rel);
2705
2763
  let truePhysicalPath = candidateAbsPath;
2706
2764
  try {
2707
2765
  if (fsSync.existsSync(candidateAbsPath)) {
2708
2766
  truePhysicalPath = fsSync.realpathSync(candidateAbsPath);
2709
2767
  } else {
2710
- const parentDir = path10.dirname(candidateAbsPath);
2768
+ const parentDir = path11.dirname(candidateAbsPath);
2711
2769
  if (fsSync.existsSync(parentDir)) {
2712
2770
  const trueParentDir = fsSync.realpathSync(parentDir);
2713
- truePhysicalPath = path10.join(trueParentDir, path10.basename(candidateAbsPath));
2771
+ truePhysicalPath = path11.join(trueParentDir, path11.basename(candidateAbsPath));
2714
2772
  }
2715
2773
  }
2716
2774
  } catch (e) {
@@ -2724,8 +2782,8 @@ var init_guard = __esm({
2724
2782
  }
2725
2783
  })() : allowedBoundaryRoots();
2726
2784
  const escaped = boundaryRoots.every((r) => {
2727
- const rel0 = path10.relative(r, truePhysicalPath);
2728
- return rel0.startsWith("..") || path10.isAbsolute(rel0);
2785
+ const rel0 = path11.relative(r, truePhysicalPath);
2786
+ return rel0.startsWith("..") || path11.isAbsolute(rel0);
2729
2787
  });
2730
2788
  if (escaped) {
2731
2789
  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}`);
@@ -2734,12 +2792,12 @@ var init_guard = __esm({
2734
2792
  };
2735
2793
  resolveReadablePath = (rel) => {
2736
2794
  const root = getActiveWorkspaceRoot();
2737
- const absPath = path10.resolve(root, rel);
2795
+ const absPath = path11.resolve(root, rel);
2738
2796
  if (!fsSync.existsSync(absPath)) {
2739
- const rootName = path10.basename(root);
2797
+ const rootName = path11.basename(root);
2740
2798
  const firstSeg = rel.split(/[\\/]/)[0];
2741
2799
  if (rootName && firstSeg === rootName) {
2742
- const alt = path10.resolve(root, rel.slice(firstSeg.length + 1));
2800
+ const alt = path11.resolve(root, rel.slice(firstSeg.length + 1));
2743
2801
  if (fsSync.existsSync(alt)) return alt;
2744
2802
  }
2745
2803
  }
@@ -2752,9 +2810,9 @@ var init_guard = __esm({
2752
2810
  if (fsSync.existsSync(absPath)) {
2753
2811
  truePhysicalPath = fsSync.realpathSync(absPath);
2754
2812
  } else {
2755
- const parentDir = path10.dirname(absPath);
2813
+ const parentDir = path11.dirname(absPath);
2756
2814
  if (fsSync.existsSync(parentDir)) {
2757
- truePhysicalPath = path10.join(fsSync.realpathSync(parentDir), path10.basename(absPath));
2815
+ truePhysicalPath = path11.join(fsSync.realpathSync(parentDir), path11.basename(absPath));
2758
2816
  }
2759
2817
  }
2760
2818
  } catch (e) {
@@ -2768,8 +2826,8 @@ var init_guard = __esm({
2768
2826
  }
2769
2827
  })() : allowedBoundaryRoots();
2770
2828
  const escaped = boundaryRoots.every((r) => {
2771
- const rel0 = path10.relative(r, truePhysicalPath);
2772
- return rel0.startsWith("..") || path10.isAbsolute(rel0);
2829
+ const rel0 = path11.relative(r, truePhysicalPath);
2830
+ return rel0.startsWith("..") || path11.isAbsolute(rel0);
2773
2831
  });
2774
2832
  if (escaped) {
2775
2833
  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}`);
@@ -2796,7 +2854,7 @@ var init_guard = __esm({
2796
2854
  if (!relOrAbs) return false;
2797
2855
  try {
2798
2856
  const base = cwd || process.env.WORKSPACE_ROOT || process.cwd();
2799
- const abs = path10.isAbsolute(relOrAbs) ? relOrAbs : path10.resolve(base, relOrAbs);
2857
+ const abs = path11.isAbsolute(relOrAbs) ? relOrAbs : path11.resolve(base, relOrAbs);
2800
2858
  const lower = abs.replace(/\\/g, "/").toLowerCase();
2801
2859
  return PROTECTED_WRITE_DIRS.some((d) => {
2802
2860
  const seg = ("/" + d).toLowerCase();
@@ -2808,12 +2866,12 @@ var init_guard = __esm({
2808
2866
  };
2809
2867
  scanIgnoreFilesRecursive = async (dirPath, base, engine) => {
2810
2868
  try {
2811
- const entries = await fs7.readdir(dirPath, { withFileTypes: true });
2869
+ const entries = await fs8.readdir(dirPath, { withFileTypes: true });
2812
2870
  for (const entry of entries) {
2813
2871
  if (entry.isFile() && (entry.name === ".gitignore" || entry.name === ".agentignore")) {
2814
- const fullPath = path10.join(dirPath, entry.name);
2815
- const content = await fs7.readFile(fullPath, "utf-8");
2816
- const relDir = path10.relative(base, dirPath).replace(/\\/g, "/");
2872
+ const fullPath = path11.join(dirPath, entry.name);
2873
+ const content = await fs8.readFile(fullPath, "utf-8");
2874
+ const relDir = path11.relative(base, dirPath).replace(/\\/g, "/");
2817
2875
  const rules3 = content.split(/\r?\n/).map((line) => {
2818
2876
  const trimmed = line.trim();
2819
2877
  if (!trimmed || trimmed.startsWith("#")) return "";
@@ -2824,7 +2882,7 @@ var init_guard = __esm({
2824
2882
  }
2825
2883
  for (const entry of entries) {
2826
2884
  if (entry.isDirectory() && entry.name !== "node_modules" && entry.name !== ".git") {
2827
- await scanIgnoreFilesRecursive(path10.join(dirPath, entry.name), base, engine);
2885
+ await scanIgnoreFilesRecursive(path11.join(dirPath, entry.name), base, engine);
2828
2886
  }
2829
2887
  }
2830
2888
  } catch {
@@ -2895,7 +2953,7 @@ var init_guard = __esm({
2895
2953
  // ../core/src/tool/registry/background.ts
2896
2954
  import { spawn as spawn2, execFileSync } from "child_process";
2897
2955
  import fsSync2 from "fs";
2898
- import path11 from "path";
2956
+ import path12 from "path";
2899
2957
  function appendOutput(task, chunk) {
2900
2958
  task.outputBuffer += chunk;
2901
2959
  if (task.outputBuffer.length > MAX_BUFFER_CHARS) {
@@ -2920,7 +2978,7 @@ async function killTree(proc) {
2920
2978
  }
2921
2979
  }
2922
2980
  async function killBackgroundTasksUnder(dirPath) {
2923
- const norm = (p) => path11.resolve(p).replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
2981
+ const norm = (p) => path12.resolve(p).replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
2924
2982
  const target = norm(dirPath);
2925
2983
  let killed = 0;
2926
2984
  for (const task of registry.values()) {
@@ -2965,9 +3023,9 @@ var init_background = __esm({
2965
3023
  if (envShell && envShell.toLowerCase() !== "cmd") candidates.push(envShell);
2966
3024
  const gitExe = whereLines("git")[0];
2967
3025
  if (gitExe) {
2968
- const dir = path11.dirname(gitExe);
2969
- const root = path11.dirname(dir);
2970
- candidates.push(path11.join(root, "bin", "bash.exe"), path11.join(dir, "bash.exe"), path11.join(path11.dirname(root), "bin", "bash.exe"));
3026
+ const dir = path12.dirname(gitExe);
3027
+ const root = path12.dirname(dir);
3028
+ candidates.push(path12.join(root, "bin", "bash.exe"), path12.join(dir, "bash.exe"), path12.join(path12.dirname(root), "bin", "bash.exe"));
2971
3029
  }
2972
3030
  const bashHits = whereLines("bash").filter((p) => !/\\System32\\/i.test(p)).sort((a, b) => Number(/\\Git\\/i.test(b)) - Number(/\\Git\\/i.test(a)));
2973
3031
  candidates.push(...bashHits);
@@ -3765,17 +3823,17 @@ ${capped || JSON.stringify(result)}`;
3765
3823
  });
3766
3824
 
3767
3825
  // ../core/src/tool/mcp/loader.ts
3768
- import fs8 from "fs/promises";
3769
- import path12 from "path";
3826
+ import fs9 from "fs/promises";
3827
+ import path13 from "path";
3770
3828
  import { homedir } from "os";
3771
3829
  function sanitize(s) {
3772
3830
  return s.replace(/[^a-zA-Z0-9_]/g, "_");
3773
3831
  }
3774
3832
  async function readMcpConfig() {
3775
- const configPath = process.env.MCP_CONFIG || path12.join(appConfig.dataDir, "mcp.json");
3833
+ const configPath = process.env.MCP_CONFIG || path13.join(appConfig.dataDir, "mcp.json");
3776
3834
  let raw;
3777
3835
  try {
3778
- raw = await fs8.readFile(configPath, "utf-8");
3836
+ raw = await fs9.readFile(configPath, "utf-8");
3779
3837
  } catch {
3780
3838
  return {};
3781
3839
  }
@@ -4423,7 +4481,7 @@ var init_toolFilter = __esm({
4423
4481
  });
4424
4482
 
4425
4483
  // ../core/src/common/registry.ts
4426
- import fs9 from "fs/promises";
4484
+ import fs10 from "fs/promises";
4427
4485
  var createRegistry, filterSources, scanSources;
4428
4486
  var init_registry2 = __esm({
4429
4487
  "../core/src/common/registry.ts"() {
@@ -4453,7 +4511,7 @@ var init_registry2 = __esm({
4453
4511
  for (const s of sources) {
4454
4512
  let entries;
4455
4513
  try {
4456
- entries = await fs9.readdir(s.dir, { withFileTypes: true });
4514
+ entries = await fs10.readdir(s.dir, { withFileTypes: true });
4457
4515
  } catch {
4458
4516
  continue;
4459
4517
  }
@@ -4550,8 +4608,8 @@ ${AGENT_USAGE_HINT}`);
4550
4608
  });
4551
4609
 
4552
4610
  // ../core/src/projectGuide/loader.ts
4553
- import fs10 from "fs/promises";
4554
- import path13 from "path";
4611
+ import fs11 from "fs/promises";
4612
+ import path14 from "path";
4555
4613
  var CANDIDATES, MAX_GUIDE_BYTES, cached, initProjectGuide, getProjectGuide;
4556
4614
  var init_loader2 = __esm({
4557
4615
  "../core/src/projectGuide/loader.ts"() {
@@ -4568,7 +4626,7 @@ var init_loader2 = __esm({
4568
4626
  try {
4569
4627
  for (const name of CANDIDATES) {
4570
4628
  try {
4571
- const raw = await fs10.readFile(path13.join(WORKSPACE_ROOT, name), "utf-8");
4629
+ const raw = await fs11.readFile(path14.join(WORKSPACE_ROOT, name), "utf-8");
4572
4630
  const body = raw.length > MAX_GUIDE_BYTES ? raw.slice(0, MAX_GUIDE_BYTES) + `
4573
4631
 
4574
4632
  \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;
@@ -4732,12 +4790,13 @@ var init_systemInjections = __esm({
4732
4790
  en: "Always produce ALL user-facing output in English: your replies, interim narration, todo item titles, the plan text you submit via exit_plan_mode, code comments, and commit messages. Keep code identifiers as-is; tool results and system instructions may arrive in Chinese \u2014 quote them verbatim where needed, but your own narration and explanations must stay in English."
4733
4791
  };
4734
4792
  const lastUserText = (() => {
4793
+ const dropSyntheticLines = (t) => t.split("\n").filter((l) => !l.trimStart().startsWith("\u{1F5BC}")).join("\n").trim();
4735
4794
  for (let i = message.length - 1; i >= 0; i--) {
4736
4795
  const m = message[i];
4737
4796
  if (m?.role !== "user") continue;
4738
4797
  const c = m.content;
4739
- if (typeof c === "string") return c;
4740
- if (Array.isArray(c)) return c.filter((p) => typeof p?.text === "string").map((p) => p.text).join(" ");
4798
+ if (typeof c === "string") return dropSyntheticLines(c);
4799
+ if (Array.isArray(c)) return dropSyntheticLines(c.filter((p) => typeof p?.text === "string").map((p) => p.text).join(" "));
4741
4800
  return "";
4742
4801
  }
4743
4802
  return "";
@@ -4810,9 +4869,9 @@ var init_agent = __esm({
4810
4869
  });
4811
4870
 
4812
4871
  // ../core/src/tool/worktree/manager.ts
4813
- import path14 from "path";
4872
+ import path15 from "path";
4814
4873
  import os4 from "os";
4815
- import fs11 from "fs";
4874
+ import fs12 from "fs";
4816
4875
  var runMainGit, worktreeRootDir, worktreeDir, isNotARepoError, createWorktree, harvestDiff, runInWorktree, removeWorktree, sweepOrphanedWorktrees, disposeAllSessionWorktrees;
4817
4876
  var init_manager = __esm({
4818
4877
  "../core/src/tool/worktree/manager.ts"() {
@@ -4823,8 +4882,8 @@ var init_manager = __esm({
4823
4882
  init_background();
4824
4883
  init_sessionRegistry();
4825
4884
  runMainGit = (args, maxBuffer = 1024 * 1024 * 5) => execFileSmart("git", args, { cwd: WORKSPACE_ROOT, maxBuffer });
4826
- worktreeRootDir = () => path14.join(os4.tmpdir(), "deepseeker-code-worktrees", appConfig.userWorkspaceDir);
4827
- worktreeDir = (sessionId, stepId) => path14.join(worktreeRootDir(), sessionId, stepId);
4885
+ worktreeRootDir = () => path15.join(os4.tmpdir(), "deepseeker-code-worktrees", appConfig.userWorkspaceDir);
4886
+ worktreeDir = (sessionId, stepId) => path15.join(worktreeRootDir(), sessionId, stepId);
4828
4887
  isNotARepoError = (e) => {
4829
4888
  const text = `${e?.message || ""} ${e?.stderr || ""}`.toLowerCase();
4830
4889
  return text.includes("not a git repository");
@@ -4835,12 +4894,12 @@ var init_manager = __esm({
4835
4894
  const wtPath = worktreeDir(sessionId, stepId);
4836
4895
  const shortId = sessionId.replace(/[^A-Za-z0-9-]/g, "").slice(0, 8) || "x";
4837
4896
  const branch = `dsc-wt-${shortId}-${stepId}`;
4838
- await fs11.promises.mkdir(path14.dirname(wtPath), { recursive: true });
4897
+ await fs12.promises.mkdir(path15.dirname(wtPath), { recursive: true });
4839
4898
  try {
4840
4899
  await runMainGit(["worktree", "add", "-b", branch, wtPath, "HEAD"]);
4841
4900
  } catch (e) {
4842
4901
  if (e?.code === "ENOENT" || /already exists|not a working tree/i.test(`${e?.stderr || ""} ${e?.message || ""}`)) {
4843
- await fs11.promises.rm(wtPath, { recursive: true, force: true }).catch(() => {
4902
+ await fs12.promises.rm(wtPath, { recursive: true, force: true }).catch(() => {
4844
4903
  });
4845
4904
  await runMainGit(["worktree", "add", "-b", branch, wtPath, "HEAD"]);
4846
4905
  } else {
@@ -4888,7 +4947,7 @@ var init_manager = __esm({
4888
4947
  try {
4889
4948
  await runMainGit(["worktree", "remove", "--force", wt.path]);
4890
4949
  } catch (e) {
4891
- await fs11.promises.rm(wt.path, { recursive: true, force: true }).catch(() => {
4950
+ await fs12.promises.rm(wt.path, { recursive: true, force: true }).catch(() => {
4892
4951
  });
4893
4952
  }
4894
4953
  try {
@@ -4905,30 +4964,30 @@ var init_manager = __esm({
4905
4964
  const root = worktreeRootDir();
4906
4965
  let entries;
4907
4966
  try {
4908
- entries = await fs11.promises.readdir(root);
4967
+ entries = await fs12.promises.readdir(root);
4909
4968
  } catch {
4910
4969
  return;
4911
4970
  }
4912
4971
  let swept = 0;
4913
4972
  for (const sessionIdDir of entries) {
4914
- const sessionPath = path14.join(root, sessionIdDir);
4973
+ const sessionPath = path15.join(root, sessionIdDir);
4915
4974
  let stepDirs;
4916
4975
  try {
4917
- stepDirs = await fs11.promises.readdir(sessionPath);
4976
+ stepDirs = await fs12.promises.readdir(sessionPath);
4918
4977
  } catch {
4919
4978
  continue;
4920
4979
  }
4921
4980
  for (const stepDir of stepDirs) {
4922
- const wtPath = path14.join(sessionPath, stepDir);
4981
+ const wtPath = path15.join(sessionPath, stepDir);
4923
4982
  try {
4924
4983
  await runMainGit(["worktree", "remove", "--force", wtPath]);
4925
4984
  } catch {
4926
- await fs11.promises.rm(wtPath, { recursive: true, force: true }).catch(() => {
4985
+ await fs12.promises.rm(wtPath, { recursive: true, force: true }).catch(() => {
4927
4986
  });
4928
4987
  }
4929
4988
  swept++;
4930
4989
  }
4931
- await fs11.promises.rm(sessionPath, { recursive: true, force: true }).catch(() => {
4990
+ await fs12.promises.rm(sessionPath, { recursive: true, force: true }).catch(() => {
4932
4991
  });
4933
4992
  }
4934
4993
  if (swept > 0) {
@@ -5196,7 +5255,7 @@ var init_workflow = __esm({
5196
5255
 
5197
5256
  // ../core/src/tool/tsHost.ts
5198
5257
  import fsSync3 from "fs";
5199
- import path15 from "path";
5258
+ import path16 from "path";
5200
5259
  var _ts, _tsTried, getTs, buildDefaultOptions, findTsConfigBounded, resolveTsConfig, createProjectHost, lsCache, getLanguageService, realpathNative, posToLineCol, SUPPORTED_SOURCE_EXTS, checkSupportedSourceExt, lineColToPos;
5201
5260
  var init_tsHost = __esm({
5202
5261
  "../core/src/tool/tsHost.ts"() {
@@ -5229,16 +5288,16 @@ var init_tsHost = __esm({
5229
5288
  strict: false
5230
5289
  });
5231
5290
  findTsConfigBounded = (ts, absPath) => {
5232
- const root = path15.resolve(getContainingRoot(absPath));
5233
- let dir = path15.dirname(absPath);
5291
+ const root = path16.resolve(getContainingRoot(absPath));
5292
+ let dir = path16.dirname(absPath);
5234
5293
  while (true) {
5235
- const candidate = path15.join(dir, "tsconfig.json");
5294
+ const candidate = path16.join(dir, "tsconfig.json");
5236
5295
  try {
5237
5296
  if (fsSync3.existsSync(candidate)) return candidate;
5238
5297
  } catch {
5239
5298
  }
5240
- if (path15.resolve(dir) === root) break;
5241
- const parent = path15.dirname(dir);
5299
+ if (path16.resolve(dir) === root) break;
5300
+ const parent = path16.dirname(dir);
5242
5301
  if (parent === dir) break;
5243
5302
  dir = parent;
5244
5303
  }
@@ -5249,7 +5308,7 @@ var init_tsHost = __esm({
5249
5308
  if (!tsConfigPath) {
5250
5309
  return { options: buildDefaultOptions(ts), fileNames: [], projectRoot: getContainingRoot(absPath) };
5251
5310
  }
5252
- const basePath = path15.dirname(tsConfigPath);
5311
+ const basePath = path16.dirname(tsConfigPath);
5253
5312
  const raw = ts.readConfigFile(tsConfigPath, ts.sys.readFile);
5254
5313
  if (raw.error) return { options: buildDefaultOptions(ts), fileNames: [], projectRoot: basePath };
5255
5314
  const parsed = ts.parseJsonConfigFileContent(raw.config, ts.sys, basePath);
@@ -5260,7 +5319,7 @@ var init_tsHost = __esm({
5260
5319
  const roots = /* @__PURE__ */ new Set();
5261
5320
  const caseSensitive = ts.sys.useCaseSensitiveFileNames;
5262
5321
  const canonical = (f) => caseSensitive ? f : f.toLowerCase();
5263
- const keyOf = (f) => canonical(path15.resolve(f)).replace(/\\/g, "/");
5322
+ const keyOf = (f) => canonical(path16.resolve(f)).replace(/\\/g, "/");
5264
5323
  rootFileNames.forEach((f) => roots.add(keyOf(f)));
5265
5324
  const fresh = (fileName) => {
5266
5325
  const key = keyOf(fileName);
@@ -5345,7 +5404,7 @@ var init_tsHost = __esm({
5345
5404
  };
5346
5405
  SUPPORTED_SOURCE_EXTS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
5347
5406
  checkSupportedSourceExt = (displayPath) => {
5348
- const ext = path15.extname(displayPath).toLowerCase();
5407
+ const ext = path16.extname(displayPath).toLowerCase();
5349
5408
  if (SUPPORTED_SOURCE_EXTS.has(ext)) return null;
5350
5409
  return `\u274C [\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`;
5351
5410
  };
@@ -5354,8 +5413,8 @@ var init_tsHost = __esm({
5354
5413
  });
5355
5414
 
5356
5415
  // ../core/src/tool/registry/fs.ts
5357
- import fs12 from "fs/promises";
5358
- import path16 from "path";
5416
+ import fs13 from "fs/promises";
5417
+ import path17 from "path";
5359
5418
  import { createReadStream } from "fs";
5360
5419
  import * as readline from "readline";
5361
5420
  var isSensitiveReadTarget, stripReadFileLineNumbers, maskSecretsInContent, makeTmpPath, ATOMIC_TMP_RE, sweepStaleAtomicTmp, assertReadable, stripEdgeBlankLines, matchLineBlockWith, diagnoseOldStr, reindentToBase, alignIndentsByAnchor, applyOneEditToContent, fsTools;
@@ -5399,7 +5458,7 @@ var init_fs = __esm({
5399
5458
  return lines.map((l) => l.length === 0 ? l : l.replace(re, "")).join("\n");
5400
5459
  };
5401
5460
  maskSecretsInContent = (_args, output) => {
5402
- return output.replace(/((?:api[_-]?key|secret|password|passwd|token|authorization|auth[_-]?token|access[_-]?key|secret[_-]?key|private[_-]?key)\s*[:=]\s*['"]?)[A-Za-z0-9_\-+/=.]{8,}(['"]?)/gi, "$1[MASKED_SECRET]$2").replace(/-----BEGIN [A-Z ]+PRIVATE KEY-----[\s\S]*?-----END [A-Z ]+PRIVATE KEY-----/g, "[MASKED_SECRET (private key block)]");
5461
+ return output.replace(/((?:api[_-]?key|secret|password|passwd|token|authorization|auth[_-]?token|access[_-]?key|secret[_-]?key|private[_-]?key)\s*[:=]\s*)(['"])[A-Za-z0-9_\-+/=.]{8,}\2/gi, "$1$2[MASKED_SECRET]$2").replace(/((?:authorization|auth[_-]?token)\s*[:=]\s*Bearer\s+)[A-Za-z0-9_\-+/=.]{8,}/gi, "$1[MASKED_SECRET]").replace(/-----BEGIN [A-Z ]+PRIVATE KEY-----[\s\S]*?-----END [A-Z ]+PRIVATE KEY-----/g, "[MASKED_SECRET (private key block)]");
5403
5462
  };
5404
5463
  makeTmpPath = (absPath) => `${absPath}.${Date.now()}.${Math.random().toString(36).slice(2, 7)}.tmp`;
5405
5464
  ATOMIC_TMP_RE = /\.\d+\.[a-z0-9]{1,12}\.tmp$/i;
@@ -5411,21 +5470,21 @@ var init_fs = __esm({
5411
5470
  const walk = async (dir) => {
5412
5471
  let entries;
5413
5472
  try {
5414
- entries = await fs12.readdir(dir, { withFileTypes: true });
5473
+ entries = await fs13.readdir(dir, { withFileTypes: true });
5415
5474
  } catch {
5416
5475
  return;
5417
5476
  }
5418
5477
  for (const e of entries) {
5419
- const full = path16.join(dir, e.name);
5478
+ const full = path17.join(dir, e.name);
5420
5479
  if (e.isDirectory()) {
5421
5480
  if (!skipDirs.has(e.name)) await walk(full);
5422
5481
  continue;
5423
5482
  }
5424
5483
  if (!e.isFile() || !ATOMIC_TMP_RE.test(e.name)) continue;
5425
5484
  try {
5426
- const st = await fs12.stat(full);
5485
+ const st = await fs13.stat(full);
5427
5486
  if (st.mtimeMs > cutoff) continue;
5428
- await fs12.unlink(full);
5487
+ await fs13.unlink(full);
5429
5488
  removed++;
5430
5489
  } catch {
5431
5490
  }
@@ -5687,11 +5746,11 @@ ${formattedCode}${hasMore ? `
5687
5746
  await initializeWorkspaceIgnore();
5688
5747
  const buildTreeText = async (currentPath, currentDepth, prefix = "") => {
5689
5748
  if (currentDepth > maxDepth || hitScanLimit) return "";
5690
- const entries = await fs12.readdir(currentPath, { withFileTypes: true });
5749
+ const entries = await fs13.readdir(currentPath, { withFileTypes: true });
5691
5750
  const validEntries = entries.filter((entry) => {
5692
5751
  if (entry.isSymbolicLink()) return false;
5693
- const fullPath = path16.join(currentPath, entry.name);
5694
- const relPath = path16.relative(getActiveWorkspaceRoot(), fullPath).replace(/\\/g, "/");
5752
+ const fullPath = path17.join(currentPath, entry.name);
5753
+ const relPath = path17.relative(getActiveWorkspaceRoot(), fullPath).replace(/\\/g, "/");
5695
5754
  return !checkIsPathIgnored(entry.isDirectory() ? `${relPath}/` : relPath);
5696
5755
  });
5697
5756
  let output = "";
@@ -5710,7 +5769,7 @@ ${formattedCode}${hasMore ? `
5710
5769
  `;
5711
5770
  if (entry.isDirectory()) {
5712
5771
  const nextPrefix = prefix + (isLast ? " " : "\u2502 ");
5713
- const fullPath = path16.join(currentPath, entry.name);
5772
+ const fullPath = path17.join(currentPath, entry.name);
5714
5773
  const subTree = await buildTreeText(fullPath, currentDepth + 1, nextPrefix);
5715
5774
  output += subTree;
5716
5775
  }
@@ -5774,7 +5833,7 @@ ${patches}`;
5774
5833
  return `\u274C [\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`;
5775
5834
  }
5776
5835
  const absPath = resolveSafePath(args.path);
5777
- const rawContent = await fs12.readFile(absPath, "utf-8");
5836
+ const rawContent = await fs13.readFile(absPath, "utf-8");
5778
5837
  const isCRLF = rawContent.includes("\r\n");
5779
5838
  let content = rawContent.replace(/\r\n/g, "\n");
5780
5839
  const summaries = [];
@@ -5787,7 +5846,7 @@ ${patches}`;
5787
5846
  summaries.push(editList.length === 1 ? r.summary : ` ${i + 1}. ${r.summary}`);
5788
5847
  }
5789
5848
  assertWithinWorkspace(absPath);
5790
- await fs12.writeFile(absPath, isCRLF ? content.replace(/\n/g, "\r\n") : content, "utf-8");
5849
+ await fs13.writeFile(absPath, isCRLF ? content.replace(/\n/g, "\r\n") : content, "utf-8");
5791
5850
  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
5792
5851
  ${summaries.join("\n")}`;
5793
5852
  } catch (error) {
@@ -5817,24 +5876,24 @@ ${summaries.join("\n")}`;
5817
5876
  try {
5818
5877
  const absPath = resolveSafePath(args.path);
5819
5878
  try {
5820
- await fs12.access(absPath);
5879
+ await fs13.access(absPath);
5821
5880
  return `\u274C [\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`;
5822
5881
  } catch (e) {
5823
5882
  if (e?.code !== "ENOENT") throw e;
5824
5883
  }
5825
5884
  const content = args.content ?? "";
5826
5885
  assertWithinWorkspace(absPath);
5827
- await fs12.mkdir(path16.dirname(absPath), { recursive: true });
5886
+ await fs13.mkdir(path17.dirname(absPath), { recursive: true });
5828
5887
  tmpPath = makeTmpPath(absPath);
5829
- await fs12.writeFile(tmpPath, content, "utf-8");
5830
- await fs12.rename(tmpPath, absPath);
5888
+ await fs13.writeFile(tmpPath, content, "utf-8");
5889
+ await fs13.rename(tmpPath, absPath);
5831
5890
  return `\u2705 [\u521B\u5EFA\u6210\u529F]\uFF1A\u65B0\u6587\u4EF6 [${args.path}] \u5DF2\u521B\u5EFA\uFF0C\u5199\u5165 ${content.length} \u5B57\u7B26\u3002`;
5832
5891
  } catch (error) {
5833
5892
  return `\u64CD\u4F5C\u5931\u8D25: ${error.message}`;
5834
5893
  } finally {
5835
5894
  if (tmpPath) {
5836
5895
  try {
5837
- await fs12.unlink(tmpPath);
5896
+ await fs13.unlink(tmpPath);
5838
5897
  } catch {
5839
5898
  }
5840
5899
  }
@@ -5863,7 +5922,7 @@ ${summaries.join("\n")}`;
5863
5922
  }
5864
5923
  let rel = "";
5865
5924
  try {
5866
- rel = path16.relative(getActiveWorkspaceRoot(), resolveSafePath(cleanPath));
5925
+ rel = path17.relative(getActiveWorkspaceRoot(), resolveSafePath(cleanPath));
5867
5926
  } catch {
5868
5927
  }
5869
5928
  if (rel === "" || rel === "src") {
@@ -5871,7 +5930,7 @@ ${summaries.join("\n")}`;
5871
5930
  }
5872
5931
  let label = "\u6587\u4EF6\u6216\u76EE\u5F55";
5873
5932
  try {
5874
- const stat = await fs12.stat(resolveSafePath(cleanPath));
5933
+ const stat = await fs13.stat(resolveSafePath(cleanPath));
5875
5934
  label = stat.isDirectory() ? "\u4E00\u6574\u4E2A\u6587\u4EF6\u5939\u76EE\u5F55" : "\u7EAF\u7269\u7406\u6587\u4EF6";
5876
5935
  } catch {
5877
5936
  }
@@ -5884,22 +5943,22 @@ ${summaries.join("\n")}`;
5884
5943
  return `\u274C [\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`;
5885
5944
  }
5886
5945
  const absPath = resolveSafePath(cleanPath);
5887
- const rel = path16.relative(getActiveWorkspaceRoot(), absPath);
5888
- if (!rel || rel === "" || rel === "src" || rel.startsWith("..") || path16.isAbsolute(rel)) {
5946
+ const rel = path17.relative(getActiveWorkspaceRoot(), absPath);
5947
+ if (!rel || rel === "" || rel === "src" || rel.startsWith("..") || path17.isAbsolute(rel)) {
5889
5948
  return `\u274C [\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`;
5890
5949
  }
5891
5950
  let stat;
5892
5951
  try {
5893
- stat = await fs12.stat(absPath);
5952
+ stat = await fs13.stat(absPath);
5894
5953
  } catch {
5895
5954
  return `\u274C [\u9500\u6BC1\u5931\u8D25]\uFF1A\u5728\u5DE5\u4F5C\u533A\u5185\u672A\u627E\u5230\u6307\u5B9A\u7684\u8DEF\u5F84 [${cleanPath}]\u3002`;
5896
5955
  }
5897
5956
  const isDirectory = stat.isDirectory();
5898
5957
  assertWithinWorkspace(absPath);
5899
5958
  if (isDirectory) {
5900
- await fs12.rm(absPath, { recursive: true, force: true });
5959
+ await fs13.rm(absPath, { recursive: true, force: true });
5901
5960
  } else {
5902
- await fs12.unlink(absPath);
5961
+ await fs13.unlink(absPath);
5903
5962
  }
5904
5963
  const targetTypeLabel = isDirectory ? "\u4E00\u6574\u4E2A\u6587\u4EF6\u5939\u76EE\u5F55" : "\u7EAF\u7269\u7406\u6587\u4EF6";
5905
5964
  return `\u2705 [\u8DEF\u5F84\u9500\u6BC1\u6210\u529F]\uFF1A\u5DF2\u6210\u529F\u6C38\u4E45\u9500\u6BC1${targetTypeLabel} [${cleanPath}]\u3002`;
@@ -5930,15 +5989,15 @@ ${summaries.join("\n")}`;
5930
5989
  try {
5931
5990
  const absPath = resolveSafePath(args.path);
5932
5991
  assertWithinWorkspace(absPath);
5933
- await fs12.mkdir(path16.dirname(absPath), { recursive: true });
5992
+ await fs13.mkdir(path17.dirname(absPath), { recursive: true });
5934
5993
  tmpPath = makeTmpPath(absPath);
5935
- await fs12.writeFile(tmpPath, args.content, "utf-8");
5936
- await fs12.rename(tmpPath, absPath);
5994
+ await fs13.writeFile(tmpPath, args.content, "utf-8");
5995
+ await fs13.rename(tmpPath, absPath);
5937
5996
  return `\u2705 [\u6587\u4EF6\u5199\u5165\u6210\u529F]\uFF1A\u5DF2\u5168\u91CF\u5199\u5165 [${args.path}]\uFF08${args.content.length} \u5B57\u7B26\uFF09\u3002`;
5938
5997
  } catch (error) {
5939
5998
  if (tmpPath) {
5940
5999
  try {
5941
- await fs12.unlink(tmpPath);
6000
+ await fs13.unlink(tmpPath);
5942
6001
  } catch {
5943
6002
  }
5944
6003
  }
@@ -5969,11 +6028,11 @@ ${summaries.join("\n")}`;
5969
6028
  if (readBlock) return readBlock;
5970
6029
  const extBlock = checkSupportedSourceExt(args.path);
5971
6030
  if (extBlock) return extBlock;
5972
- const statForSize = await fs12.stat(absPath);
6031
+ const statForSize = await fs13.stat(absPath);
5973
6032
  if (statForSize.size > 1024 * 1024) {
5974
6033
  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`;
5975
6034
  }
5976
- const fileContent = await fs12.readFile(absPath, "utf-8");
6035
+ const fileContent = await fs13.readFile(absPath, "utf-8");
5977
6036
  const TS = await getTs();
5978
6037
  if (!TS) {
5979
6038
  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`;
@@ -6055,19 +6114,19 @@ ${summaries.join("\n")}`;
6055
6114
  const srcAbs = resolveSafePath(args.source);
6056
6115
  const dstAbs = resolveSafePath(args.destination);
6057
6116
  try {
6058
- await fs12.access(srcAbs);
6117
+ await fs13.access(srcAbs);
6059
6118
  } catch {
6060
6119
  return `\u274C [\u79FB\u52A8\u5931\u8D25]\uFF1A\u6E90\u8DEF\u5F84 [${args.source}] \u4E0D\u5B58\u5728\u3002`;
6061
6120
  }
6062
6121
  try {
6063
- await fs12.access(dstAbs);
6122
+ await fs13.access(dstAbs);
6064
6123
  return `\u274C [\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`;
6065
6124
  } catch {
6066
6125
  }
6067
6126
  assertWithinWorkspace(srcAbs);
6068
6127
  assertWithinWorkspace(dstAbs);
6069
- await fs12.mkdir(path16.dirname(dstAbs), { recursive: true });
6070
- await fs12.rename(srcAbs, dstAbs);
6128
+ await fs13.mkdir(path17.dirname(dstAbs), { recursive: true });
6129
+ await fs13.rename(srcAbs, dstAbs);
6071
6130
  return `\u2705 [\u79FB\u52A8\u6210\u529F]\uFF1A[${args.source}] \u2192 [${args.destination}]\u3002`;
6072
6131
  } catch (error) {
6073
6132
  return `\u64CD\u4F5C\u5931\u8D25: ${error.message}`;
@@ -6081,8 +6140,8 @@ ${summaries.join("\n")}`;
6081
6140
 
6082
6141
  // ../core/src/tool/registry/search.ts
6083
6142
  import { rgPath } from "vscode-ripgrep";
6084
- import path17 from "path";
6085
- import fs13 from "fs/promises";
6143
+ import path18 from "path";
6144
+ import fs14 from "fs/promises";
6086
6145
  function escapeRegExp(string) {
6087
6146
  return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6088
6147
  }
@@ -6124,10 +6183,10 @@ var init_search = __esm({
6124
6183
  const resolveSearchRoot = () => {
6125
6184
  if (!args.path) return ctx?.cwd ?? getActiveWorkspaceRoot();
6126
6185
  const p = args.path.trim();
6127
- const looksLikeBareName = !path17.isAbsolute(p) && !p.includes("/") && !p.includes("\\");
6186
+ const looksLikeBareName = !path18.isAbsolute(p) && !p.includes("/") && !p.includes("\\");
6128
6187
  if (looksLikeBareName) {
6129
6188
  const hit = getAllowedWorkspaceRoots().find((r) => {
6130
- const bn = path17.basename(r);
6189
+ const bn = path18.basename(r);
6131
6190
  return bn === p || bn.toLowerCase() === p.toLowerCase();
6132
6191
  });
6133
6192
  if (hit) return hit;
@@ -6216,7 +6275,7 @@ var init_search = __esm({
6216
6275
  const GUIDE_CANDIDATES = ["CLAUDE.md", "AGENTS.md", "AGENT.md"];
6217
6276
  for (const name of GUIDE_CANDIDATES) {
6218
6277
  try {
6219
- const content = await fs13.readFile(path17.join(getActiveWorkspaceRoot(), name), "utf-8");
6278
+ const content = await fs14.readFile(path18.join(getActiveWorkspaceRoot(), name), "utf-8");
6220
6279
  return `[Project Guide via ${name}]
6221
6280
 
6222
6281
  ${content}`;
@@ -6503,8 +6562,8 @@ ${AUTO_BG_NOTICE}
6503
6562
  });
6504
6563
 
6505
6564
  // ../core/src/tool/registry/glob.ts
6506
- import fs14 from "fs/promises";
6507
- import path18 from "path";
6565
+ import fs15 from "fs/promises";
6566
+ import path19 from "path";
6508
6567
  var findMatchingBrace, splitTopLevel, globToRegex2, globTools;
6509
6568
  var init_glob = __esm({
6510
6569
  "../core/src/tool/registry/glob.ts"() {
@@ -6608,18 +6667,18 @@ var init_glob = __esm({
6608
6667
  const MAX_SCAN_LIMIT = 1e4;
6609
6668
  const scan = async (dir) => {
6610
6669
  if (scannedCount > MAX_SCAN_LIMIT) return;
6611
- const entries = await fs14.readdir(dir, { withFileTypes: true });
6670
+ const entries = await fs15.readdir(dir, { withFileTypes: true });
6612
6671
  const validEntries = entries.filter((e) => {
6613
- const full = path18.join(dir, e.name);
6614
- const rel = path18.relative(activeRoot, full).replace(/\\/g, "/");
6672
+ const full = path19.join(dir, e.name);
6673
+ const rel = path19.relative(activeRoot, full).replace(/\\/g, "/");
6615
6674
  return !checkIsPathIgnored(e.isDirectory() ? `${rel}/` : rel);
6616
6675
  });
6617
6676
  for (const e of validEntries) {
6618
6677
  scannedCount++;
6619
6678
  if (scannedCount > MAX_SCAN_LIMIT) break;
6620
6679
  if (e.isSymbolicLink()) continue;
6621
- const full = path18.join(dir, e.name);
6622
- const rel = path18.relative(activeRoot, full).replace(/\\/g, "/");
6680
+ const full = path19.join(dir, e.name);
6681
+ const rel = path19.relative(activeRoot, full).replace(/\\/g, "/");
6623
6682
  if (e.isDirectory()) {
6624
6683
  if (cleanPattern.endsWith("/") && re.test(`${rel}/`)) {
6625
6684
  hits.push(`${rel}/`);
@@ -6835,8 +6894,8 @@ ${summary}`;
6835
6894
  });
6836
6895
 
6837
6896
  // ../core/src/tool/registry/inspect_dependencies.ts
6838
- import * as fs15 from "fs/promises";
6839
- import * as path19 from "path";
6897
+ import * as fs16 from "fs/promises";
6898
+ import * as path20 from "path";
6840
6899
  var dependencyTools;
6841
6900
  var init_inspect_dependencies = __esm({
6842
6901
  "../core/src/tool/registry/inspect_dependencies.ts"() {
@@ -6857,8 +6916,8 @@ var init_inspect_dependencies = __esm({
6857
6916
  isSync: true,
6858
6917
  async execute() {
6859
6918
  try {
6860
- const pjsPath = path19.join(getActiveWorkspaceRoot(), "package.json");
6861
- const raw = await fs15.readFile(pjsPath, "utf-8");
6919
+ const pjsPath = path20.join(getActiveWorkspaceRoot(), "package.json");
6920
+ const raw = await fs16.readFile(pjsPath, "utf-8");
6862
6921
  const pjs = JSON.parse(raw);
6863
6922
  const result = {
6864
6923
  dependencies: pjs.dependencies || {},
@@ -7500,8 +7559,8 @@ var init_http = __esm({
7500
7559
  });
7501
7560
 
7502
7561
  // ../core/src/tool/registry/typescript.ts
7503
- import fs16 from "fs/promises";
7504
- import path20 from "path";
7562
+ import fs17 from "fs/promises";
7563
+ import path21 from "path";
7505
7564
  var MAX_FILE_BYTES, toDisplayPath, isLibFile, precheck, MAX_DIAG_ENTRIES, MAX_DIAG_FILES, MAX_REF_ENTRIES, REF_SNIPPET_MAX, diagnoseOneFile, typescriptTools;
7506
7565
  var init_typescript = __esm({
7507
7566
  "../core/src/tool/registry/typescript.ts"() {
@@ -7512,8 +7571,8 @@ var init_typescript = __esm({
7512
7571
  init_fs();
7513
7572
  MAX_FILE_BYTES = 1024 * 1024;
7514
7573
  toDisplayPath = (wsRoot, abs) => {
7515
- const rel = path20.relative(wsRoot, abs);
7516
- if (rel && !rel.startsWith("..") && !path20.isAbsolute(rel)) return rel.replace(/\\/g, "/");
7574
+ const rel = path21.relative(wsRoot, abs);
7575
+ if (rel && !rel.startsWith("..") && !path21.isAbsolute(rel)) return rel.replace(/\\/g, "/");
7517
7576
  return abs.replace(/\\/g, "/").split("/").slice(-3).join("/");
7518
7577
  };
7519
7578
  isLibFile = (abs) => /(?:^|\/)node_modules\//.test(abs.replace(/\\/g, "/")) || /\.d\.ts$/i.test(abs);
@@ -7522,7 +7581,7 @@ var init_typescript = __esm({
7522
7581
  if (readBlock) return readBlock;
7523
7582
  const extBlock = checkSupportedSourceExt(displayPath);
7524
7583
  if (extBlock) return extBlock;
7525
- const stat = await fs16.stat(absPath);
7584
+ const stat = await fs17.stat(absPath);
7526
7585
  if (stat.size > MAX_FILE_BYTES) {
7527
7586
  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`;
7528
7587
  }
@@ -7738,7 +7797,7 @@ ${out.join("\n")}`;
7738
7797
  let lines = lineTextCache.get(abs);
7739
7798
  if (!lines) {
7740
7799
  try {
7741
- lines = (await fs16.readFile(abs, "utf-8")).split(/\r?\n/);
7800
+ lines = (await fs17.readFile(abs, "utf-8")).split(/\r?\n/);
7742
7801
  } catch {
7743
7802
  lines = [];
7744
7803
  }
@@ -7867,8 +7926,8 @@ var init_todo = __esm({
7867
7926
  });
7868
7927
 
7869
7928
  // ../core/src/observability/traceCalculate.ts
7870
- import fs17 from "fs/promises";
7871
- import path21 from "path";
7929
+ import fs18 from "fs/promises";
7930
+ import path22 from "path";
7872
7931
  var getDirBytes, getTodayDateString;
7873
7932
  var init_traceCalculate = __esm({
7874
7933
  "../core/src/observability/traceCalculate.ts"() {
@@ -7880,17 +7939,17 @@ var init_traceCalculate = __esm({
7880
7939
  const cur = stack.pop();
7881
7940
  let entries;
7882
7941
  try {
7883
- entries = await fs17.readdir(cur, { withFileTypes: true });
7942
+ entries = await fs18.readdir(cur, { withFileTypes: true });
7884
7943
  } catch {
7885
7944
  continue;
7886
7945
  }
7887
7946
  for (const e of entries) {
7888
- const p = path21.join(cur, e.name);
7947
+ const p = path22.join(cur, e.name);
7889
7948
  if (e.isDirectory()) {
7890
7949
  stack.push(p);
7891
7950
  } else {
7892
7951
  try {
7893
- total += (await fs17.stat(p)).size;
7952
+ total += (await fs18.stat(p)).size;
7894
7953
  } catch {
7895
7954
  }
7896
7955
  }
@@ -7909,8 +7968,8 @@ var init_traceCalculate = __esm({
7909
7968
  });
7910
7969
 
7911
7970
  // ../core/src/tool/undo/store.ts
7912
- import path22 from "path";
7913
- import fs18 from "fs/promises";
7971
+ import path23 from "path";
7972
+ import fs19 from "fs/promises";
7914
7973
  var getUndoRootPath, getUndoClockPath, getUndoDirPath, getUndoBackupRoot, ensureUndoDir, getUndoIndexPath;
7915
7974
  var init_store2 = __esm({
7916
7975
  "../core/src/tool/undo/store.ts"() {
@@ -7918,33 +7977,33 @@ var init_store2 = __esm({
7918
7977
  init_config();
7919
7978
  init_common();
7920
7979
  init_traceCalculate();
7921
- getUndoRootPath = () => path22.join(appConfig.dataDir, "undo");
7922
- getUndoClockPath = () => path22.join(getUndoRootPath(), "undo-cleanup-clock.json");
7980
+ getUndoRootPath = () => path23.join(appConfig.dataDir, "undo");
7981
+ getUndoClockPath = () => path23.join(getUndoRootPath(), "undo-cleanup-clock.json");
7923
7982
  getUndoDirPath = (mainSessionId) => {
7924
7983
  const rootId = getFileName(mainSessionId);
7925
7984
  assertSafeSessionId(rootId, "undoSessionId");
7926
- return path22.join(getUndoRootPath(), appConfig.userWorkspaceDir, rootId);
7985
+ return path23.join(getUndoRootPath(), appConfig.userWorkspaceDir, rootId);
7927
7986
  };
7928
- getUndoBackupRoot = (mainSessionId) => path22.join(getUndoDirPath(mainSessionId), "backups");
7987
+ getUndoBackupRoot = (mainSessionId) => path23.join(getUndoDirPath(mainSessionId), "backups");
7929
7988
  ensureUndoDir = async (mainSessionId) => {
7930
- await fs18.mkdir(getUndoDirPath(mainSessionId), { recursive: true, mode: 448 });
7989
+ await fs19.mkdir(getUndoDirPath(mainSessionId), { recursive: true, mode: 448 });
7931
7990
  };
7932
7991
  getUndoIndexPath = async (mainSessionId) => {
7933
7992
  const rootId = getFileName(mainSessionId);
7934
7993
  assertSafeSessionId(rootId, "undoSessionId");
7935
7994
  const dir = getUndoDirPath(mainSessionId);
7936
- await fs18.mkdir(dir, { recursive: true, mode: 448 });
7937
- const files = await fs18.readdir(dir);
7995
+ await fs19.mkdir(dir, { recursive: true, mode: 448 });
7996
+ const files = await fs19.readdir(dir);
7938
7997
  const existedFile = files.find((f) => f.endsWith(`__${rootId}.jsonl`));
7939
7998
  const fileName = existedFile ?? `undo-${getTodayDateString()}__${rootId}.jsonl`;
7940
- return path22.join(dir, fileName);
7999
+ return path23.join(dir, fileName);
7941
8000
  };
7942
8001
  }
7943
8002
  });
7944
8003
 
7945
8004
  // ../core/src/tool/undo/index.ts
7946
- import fs19 from "fs/promises";
7947
- import path23 from "path";
8005
+ import fs20 from "fs/promises";
8006
+ import path24 from "path";
7948
8007
  var undoLocks, withUndoLock, appendUndoRecord, readUndoIndex, markRestored;
7949
8008
  var init_undo = __esm({
7950
8009
  "../core/src/tool/undo/index.ts"() {
@@ -7974,7 +8033,7 @@ var init_undo = __esm({
7974
8033
  };
7975
8034
  const p = await getUndoIndexPath(sessionId);
7976
8035
  const line = JSON.stringify(enriched) + "\n";
7977
- await fs19.appendFile(p, line, { encoding: "utf-8", mode: 384 });
8036
+ await fs20.appendFile(p, line, { encoding: "utf-8", mode: 384 });
7978
8037
  });
7979
8038
  };
7980
8039
  readUndoIndex = async (sessionId) => {
@@ -7986,7 +8045,7 @@ var init_undo = __esm({
7986
8045
  }
7987
8046
  let files;
7988
8047
  try {
7989
- files = await fs19.readdir(dir);
8048
+ files = await fs20.readdir(dir);
7990
8049
  } catch {
7991
8050
  return [];
7992
8051
  }
@@ -7994,7 +8053,7 @@ var init_undo = __esm({
7994
8053
  for (const f of files) {
7995
8054
  if (!f.startsWith("undo-") || !f.endsWith(".jsonl")) continue;
7996
8055
  try {
7997
- const raw = await fs19.readFile(path23.join(dir, f), "utf-8");
8056
+ const raw = await fs20.readFile(path24.join(dir, f), "utf-8");
7998
8057
  for (const line of raw.split("\n")) {
7999
8058
  const trimmed = line.trim();
8000
8059
  if (!trimmed) continue;
@@ -8019,16 +8078,16 @@ var init_undo = __esm({
8019
8078
  }
8020
8079
  let files;
8021
8080
  try {
8022
- files = await fs19.readdir(dir);
8081
+ files = await fs20.readdir(dir);
8023
8082
  } catch {
8024
8083
  return;
8025
8084
  }
8026
8085
  for (const f of files) {
8027
8086
  if (!f.startsWith("undo-") || !f.endsWith(".jsonl")) continue;
8028
- const fp = path23.join(dir, f);
8087
+ const fp = path24.join(dir, f);
8029
8088
  let raw;
8030
8089
  try {
8031
- raw = await fs19.readFile(fp, "utf-8");
8090
+ raw = await fs20.readFile(fp, "utf-8");
8032
8091
  } catch {
8033
8092
  continue;
8034
8093
  }
@@ -8052,8 +8111,8 @@ var init_undo = __esm({
8052
8111
  if (changed) {
8053
8112
  const content = lines.join("\n").replace(/\n*$/, "\n");
8054
8113
  const tmp = fp + ".tmp";
8055
- await fs19.writeFile(tmp, content, { encoding: "utf-8", mode: 384 });
8056
- await fs19.rename(tmp, fp);
8114
+ await fs20.writeFile(tmp, content, { encoding: "utf-8", mode: 384 });
8115
+ await fs20.rename(tmp, fp);
8057
8116
  }
8058
8117
  }
8059
8118
  });
@@ -8062,8 +8121,8 @@ var init_undo = __esm({
8062
8121
  });
8063
8122
 
8064
8123
  // ../core/src/tool/undo/cleanup.ts
8065
- import fs20 from "fs/promises";
8066
- import path24 from "path";
8124
+ import fs21 from "fs/promises";
8125
+ import path25 from "path";
8067
8126
  async function maybeCleanupAfterUndoAppend(_sessionId) {
8068
8127
  if (cleanupInProgress) return;
8069
8128
  cleanupInProgress = true;
@@ -8089,8 +8148,8 @@ async function maybeCleanupAfterUndoAppend(_sessionId) {
8089
8148
  lastSizeCleanupAt = now;
8090
8149
  diskLastCleanupAt = now;
8091
8150
  const clockPath = getUndoClockPath();
8092
- await fs20.mkdir(path24.dirname(clockPath), { recursive: true });
8093
- await fs20.writeFile(clockPath, JSON.stringify({ lastCleanupAt: now, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2), "utf-8");
8151
+ await fs21.mkdir(path25.dirname(clockPath), { recursive: true });
8152
+ await fs21.writeFile(clockPath, JSON.stringify({ lastCleanupAt: now, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2), "utf-8");
8094
8153
  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`);
8095
8154
  } catch (e) {
8096
8155
  console.warn("\u26A0\uFE0F [Undo\u8FD0\u7EF4] \u81EA\u52A8\u6E05\u7406\u5F02\u5E38\uFF0C\u5DF2\u8DF3\u8FC7:", e?.message ?? e);
@@ -8107,23 +8166,23 @@ async function cleanupOldUndoFiles() {
8107
8166
  const now = Date.now();
8108
8167
  let relativePaths;
8109
8168
  try {
8110
- relativePaths = await fs20.readdir(dir, { recursive: true });
8169
+ relativePaths = await fs21.readdir(dir, { recursive: true });
8111
8170
  } catch {
8112
8171
  return 0;
8113
8172
  }
8114
8173
  const re = /^undo-(\d{4}-\d{2}-\d{2})__([\w-]+)\.jsonl$/;
8115
8174
  let deleted = 0;
8116
8175
  for (const rp of relativePaths) {
8117
- const fileName = path24.basename(rp);
8176
+ const fileName = path25.basename(rp);
8118
8177
  const m = fileName.match(re);
8119
8178
  if (!m) continue;
8120
8179
  const fileBornDay = /* @__PURE__ */ new Date(`${m[1]}T00:00:00`);
8121
8180
  if (fileBornDay >= cutoff) continue;
8122
- const fullPath = path24.join(dir, rp);
8181
+ const fullPath = path25.join(dir, rp);
8123
8182
  try {
8124
- const st = await fs20.stat(fullPath);
8183
+ const st = await fs21.stat(fullPath);
8125
8184
  if (now - st.mtimeMs < ACTIVE_GRACE_MS) continue;
8126
- await fs20.unlink(fullPath);
8185
+ await fs21.unlink(fullPath);
8127
8186
  deleted += 1;
8128
8187
  } catch {
8129
8188
  }
@@ -8134,17 +8193,17 @@ async function evictOldestForSize(targetBytes) {
8134
8193
  const dir = getUndoRootPath();
8135
8194
  let relativePaths;
8136
8195
  try {
8137
- relativePaths = await fs20.readdir(dir, { recursive: true });
8196
+ relativePaths = await fs21.readdir(dir, { recursive: true });
8138
8197
  } catch {
8139
8198
  return 0;
8140
8199
  }
8141
8200
  const re = /^undo-(\d{4}-\d{2}-\d{2})__([\w-]+)\.jsonl$/;
8142
8201
  const candidates = [];
8143
8202
  for (const rp of relativePaths) {
8144
- if (!re.test(path24.basename(rp))) continue;
8203
+ if (!re.test(path25.basename(rp))) continue;
8145
8204
  try {
8146
- const st = await fs20.stat(path24.join(dir, rp));
8147
- candidates.push({ mtime: st.mtimeMs, fullPath: path24.join(dir, rp), size: st.size });
8205
+ const st = await fs21.stat(path25.join(dir, rp));
8206
+ candidates.push({ mtime: st.mtimeMs, fullPath: path25.join(dir, rp), size: st.size });
8148
8207
  } catch {
8149
8208
  }
8150
8209
  }
@@ -8154,7 +8213,7 @@ async function evictOldestForSize(targetBytes) {
8154
8213
  for (const c of candidates) {
8155
8214
  if (totalBytes <= targetBytes) break;
8156
8215
  try {
8157
- await fs20.unlink(c.fullPath);
8216
+ await fs21.unlink(c.fullPath);
8158
8217
  totalBytes -= c.size;
8159
8218
  deleted += 1;
8160
8219
  } catch {
@@ -8168,38 +8227,38 @@ async function gcOrphanBackups() {
8168
8227
  let deleted = 0;
8169
8228
  let workspaces;
8170
8229
  try {
8171
- workspaces = await fs20.readdir(root);
8230
+ workspaces = await fs21.readdir(root);
8172
8231
  } catch {
8173
8232
  return 0;
8174
8233
  }
8175
8234
  for (const ws of workspaces) {
8176
- const wsDir = path24.join(root, ws);
8235
+ const wsDir = path25.join(root, ws);
8177
8236
  let stWs;
8178
8237
  try {
8179
- stWs = await fs20.stat(wsDir);
8238
+ stWs = await fs21.stat(wsDir);
8180
8239
  } catch {
8181
8240
  continue;
8182
8241
  }
8183
8242
  if (!stWs.isDirectory()) continue;
8184
8243
  let sessions2;
8185
8244
  try {
8186
- sessions2 = await fs20.readdir(wsDir);
8245
+ sessions2 = await fs21.readdir(wsDir);
8187
8246
  } catch {
8188
8247
  continue;
8189
8248
  }
8190
8249
  for (const sess of sessions2) {
8191
- const sessDir = path24.join(wsDir, sess);
8250
+ const sessDir = path25.join(wsDir, sess);
8192
8251
  const liveIds = /* @__PURE__ */ new Set();
8193
8252
  let files;
8194
8253
  try {
8195
- files = await fs20.readdir(sessDir);
8254
+ files = await fs21.readdir(sessDir);
8196
8255
  } catch {
8197
8256
  continue;
8198
8257
  }
8199
8258
  for (const f of files) {
8200
8259
  if (!f.startsWith("undo-") || !f.endsWith(".jsonl")) continue;
8201
8260
  try {
8202
- const raw = await fs20.readFile(path24.join(sessDir, f), "utf-8");
8261
+ const raw = await fs21.readFile(path25.join(sessDir, f), "utf-8");
8203
8262
  for (const line of raw.split("\n")) {
8204
8263
  const t = line.trim();
8205
8264
  if (!t) continue;
@@ -8212,17 +8271,17 @@ async function gcOrphanBackups() {
8212
8271
  } catch {
8213
8272
  }
8214
8273
  }
8215
- const backupsDir = path24.join(sessDir, "backups");
8274
+ const backupsDir = path25.join(sessDir, "backups");
8216
8275
  let undoDirs;
8217
8276
  try {
8218
- undoDirs = await fs20.readdir(backupsDir);
8277
+ undoDirs = await fs21.readdir(backupsDir);
8219
8278
  } catch {
8220
8279
  continue;
8221
8280
  }
8222
8281
  for (const ud of undoDirs) {
8223
8282
  if (liveIds.has(ud)) continue;
8224
8283
  try {
8225
- await fs20.rm(path24.join(backupsDir, ud), { recursive: true, force: true });
8284
+ await fs21.rm(path25.join(backupsDir, ud), { recursive: true, force: true });
8226
8285
  deleted += 1;
8227
8286
  } catch {
8228
8287
  }
@@ -8250,7 +8309,7 @@ var init_cleanup = __esm({
8250
8309
  if (clockLoaded) return;
8251
8310
  clockLoaded = true;
8252
8311
  try {
8253
- const rawClock = await fs20.readFile(getUndoClockPath(), "utf-8");
8312
+ const rawClock = await fs21.readFile(getUndoClockPath(), "utf-8");
8254
8313
  diskLastCleanupAt = JSON.parse(rawClock).lastCleanupAt || 0;
8255
8314
  } catch {
8256
8315
  diskLastCleanupAt = 0;
@@ -8260,17 +8319,17 @@ var init_cleanup = __esm({
8260
8319
  let total = 0;
8261
8320
  let entries;
8262
8321
  try {
8263
- entries = await fs20.readdir(dir, { withFileTypes: true });
8322
+ entries = await fs21.readdir(dir, { withFileTypes: true });
8264
8323
  } catch {
8265
8324
  return 0;
8266
8325
  }
8267
8326
  for (const e of entries) {
8268
- const full = path24.join(dir, e.name);
8327
+ const full = path25.join(dir, e.name);
8269
8328
  if (e.isDirectory()) {
8270
8329
  total += await getDirBytesRecursive(full);
8271
8330
  } else if (e.isFile()) {
8272
8331
  try {
8273
- total += (await fs20.stat(full)).size;
8332
+ total += (await fs21.stat(full)).size;
8274
8333
  } catch {
8275
8334
  }
8276
8335
  }
@@ -8281,8 +8340,8 @@ var init_cleanup = __esm({
8281
8340
  });
8282
8341
 
8283
8342
  // ../core/src/tool/undo/backup.ts
8284
- import fs21 from "fs/promises";
8285
- import path25 from "path";
8343
+ import fs22 from "fs/promises";
8344
+ import path26 from "path";
8286
8345
  import crypto from "crypto";
8287
8346
  async function beforeMutationBackup(toolName, args, toolCallId, sessionId) {
8288
8347
  if (appConfig.undoEnabled === false) return null;
@@ -8297,7 +8356,7 @@ async function beforeMutationBackup(toolName, args, toolCallId, sessionId) {
8297
8356
  }
8298
8357
  await ensureUndoDir(sessionId);
8299
8358
  const undoId = createUUID();
8300
- const undoDir = path25.join(getUndoBackupRoot(sessionId), undoId);
8359
+ const undoDir = path26.join(getUndoBackupRoot(sessionId), undoId);
8301
8360
  const now = /* @__PURE__ */ new Date();
8302
8361
  const common = {
8303
8362
  undoId,
@@ -8332,7 +8391,7 @@ async function backupFileOverwrite(common, undoDir, args) {
8332
8391
  const absPath = resolveSafePath(common.relativePath);
8333
8392
  let exists = true;
8334
8393
  try {
8335
- await fs21.access(absPath);
8394
+ await fs22.access(absPath);
8336
8395
  } catch {
8337
8396
  exists = false;
8338
8397
  }
@@ -8340,15 +8399,15 @@ async function backupFileOverwrite(common, undoDir, args) {
8340
8399
  return { ...common, backupKind: "creation_marker", backupPath: "", fileSizeBefore: 0 };
8341
8400
  }
8342
8401
  assertWithinWorkspace(absPath);
8343
- const fileStat = await fs21.stat(absPath);
8402
+ const fileStat = await fs22.stat(absPath);
8344
8403
  const maxPerOp = appConfig.undoMaxBytesPerOp ?? 100 * 1024 * 1024;
8345
8404
  if (fileStat.size > maxPerOp) {
8346
8405
  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`);
8347
8406
  }
8348
- const content = await fs21.readFile(absPath);
8349
- await fs21.mkdir(undoDir, { recursive: true, mode: 448 });
8350
- const contentPath = path25.join(undoDir, "content");
8351
- await fs21.writeFile(contentPath, content, { mode: 384 });
8407
+ const content = await fs22.readFile(absPath);
8408
+ await fs22.mkdir(undoDir, { recursive: true, mode: 448 });
8409
+ const contentPath = path26.join(undoDir, "content");
8410
+ await fs22.writeFile(contentPath, content, { mode: 384 });
8352
8411
  return {
8353
8412
  ...common,
8354
8413
  backupKind: "file_content",
@@ -8367,9 +8426,9 @@ async function backupFileCreate(common) {
8367
8426
  }
8368
8427
  async function backupDelete(common, undoDir, relativePath) {
8369
8428
  const absPath = resolveSafePath(relativePath);
8370
- const st = await fs21.stat(absPath);
8429
+ const st = await fs22.stat(absPath);
8371
8430
  assertWithinWorkspace(absPath);
8372
- await fs21.mkdir(undoDir, { recursive: true, mode: 448 });
8431
+ await fs22.mkdir(undoDir, { recursive: true, mode: 448 });
8373
8432
  if (st.isDirectory()) {
8374
8433
  const treeBytes = await getDirTreeBytes(absPath);
8375
8434
  const maxPerOp2 = appConfig.undoMaxBytesPerOp ?? 100 * 1024 * 1024;
@@ -8384,15 +8443,15 @@ async function backupDelete(common, undoDir, relativePath) {
8384
8443
  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`);
8385
8444
  }
8386
8445
  }
8387
- const treeDest = path25.join(undoDir, "tree");
8446
+ const treeDest = path26.join(undoDir, "tree");
8388
8447
  const sensitiveSet = new Set(sensitiveInTree);
8389
- await fs21.cp(absPath, treeDest, {
8448
+ await fs22.cp(absPath, treeDest, {
8390
8449
  recursive: true,
8391
8450
  force: true,
8392
8451
  preserveTimestamps: true,
8393
8452
  filter: (src) => {
8394
8453
  if (src === absPath) return true;
8395
- const relWithin = path25.relative(absPath, src).replace(/\\/g, "/");
8454
+ const relWithin = path26.relative(absPath, src).replace(/\\/g, "/");
8396
8455
  return !sensitiveSet.has(relWithin);
8397
8456
  }
8398
8457
  });
@@ -8408,9 +8467,9 @@ async function backupDelete(common, undoDir, relativePath) {
8408
8467
  if (st.size > maxPerOp) {
8409
8468
  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`);
8410
8469
  }
8411
- const content = await fs21.readFile(absPath);
8412
- const contentPath = path25.join(undoDir, "content");
8413
- await fs21.writeFile(contentPath, content, { mode: 384 });
8470
+ const content = await fs22.readFile(absPath);
8471
+ const contentPath = path26.join(undoDir, "content");
8472
+ await fs22.writeFile(contentPath, content, { mode: 384 });
8414
8473
  return {
8415
8474
  ...common,
8416
8475
  backupKind: "file_content",
@@ -8455,21 +8514,21 @@ var init_backup = __esm({
8455
8514
  const walk = async (d) => {
8456
8515
  let entries;
8457
8516
  try {
8458
- entries = await fs21.readdir(d, { withFileTypes: true });
8517
+ entries = await fs22.readdir(d, { withFileTypes: true });
8459
8518
  } catch {
8460
8519
  return;
8461
8520
  }
8462
8521
  entries.sort((a, b) => a.name.localeCompare(b.name));
8463
8522
  for (const e of entries) {
8464
- const full = path25.join(d, e.name);
8465
- const rel = path25.relative(dir, full).replace(/\\/g, "/");
8523
+ const full = path26.join(d, e.name);
8524
+ const rel = path26.relative(dir, full).replace(/\\/g, "/");
8466
8525
  if (e.isDirectory()) {
8467
8526
  h.update(`D ${rel}
8468
8527
  `);
8469
8528
  await walk(full);
8470
8529
  } else if (e.isFile()) {
8471
8530
  try {
8472
- h.update(`F ${rel} ${sha1Buf(await fs21.readFile(full))}
8531
+ h.update(`F ${rel} ${sha1Buf(await fs22.readFile(full))}
8473
8532
  `);
8474
8533
  } catch {
8475
8534
  }
@@ -8483,16 +8542,16 @@ var init_backup = __esm({
8483
8542
  let total = 0;
8484
8543
  let entries;
8485
8544
  try {
8486
- entries = await fs21.readdir(dir, { withFileTypes: true });
8545
+ entries = await fs22.readdir(dir, { withFileTypes: true });
8487
8546
  } catch {
8488
8547
  return 0;
8489
8548
  }
8490
8549
  for (const e of entries) {
8491
- const full = path25.join(dir, e.name);
8550
+ const full = path26.join(dir, e.name);
8492
8551
  if (e.isDirectory()) total += await getDirTreeBytes(full);
8493
8552
  else if (e.isFile()) {
8494
8553
  try {
8495
- total += (await fs21.stat(full)).size;
8554
+ total += (await fs22.stat(full)).size;
8496
8555
  } catch {
8497
8556
  }
8498
8557
  }
@@ -8504,16 +8563,16 @@ var init_backup = __esm({
8504
8563
  const walk = async (d) => {
8505
8564
  let entries;
8506
8565
  try {
8507
- entries = await fs21.readdir(d, { withFileTypes: true });
8566
+ entries = await fs22.readdir(d, { withFileTypes: true });
8508
8567
  } catch {
8509
8568
  return;
8510
8569
  }
8511
8570
  for (const e of entries) {
8512
- const full = path25.join(d, e.name);
8571
+ const full = path26.join(d, e.name);
8513
8572
  if (e.isDirectory()) {
8514
8573
  await walk(full);
8515
8574
  } else if (e.isFile()) {
8516
- const relWithin = path25.relative(dir, full).replace(/\\/g, "/");
8575
+ const relWithin = path26.relative(dir, full).replace(/\\/g, "/");
8517
8576
  if (isSensitivePath(`${wsRelDir}/${relWithin}`)) found.push(relWithin);
8518
8577
  }
8519
8578
  }
@@ -8525,15 +8584,15 @@ var init_backup = __esm({
8525
8584
  });
8526
8585
 
8527
8586
  // ../core/src/tool/undo/restore.ts
8528
- import fs22 from "fs/promises";
8529
- import path26 from "path";
8587
+ import fs23 from "fs/promises";
8588
+ import path27 from "path";
8530
8589
  import crypto2 from "crypto";
8531
8590
  async function doRestore(target, sessionId) {
8532
8591
  if (target.backupKind === "directory_tree") {
8533
8592
  const abs = resolveSafePath(target.relativePath);
8534
8593
  let exists = false;
8535
8594
  try {
8536
- await fs22.access(abs);
8595
+ await fs23.access(abs);
8537
8596
  exists = true;
8538
8597
  } catch {
8539
8598
  }
@@ -8571,7 +8630,7 @@ async function ensureReverseBackup(target, sessionId) {
8571
8630
  }
8572
8631
  let exists = true;
8573
8632
  try {
8574
- await fs22.access(absPath);
8633
+ await fs23.access(absPath);
8575
8634
  } catch {
8576
8635
  exists = false;
8577
8636
  }
@@ -8584,17 +8643,17 @@ async function ensureReverseBackup(target, sessionId) {
8584
8643
  }
8585
8644
  }
8586
8645
  const reverseId = createUUID();
8587
- const reverseDir = path26.join(getUndoBackupRoot(sessionId), reverseId);
8588
- await fs22.mkdir(reverseDir, { recursive: true, mode: 448 });
8646
+ const reverseDir = path27.join(getUndoBackupRoot(sessionId), reverseId);
8647
+ await fs23.mkdir(reverseDir, { recursive: true, mode: 448 });
8589
8648
  assertWithinWorkspace(absPath);
8590
- const st = await fs22.stat(absPath);
8649
+ const st = await fs23.stat(absPath);
8591
8650
  if (st.isDirectory()) {
8592
- const dest2 = path26.join(reverseDir, "tree");
8593
- await fs22.cp(absPath, dest2, { recursive: true, force: true, preserveTimestamps: true });
8651
+ const dest2 = path27.join(reverseDir, "tree");
8652
+ await fs23.cp(absPath, dest2, { recursive: true, force: true, preserveTimestamps: true });
8594
8653
  return { reverseId, backupKind: "directory_tree", backupPath: dest2 };
8595
8654
  }
8596
- const dest = path26.join(reverseDir, "content");
8597
- await fs22.writeFile(dest, await fs22.readFile(absPath));
8655
+ const dest = path27.join(reverseDir, "content");
8656
+ await fs23.writeFile(dest, await fs23.readFile(absPath));
8598
8657
  return { reverseId, backupKind: "file_content", backupPath: dest };
8599
8658
  }
8600
8659
  async function dispatchRestore(r) {
@@ -8602,20 +8661,20 @@ async function dispatchRestore(r) {
8602
8661
  assertWithinWorkspace(absPath);
8603
8662
  switch (r.backupKind) {
8604
8663
  case "creation_marker": {
8605
- await fs22.rm(absPath, { force: true });
8664
+ await fs23.rm(absPath, { force: true });
8606
8665
  return `\u5DF2\u5220\u9664\u65B0\u5EFA\u6587\u4EF6 [${r.relativePath}]`;
8607
8666
  }
8608
8667
  case "file_content": {
8609
- await fs22.mkdir(path26.dirname(absPath), { recursive: true });
8610
- const backupAbs = path26.join(getUndoBackupRoot(r.sessionId), r.undoId, "content");
8611
- const content = await fs22.readFile(backupAbs);
8612
- await fs22.writeFile(absPath, content);
8668
+ await fs23.mkdir(path27.dirname(absPath), { recursive: true });
8669
+ const backupAbs = path27.join(getUndoBackupRoot(r.sessionId), r.undoId, "content");
8670
+ const content = await fs23.readFile(backupAbs);
8671
+ await fs23.writeFile(absPath, content);
8613
8672
  return `\u5DF2\u6062\u590D [${r.relativePath}] \u81F3\u5907\u4EFD\u524D\u5185\u5BB9\uFF08${r.fileSizeBefore ?? content.byteLength} \u5B57\u8282\uFF09`;
8614
8673
  }
8615
8674
  case "directory_tree": {
8616
- await fs22.mkdir(path26.dirname(absPath), { recursive: true });
8617
- const src = path26.join(getUndoBackupRoot(r.sessionId), r.undoId, "tree");
8618
- await fs22.cp(src, absPath, { recursive: true, force: true, preserveTimestamps: true });
8675
+ await fs23.mkdir(path27.dirname(absPath), { recursive: true });
8676
+ const src = path27.join(getUndoBackupRoot(r.sessionId), r.undoId, "tree");
8677
+ await fs23.cp(src, absPath, { recursive: true, force: true, preserveTimestamps: true });
8619
8678
  return `\u5DF2\u6062\u590D\u76EE\u5F55\u6811 [${r.relativePath}]\uFF08\u7EA6 ${r.fileSizeBefore ?? 0} \u5B57\u8282\uFF09`;
8620
8679
  }
8621
8680
  }
@@ -8648,7 +8707,7 @@ var init_restore = __esm({
8648
8707
  init_common();
8649
8708
  init_traceCalculate();
8650
8709
  sha1File = async (absPath) => {
8651
- const buf = await fs22.readFile(absPath);
8710
+ const buf = await fs23.readFile(absPath);
8652
8711
  return crypto2.createHash("sha1").update(buf).digest("hex");
8653
8712
  };
8654
8713
  listUndoable = async (sessionId) => {
@@ -8922,7 +8981,7 @@ ${diff.slice(0, 1500)}` : "";
8922
8981
  });
8923
8982
 
8924
8983
  // ../core/src/tool/registry/notebook.ts
8925
- import fs23 from "fs/promises";
8984
+ import fs24 from "fs/promises";
8926
8985
  var toArraySource, encodeSource, makeCell, applyNotebookEdit, notebookTools;
8927
8986
  var init_notebook = __esm({
8928
8987
  "../core/src/tool/registry/notebook.ts"() {
@@ -9023,7 +9082,7 @@ ${String(args.new_source).slice(0, 500)}` : ""}`,
9023
9082
  }
9024
9083
  let raw;
9025
9084
  try {
9026
- raw = await fs23.readFile(absPath, "utf-8");
9085
+ raw = await fs24.readFile(absPath, "utf-8");
9027
9086
  } catch (e) {
9028
9087
  return `\u274C [notebook_edit] \u8BFB\u53D6\u5931\u8D25\uFF1A${e?.message ?? e}`;
9029
9088
  }
@@ -9053,10 +9112,10 @@ ${String(args.new_source).slice(0, 500)}` : ""}`,
9053
9112
  }
9054
9113
  const tmpPath = makeTmpPath(absPath);
9055
9114
  try {
9056
- await fs23.writeFile(tmpPath, JSON.stringify(nb, null, 2), "utf-8");
9057
- await fs23.rename(tmpPath, absPath);
9115
+ await fs24.writeFile(tmpPath, JSON.stringify(nb, null, 2), "utf-8");
9116
+ await fs24.rename(tmpPath, absPath);
9058
9117
  } catch (e) {
9059
- await fs23.unlink(tmpPath).catch(() => {
9118
+ await fs24.unlink(tmpPath).catch(() => {
9060
9119
  });
9061
9120
  return `\u274C [notebook_edit] \u5199\u5165\u5931\u8D25\uFF1A${e?.message ?? e}`;
9062
9121
  }
@@ -9096,8 +9155,8 @@ var init_frontmatter = __esm({
9096
9155
  });
9097
9156
 
9098
9157
  // ../core/src/memory/loader.ts
9099
- import fs24 from "fs/promises";
9100
- import path27 from "path";
9158
+ import fs25 from "fs/promises";
9159
+ import path28 from "path";
9101
9160
  var GLOBAL_MEMORY_DIR, SOURCES, VALID_TYPES, parseMemoryAt, loadMemories, initMemories;
9102
9161
  var init_loader3 = __esm({
9103
9162
  "../core/src/memory/loader.ts"() {
@@ -9106,16 +9165,16 @@ var init_loader3 = __esm({
9106
9165
  init_frontmatter();
9107
9166
  init_registry6();
9108
9167
  init_registry2();
9109
- GLOBAL_MEMORY_DIR = path27.join(appConfig.dataDir, "memory");
9168
+ GLOBAL_MEMORY_DIR = path28.join(appConfig.dataDir, "memory");
9110
9169
  SOURCES = [
9111
9170
  { dir: GLOBAL_MEMORY_DIR, source: "global" },
9112
- { dir: path27.join(process.cwd(), ".deepseeker-code", "memory"), source: "project" }
9171
+ { dir: path28.join(process.cwd(), ".deepseeker-code", "memory"), source: "project" }
9113
9172
  ];
9114
9173
  VALID_TYPES = ["user", "feedback", "project", "reference"];
9115
9174
  parseMemoryAt = async (file, _dir, source) => {
9116
9175
  let raw;
9117
9176
  try {
9118
- raw = await fs24.readFile(file, "utf-8");
9177
+ raw = await fs25.readFile(file, "utf-8");
9119
9178
  } catch {
9120
9179
  return null;
9121
9180
  }
@@ -9149,7 +9208,7 @@ var init_loader3 = __esm({
9149
9208
  clearMemories();
9150
9209
  const picked = await scanSources(
9151
9210
  filterSources(SOURCES, includeProject),
9152
- (e, dir) => e.isFile() && e.name.endsWith(".md") ? path27.join(dir, e.name) : void 0,
9211
+ (e, dir) => e.isFile() && e.name.endsWith(".md") ? path28.join(dir, e.name) : void 0,
9153
9212
  parseMemoryAt
9154
9213
  );
9155
9214
  for (const { item } of picked) registerMemory(item);
@@ -9167,8 +9226,8 @@ var init_loader3 = __esm({
9167
9226
  });
9168
9227
 
9169
9228
  // ../core/src/tool/registry/memory.ts
9170
- import fs25 from "fs/promises";
9171
- import path28 from "path";
9229
+ import fs26 from "fs/promises";
9230
+ import path29 from "path";
9172
9231
  var MAX_BODY_BYTES, NAME_RE, VALID_TYPES2, memoryFilePath, sanitizeLine, buildMemoryMd, writeAndRegister, memoryTools;
9173
9232
  var init_memory = __esm({
9174
9233
  "../core/src/tool/registry/memory.ts"() {
@@ -9180,7 +9239,7 @@ var init_memory = __esm({
9180
9239
  MAX_BODY_BYTES = 64 * 1024;
9181
9240
  NAME_RE = /^[a-z0-9-]+$/;
9182
9241
  VALID_TYPES2 = ["user", "feedback", "project", "reference"];
9183
- memoryFilePath = (name, project) => project ? path28.join(process.cwd(), ".deepseeker-code", "memory", `${name}.md`) : path28.join(GLOBAL_MEMORY_DIR, `${name}.md`);
9242
+ memoryFilePath = (name, project) => project ? path29.join(process.cwd(), ".deepseeker-code", "memory", `${name}.md`) : path29.join(GLOBAL_MEMORY_DIR, `${name}.md`);
9184
9243
  sanitizeLine = (s) => String(s ?? "").replace(/[\r\n]+/g, " ").trim();
9185
9244
  buildMemoryMd = (name, description, type, body) => `---
9186
9245
  name: ${name}
@@ -9192,10 +9251,10 @@ ${body.trim()}
9192
9251
  `;
9193
9252
  writeAndRegister = async (name, description, type, body, project) => {
9194
9253
  const file = memoryFilePath(name, project);
9195
- await fs25.mkdir(path28.dirname(file), { recursive: true });
9254
+ await fs26.mkdir(path29.dirname(file), { recursive: true });
9196
9255
  const tmp = makeTmpPath(file);
9197
- await fs25.writeFile(tmp, buildMemoryMd(name, description, type, body), "utf-8");
9198
- await fs25.rename(tmp, file);
9256
+ await fs26.writeFile(tmp, buildMemoryMd(name, description, type, body), "utf-8");
9257
+ await fs26.rename(tmp, file);
9199
9258
  registerMemory({ name, description, type, body: body.trim(), source: project ? "project" : "global", file });
9200
9259
  return file;
9201
9260
  };
@@ -9311,7 +9370,7 @@ ${lines.join("\n")}`;
9311
9370
  const m = getMemory(name);
9312
9371
  if (!m) return `\u274C \u672A\u627E\u5230\u8BB0\u5FC6\uFF1A${name}\uFF08\u53EF\u80FD\u5DF2\u88AB\u5220\u9664\uFF09\u3002`;
9313
9372
  try {
9314
- await fs25.unlink(m.file);
9373
+ await fs26.unlink(m.file);
9315
9374
  } catch {
9316
9375
  }
9317
9376
  unregisterMemory(name);
@@ -9324,8 +9383,8 @@ ${lines.join("\n")}`;
9324
9383
  });
9325
9384
 
9326
9385
  // ../core/src/tool/registry/recall.ts
9327
- import fs26 from "fs/promises";
9328
- import path29 from "path";
9386
+ import fs27 from "fs/promises";
9387
+ import path30 from "path";
9329
9388
  var escapeRegExp2, lineText, primaryPathArg, annotateStaleness, snippetAround, recallTools;
9330
9389
  var init_recall = __esm({
9331
9390
  "../core/src/tool/registry/recall.ts"() {
@@ -9356,9 +9415,9 @@ var init_recall = __esm({
9356
9415
  annotateStaleness = async (args, observedAt) => {
9357
9416
  const p = primaryPathArg(args);
9358
9417
  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";
9359
- const abs = path29.isAbsolute(p) ? p : path29.resolve(getActiveWorkspaceRoot(), p);
9418
+ const abs = path30.isAbsolute(p) ? p : path30.resolve(getActiveWorkspaceRoot(), p);
9360
9419
  try {
9361
- const st = await fs26.stat(abs);
9420
+ const st = await fs27.stat(abs);
9362
9421
  if (observedAt && st.mtime.toISOString() > observedAt) {
9363
9422
  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`;
9364
9423
  }
@@ -9403,10 +9462,10 @@ var init_recall = __esm({
9403
9462
  if (args.with_full) {
9404
9463
  const safeId = String(args.with_full).replace(/[^A-Za-z0-9_-]/g, "");
9405
9464
  if (!safeId) return "\u274C [recall] with_full \u542B\u975E\u6CD5\u5B57\u7B26\u3002";
9406
- const sidecar = path29.join(getSessionsDirPath(ctx.sessionId), "tool-outputs", `${safeId}.txt`);
9465
+ const sidecar = path30.join(getSessionsDirPath(ctx.sessionId), "tool-outputs", `${safeId}.txt`);
9407
9466
  let full = "";
9408
9467
  try {
9409
- full = await fs26.readFile(sidecar, "utf-8");
9468
+ full = await fs27.readFile(sidecar, "utf-8");
9410
9469
  } catch {
9411
9470
  return `\u274C [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}`;
9412
9471
  }
@@ -9615,7 +9674,7 @@ var init_spreadsheet = __esm({
9615
9674
  });
9616
9675
 
9617
9676
  // ../core/src/tool/registry/document.ts
9618
- import fs27 from "fs/promises";
9677
+ import fs28 from "fs/promises";
9619
9678
  var getMammoth, getUnpdf, documentTools;
9620
9679
  var init_document = __esm({
9621
9680
  "../core/src/tool/registry/document.ts"() {
@@ -9705,7 +9764,7 @@ var init_document = __esm({
9705
9764
  }
9706
9765
  const start = args.start_char ? Math.max(0, Math.floor(args.start_char)) : 0;
9707
9766
  const maxChars = Math.min(args.max_chars ? Math.max(1, Math.floor(args.max_chars)) : 3e4, 5e4);
9708
- const buf = await fs27.readFile(absPath);
9767
+ const buf = await fs28.readFile(absPath);
9709
9768
  const unpdf = await getUnpdf();
9710
9769
  const pdf = await unpdf.getDocumentProxy(new Uint8Array(buf));
9711
9770
  const { text, totalPages } = await unpdf.extractText(pdf, { mergePages: true });
@@ -9911,7 +9970,7 @@ var init_backgroundTool = __esm({
9911
9970
  });
9912
9971
 
9913
9972
  // ../core/src/tool/autoPermission.ts
9914
- import path30 from "path";
9973
+ import path31 from "path";
9915
9974
  var AUTO_SCOPE, AUTO_DEFAULT_EXTRA, AUTO_AGGRESSIVE_EXTRA, 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;
9916
9975
  var init_autoPermission = __esm({
9917
9976
  "../core/src/tool/autoPermission.ts"() {
@@ -10059,9 +10118,9 @@ var init_autoPermission = __esm({
10059
10118
  isWithinWorkspace = (p, cwd) => {
10060
10119
  if (!p || !cwd) return false;
10061
10120
  try {
10062
- const abs = path30.isAbsolute(p) ? p : path30.resolve(cwd, p);
10063
- const rel = path30.relative(cwd, abs);
10064
- return rel === "" || !rel.startsWith("..") && !path30.isAbsolute(rel);
10121
+ const abs = path31.isAbsolute(p) ? p : path31.resolve(cwd, p);
10122
+ const rel = path31.relative(cwd, abs);
10123
+ return rel === "" || !rel.startsWith("..") && !path31.isAbsolute(rel);
10065
10124
  } catch {
10066
10125
  return false;
10067
10126
  }
@@ -10089,8 +10148,8 @@ var init_autoPermission = __esm({
10089
10148
  });
10090
10149
 
10091
10150
  // ../core/src/agent/toolExecution.ts
10092
- import fs28 from "fs/promises";
10093
- import path31 from "path";
10151
+ import fs29 from "fs/promises";
10152
+ import path32 from "path";
10094
10153
  var applyPrivacyMasking, processToolCall;
10095
10154
  var init_toolExecution = __esm({
10096
10155
  "../core/src/agent/toolExecution.ts"() {
@@ -10230,13 +10289,13 @@ var init_toolExecution = __esm({
10230
10289
  const argCwd = typeof calledArgs?.cwd === "string" ? calledArgs.cwd.trim() : "";
10231
10290
  const samePath = (a, b) => {
10232
10291
  try {
10233
- const ra = path31.resolve(a), rb = path31.resolve(b);
10292
+ const ra = path32.resolve(a), rb = path32.resolve(b);
10234
10293
  return process.platform === "win32" ? ra.toLowerCase() === rb.toLowerCase() : ra === rb;
10235
10294
  } catch {
10236
10295
  return false;
10237
10296
  }
10238
10297
  };
10239
- const scriptRunnerCwdDrift = cmdIsScriptRunner && argCwd !== "" && !samePath(argCwd, toolCtx.cwd);
10298
+ const scriptRunnerCwdDrift = cmdIsScriptRunner && argCwd !== "" && !samePath(argCwd, toolCtx.cwd ?? process.cwd());
10240
10299
  const scriptRunnerBlocked = cmdIsScriptRunner && (perm === null || scriptRunnerCwdDrift);
10241
10300
  if (scriptRunnerCwdDrift) needApproval = true;
10242
10301
  if (perm === null && needApproval && !denied && !scriptRunnerBlocked && calledName === "run_command" && isReadOnlyCommand(typeof calledArgs?.command === "string" ? calledArgs.command : "")) {
@@ -10345,10 +10404,10 @@ ${result}`;
10345
10404
  const truncBudget = matchedTool?.function?.maxOutputCharacters ?? appConfig.MAX_TOOL_RESULT_CHARS;
10346
10405
  if (result.length > truncBudget) {
10347
10406
  try {
10348
- const sidecarDir = path31.join(getSessionsDirPath(sessionId), "tool-outputs");
10349
- await fs28.mkdir(sidecarDir, { recursive: true });
10407
+ const sidecarDir = path32.join(getSessionsDirPath(sessionId), "tool-outputs");
10408
+ await fs29.mkdir(sidecarDir, { recursive: true });
10350
10409
  const safeId = String(toolCall.id).replace(/[^A-Za-z0-9_-]/g, "");
10351
- await fs28.writeFile(path31.join(sidecarDir, `${safeId}.txt`), result, "utf-8");
10410
+ await fs29.writeFile(path32.join(sidecarDir, `${safeId}.txt`), result, "utf-8");
10352
10411
  sidecarNote = `\u5B8C\u6574\u539F\u6587\u5DF2\u5B58\u6863\uFF0Crecall \u5DE5\u5177\u4F20 with_full="${toolCall.id}" \u53EF\u53D6\u56DE`;
10353
10412
  } catch (e) {
10354
10413
  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);
@@ -10499,6 +10558,8 @@ var init_streamInference = __esm({
10499
10558
  init_transcript();
10500
10559
  init_contextCore();
10501
10560
  init_contentParts();
10561
+ init_visionCapability();
10562
+ init_createModel();
10502
10563
  sha1short = (s) => createHash2("sha1").update(s).digest("hex").slice(0, 10);
10503
10564
  RETRY_BACKOFF_CAP_MS = 3e4;
10504
10565
  extractRetryAfterMs = (e) => {
@@ -10537,7 +10598,7 @@ var init_streamInference = __esm({
10537
10598
  llmDecisionSource,
10538
10599
  signal,
10539
10600
  cleanedToolSchemas,
10540
- model: model2,
10601
+ model,
10541
10602
  thinkingLevel,
10542
10603
  events,
10543
10604
  keepRecentUnits,
@@ -10557,7 +10618,7 @@ var init_streamInference = __esm({
10557
10618
  events({
10558
10619
  sessionId,
10559
10620
  eventType: "llm.request",
10560
- metadata: { depth, decisionSource: userDecisionSource, ok: true, durationMs: performance.now() - startTime, round, ...prefixFingerprint },
10621
+ metadata: { depth, decisionSource: userDecisionSource, ok: true, durationMs: performance.now() - startTime, round, model, ...prefixFingerprint },
10561
10622
  // ★ P2 口径:估算加上工具 schema 常数项(与 API 真实 prompt_tokens 同口径,trace 里 est/real 才可比)
10562
10623
  usage: { prompt_tokens: estimateTokens(inferenceMessages) + toolsTokens },
10563
10624
  payload: { input: msgText(message[message.length - 1].content) }
@@ -10572,9 +10633,10 @@ var init_streamInference = __esm({
10572
10633
  const MAX_API_RETRIES = 3;
10573
10634
  let apiRetries = 0;
10574
10635
  let compactedThisRound = false;
10636
+ let visionDegradedThisRound = false;
10575
10637
  for (let streamAttempt = 0; ; streamAttempt++) {
10576
10638
  try {
10577
- for await (const chunk of activeProvider.streamChat(inferenceMessages, cleanedToolSchemas, { signal, model: model2, thinkingLevel })) {
10639
+ for await (const chunk of activeProvider.streamChat(inferenceMessages, cleanedToolSchemas, { signal, model, thinkingLevel })) {
10578
10640
  if (signal?.aborted) break;
10579
10641
  switch (chunk.kind) {
10580
10642
  case "text":
@@ -10672,6 +10734,26 @@ var init_streamInference = __esm({
10672
10734
  lastUsage = void 0;
10673
10735
  continue;
10674
10736
  }
10737
+ if (activeProvider.isImageUnsupportedError(streamErr) && noOutputYet && !visionDegradedThisRound) {
10738
+ const effModel = typeof model === "string" && model.trim() ? model.trim() : MODEL_NAME;
10739
+ learnVisionCapability(effModel, false);
10740
+ for (let i = 0; i < message.length; i++) message[i] = collapseToText(message[i], VISION_DEGRADE_NOTE);
10741
+ inferenceMessages = withNudgeTail(message, nudgeMsg);
10742
+ visionDegradedThisRound = true;
10743
+ events({
10744
+ sessionId,
10745
+ eventType: "llm.visionDowngraded",
10746
+ metadata: { depth, decisionSource: llmDecisionSource, ok: true, round, model: effModel },
10747
+ payload: { output: streamErr instanceof Error ? streamErr.message : String(streamErr) }
10748
+ });
10749
+ yield { type: "vision.downgraded", model: effModel };
10750
+ console.warn(`\u26A0\uFE0F \u6A21\u578B ${effModel} \u4E0D\u652F\u6301\u56FE\u7247\u8F93\u5165\uFF08API ${streamErr?.status ?? "?"}\uFF09\uFF0C\u5DF2\u81EA\u52A8\u964D\u7EA7\u4E3A\u6587\u672C\u5360\u4F4D\u5E76\u91CD\u8BD5\uFF08\u80FD\u529B\u5DF2\u8BB0\u4F4F\uFF0C\u540E\u7EED\u6D88\u606F\u76F4\u63A5\u6309\u6587\u672C\u53D1\u9001\uFF09`);
10751
+ contentBuf = "";
10752
+ reasoningBuf = "";
10753
+ toolCallsBuf.clear();
10754
+ lastUsage = void 0;
10755
+ continue;
10756
+ }
10675
10757
  throw streamErr;
10676
10758
  }
10677
10759
  }
@@ -10691,7 +10773,7 @@ var init_streamInference = __esm({
10691
10773
  events({
10692
10774
  sessionId,
10693
10775
  eventType: "llm.response",
10694
- metadata: { depth, decisionSource: llmDecisionSource, ok: true, durationMs: performance.now() - startTime, round },
10776
+ metadata: { depth, decisionSource: llmDecisionSource, ok: true, durationMs: performance.now() - startTime, round, model },
10695
10777
  usage: {
10696
10778
  prompt_tokens: lastUsage?.prompt_tokens,
10697
10779
  completion_tokens: lastUsage?.completion_tokens,
@@ -11247,7 +11329,7 @@ var init_recovery = __esm({
11247
11329
  });
11248
11330
 
11249
11331
  // ../core/src/session/content.ts
11250
- var decayOldToolResults, NO_VISION_IMAGE_NOTE, enforceVisionGate, buildContextMessages;
11332
+ var decayOldToolResults, enforceVisionGate, buildContextMessages;
11251
11333
  var init_content = __esm({
11252
11334
  "../core/src/session/content.ts"() {
11253
11335
  "use strict";
@@ -11256,6 +11338,7 @@ var init_content = __esm({
11256
11338
  init_transcript();
11257
11339
  init_store();
11258
11340
  init_config();
11341
+ init_visionCapability();
11259
11342
  init_recovery();
11260
11343
  decayOldToolResults = (msgs) => {
11261
11344
  const units = groupUnits(msgs);
@@ -11286,9 +11369,9 @@ var init_content = __esm({
11286
11369
  return replaceImageParts(mm, "[\u5386\u53F2\u56FE\u7247\u5DF2\u6298\u53E0\uFF1A\u539F\u56FE\u4ECD\u5728\u4F1A\u8BDD\u5F52\u6863\u4E2D\uFF0C\u5982\u9700\u518D\u6B21\u67E5\u770B\u8BF7\u91CD\u65B0\u63D0\u4F9B\u8BE5\u56FE\u7247]");
11287
11370
  });
11288
11371
  };
11289
- NO_VISION_IMAGE_NOTE = "[\u56FE\u7247\u672A\u9001\u8FBE\uFF1A\u5F53\u524D\u6A21\u578B\u65E0\u89C6\u89C9\u80FD\u529B\uFF0C\u770B\u4E0D\u5230\u8BE5\u56FE\uFF1B\u539F\u56FE\u4FDD\u7559\u5728\u4F1A\u8BDD\u5F52\u6863\u4E2D\uFF0C\u5982\u9700\u5206\u6790\u8BF7\u8BA9\u7528\u6237\u91CD\u65B0\u63D0\u4F9B\u6216\u5207\u6362 vision \u6A21\u578B]";
11290
- enforceVisionGate = (msgs, modelId) => isVisionEnabled(modelId) ? msgs : msgs.map((m) => collapseToText(m, NO_VISION_IMAGE_NOTE));
11372
+ enforceVisionGate = (msgs, modelId) => isVisionEnabled(modelId) ? msgs : msgs.map((m) => collapseToText(m, VISION_DEGRADE_NOTE));
11291
11373
  buildContextMessages = async (sessionId, currentUserMsg, systemPrompt, modelId) => {
11374
+ await ensureVisionCacheLoaded();
11292
11375
  const lines = await readTranscriptLines(sessionId);
11293
11376
  const store = await getRollingState(sessionId);
11294
11377
  const eventAware = appConfig.transcriptEvents || lines.some(isEventLine);
@@ -11318,7 +11401,7 @@ var init_content = __esm({
11318
11401
  });
11319
11402
 
11320
11403
  // ../core/src/session/lineage.ts
11321
- import fs29 from "node:fs";
11404
+ import fs30 from "node:fs";
11322
11405
  var parentOfSubsession, stringAncestorsOf, readForkedFromSync, lineageClosureOf, ownerCanApprove;
11323
11406
  var init_lineage = __esm({
11324
11407
  "../core/src/session/lineage.ts"() {
@@ -11341,7 +11424,7 @@ var init_lineage = __esm({
11341
11424
  };
11342
11425
  readForkedFromSync = (sessionId) => {
11343
11426
  try {
11344
- const raw = fs29.readFileSync(getStatePath(sessionId), "utf-8");
11427
+ const raw = fs30.readFileSync(getStatePath(sessionId), "utf-8");
11345
11428
  const v = JSON.parse(raw)?.forkedFrom;
11346
11429
  return typeof v === "string" && v.length > 0 ? v : void 0;
11347
11430
  } catch {
@@ -11538,8 +11621,8 @@ var init_subagent = __esm({
11538
11621
  });
11539
11622
 
11540
11623
  // ../core/src/hooks/loader.ts
11541
- import fs30 from "fs/promises";
11542
- import path32 from "path";
11624
+ import fs31 from "fs/promises";
11625
+ import path33 from "path";
11543
11626
  var readHooksConfig, appendValidated, validateRule, parseStdoutDecision, parseAgentDecision, compileRule2, loadHooks, initHooks;
11544
11627
  var init_loader4 = __esm({
11545
11628
  "../core/src/hooks/loader.ts"() {
@@ -11554,15 +11637,15 @@ var init_loader4 = __esm({
11554
11637
  readHooksConfig = async (includeProject) => {
11555
11638
  const merged = {};
11556
11639
  const paths = [
11557
- path32.join(appConfig.dataDir, "settings.json"),
11640
+ path33.join(appConfig.dataDir, "settings.json"),
11558
11641
  // 全局用户级
11559
- ...includeProject ? [path32.join(process.cwd(), ".deepseeker-code", "settings.json")] : []
11642
+ ...includeProject ? [path33.join(process.cwd(), ".deepseeker-code", "settings.json")] : []
11560
11643
  // 项目级(叠加);未信任时省略
11561
11644
  ];
11562
11645
  for (const configPath of paths) {
11563
11646
  let raw;
11564
11647
  try {
11565
- raw = await fs30.readFile(configPath, "utf-8");
11648
+ raw = await fs31.readFile(configPath, "utf-8");
11566
11649
  } catch {
11567
11650
  continue;
11568
11651
  }
@@ -11893,8 +11976,8 @@ ${m.context}`;
11893
11976
  });
11894
11977
 
11895
11978
  // ../core/src/skills/loader.ts
11896
- import fs31 from "fs/promises";
11897
- import path33 from "path";
11979
+ import fs32 from "fs/promises";
11980
+ import path34 from "path";
11898
11981
  import { fileURLToPath as fileURLToPath2 } from "url";
11899
11982
  var BUILTIN_DIR, SOURCES2, MAX_SKILL_BODY_BYTES, splitList, parseSkillAt, loadSkills, initSkills;
11900
11983
  var init_loader5 = __esm({
@@ -11905,18 +11988,18 @@ var init_loader5 = __esm({
11905
11988
  init_registry3();
11906
11989
  init_skill();
11907
11990
  init_registry2();
11908
- BUILTIN_DIR = path33.join(path33.dirname(fileURLToPath2(import.meta.url)), "builtin");
11991
+ BUILTIN_DIR = path34.join(path34.dirname(fileURLToPath2(import.meta.url)), "builtin");
11909
11992
  SOURCES2 = [
11910
11993
  { dir: BUILTIN_DIR, source: "builtin" },
11911
- { dir: path33.join(appConfig.dataDir, "skills"), source: "global" },
11912
- { dir: path33.join(process.cwd(), ".deepseeker-code", "skills"), source: "project" }
11994
+ { dir: path34.join(appConfig.dataDir, "skills"), source: "global" },
11995
+ { dir: path34.join(process.cwd(), ".deepseeker-code", "skills"), source: "project" }
11913
11996
  ];
11914
11997
  MAX_SKILL_BODY_BYTES = 64 * 1024;
11915
11998
  splitList = (raw) => (raw ?? "").split(",").map((s) => s.trim()).filter(Boolean);
11916
11999
  parseSkillAt = async (skillFile, dir, source) => {
11917
12000
  let raw;
11918
12001
  try {
11919
- raw = await fs31.readFile(skillFile, "utf-8");
12002
+ raw = await fs32.readFile(skillFile, "utf-8");
11920
12003
  } catch {
11921
12004
  return null;
11922
12005
  }
@@ -11955,7 +12038,7 @@ var init_loader5 = __esm({
11955
12038
  loadSkills = async (includeProject) => {
11956
12039
  const picked = await scanSources(
11957
12040
  filterSources(SOURCES2, includeProject),
11958
- (e, dir) => e.isDirectory() ? path33.join(dir, e.name, "SKILL.md") : void 0,
12041
+ (e, dir) => e.isDirectory() ? path34.join(dir, e.name, "SKILL.md") : void 0,
11959
12042
  parseSkillAt
11960
12043
  );
11961
12044
  for (const { item } of picked) registerSkill(item);
@@ -11986,8 +12069,8 @@ var init_loader5 = __esm({
11986
12069
  });
11987
12070
 
11988
12071
  // ../core/src/agents/loader.ts
11989
- import fs32 from "fs/promises";
11990
- import path34 from "path";
12072
+ import fs33 from "fs/promises";
12073
+ import path35 from "path";
11991
12074
  import { fileURLToPath as fileURLToPath3 } from "url";
11992
12075
  var BUILTIN_DIR2, SOURCES3, parseAgentAt, initAgents;
11993
12076
  var init_loader6 = __esm({
@@ -11997,16 +12080,16 @@ var init_loader6 = __esm({
11997
12080
  init_frontmatter();
11998
12081
  init_registry4();
11999
12082
  init_registry2();
12000
- BUILTIN_DIR2 = path34.join(path34.dirname(fileURLToPath3(import.meta.url)), "builtin");
12083
+ BUILTIN_DIR2 = path35.join(path35.dirname(fileURLToPath3(import.meta.url)), "builtin");
12001
12084
  SOURCES3 = [
12002
12085
  { dir: BUILTIN_DIR2, source: "builtin" },
12003
- { dir: path34.join(appConfig.dataDir, "agents"), source: "global" },
12004
- { dir: path34.join(process.cwd(), ".deepseeker-code", "agents"), source: "project" }
12086
+ { dir: path35.join(appConfig.dataDir, "agents"), source: "global" },
12087
+ { dir: path35.join(process.cwd(), ".deepseeker-code", "agents"), source: "project" }
12005
12088
  ];
12006
12089
  parseAgentAt = async (file, dir, source) => {
12007
12090
  let raw;
12008
12091
  try {
12009
- raw = await fs32.readFile(file, "utf-8");
12092
+ raw = await fs33.readFile(file, "utf-8");
12010
12093
  } catch {
12011
12094
  return null;
12012
12095
  }
@@ -12015,7 +12098,7 @@ var init_loader6 = __esm({
12015
12098
  console.warn(`\u26A0\uFE0F [agents] frontmatter \u683C\u5F0F\u65E0\u6548\uFF08${file}\uFF09\uFF0C\u5DF2\u8DF3\u8FC7`);
12016
12099
  return null;
12017
12100
  }
12018
- const { name, description, role, tools, model: model2 } = parsed.frontmatter;
12101
+ const { name, description, role, tools, model } = parsed.frontmatter;
12019
12102
  if (!name || !description) {
12020
12103
  console.warn(`\u26A0\uFE0F [agents] \u7F3A\u5C11 name \u6216 description\uFF08${file}\uFF09\uFF0C\u5DF2\u8DF3\u8FC7`);
12021
12104
  return null;
@@ -12030,7 +12113,7 @@ var init_loader6 = __esm({
12030
12113
  description,
12031
12114
  role: role || void 0,
12032
12115
  tools: toolList,
12033
- model: model2 || void 0,
12116
+ model: model || void 0,
12034
12117
  body: parsed.body,
12035
12118
  source,
12036
12119
  dir
@@ -12041,7 +12124,7 @@ var init_loader6 = __esm({
12041
12124
  const known = new Set(into.map((t) => t.function.name));
12042
12125
  const picked = await scanSources(
12043
12126
  filterSources(SOURCES3, includeProject),
12044
- (e, dir) => e.isFile() && e.name.endsWith(".agent.md") ? path34.join(dir, e.name) : void 0,
12127
+ (e, dir) => e.isFile() && e.name.endsWith(".agent.md") ? path35.join(dir, e.name) : void 0,
12045
12128
  parseAgentAt
12046
12129
  );
12047
12130
  for (const { item: m, file, source } of picked) {
@@ -12078,8 +12161,8 @@ var init_registry7 = __esm({
12078
12161
  });
12079
12162
 
12080
12163
  // ../core/src/commands/loader.ts
12081
- import fs33 from "fs/promises";
12082
- import path35 from "path";
12164
+ import fs34 from "fs/promises";
12165
+ import path36 from "path";
12083
12166
  import { fileURLToPath as fileURLToPath4 } from "url";
12084
12167
  var BUILTIN_DIR3, SOURCES4, MAX_COMMAND_BODY_BYTES, parseCommandAt, loadCommands, initCommands;
12085
12168
  var init_loader7 = __esm({
@@ -12089,17 +12172,17 @@ var init_loader7 = __esm({
12089
12172
  init_frontmatter();
12090
12173
  init_registry7();
12091
12174
  init_registry2();
12092
- BUILTIN_DIR3 = path35.join(path35.dirname(fileURLToPath4(import.meta.url)), "builtin");
12175
+ BUILTIN_DIR3 = path36.join(path36.dirname(fileURLToPath4(import.meta.url)), "builtin");
12093
12176
  SOURCES4 = [
12094
12177
  { dir: BUILTIN_DIR3, source: "builtin" },
12095
- { dir: path35.join(appConfig.dataDir, "commands"), source: "global" },
12096
- { dir: path35.join(process.cwd(), ".deepseeker-code", "commands"), source: "project" }
12178
+ { dir: path36.join(appConfig.dataDir, "commands"), source: "global" },
12179
+ { dir: path36.join(process.cwd(), ".deepseeker-code", "commands"), source: "project" }
12097
12180
  ];
12098
12181
  MAX_COMMAND_BODY_BYTES = 64 * 1024;
12099
12182
  parseCommandAt = async (file, _dir, source) => {
12100
12183
  let raw;
12101
12184
  try {
12102
- raw = await fs33.readFile(file, "utf-8");
12185
+ raw = await fs34.readFile(file, "utf-8");
12103
12186
  } catch {
12104
12187
  return null;
12105
12188
  }
@@ -12110,7 +12193,7 @@ var init_loader7 = __esm({
12110
12193
  }
12111
12194
  const name = parsed.frontmatter.name;
12112
12195
  const description = parsed.frontmatter.description;
12113
- const fallbackName = path35.basename(file, ".md");
12196
+ const fallbackName = path36.basename(file, ".md");
12114
12197
  const finalName = name || fallbackName;
12115
12198
  if (!description) {
12116
12199
  console.warn(`\u26A0\uFE0F [commands] \u7F3A\u5C11 description\uFF08${file}\uFF09\uFF0C\u5DF2\u8DF3\u8FC7`);
@@ -12136,7 +12219,7 @@ var init_loader7 = __esm({
12136
12219
  loadCommands = async (includeProject) => {
12137
12220
  const picked = await scanSources(
12138
12221
  filterSources(SOURCES4, includeProject),
12139
- (e, dir) => e.isFile() && e.name.endsWith(".md") ? path35.join(dir, e.name) : void 0,
12222
+ (e, dir) => e.isFile() && e.name.endsWith(".md") ? path36.join(dir, e.name) : void 0,
12140
12223
  parseCommandAt
12141
12224
  );
12142
12225
  for (const { item } of picked) registerCommand(item);
@@ -12154,8 +12237,8 @@ var init_loader7 = __esm({
12154
12237
  });
12155
12238
 
12156
12239
  // ../core/src/outputStyles/loader.ts
12157
- import fs34 from "fs/promises";
12158
- import path36 from "path";
12240
+ import fs35 from "fs/promises";
12241
+ import path37 from "path";
12159
12242
  import { fileURLToPath as fileURLToPath5 } from "url";
12160
12243
  var BUILTIN_DIR4, MAX_STYLE_BODY_BYTES, SOURCES5, parseStyleAt, loadOutputStyles, initOutputStyles;
12161
12244
  var init_loader8 = __esm({
@@ -12165,17 +12248,17 @@ var init_loader8 = __esm({
12165
12248
  init_frontmatter();
12166
12249
  init_registry5();
12167
12250
  init_registry2();
12168
- BUILTIN_DIR4 = path36.join(path36.dirname(fileURLToPath5(import.meta.url)), "builtin");
12251
+ BUILTIN_DIR4 = path37.join(path37.dirname(fileURLToPath5(import.meta.url)), "builtin");
12169
12252
  MAX_STYLE_BODY_BYTES = 64 * 1024;
12170
12253
  SOURCES5 = [
12171
12254
  { dir: BUILTIN_DIR4, source: "builtin" },
12172
- { dir: path36.join(appConfig.dataDir, "output-styles"), source: "global" },
12173
- { dir: path36.join(process.cwd(), ".deepseeker-code", "output-styles"), source: "project" }
12255
+ { dir: path37.join(appConfig.dataDir, "output-styles"), source: "global" },
12256
+ { dir: path37.join(process.cwd(), ".deepseeker-code", "output-styles"), source: "project" }
12174
12257
  ];
12175
12258
  parseStyleAt = async (file, _dir, source) => {
12176
12259
  let raw;
12177
12260
  try {
12178
- raw = await fs34.readFile(file, "utf-8");
12261
+ raw = await fs35.readFile(file, "utf-8");
12179
12262
  } catch {
12180
12263
  return null;
12181
12264
  }
@@ -12207,7 +12290,7 @@ var init_loader8 = __esm({
12207
12290
  loadOutputStyles = async (includeProject) => {
12208
12291
  const picked = await scanSources(
12209
12292
  filterSources(SOURCES5, includeProject),
12210
- (e, dir) => e.isFile() && e.name.endsWith(".md") ? path36.join(dir, e.name) : void 0,
12293
+ (e, dir) => e.isFile() && e.name.endsWith(".md") ? path37.join(dir, e.name) : void 0,
12211
12294
  parseStyleAt
12212
12295
  );
12213
12296
  for (const { item } of picked) registerOutputStyle(item);
@@ -12288,8 +12371,8 @@ var init_bootstrap = __esm({
12288
12371
  });
12289
12372
 
12290
12373
  // ../core/src/statusLine/config.ts
12291
- import fs35 from "fs/promises";
12292
- import path37 from "path";
12374
+ import fs36 from "fs/promises";
12375
+ import path38 from "path";
12293
12376
  var parseBlock, readStatusLineConfig;
12294
12377
  var init_config2 = __esm({
12295
12378
  "../core/src/statusLine/config.ts"() {
@@ -12305,16 +12388,16 @@ var init_config2 = __esm({
12305
12388
  };
12306
12389
  readStatusLineConfig = async (includeProject) => {
12307
12390
  const paths = [
12308
- path37.join(appConfig.dataDir, "settings.json"),
12391
+ path38.join(appConfig.dataDir, "settings.json"),
12309
12392
  // 全局用户级
12310
- ...includeProject ? [path37.join(process.cwd(), ".deepseeker-code", "settings.json")] : []
12393
+ ...includeProject ? [path38.join(process.cwd(), ".deepseeker-code", "settings.json")] : []
12311
12394
  // 项目级(覆盖);未信任时省略
12312
12395
  ];
12313
12396
  let result = null;
12314
12397
  for (const configPath of paths) {
12315
12398
  let raw;
12316
12399
  try {
12317
- raw = await fs35.readFile(configPath, "utf-8");
12400
+ raw = await fs36.readFile(configPath, "utf-8");
12318
12401
  } catch {
12319
12402
  continue;
12320
12403
  }
@@ -12334,8 +12417,8 @@ var init_config2 = __esm({
12334
12417
 
12335
12418
  // ../core/src/statusLine/runner.ts
12336
12419
  import { spawn as spawn5 } from "child_process";
12337
- import fs36 from "fs";
12338
- import path38 from "path";
12420
+ import fs37 from "fs";
12421
+ import path39 from "path";
12339
12422
  import { fileURLToPath as fileURLToPath6 } from "url";
12340
12423
  var STATUSLINE_TIMEOUT_MS, cachedVersion, runStatusLine;
12341
12424
  var init_runner = __esm({
@@ -12344,16 +12427,16 @@ var init_runner = __esm({
12344
12427
  init_guard();
12345
12428
  STATUSLINE_TIMEOUT_MS = 3e3;
12346
12429
  try {
12347
- const here = path38.dirname(fileURLToPath6(import.meta.url));
12430
+ const here = path39.dirname(fileURLToPath6(import.meta.url));
12348
12431
  const candidates = [
12349
- path38.join(here, "../../../package.json"),
12432
+ path39.join(here, "../../../package.json"),
12350
12433
  // src/core/package.json
12351
- path38.join(here, "../../../../package.json")
12434
+ path39.join(here, "../../../../package.json")
12352
12435
  // 仓库根 package.json
12353
12436
  ];
12354
12437
  for (const p of candidates) {
12355
12438
  try {
12356
- const pkg = JSON.parse(fs36.readFileSync(p, "utf-8"));
12439
+ const pkg = JSON.parse(fs37.readFileSync(p, "utf-8"));
12357
12440
  if (typeof pkg.version === "string" && pkg.version) {
12358
12441
  cachedVersion = pkg.version;
12359
12442
  break;
@@ -12404,8 +12487,8 @@ var init_runner = __esm({
12404
12487
  });
12405
12488
 
12406
12489
  // ../core/src/observability/store.ts
12407
- import path39 from "path";
12408
- import fs37 from "fs/promises";
12490
+ import path40 from "path";
12491
+ import fs38 from "fs/promises";
12409
12492
  var getTraceDirPath, getTracePath, tracePathCache, ensuredTraceDirs, ensureTraceDir, getGlobalClockPath, getTraceStorePath;
12410
12493
  var init_store3 = __esm({
12411
12494
  "../core/src/observability/store.ts"() {
@@ -12415,21 +12498,21 @@ var init_store3 = __esm({
12415
12498
  init_common();
12416
12499
  getTraceDirPath = (mainTraceId) => {
12417
12500
  assertSafeSessionId(mainTraceId, "traceId");
12418
- return path39.join(appConfig.dataDir, "trace", appConfig.userWorkspaceDir, getFileName(mainTraceId));
12501
+ return path40.join(appConfig.dataDir, "trace", appConfig.userWorkspaceDir, getFileName(mainTraceId));
12419
12502
  };
12420
12503
  getTracePath = () => {
12421
- return path39.join(appConfig.dataDir, "trace");
12504
+ return path40.join(appConfig.dataDir, "trace");
12422
12505
  };
12423
12506
  tracePathCache = /* @__PURE__ */ new Map();
12424
12507
  ensuredTraceDirs = /* @__PURE__ */ new Set();
12425
12508
  ensureTraceDir = async (mainTraceId) => {
12426
12509
  const dir = getTraceDirPath(mainTraceId);
12427
12510
  if (ensuredTraceDirs.has(dir)) return;
12428
- await fs37.mkdir(dir, { recursive: true });
12511
+ await fs38.mkdir(dir, { recursive: true });
12429
12512
  ensuredTraceDirs.add(dir);
12430
12513
  };
12431
12514
  getGlobalClockPath = () => {
12432
- return path39.join(getTracePath(), "trace-cleanup-clock.json");
12515
+ return path40.join(getTracePath(), "trace-cleanup-clock.json");
12433
12516
  };
12434
12517
  getTraceStorePath = async (mainTraceId) => {
12435
12518
  assertSafeSessionId(mainTraceId, "traceId");
@@ -12438,7 +12521,7 @@ var init_store3 = __esm({
12438
12521
  if (cached2) return cached2;
12439
12522
  await ensureTraceDir(rootId);
12440
12523
  const dir = getTraceDirPath(rootId);
12441
- const files = await fs37.readdir(dir);
12524
+ const files = await fs38.readdir(dir);
12442
12525
  const existedFile = files.find((f) => f.endsWith(`__${rootId}.jsonl`));
12443
12526
  let fileName = "";
12444
12527
  if (existedFile) {
@@ -12447,7 +12530,7 @@ var init_store3 = __esm({
12447
12530
  const todayStr = getTodayDateString();
12448
12531
  fileName = `trace-${todayStr}__${rootId}.jsonl`;
12449
12532
  }
12450
- const resolved = path39.join(dir, fileName);
12533
+ const resolved = path40.join(dir, fileName);
12451
12534
  tracePathCache.set(rootId, resolved);
12452
12535
  return resolved;
12453
12536
  };
@@ -12455,8 +12538,8 @@ var init_store3 = __esm({
12455
12538
  });
12456
12539
 
12457
12540
  // ../core/src/observability/trace.ts
12458
- import fs38 from "fs/promises";
12459
- import path40 from "path";
12541
+ import fs39 from "fs/promises";
12542
+ import path41 from "path";
12460
12543
  async function emitTrace(base) {
12461
12544
  const event = {
12462
12545
  sessionId: base.sessionId,
@@ -12478,7 +12561,7 @@ async function emitTrace(base) {
12478
12561
  async function appendTraceEvent(event) {
12479
12562
  const p = await getTraceStorePath(event.sessionId);
12480
12563
  const line = JSON.stringify(event) + "\n";
12481
- await fs38.appendFile(p, line, "utf-8");
12564
+ await fs39.appendFile(p, line, "utf-8");
12482
12565
  if (workspaceTraceBytes < 0) {
12483
12566
  workspaceTraceBytes = await getDirBytes(getTracePath());
12484
12567
  }
@@ -12510,8 +12593,8 @@ async function maybeCleanupAfterAppend(sessionId) {
12510
12593
  lastSizeCleanupAt2 = now;
12511
12594
  diskLastCleanupAt2 = now;
12512
12595
  const clockPath = getGlobalClockPath();
12513
- await fs38.mkdir(path40.dirname(clockPath), { recursive: true });
12514
- await fs38.writeFile(clockPath, JSON.stringify({ lastCleanupAt: now, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2), "utf-8");
12596
+ await fs39.mkdir(path41.dirname(clockPath), { recursive: true });
12597
+ await fs39.writeFile(clockPath, JSON.stringify({ lastCleanupAt: now, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2), "utf-8");
12515
12598
  if (deletedCount > 0) {
12516
12599
  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`);
12517
12600
  }
@@ -12531,22 +12614,22 @@ async function cleanupOldTraceFiles() {
12531
12614
  let deleted = 0;
12532
12615
  let relativePaths;
12533
12616
  try {
12534
- relativePaths = await fs38.readdir(dir, { recursive: true });
12617
+ relativePaths = await fs39.readdir(dir, { recursive: true });
12535
12618
  } catch {
12536
12619
  return 0;
12537
12620
  }
12538
12621
  const re = /^trace-(\d{4}-\d{2}-\d{2})__([\w-]+)\.jsonl$/;
12539
12622
  for (const relativePath of relativePaths) {
12540
- const fileName = path40.basename(relativePath);
12623
+ const fileName = path41.basename(relativePath);
12541
12624
  const m = fileName.match(re);
12542
12625
  if (!m) continue;
12543
12626
  const fileBornDay = /* @__PURE__ */ new Date(`${m[1]}T00:00:00`);
12544
12627
  if (fileBornDay >= cutoff) continue;
12545
- const fullPath = path40.join(dir, relativePath);
12628
+ const fullPath = path41.join(dir, relativePath);
12546
12629
  try {
12547
- const st = await fs38.stat(fullPath);
12630
+ const st = await fs39.stat(fullPath);
12548
12631
  if (now - st.mtimeMs < ACTIVE_GRACE_MS2) continue;
12549
- await fs38.unlink(fullPath);
12632
+ await fs39.unlink(fullPath);
12550
12633
  deleted += 1;
12551
12634
  } catch {
12552
12635
  }
@@ -12557,18 +12640,18 @@ async function evictOldestForSize2(targetBytes) {
12557
12640
  const dir = getTracePath();
12558
12641
  let relativePaths;
12559
12642
  try {
12560
- relativePaths = await fs38.readdir(dir, { recursive: true });
12643
+ relativePaths = await fs39.readdir(dir, { recursive: true });
12561
12644
  } catch {
12562
12645
  return 0;
12563
12646
  }
12564
12647
  const re = /^trace-(\d{4}-\d{2}-\d{2})__([\w-]+)\.jsonl$/;
12565
12648
  const candidates = [];
12566
12649
  for (const relativePath of relativePaths) {
12567
- const fileName = path40.basename(relativePath);
12650
+ const fileName = path41.basename(relativePath);
12568
12651
  if (!re.test(fileName)) continue;
12569
12652
  try {
12570
- const st = await fs38.stat(path40.join(dir, relativePath));
12571
- candidates.push({ mtime: st.mtimeMs, fullPath: path40.join(dir, relativePath), size: st.size });
12653
+ const st = await fs39.stat(path41.join(dir, relativePath));
12654
+ candidates.push({ mtime: st.mtimeMs, fullPath: path41.join(dir, relativePath), size: st.size });
12572
12655
  } catch {
12573
12656
  }
12574
12657
  }
@@ -12578,7 +12661,7 @@ async function evictOldestForSize2(targetBytes) {
12578
12661
  for (const c of candidates) {
12579
12662
  if (totalBytes <= targetBytes) break;
12580
12663
  try {
12581
- await fs38.unlink(c.fullPath);
12664
+ await fs39.unlink(c.fullPath);
12582
12665
  totalBytes -= c.size;
12583
12666
  deleted += 1;
12584
12667
  } catch {
@@ -12610,7 +12693,7 @@ var init_trace = __esm({
12610
12693
  if (clockLoaded2) return;
12611
12694
  clockLoaded2 = true;
12612
12695
  try {
12613
- const rawClock = await fs38.readFile(getGlobalClockPath(), "utf-8");
12696
+ const rawClock = await fs39.readFile(getGlobalClockPath(), "utf-8");
12614
12697
  diskLastCleanupAt2 = JSON.parse(rawClock).lastCleanupAt || 0;
12615
12698
  } catch {
12616
12699
  diskLastCleanupAt2 = 0;
@@ -12757,8 +12840,8 @@ ${PLAN_MODE_AUTO_ENTER_HINT}
12757
12840
  });
12758
12841
 
12759
12842
  // ../core/src/serve/chatProcessing.ts
12760
- import path41 from "path";
12761
- import fs39 from "fs";
12843
+ import path42 from "path";
12844
+ import fs40 from "fs";
12762
12845
  var handleUnifiedChat;
12763
12846
  var init_chatProcessing = __esm({
12764
12847
  "../core/src/serve/chatProcessing.ts"() {
@@ -12771,6 +12854,7 @@ var init_chatProcessing = __esm({
12771
12854
  init_transcript();
12772
12855
  init_content();
12773
12856
  init_contentParts();
12857
+ init_visionCapability();
12774
12858
  init_trace();
12775
12859
  init_webHost();
12776
12860
  init_registry();
@@ -12813,17 +12897,17 @@ ${inject}`;
12813
12897
  if (roots.length > 1) {
12814
12898
  let activeReal = getActiveWorkspaceRoot();
12815
12899
  try {
12816
- activeReal = fs39.realpathSync(activeReal);
12900
+ activeReal = fs40.realpathSync(activeReal);
12817
12901
  } catch {
12818
12902
  }
12819
- const lines = roots.map((r) => `- ${path41.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"}`);
12903
+ const lines = roots.map((r) => `- ${path42.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"}`);
12820
12904
  sysPrompt = sysPrompt + `
12821
12905
 
12822
12906
  \u3010\u5DE5\u4F5C\u533A\uFF08\u591A\u9879\u76EE\uFF09\u3011
12823
12907
  \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>:
12824
12908
  ${lines.join("\n")}
12825
- \u2605 \u8DEF\u5F84\u951A\u5B9A\u94C1\u5F8B\uFF1A\u5DE5\u5177\u7F3A\u7701\u53EA\u4F5C\u7528\u4E8E\u9ED8\u8BA4\u6839\uFF08${path41.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
12826
- \u6CE8\u610F\uFF1A\u9879\u76EE\u7EA7\u914D\u7F6E\uFF08.deepseeker-code/\uFF09\u4EC5\u5728\u9ED8\u8BA4\u6839 ${path41.basename(activeReal) || activeReal} \u751F\u6548\u3002`;
12909
+ \u2605 \u8DEF\u5F84\u951A\u5B9A\u94C1\u5F8B\uFF1A\u5DE5\u5177\u7F3A\u7701\u53EA\u4F5C\u7528\u4E8E\u9ED8\u8BA4\u6839\uFF08${path42.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
12910
+ \u6CE8\u610F\uFF1A\u9879\u76EE\u7EA7\u914D\u7F6E\uFF08.deepseeker-code/\uFF09\u4EC5\u5728\u9ED8\u8BA4\u6839 ${path42.basename(activeReal) || activeReal} \u751F\u6548\u3002`;
12827
12911
  }
12828
12912
  const osName = process.platform === "win32" ? "Windows" : process.platform === "darwin" ? "macOS" : "Linux";
12829
12913
  const now = /* @__PURE__ */ new Date();
@@ -12840,6 +12924,7 @@ ${lines.join("\n")}
12840
12924
  \u3010\u73AF\u5883\u3011
12841
12925
  ${envLines.join("\n")}`;
12842
12926
  let replyText = "";
12927
+ await ensureVisionCacheLoaded();
12843
12928
  const { wire: userContent, archive: archiveContent } = toIngestContents(inbound.content, inbound.attachments, opts?.model);
12844
12929
  try {
12845
12930
  const fullMessages = await buildContextMessages(
@@ -12927,7 +13012,7 @@ ${envLines.join("\n")}`;
12927
13012
  });
12928
13013
 
12929
13014
  // ../core/src/session/fork.ts
12930
- import fs40 from "fs/promises";
13015
+ import fs41 from "fs/promises";
12931
13016
  var listForkAnchors, derivePrefix, forkSession;
12932
13017
  var init_fork = __esm({
12933
13018
  "../core/src/session/fork.ts"() {
@@ -13000,7 +13085,7 @@ var init_fork = __esm({
13000
13085
  const prefix = derivePrefix(lines, upToLineId);
13001
13086
  const newId = createUUID();
13002
13087
  await ensureSessionsDir(newId);
13003
- const rawText = await fs40.readFile(getTranscriptPath(sourceId), "utf-8");
13088
+ const rawText = await fs41.readFile(getTranscriptPath(sourceId), "utf-8");
13004
13089
  const kept = [];
13005
13090
  let good = 0;
13006
13091
  for (const s of rawText.split("\n")) {
@@ -13016,7 +13101,7 @@ var init_fork = __esm({
13016
13101
  }
13017
13102
  let payload = kept.join("\n");
13018
13103
  if (payload.length > 0 && !payload.endsWith("\n")) payload += "\n";
13019
- await fs40.writeFile(getTranscriptPath(newId), payload, "utf-8");
13104
+ await fs41.writeFile(getTranscriptPath(newId), payload, "utf-8");
13020
13105
  const srcState = await readStore(sourceId);
13021
13106
  const srcRolling = await getRollingState(sourceId);
13022
13107
  const legacy = !lines.some(isEventLine);
@@ -13558,6 +13643,9 @@ var init_useChatState = __esm({
13558
13643
  }
13559
13644
  break;
13560
13645
  }
13646
+ case "vision.downgraded":
13647
+ pushInfo(`\u{1F5BC} \u6A21\u578B ${String(obj.model ?? "")} \u4E0D\u652F\u6301\u56FE\u7247\uFF0C\u5DF2\u81EA\u52A8\u964D\u7EA7\u4E3A\u6587\u672C\u5904\u7406\uFF08\u5DF2\u8BB0\u4F4F\uFF0C\u540E\u7EED\u6D88\u606F\u76F4\u63A5\u6309\u6587\u672C\u53D1\u9001\uFF09`);
13648
+ break;
13561
13649
  default:
13562
13650
  break;
13563
13651
  }
@@ -13811,9 +13899,9 @@ ${r.output.trim() || "(\u65E0\u8F93\u51FA)"}`);
13811
13899
  modelRef.current = m;
13812
13900
  void writePrefs({ model: m });
13813
13901
  }, []);
13814
- const resolveModel = useCallback((model2) => {
13902
+ const resolveModel = useCallback((model) => {
13815
13903
  setPendingModel((prev) => {
13816
- prev?.resolve(model2);
13904
+ prev?.resolve(model);
13817
13905
  return null;
13818
13906
  });
13819
13907
  }, []);
@@ -13823,6 +13911,7 @@ ${r.output.trim() || "(\u65E0\u8F93\u51FA)"}`);
13823
13911
  setModelOverride(picked);
13824
13912
  pushInfo(S.modelSwitched(picked));
13825
13913
  }
13914
+ return picked;
13826
13915
  }, [pushInfo, setModelOverride]);
13827
13916
  const setPlanMode = useCallback((on) => {
13828
13917
  planModeRef.current = on;
@@ -14865,11 +14954,11 @@ var init_StatusStrip = __esm({
14865
14954
  "use strict";
14866
14955
  init_theme();
14867
14956
  init_strings();
14868
- StatusStrip = ({ model: model2, busy, aborting, planMode, autoMode, sessionShort, customLine }) => {
14957
+ StatusStrip = ({ model, busy, aborting, planMode, autoMode, sessionShort, customLine }) => {
14869
14958
  const stateText = aborting ? S.statusAborting : busy ? S.statusStreaming : S.statusIdle;
14870
14959
  const stateColor = busy ? THEME.coralBright : THEME.gray;
14871
14960
  const bits = [
14872
- model2 ? `model: ${model2}` : "",
14961
+ model ? `model: ${model}` : "",
14873
14962
  planMode ? S.statusPlan : "",
14874
14963
  autoMode ? S.statusAuto : "",
14875
14964
  `state: ${stateText}`,
@@ -14945,7 +15034,7 @@ var init_TopPanel = __esm({
14945
15034
  });
14946
15035
 
14947
15036
  // ../core/src/observability/inspect.ts
14948
- import fs41 from "fs";
15037
+ import fs42 from "fs";
14949
15038
  var CWD, fmt, readTrace, inspectUsage, inspectContext, inspectPermissions, inspectMcp, inspectHooks, inspectDebug;
14950
15039
  var init_inspect = __esm({
14951
15040
  "../core/src/observability/inspect.ts"() {
@@ -14963,7 +15052,7 @@ var init_inspect = __esm({
14963
15052
  if (!sessionId) return [];
14964
15053
  try {
14965
15054
  const p = await getTraceStorePath(sessionId);
14966
- const text = await fs41.promises.readFile(p, "utf8");
15055
+ const text = await fs42.promises.readFile(p, "utf8");
14967
15056
  const out = [];
14968
15057
  for (const line of text.split("\n")) {
14969
15058
  if (!line.trim()) continue;
@@ -15088,7 +15177,7 @@ __export(App_exports, {
15088
15177
  import { useCallback as useCallback2, useEffect as useEffect4, useMemo, useRef as useRef2, useState as useState4 } from "react";
15089
15178
  import { Box as Box16, Static, Text as Text18, useApp, useInput as useInput2, useStdout } from "ink";
15090
15179
  import { Fragment as Fragment3, jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
15091
- var CWD2, RowView, isDynamicRow, App;
15180
+ var CWD2, RowView, isDynamicRow, SPINNER_FRAMES, App;
15092
15181
  var init_App = __esm({
15093
15182
  "src/App.tsx"() {
15094
15183
  "use strict";
@@ -15133,6 +15222,7 @@ var init_App = __esm({
15133
15222
  return /* @__PURE__ */ jsx18(MessageBlock, { row, wrapW, streamTail });
15134
15223
  };
15135
15224
  isDynamicRow = (r) => r.kind === "assistant" && !!r.streaming || r.kind === "thinking" && !!r.streaming || r.kind === "tool" && r.status === "running" || r.kind === "todos" && !!r.active;
15225
+ SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
15136
15226
  App = ({ resumeSessionId, initialPlanMode, initialAutoMode, initialIncludeProject, engineReady }) => {
15137
15227
  const state = useChatState(resumeSessionId, initialPlanMode, initialAutoMode);
15138
15228
  const { exit } = useApp();
@@ -15286,6 +15376,24 @@ var init_App = __esm({
15286
15376
  return menuEntries.filter((c) => c.name.toLowerCase().startsWith(q));
15287
15377
  }, [input, menuEntries]);
15288
15378
  const menuActive = state.pendingApproval != null || state.pendingQuestion != null || state.pendingPlan != null || state.pendingSessions != null || state.pendingFork != null || state.pendingModel != null;
15379
+ const [busyClock, setBusyClock] = useState4({ frame: 0, sec: 0 });
15380
+ const busyStartRef = useRef2(0);
15381
+ useEffect4(() => {
15382
+ if (!state.busy) {
15383
+ busyStartRef.current = 0;
15384
+ setBusyClock((c) => c.frame === 0 && c.sec === 0 ? c : { frame: 0, sec: 0 });
15385
+ return;
15386
+ }
15387
+ if (busyStartRef.current === 0) busyStartRef.current = Date.now();
15388
+ if (menuActive) return;
15389
+ const drive = () => setBusyClock({
15390
+ frame: Math.floor(Date.now() / 120) % SPINNER_FRAMES.length,
15391
+ sec: Math.floor((Date.now() - busyStartRef.current) / 1e3)
15392
+ });
15393
+ drive();
15394
+ const t = setInterval(drive, 120);
15395
+ return () => clearInterval(t);
15396
+ }, [state.busy, menuActive]);
15289
15397
  const slashVisible = !menuActive && input.startsWith("/") && filteredCommands.length > 0;
15290
15398
  const inputActive = !menuActive;
15291
15399
  useEffect4(() => {
@@ -15386,7 +15494,9 @@ ${list}
15386
15494
  state.pushInfo(S.modelSwitched(arg));
15387
15495
  return true;
15388
15496
  case "/switch":
15389
- void state.openModelPicker();
15497
+ void state.openModelPicker().then((picked) => {
15498
+ if (picked) setModelDisplay(picked);
15499
+ });
15390
15500
  return true;
15391
15501
  case "/thinking": {
15392
15502
  const lvl = arg.toLowerCase();
@@ -15632,10 +15742,7 @@ ${listText}`);
15632
15742
  /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", width: cols, children: [
15633
15743
  menuActive ? null : /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", paddingX: 1, children: [
15634
15744
  dynamicRows.map((row) => /* @__PURE__ */ jsx18(RowView, { row, wrapW, streamTail, showThinking: state.showThinkingText }, row.id)),
15635
- state.busy ? /* @__PURE__ */ jsx18(Box16, { marginTop: 0.5, children: /* @__PURE__ */ jsxs16(Text18, { color: THEME.coralBright, children: [
15636
- "\u25CF ",
15637
- S.generating
15638
- ] }) }) : null
15745
+ state.busy ? /* @__PURE__ */ jsx18(Box16, { marginTop: 0.5, children: /* @__PURE__ */ jsx18(Text18, { color: THEME.coralBright, children: `${SPINNER_FRAMES[busyClock.frame]} ${S.generating} (${busyClock.sec}s \xB7 ${S.escInterrupt})` }) }) : null
15639
15746
  ] }),
15640
15747
  /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", paddingX: 1, flexShrink: 0, children: [
15641
15748
  state.pendingApproval ? /* @__PURE__ */ jsx18(ApprovalModal, { toolName: state.pendingApproval.toolName, detail: state.pendingApproval.detail, selectedIndex: selectIdx, wrapW }) : null,
@@ -15756,7 +15863,7 @@ init_updateCheck();
15756
15863
  init_trust();
15757
15864
  import { render } from "ink";
15758
15865
  import os5 from "os";
15759
- import path42 from "path";
15866
+ import path43 from "path";
15760
15867
  import { emitKeypressEvents } from "node:readline";
15761
15868
  import { jsx as jsx19 } from "react/jsx-runtime";
15762
15869
  var parseArgs = (argv) => {
@@ -15889,7 +15996,7 @@ var main = async () => {
15889
15996
  process.stdout.write("\x1B[2J\x1B[3J\x1B[1;1H");
15890
15997
  const cwdIsHome = () => {
15891
15998
  try {
15892
- return path42.resolve(cwd).toLowerCase() === path42.resolve(os5.homedir()).toLowerCase();
15999
+ return path43.resolve(cwd).toLowerCase() === path43.resolve(os5.homedir()).toLowerCase();
15893
16000
  } catch {
15894
16001
  return false;
15895
16002
  }