deepseeker-code 1.0.4 → 1.0.42

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 +1 -1
  2. package/dist/cli.mjs +805 -480
  3. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -9,12 +9,88 @@ var __export = (target, all) => {
9
9
  __defProp(target, name, { get: all[name], enumerable: true });
10
10
  };
11
11
 
12
+ // src/updateCheck.ts
13
+ var updateCheck_exports = {};
14
+ __export(updateCheck_exports, {
15
+ getCachedLatestIfNewer: () => getCachedLatestIfNewer,
16
+ readLocalVersion: () => readLocalVersion,
17
+ refreshUpdateCache: () => refreshUpdateCache
18
+ });
19
+ import { readFileSync as readFileSync2, writeFileSync, mkdirSync } from "node:fs";
20
+ import path2 from "node:path";
21
+ import os2 from "os";
22
+ import { fileURLToPath } from "node:url";
23
+ var PKG_NAME, REGISTRY, CACHE_TTL_MS, FETCH_TIMEOUT_MS, cacheFile, readLocalVersion, parseSemver, compareVersion, readCache, writeCache, getCachedLatestIfNewer, refreshUpdateCache;
24
+ var init_updateCheck = __esm({
25
+ "src/updateCheck.ts"() {
26
+ "use strict";
27
+ PKG_NAME = "deepseeker-code";
28
+ REGISTRY = "https://registry.npmjs.org";
29
+ CACHE_TTL_MS = 6 * 60 * 60 * 1e3;
30
+ FETCH_TIMEOUT_MS = 3e3;
31
+ cacheFile = () => path2.join(os2.homedir(), ".deepseeker-code", "update-check.json");
32
+ readLocalVersion = () => {
33
+ try {
34
+ const here = path2.dirname(fileURLToPath(import.meta.url));
35
+ return JSON.parse(readFileSync2(path2.join(here, "..", "package.json"), "utf8")).version ?? "0.0.0";
36
+ } catch {
37
+ return "0.0.0";
38
+ }
39
+ };
40
+ parseSemver = (v) => {
41
+ const m = String(v ?? "").match(/^(\d+)\.(\d+)\.(\d+)/);
42
+ return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : [0, 0, 0];
43
+ };
44
+ compareVersion = (a, b) => {
45
+ const [a1, a2, a3] = parseSemver(a);
46
+ const [b1, b2, b3] = parseSemver(b);
47
+ return a1 - b1 || a2 - b2 || a3 - b3;
48
+ };
49
+ readCache = () => {
50
+ try {
51
+ const obj = JSON.parse(readFileSync2(cacheFile(), "utf8"));
52
+ return typeof obj.latestVersion === "string" && typeof obj.lastCheck === "number" ? obj : null;
53
+ } catch {
54
+ return null;
55
+ }
56
+ };
57
+ writeCache = (latestVersion) => {
58
+ try {
59
+ mkdirSync(path2.dirname(cacheFile()), { recursive: true });
60
+ writeFileSync(cacheFile(), JSON.stringify({ lastCheck: Date.now(), latestVersion }), "utf8");
61
+ } catch {
62
+ }
63
+ };
64
+ getCachedLatestIfNewer = (currentVersion) => {
65
+ const cache = readCache();
66
+ if (!cache) return null;
67
+ return compareVersion(cache.latestVersion, currentVersion) > 0 ? cache.latestVersion : null;
68
+ };
69
+ refreshUpdateCache = () => {
70
+ const cache = readCache();
71
+ if (cache && Date.now() - cache.lastCheck < CACHE_TTL_MS) return;
72
+ void (async () => {
73
+ try {
74
+ const res = await fetch(`${REGISTRY}/${PKG_NAME}/latest`, {
75
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
76
+ });
77
+ if (!res.ok) return;
78
+ const info = await res.json();
79
+ if (info.version) writeCache(info.version);
80
+ } catch {
81
+ }
82
+ })();
83
+ };
84
+ }
85
+ });
86
+
12
87
  // src/strings.ts
13
88
  var VERSION, STRINGS, locale, getLocale, setLocale, S, LOCAL_COMMAND_NAMES;
14
89
  var init_strings = __esm({
15
90
  "src/strings.ts"() {
16
91
  "use strict";
17
- VERSION = "v1.0.0";
92
+ init_updateCheck();
93
+ VERSION = `v${readLocalVersion()}`;
18
94
  STRINGS = {
19
95
  zh: {
20
96
  brand: "DeepSeeker-Code",
@@ -34,17 +110,19 @@ var init_strings = __esm({
34
110
  toolRunning: (name) => `\u23FA ${name} \u8FD0\u884C\u4E2D\u2026`,
35
111
  toolDone: (name, ok) => `\u23FA ${name} \xB7 ${ok ? "\u6210\u529F" : "\u5931\u8D25"}`,
36
112
  toolDenied: (name) => `\u{1F6AB} ${name} \u5DF2\u88AB\u62D2\u7EDD`,
37
- planTitle: "\u2705 \u5B9E\u73B0\u65B9\u6848\uFF08\u8BA1\u5212\u6A21\u5F0F\uFF09",
38
- planPrompt: "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u786E\u8BA4\uFF08\u4FEE\u6539\u9879\u8FDB\u5165\u7F16\u8F91\uFF0CEnter \u63D0\u4EA4 / Esc \u53D6\u6D88\uFF09\u3002",
39
- planAcceptAuto: "\u63A5\u53D7\u5E76\u81EA\u52A8\u6267\u884C\uFF08\u5B9E\u73B0\u9636\u6BB5\u514D\u5BA1\u6279\uFF09",
40
- planAcceptManual: "\u63A5\u53D7\u5E76\u624B\u52A8\u6267\u884C\uFF08\u9010\u6B65\u5BA1\u6279\u6BCF\u4E2A\u5DE5\u5177\uFF09",
41
- planEdit: "\u4FEE\u6539\u65B9\u6848",
42
- planReject: "\u62D2\u7EDD\uFF0C\u56DE\u5230\u8F93\u5165\u6846",
113
+ planTitle: "\u51C6\u5907\u5F00\u59CB\u7F16\u7801\uFF1F",
114
+ planPrompt: "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u786E\u8BA4\uFF08\u7F16\u8F91\u9879\u8FDB\u5165\u7F16\u8F91\u5668\uFF0CEnter \u63D0\u4EA4 / Esc \u53D6\u6D88\uFF09\u3002",
115
+ planAcceptAuto: "\u662F\uFF0C\u5E76\u81EA\u52A8\u63A5\u53D7\u7F16\u8F91\uFF08\u5B9E\u73B0\u9636\u6BB5\u514D\u5BA1\u6279\uFF09",
116
+ planAcceptManual: "\u662F\uFF0C\u5E76\u624B\u52A8\u5BA1\u6279\u7F16\u8F91\uFF08\u9010\u6B65\u5BA1\u6279\u6BCF\u4E2A\u5DE5\u5177\uFF09",
117
+ planEdit: "\u7F16\u8F91\u65B9\u6848",
118
+ planReject: "\u5426\uFF0C\u7EE7\u7EED\u89C4\u5212",
43
119
  planEditTitle: "\u270F\uFE0F \u7F16\u8F91\u65B9\u6848",
44
120
  planEditHint: "Enter \u6309\u6B64\u65B9\u6848\u6267\u884C \xB7 Esc \u53D6\u6D88\u56DE\u5230\u9009\u9879",
45
- planRejected: "\u270B \u5DF2\u62D2\u7EDD\u65B9\u6848\uFF0C\u672C\u8F6E\u672A\u6267\u884C\u3002",
121
+ planKeepPlanning: "\u270B \u5DF2\u7559\u5728\u8BA1\u5212\u6A21\u5F0F\uFF1A\u7EE7\u7EED\u8F93\u5165\u8865\u5145\u8981\u6C42\uFF0C\u6A21\u578B\u5C06\u4FEE\u8BA2\u65B9\u6848\u540E\u518D\u6B21\u63D0\u4EA4\uFF08/plan \u53EF\u9000\u51FA\uFF09\u3002",
46
122
  planEditEmpty: "\u65B9\u6848\u4E0D\u80FD\u4E3A\u7A7A",
47
123
  planAutoExecute: "\u26A1 \u5DF2\u8FDB\u5165\u81EA\u52A8\u6267\u884C\uFF1A\u5B9E\u73B0\u9636\u6BB5\u5DE5\u5177\u5C06\u514D\u5BA1\u6279\u76F4\u63A5\u8FD0\u884C\u3002",
124
+ inputBadgePlan: "plan mode on\uFF08\u53EA\u8BFB\u8C03\u7814 \u2192 \u65B9\u6848\u5BA1\u6279 \u2192 \u5B9E\u73B0\uFF09",
125
+ inputBadgeAuto: "auto-accept edits on",
48
126
  approvalTitle: "\u{1F510} \u64CD\u4F5C\u5BA1\u6279",
49
127
  approvalPrompt: "\u2191\u2193 \u9009\u62E9\u540E Enter\uFF08Esc \u62D2\u7EDD\uFF09\uFF1A\u5141\u8BB8\u672C\u6B21 / \u603B\u662F\u5141\u8BB8\uFF08\u5199\u6301\u4E45\u89C4\u5219\uFF09/ \u62D2\u7EDD\u3002",
50
128
  approvalAllow: "\u5141\u8BB8\u672C\u6B21",
@@ -172,17 +250,19 @@ DeepSeeker-Code \u5C06\u5728\u6B64\u76EE\u5F55\u8BFB\u53D6\u3001\u7F16\u8F91\u54
172
250
  toolRunning: (name) => `\u23FA ${name} running\u2026`,
173
251
  toolDone: (name, ok) => `\u23FA ${name} \xB7 ${ok ? "ok" : "failed"}`,
174
252
  toolDenied: (name) => `\u{1F6AB} ${name} denied`,
175
- planTitle: "\u2705 Implementation plan (plan mode)",
253
+ planTitle: "Ready to code?",
176
254
  planPrompt: "\u2191\u2193 then Enter (edit opens the editor: Enter to save / Esc to cancel).",
177
- planAcceptAuto: "Accept & auto-run (skip impl approvals)",
178
- planAcceptManual: "Accept & step-by-step (approve each tool)",
255
+ planAcceptAuto: "Yes, and auto-accept edits (skip impl approvals)",
256
+ planAcceptManual: "Yes, and manually approve edits (step-by-step)",
179
257
  planEdit: "Edit plan",
180
- planReject: "Reject, back to prompt",
258
+ planReject: "No, keep planning",
181
259
  planEditTitle: "\u270F\uFE0F Edit plan",
182
260
  planEditHint: "Enter to implement with this plan \xB7 Esc back to options",
183
- planRejected: "\u270B Plan rejected, nothing executed this turn.",
261
+ planKeepPlanning: "\u270B Staying in plan mode: add feedback and the plan will be revised and resubmitted (/plan to exit).",
184
262
  planEditEmpty: "Plan cannot be empty",
185
263
  planAutoExecute: "\u26A1 Auto-run: implementation tools will execute without approval.",
264
+ inputBadgePlan: "plan mode on (read-only research \u2192 approve \u2192 implement)",
265
+ inputBadgeAuto: "auto-accept edits on",
186
266
  approvalTitle: "\u{1F510} Action approval",
187
267
  approvalPrompt: "\u2191\u2193 then Enter (Esc to deny): allow once / always allow (persist rule) / deny.",
188
268
  approvalAllow: "Allow once",
@@ -313,15 +393,15 @@ __export(config_exports, {
313
393
  appConfig: () => appConfig,
314
394
  configSources: () => configSources
315
395
  });
316
- import path2 from "path";
317
- import os2 from "os";
318
- import { readFileSync as readFileSync2 } from "fs";
396
+ import path3 from "path";
397
+ import os3 from "os";
398
+ import { readFileSync as readFileSync3 } from "fs";
319
399
  import { createHash } from "crypto";
320
400
  var _DataDir, appConfig, ENV_SOURCES, configSources, ENGINE_OVERRIDE_VALIDATORS, ENGINE_OVERRIDE_KEYS, applyEngineOverrides;
321
401
  var init_config = __esm({
322
402
  "../core/src/config/index.ts"() {
323
403
  "use strict";
324
- _DataDir = process.env.DEEPSEEKER_CODE_DATA_DIR ? path2.resolve(process.env.DEEPSEEKER_CODE_DATA_DIR) : path2.join(os2.homedir(), ".deepseeker-code");
404
+ _DataDir = process.env.DEEPSEEKER_CODE_DATA_DIR ? path3.resolve(process.env.DEEPSEEKER_CODE_DATA_DIR) : path3.join(os3.homedir(), ".deepseeker-code");
325
405
  appConfig = {
326
406
  dataDir: _DataDir,
327
407
  maxReasoningRounds: 3,
@@ -348,8 +428,8 @@ var init_config = __esm({
348
428
  if (/^[a-z]:/i.test(cwd)) {
349
429
  cwd = cwd.charAt(0).toUpperCase() + cwd.slice(1);
350
430
  }
351
- const currentFolder = path2.basename(cwd);
352
- const parentFolder = path2.basename(path2.dirname(cwd));
431
+ const currentFolder = path3.basename(cwd);
432
+ const parentFolder = path3.basename(path3.dirname(cwd));
353
433
  const hash = createHash("sha256").update(cwd).digest("hex").slice(0, 8);
354
434
  return `${parentFolder}-${currentFolder}-${hash}`;
355
435
  })(),
@@ -447,15 +527,15 @@ var init_config = __esm({
447
527
  ENGINE_OVERRIDE_KEYS = Object.keys(ENGINE_OVERRIDE_VALIDATORS);
448
528
  applyEngineOverrides = (cfg) => {
449
529
  const paths = [
450
- { scope: "settings.global", configPath: path2.join(cfg.dataDir, "settings.json") },
530
+ { scope: "settings.global", configPath: path3.join(cfg.dataDir, "settings.json") },
451
531
  // 全局用户级
452
- { scope: "settings.project", configPath: path2.join(process.cwd(), ".deepseeker-code", "settings.json") }
532
+ { scope: "settings.project", configPath: path3.join(process.cwd(), ".deepseeker-code", "settings.json") }
453
533
  // 项目级(覆盖全局)
454
534
  ];
455
535
  for (const { scope, configPath } of paths) {
456
536
  let raw;
457
537
  try {
458
- raw = readFileSync2(configPath, "utf-8");
538
+ raw = readFileSync3(configPath, "utf-8");
459
539
  } catch {
460
540
  continue;
461
541
  }
@@ -592,7 +672,7 @@ ${body}`) return;
592
672
  });
593
673
 
594
674
  // src/prefs.ts
595
- import path3 from "path";
675
+ import path4 from "path";
596
676
  import fs2 from "fs/promises";
597
677
  var PREFS_FILE, readPrefs, readLocale, writePrefs, writeLocale;
598
678
  var init_prefs = __esm({
@@ -600,7 +680,7 @@ var init_prefs = __esm({
600
680
  "use strict";
601
681
  init_config();
602
682
  init_common();
603
- PREFS_FILE = path3.join(appConfig.dataDir, "prefs.json");
683
+ PREFS_FILE = path4.join(appConfig.dataDir, "prefs.json");
604
684
  readPrefs = async () => {
605
685
  const p = await readJSONFile(PREFS_FILE);
606
686
  return p && typeof p === "object" ? p : {};
@@ -621,7 +701,7 @@ var init_prefs = __esm({
621
701
  });
622
702
 
623
703
  // ../core/src/trust/index.ts
624
- import path4 from "path";
704
+ import path5 from "path";
625
705
  import fs3 from "fs/promises";
626
706
  var TRUSTED_FILE, normalizeDir, readTrustedDirs, isTrustedDir, trustDir, untrustDir;
627
707
  var init_trust = __esm({
@@ -629,9 +709,9 @@ var init_trust = __esm({
629
709
  "use strict";
630
710
  init_config();
631
711
  init_common();
632
- TRUSTED_FILE = path4.join(appConfig.dataDir, "trusted_dirs.json");
712
+ TRUSTED_FILE = path5.join(appConfig.dataDir, "trusted_dirs.json");
633
713
  normalizeDir = (dir) => {
634
- let d = path4.resolve(dir).replace(/\\/g, "/");
714
+ let d = path5.resolve(dir).replace(/\\/g, "/");
635
715
  if (/^[a-z]:/i.test(d)) d = d.charAt(0).toUpperCase() + d.slice(1);
636
716
  return d;
637
717
  };
@@ -974,7 +1054,7 @@ var init_replay = __esm({
974
1054
  });
975
1055
 
976
1056
  // ../core/src/llm/model.ts
977
- import { readFileSync as readFileSync3 } from "fs";
1057
+ import { readFileSync as readFileSync4 } from "fs";
978
1058
  var resolveInitialProvider, activeProvider, chatWithModelWithSummary, classifyToolRisk;
979
1059
  var init_model = __esm({
980
1060
  "../core/src/llm/model.ts"() {
@@ -989,7 +1069,7 @@ var init_model = __esm({
989
1069
  }
990
1070
  let raw;
991
1071
  try {
992
- raw = JSON.parse(readFileSync3(scriptPath, "utf-8"));
1072
+ raw = JSON.parse(readFileSync4(scriptPath, "utf-8"));
993
1073
  } catch (e) {
994
1074
  throw new Error(`\u56DE\u653E\u5267\u672C\u52A0\u8F7D\u5931\u8D25\uFF08${scriptPath}\uFF09: ${e?.message ?? e}`);
995
1075
  }
@@ -1109,7 +1189,7 @@ __export(store_exports, {
1109
1189
  writeStore: () => writeStore
1110
1190
  });
1111
1191
  import fs4 from "fs/promises";
1112
- import path5 from "path";
1192
+ import path6 from "path";
1113
1193
  async function getRollingState(sessionId) {
1114
1194
  const store = await readStore(sessionId);
1115
1195
  if (!store) {
@@ -1156,16 +1236,16 @@ var init_store = __esm({
1156
1236
  getSessionsDirPath = (mainSessionId) => {
1157
1237
  assertSafeSessionId(mainSessionId);
1158
1238
  const fileName = getFileName(mainSessionId);
1159
- return path5.join(appConfig.dataDir, "sessions", appConfig.userWorkspaceDir, fileName);
1239
+ return path6.join(appConfig.dataDir, "sessions", appConfig.userWorkspaceDir, fileName);
1160
1240
  };
1161
- getWorkspaceSessionsDir = () => path5.join(appConfig.dataDir, "sessions", appConfig.userWorkspaceDir);
1241
+ getWorkspaceSessionsDir = () => path6.join(appConfig.dataDir, "sessions", appConfig.userWorkspaceDir);
1162
1242
  getStatePath = (sessionId) => {
1163
1243
  assertSafeSessionId(sessionId);
1164
- return path5.join(getSessionsDirPath(sessionId), `${sessionId}.state.json`);
1244
+ return path6.join(getSessionsDirPath(sessionId), `${sessionId}.state.json`);
1165
1245
  };
1166
1246
  getTranscriptPath = (sessionId) => {
1167
1247
  assertSafeSessionId(sessionId);
1168
- return path5.join(getSessionsDirPath(sessionId), `${sessionId}.jsonl`);
1248
+ return path6.join(getSessionsDirPath(sessionId), `${sessionId}.jsonl`);
1169
1249
  };
1170
1250
  ensureSessionsDir = async (sessionId) => {
1171
1251
  await fs4.mkdir(getSessionsDirPath(sessionId), { recursive: true });
@@ -1175,7 +1255,7 @@ var init_store = __esm({
1175
1255
  migrateLegacyFiles = async (sessionId) => {
1176
1256
  assertSafeSessionId(sessionId);
1177
1257
  const dir = getSessionsDirPath(sessionId);
1178
- const legacy = path5.join(dir, `${sessionId}.json`);
1258
+ const legacy = path6.join(dir, `${sessionId}.json`);
1179
1259
  const transcriptPath = getTranscriptPath(sessionId);
1180
1260
  const statePath = getStatePath(sessionId);
1181
1261
  let legacyText;
@@ -1300,7 +1380,7 @@ var init_store = __esm({
1300
1380
  if (!entry.isDirectory()) continue;
1301
1381
  const sessionId = entry.name;
1302
1382
  if (!isSafeSessionId(sessionId)) continue;
1303
- const dirPath = path5.join(root, sessionId);
1383
+ const dirPath = path6.join(root, sessionId);
1304
1384
  const state = await readJSONFile(getStatePath(sessionId));
1305
1385
  let messageCount = 0;
1306
1386
  let preview = "";
@@ -1477,7 +1557,7 @@ var init_types = __esm({
1477
1557
 
1478
1558
  // ../core/src/hooks/shellExecutor.ts
1479
1559
  import { spawn } from "child_process";
1480
- import path6 from "path";
1560
+ import path7 from "path";
1481
1561
  var MAX_OUTPUT, DEFAULT_TIMEOUT_MS, HARD_TIMEOUT_CAP_MS, ENV_WHITELIST, truncate, MAX_STDIN_FIELD, capFieldStrings, extractFilePath, executeHookCommand;
1482
1562
  var init_shellExecutor = __esm({
1483
1563
  "../core/src/hooks/shellExecutor.ts"() {
@@ -1523,7 +1603,7 @@ var init_shellExecutor = __esm({
1523
1603
  if (typeof rel !== "string" || !rel.trim()) return void 0;
1524
1604
  const base = typeof p.cwd === "string" && p.cwd || process.env.WORKSPACE_ROOT || process.cwd();
1525
1605
  try {
1526
- return path6.resolve(base, rel);
1606
+ return path7.resolve(base, rel);
1527
1607
  } catch {
1528
1608
  return void 0;
1529
1609
  }
@@ -1728,7 +1808,7 @@ var init_hooks = __esm({
1728
1808
  });
1729
1809
 
1730
1810
  // ../core/src/agent/truncate.ts
1731
- import path7 from "path";
1811
+ import path8 from "path";
1732
1812
  function stripAnsi(text) {
1733
1813
  return text.replace(ANSI_ESCAPE, "");
1734
1814
  }
@@ -1767,10 +1847,10 @@ var init_truncate = __esm({
1767
1847
  if (!text) return text;
1768
1848
  const roots = /* @__PURE__ */ new Set();
1769
1849
  try {
1770
- roots.add(path7.resolve(appConfig.userWorkspaceDir));
1850
+ roots.add(path8.resolve(appConfig.userWorkspaceDir));
1771
1851
  for (const r of getFileAccessRoots()) {
1772
1852
  try {
1773
- roots.add(path7.resolve(r));
1853
+ roots.add(path8.resolve(r));
1774
1854
  } catch {
1775
1855
  }
1776
1856
  }
@@ -2037,7 +2117,7 @@ ${line}` : line;
2037
2117
 
2038
2118
  // ../core/src/tool/permissions.ts
2039
2119
  import fs6 from "fs/promises";
2040
- import path8 from "path";
2120
+ import path9 from "path";
2041
2121
  var PRIMARY_ARG, rules2, trustedProject, globCache, globToRegex, DANGER_COMMAND_TOOLS, compileRule, readPermissionConfig, toolNameMatches, ruleMatches, initPermissions, checkPermission, listPermissionRules, buildScopedAllowRule, resolveSettingsPath, addPermissionRule;
2042
2122
  var init_permissions = __esm({
2043
2123
  "../core/src/tool/permissions.ts"() {
@@ -2099,9 +2179,9 @@ var init_permissions = __esm({
2099
2179
  readPermissionConfig = async (includeProject) => {
2100
2180
  const merged = { allow: [], deny: [], ask: [] };
2101
2181
  const paths = [
2102
- path8.join(appConfig.dataDir, "settings.json"),
2182
+ path9.join(appConfig.dataDir, "settings.json"),
2103
2183
  // 全局用户级
2104
- ...includeProject ? [path8.join(process.cwd(), ".deepseeker-code", "settings.json")] : []
2184
+ ...includeProject ? [path9.join(process.cwd(), ".deepseeker-code", "settings.json")] : []
2105
2185
  // 项目级(叠加);未信任时省略
2106
2186
  ];
2107
2187
  for (const configPath of paths) {
@@ -2192,7 +2272,7 @@ var init_permissions = __esm({
2192
2272
  }
2193
2273
  return `${toolName}(${val})`;
2194
2274
  };
2195
- resolveSettingsPath = (scope) => scope === "global" ? path8.join(appConfig.dataDir, "settings.json") : path8.join(process.cwd(), ".deepseeker-code", "settings.json");
2275
+ resolveSettingsPath = (scope) => scope === "global" ? path9.join(appConfig.dataDir, "settings.json") : path9.join(process.cwd(), ".deepseeker-code", "settings.json");
2196
2276
  addPermissionRule = async (scope, kind, ruleStr) => {
2197
2277
  if (scope === "project" && !trustedProject) return false;
2198
2278
  const compiled = compileRule(ruleStr, `runtime:addPermissionRule(${scope})`, kind);
@@ -2204,7 +2284,7 @@ var init_permissions = __esm({
2204
2284
  const arr = Array.isArray(cfg.permissions[kind]) ? cfg.permissions[kind] : cfg.permissions[kind] = [];
2205
2285
  if (!arr.includes(ruleStr)) {
2206
2286
  arr.push(ruleStr);
2207
- await fs6.mkdir(path8.dirname(file), { recursive: true });
2287
+ await fs6.mkdir(path9.dirname(file), { recursive: true });
2208
2288
  await atomicWriteJSON(file, cfg);
2209
2289
  }
2210
2290
  if (!rules2[kind].some((r) => r.raw === compiled.raw)) rules2[kind].push(compiled);
@@ -2244,7 +2324,7 @@ var init_sessionRegistry = __esm({
2244
2324
  // ../core/src/tool/guard.ts
2245
2325
  import fs7 from "fs/promises";
2246
2326
  import fsSync from "fs";
2247
- import path9 from "path";
2327
+ import path10 from "path";
2248
2328
  import ignore from "ignore";
2249
2329
  import { AsyncLocalStorage } from "node:async_hooks";
2250
2330
  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;
@@ -2300,8 +2380,8 @@ var init_guard = __esm({
2300
2380
  getContainingRoot = (absPath) => {
2301
2381
  let best;
2302
2382
  for (const r of allowedBoundaryRoots()) {
2303
- const rel = path9.relative(r, absPath);
2304
- if (!rel.startsWith("..") && !path9.isAbsolute(rel)) {
2383
+ const rel = path10.relative(r, absPath);
2384
+ if (!rel.startsWith("..") && !path10.isAbsolute(rel)) {
2305
2385
  if (!best || r.length > best.length) best = r;
2306
2386
  }
2307
2387
  }
@@ -2318,16 +2398,16 @@ var init_guard = __esm({
2318
2398
  };
2319
2399
  resolveSafePath = (rel, base) => {
2320
2400
  const root = base ?? getActiveWorkspaceRoot();
2321
- const candidateAbsPath = path9.resolve(root, rel);
2401
+ const candidateAbsPath = path10.resolve(root, rel);
2322
2402
  let truePhysicalPath = candidateAbsPath;
2323
2403
  try {
2324
2404
  if (fsSync.existsSync(candidateAbsPath)) {
2325
2405
  truePhysicalPath = fsSync.realpathSync(candidateAbsPath);
2326
2406
  } else {
2327
- const parentDir = path9.dirname(candidateAbsPath);
2407
+ const parentDir = path10.dirname(candidateAbsPath);
2328
2408
  if (fsSync.existsSync(parentDir)) {
2329
2409
  const trueParentDir = fsSync.realpathSync(parentDir);
2330
- truePhysicalPath = path9.join(trueParentDir, path9.basename(candidateAbsPath));
2410
+ truePhysicalPath = path10.join(trueParentDir, path10.basename(candidateAbsPath));
2331
2411
  }
2332
2412
  }
2333
2413
  } catch (e) {
@@ -2341,8 +2421,8 @@ var init_guard = __esm({
2341
2421
  }
2342
2422
  })() : allowedBoundaryRoots();
2343
2423
  const escaped = boundaryRoots.every((r) => {
2344
- const rel0 = path9.relative(r, truePhysicalPath);
2345
- return rel0.startsWith("..") || path9.isAbsolute(rel0);
2424
+ const rel0 = path10.relative(r, truePhysicalPath);
2425
+ return rel0.startsWith("..") || path10.isAbsolute(rel0);
2346
2426
  });
2347
2427
  if (escaped) {
2348
2428
  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}`);
@@ -2351,12 +2431,12 @@ var init_guard = __esm({
2351
2431
  };
2352
2432
  resolveReadablePath = (rel) => {
2353
2433
  const root = getActiveWorkspaceRoot();
2354
- const absPath = path9.resolve(root, rel);
2434
+ const absPath = path10.resolve(root, rel);
2355
2435
  if (!fsSync.existsSync(absPath)) {
2356
- const rootName = path9.basename(root);
2436
+ const rootName = path10.basename(root);
2357
2437
  const firstSeg = rel.split(/[\\/]/)[0];
2358
2438
  if (rootName && firstSeg === rootName) {
2359
- const alt = path9.resolve(root, rel.slice(firstSeg.length + 1));
2439
+ const alt = path10.resolve(root, rel.slice(firstSeg.length + 1));
2360
2440
  if (fsSync.existsSync(alt)) return alt;
2361
2441
  }
2362
2442
  }
@@ -2369,9 +2449,9 @@ var init_guard = __esm({
2369
2449
  if (fsSync.existsSync(absPath)) {
2370
2450
  truePhysicalPath = fsSync.realpathSync(absPath);
2371
2451
  } else {
2372
- const parentDir = path9.dirname(absPath);
2452
+ const parentDir = path10.dirname(absPath);
2373
2453
  if (fsSync.existsSync(parentDir)) {
2374
- truePhysicalPath = path9.join(fsSync.realpathSync(parentDir), path9.basename(absPath));
2454
+ truePhysicalPath = path10.join(fsSync.realpathSync(parentDir), path10.basename(absPath));
2375
2455
  }
2376
2456
  }
2377
2457
  } catch (e) {
@@ -2385,8 +2465,8 @@ var init_guard = __esm({
2385
2465
  }
2386
2466
  })() : allowedBoundaryRoots();
2387
2467
  const escaped = boundaryRoots.every((r) => {
2388
- const rel0 = path9.relative(r, truePhysicalPath);
2389
- return rel0.startsWith("..") || path9.isAbsolute(rel0);
2468
+ const rel0 = path10.relative(r, truePhysicalPath);
2469
+ return rel0.startsWith("..") || path10.isAbsolute(rel0);
2390
2470
  });
2391
2471
  if (escaped) {
2392
2472
  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}`);
@@ -2397,9 +2477,14 @@ var init_guard = __esm({
2397
2477
  SENSITIVE_ENV_PATTERN = /(KEY|TOKEN|SECRET|PASSWORD|PASSPHRASE|CREDENTIAL|PRIVATE|AUTH)/i;
2398
2478
  scrubCommandEnv = (env = process.env) => {
2399
2479
  const next = {};
2480
+ const GIT_CONFIG_MEMBER = /^GIT_CONFIG_(KEY|VALUE)_\d+$/;
2481
+ const gitConfigFamilyHit = Object.keys(env).some(
2482
+ (k) => GIT_CONFIG_MEMBER.test(k) && (COMMAND_ENV_DENYLIST.includes(k) || SENSITIVE_ENV_PATTERN.test(k))
2483
+ );
2400
2484
  for (const [k, v] of Object.entries(env)) {
2401
2485
  if (COMMAND_ENV_DENYLIST.includes(k)) continue;
2402
2486
  if (SENSITIVE_ENV_PATTERN.test(k)) continue;
2487
+ if (gitConfigFamilyHit && (k === "GIT_CONFIG_COUNT" || GIT_CONFIG_MEMBER.test(k))) continue;
2403
2488
  next[k] = v;
2404
2489
  }
2405
2490
  return next;
@@ -2408,7 +2493,7 @@ var init_guard = __esm({
2408
2493
  if (!relOrAbs) return false;
2409
2494
  try {
2410
2495
  const base = cwd || process.env.WORKSPACE_ROOT || process.cwd();
2411
- const abs = path9.isAbsolute(relOrAbs) ? relOrAbs : path9.resolve(base, relOrAbs);
2496
+ const abs = path10.isAbsolute(relOrAbs) ? relOrAbs : path10.resolve(base, relOrAbs);
2412
2497
  const lower = abs.replace(/\\/g, "/").toLowerCase();
2413
2498
  return PROTECTED_WRITE_DIRS.some((d) => {
2414
2499
  const seg = ("/" + d).toLowerCase();
@@ -2423,9 +2508,9 @@ var init_guard = __esm({
2423
2508
  const entries = await fs7.readdir(dirPath, { withFileTypes: true });
2424
2509
  for (const entry of entries) {
2425
2510
  if (entry.isFile() && (entry.name === ".gitignore" || entry.name === ".agentignore")) {
2426
- const fullPath = path9.join(dirPath, entry.name);
2511
+ const fullPath = path10.join(dirPath, entry.name);
2427
2512
  const content = await fs7.readFile(fullPath, "utf-8");
2428
- const relDir = path9.relative(base, dirPath).replace(/\\/g, "/");
2513
+ const relDir = path10.relative(base, dirPath).replace(/\\/g, "/");
2429
2514
  const rules3 = content.split(/\r?\n/).map((line) => {
2430
2515
  const trimmed = line.trim();
2431
2516
  if (!trimmed || trimmed.startsWith("#")) return "";
@@ -2436,7 +2521,7 @@ var init_guard = __esm({
2436
2521
  }
2437
2522
  for (const entry of entries) {
2438
2523
  if (entry.isDirectory() && entry.name !== "node_modules" && entry.name !== ".git") {
2439
- await scanIgnoreFilesRecursive(path9.join(dirPath, entry.name), base, engine);
2524
+ await scanIgnoreFilesRecursive(path10.join(dirPath, entry.name), base, engine);
2440
2525
  }
2441
2526
  }
2442
2527
  } catch {
@@ -2507,7 +2592,7 @@ var init_guard = __esm({
2507
2592
  // ../core/src/tool/registry/background.ts
2508
2593
  import { spawn as spawn2, execFileSync } from "child_process";
2509
2594
  import fsSync2 from "fs";
2510
- import path10 from "path";
2595
+ import path11 from "path";
2511
2596
  function appendOutput(task, chunk) {
2512
2597
  task.outputBuffer += chunk;
2513
2598
  if (task.outputBuffer.length > MAX_BUFFER_CHARS) {
@@ -2532,7 +2617,7 @@ async function killTree(proc) {
2532
2617
  }
2533
2618
  }
2534
2619
  async function killBackgroundTasksUnder(dirPath) {
2535
- const norm = (p) => path10.resolve(p).replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
2620
+ const norm = (p) => path11.resolve(p).replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
2536
2621
  const target = norm(dirPath);
2537
2622
  let killed = 0;
2538
2623
  for (const task of registry.values()) {
@@ -2577,9 +2662,9 @@ var init_background = __esm({
2577
2662
  if (envShell && envShell.toLowerCase() !== "cmd") candidates.push(envShell);
2578
2663
  const gitExe = whereLines("git")[0];
2579
2664
  if (gitExe) {
2580
- const dir = path10.dirname(gitExe);
2581
- const root = path10.dirname(dir);
2582
- candidates.push(path10.join(root, "bin", "bash.exe"), path10.join(dir, "bash.exe"), path10.join(path10.dirname(root), "bin", "bash.exe"));
2665
+ const dir = path11.dirname(gitExe);
2666
+ const root = path11.dirname(dir);
2667
+ candidates.push(path11.join(root, "bin", "bash.exe"), path11.join(dir, "bash.exe"), path11.join(path11.dirname(root), "bin", "bash.exe"));
2583
2668
  }
2584
2669
  const bashHits = whereLines("bash").filter((p) => !/\\System32\\/i.test(p)).sort((a, b) => Number(/\\Git\\/i.test(b)) - Number(/\\Git\\/i.test(a)));
2585
2670
  candidates.push(...bashHits);
@@ -3322,13 +3407,13 @@ ${capped || JSON.stringify(result)}`;
3322
3407
 
3323
3408
  // ../core/src/tool/mcp/loader.ts
3324
3409
  import fs8 from "fs/promises";
3325
- import path11 from "path";
3410
+ import path12 from "path";
3326
3411
  import { homedir } from "os";
3327
3412
  function sanitize(s) {
3328
3413
  return s.replace(/[^a-zA-Z0-9_]/g, "_");
3329
3414
  }
3330
3415
  async function readMcpConfig() {
3331
- const configPath = process.env.MCP_CONFIG || path11.join(appConfig.dataDir, "mcp.json");
3416
+ const configPath = process.env.MCP_CONFIG || path12.join(appConfig.dataDir, "mcp.json");
3332
3417
  let raw;
3333
3418
  try {
3334
3419
  raw = await fs8.readFile(configPath, "utf-8");
@@ -3899,7 +3984,6 @@ var init_planMode = __esm({
3899
3984
  "../core/src/agent/planMode.ts"() {
3900
3985
  "use strict";
3901
3986
  PLAN_ALLOWED_TOOLS = /* @__PURE__ */ new Set([
3902
- "getTime",
3903
3987
  "read_file",
3904
3988
  "list_dir",
3905
3989
  "view_symbol_outline",
@@ -4104,7 +4188,7 @@ ${AGENT_USAGE_HINT}`);
4104
4188
 
4105
4189
  // ../core/src/projectGuide/loader.ts
4106
4190
  import fs10 from "fs/promises";
4107
- import path12 from "path";
4191
+ import path13 from "path";
4108
4192
  var CANDIDATES, MAX_GUIDE_BYTES, cached, initProjectGuide, getProjectGuide;
4109
4193
  var init_loader2 = __esm({
4110
4194
  "../core/src/projectGuide/loader.ts"() {
@@ -4121,7 +4205,7 @@ var init_loader2 = __esm({
4121
4205
  try {
4122
4206
  for (const name of CANDIDATES) {
4123
4207
  try {
4124
- const raw = await fs10.readFile(path12.join(WORKSPACE_ROOT, name), "utf-8");
4208
+ const raw = await fs10.readFile(path13.join(WORKSPACE_ROOT, name), "utf-8");
4125
4209
  const body = raw.length > MAX_GUIDE_BYTES ? raw.slice(0, MAX_GUIDE_BYTES) + `
4126
4210
 
4127
4211
  \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;
@@ -4293,36 +4377,6 @@ var init_systemInjections = __esm({
4293
4377
  }
4294
4378
  });
4295
4379
 
4296
- // ../core/src/tool/registry/system.ts
4297
- var systemTools;
4298
- var init_system = __esm({
4299
- "../core/src/tool/registry/system.ts"() {
4300
- "use strict";
4301
- init_type();
4302
- systemTools = [
4303
- {
4304
- type: "function",
4305
- function: {
4306
- name: "getTime",
4307
- description: "\u8FD4\u56DE\u5F53\u524D\u670D\u52A1\u5668\u7684\u65E5\u671F\u4E0E\u65F6\u95F4\uFF08\u672C\u5730\u65F6\u533A\uFF09",
4308
- parameters: {
4309
- type: "object",
4310
- properties: {
4311
- // Q-7:location 改为可选——旧版 required 却完全不消费,迫使模型填无意义城市名。
4312
- location: { type: "string", description: "\u57CE\u5E02\u540D\u79F0\uFF08\u53EF\u9009\uFF0C\u4EC5\u4F5C\u8BB0\u5F55\uFF1B\u670D\u52A1\u5668\u59CB\u7EC8\u8FD4\u56DE\u5176\u672C\u5730\u65F6\u95F4\uFF09" }
4313
- }
4314
- },
4315
- safetyLevel: "safe" /* SAFE */,
4316
- isSync: true,
4317
- async execute() {
4318
- return (/* @__PURE__ */ new Date()).toLocaleString("zh-CN", { dateStyle: "medium", timeStyle: "medium" });
4319
- }
4320
- }
4321
- }
4322
- ];
4323
- }
4324
- });
4325
-
4326
4380
  // ../core/src/tool/registry/agent.ts
4327
4381
  var createAgentTools;
4328
4382
  var init_agent = __esm({
@@ -4371,8 +4425,8 @@ var init_agent = __esm({
4371
4425
  });
4372
4426
 
4373
4427
  // ../core/src/tool/worktree/manager.ts
4374
- import path13 from "path";
4375
- import os3 from "os";
4428
+ import path14 from "path";
4429
+ import os4 from "os";
4376
4430
  import fs11 from "fs";
4377
4431
  var runMainGit, worktreeRootDir, worktreeDir, isNotARepoError, createWorktree, harvestDiff, runInWorktree, removeWorktree, sweepOrphanedWorktrees, disposeAllSessionWorktrees;
4378
4432
  var init_manager = __esm({
@@ -4384,8 +4438,8 @@ var init_manager = __esm({
4384
4438
  init_background();
4385
4439
  init_sessionRegistry();
4386
4440
  runMainGit = (args, maxBuffer = 1024 * 1024 * 5) => execFileSmart("git", args, { cwd: WORKSPACE_ROOT, maxBuffer });
4387
- worktreeRootDir = () => path13.join(os3.tmpdir(), "deepseeker-code-worktrees", appConfig.userWorkspaceDir);
4388
- worktreeDir = (sessionId, stepId) => path13.join(worktreeRootDir(), sessionId, stepId);
4441
+ worktreeRootDir = () => path14.join(os4.tmpdir(), "deepseeker-code-worktrees", appConfig.userWorkspaceDir);
4442
+ worktreeDir = (sessionId, stepId) => path14.join(worktreeRootDir(), sessionId, stepId);
4389
4443
  isNotARepoError = (e) => {
4390
4444
  const text = `${e?.message || ""} ${e?.stderr || ""}`.toLowerCase();
4391
4445
  return text.includes("not a git repository");
@@ -4396,7 +4450,7 @@ var init_manager = __esm({
4396
4450
  const wtPath = worktreeDir(sessionId, stepId);
4397
4451
  const shortId = sessionId.replace(/[^A-Za-z0-9-]/g, "").slice(0, 8) || "x";
4398
4452
  const branch = `dsc-wt-${shortId}-${stepId}`;
4399
- await fs11.promises.mkdir(path13.dirname(wtPath), { recursive: true });
4453
+ await fs11.promises.mkdir(path14.dirname(wtPath), { recursive: true });
4400
4454
  try {
4401
4455
  await runMainGit(["worktree", "add", "-b", branch, wtPath, "HEAD"]);
4402
4456
  } catch (e) {
@@ -4472,7 +4526,7 @@ var init_manager = __esm({
4472
4526
  }
4473
4527
  let swept = 0;
4474
4528
  for (const sessionIdDir of entries) {
4475
- const sessionPath = path13.join(root, sessionIdDir);
4529
+ const sessionPath = path14.join(root, sessionIdDir);
4476
4530
  let stepDirs;
4477
4531
  try {
4478
4532
  stepDirs = await fs11.promises.readdir(sessionPath);
@@ -4480,7 +4534,7 @@ var init_manager = __esm({
4480
4534
  continue;
4481
4535
  }
4482
4536
  for (const stepDir of stepDirs) {
4483
- const wtPath = path13.join(sessionPath, stepDir);
4537
+ const wtPath = path14.join(sessionPath, stepDir);
4484
4538
  try {
4485
4539
  await runMainGit(["worktree", "remove", "--force", wtPath]);
4486
4540
  } catch {
@@ -4761,7 +4815,7 @@ var init_workflow = __esm({
4761
4815
 
4762
4816
  // ../core/src/tool/tsHost.ts
4763
4817
  import fsSync3 from "fs";
4764
- import path14 from "path";
4818
+ import path15 from "path";
4765
4819
  var _ts, _tsTried, getTs, buildDefaultOptions, findTsConfigBounded, resolveTsConfig, createProjectHost, lsCache, getLanguageService, realpathNative, posToLineCol, lineColToPos;
4766
4820
  var init_tsHost = __esm({
4767
4821
  "../core/src/tool/tsHost.ts"() {
@@ -4794,16 +4848,16 @@ var init_tsHost = __esm({
4794
4848
  strict: false
4795
4849
  });
4796
4850
  findTsConfigBounded = (ts, absPath) => {
4797
- const root = path14.resolve(getContainingRoot(absPath));
4798
- let dir = path14.dirname(absPath);
4851
+ const root = path15.resolve(getContainingRoot(absPath));
4852
+ let dir = path15.dirname(absPath);
4799
4853
  while (true) {
4800
- const candidate = path14.join(dir, "tsconfig.json");
4854
+ const candidate = path15.join(dir, "tsconfig.json");
4801
4855
  try {
4802
4856
  if (fsSync3.existsSync(candidate)) return candidate;
4803
4857
  } catch {
4804
4858
  }
4805
- if (path14.resolve(dir) === root) break;
4806
- const parent = path14.dirname(dir);
4859
+ if (path15.resolve(dir) === root) break;
4860
+ const parent = path15.dirname(dir);
4807
4861
  if (parent === dir) break;
4808
4862
  dir = parent;
4809
4863
  }
@@ -4814,7 +4868,7 @@ var init_tsHost = __esm({
4814
4868
  if (!tsConfigPath) {
4815
4869
  return { options: buildDefaultOptions(ts), fileNames: [], projectRoot: getContainingRoot(absPath) };
4816
4870
  }
4817
- const basePath = path14.dirname(tsConfigPath);
4871
+ const basePath = path15.dirname(tsConfigPath);
4818
4872
  const raw = ts.readConfigFile(tsConfigPath, ts.sys.readFile);
4819
4873
  if (raw.error) return { options: buildDefaultOptions(ts), fileNames: [], projectRoot: basePath };
4820
4874
  const parsed = ts.parseJsonConfigFileContent(raw.config, ts.sys, basePath);
@@ -4825,7 +4879,7 @@ var init_tsHost = __esm({
4825
4879
  const roots = /* @__PURE__ */ new Set();
4826
4880
  const caseSensitive = ts.sys.useCaseSensitiveFileNames;
4827
4881
  const canonical = (f) => caseSensitive ? f : f.toLowerCase();
4828
- const keyOf = (f) => canonical(path14.resolve(f)).replace(/\\/g, "/");
4882
+ const keyOf = (f) => canonical(path15.resolve(f)).replace(/\\/g, "/");
4829
4883
  rootFileNames.forEach((f) => roots.add(keyOf(f)));
4830
4884
  const fresh = (fileName) => {
4831
4885
  const key = keyOf(fileName);
@@ -4914,10 +4968,10 @@ var init_tsHost = __esm({
4914
4968
 
4915
4969
  // ../core/src/tool/registry/fs.ts
4916
4970
  import fs12 from "fs/promises";
4917
- import path15 from "path";
4971
+ import path16 from "path";
4918
4972
  import { createReadStream } from "fs";
4919
4973
  import * as readline from "readline";
4920
- var isSensitiveReadTarget, stripReadFileLineNumbers, maskSecretsInContent, makeTmpPath, ATOMIC_TMP_RE, sweepStaleAtomicTmp, assertReadable, stripEdgeBlankLines, matchLineBlockWith, diagnoseOldStr, reindentToBase, fsTools;
4974
+ var isSensitiveReadTarget, stripReadFileLineNumbers, maskSecretsInContent, makeTmpPath, ATOMIC_TMP_RE, sweepStaleAtomicTmp, assertReadable, stripEdgeBlankLines, matchLineBlockWith, diagnoseOldStr, reindentToBase, alignIndentsByAnchor, applyOneEditToContent, fsTools;
4921
4975
  var init_fs = __esm({
4922
4976
  "../core/src/tool/registry/fs.ts"() {
4923
4977
  "use strict";
@@ -4975,7 +5029,7 @@ var init_fs = __esm({
4975
5029
  return;
4976
5030
  }
4977
5031
  for (const e of entries) {
4978
- const full = path15.join(dir, e.name);
5032
+ const full = path16.join(dir, e.name);
4979
5033
  if (e.isDirectory()) {
4980
5034
  if (!skipDirs.has(e.name)) await walk(full);
4981
5035
  continue;
@@ -5005,7 +5059,7 @@ var init_fs = __esm({
5005
5059
  while (lines.length > 1 && lines[lines.length - 1].trim() === "") lines.pop();
5006
5060
  return lines.join("\n");
5007
5061
  };
5008
- matchLineBlockWith = (content, oldBlock, newBlock, replaceAll, norm) => {
5062
+ matchLineBlockWith = (content, oldBlock, newBlock, replaceAll, norm, anchorAlign) => {
5009
5063
  const contentLines = content.split("\n");
5010
5064
  const oldLines = oldBlock.split("\n");
5011
5065
  if (oldLines.length === 0 || oldLines.length > contentLines.length) {
@@ -5034,7 +5088,11 @@ var init_fs = __esm({
5034
5088
  break;
5035
5089
  }
5036
5090
  }
5037
- const aligned = baseIndent ? reindentToBase(newBlock, baseIndent) : newBlock;
5091
+ let aligned = baseIndent ? reindentToBase(newBlock, baseIndent) : newBlock;
5092
+ if (anchorAlign) {
5093
+ const anchored = alignIndentsByAnchor(newBlock, oldLines, contentLines, start);
5094
+ if (anchored !== null) aligned = anchored;
5095
+ }
5038
5096
  out.splice(start, oldLines.length, ...aligned.split("\n"));
5039
5097
  }
5040
5098
  return { ok: true, content: out.join("\n"), count: hits.length };
@@ -5069,6 +5127,92 @@ var init_fs = __esm({
5069
5127
  return baseIndent + (l.startsWith(common) ? l.slice(common.length) : l);
5070
5128
  }).join("\n");
5071
5129
  };
5130
+ alignIndentsByAnchor = (newBlock, oldLines, contentLines, start) => {
5131
+ const stripLead = (l) => l.replace(/^[ \t]+/, "");
5132
+ const out = [];
5133
+ let cursor = 0;
5134
+ let lastIndent = null;
5135
+ let anchors = 0;
5136
+ for (const line of newBlock.split("\n")) {
5137
+ if (line.trim() === "") {
5138
+ out.push(line);
5139
+ continue;
5140
+ }
5141
+ const bare = stripLead(line);
5142
+ let idx = -1;
5143
+ for (let i = cursor; i < oldLines.length; i++) {
5144
+ if (oldLines[i].trim() !== "" && stripLead(oldLines[i]) === bare) {
5145
+ idx = i;
5146
+ break;
5147
+ }
5148
+ }
5149
+ if (idx === -1) {
5150
+ out.push(lastIndent === null ? line : lastIndent + bare);
5151
+ continue;
5152
+ }
5153
+ cursor = idx + 1;
5154
+ lastIndent = contentLines[start + idx].match(/^[ \t]*/)?.[0] ?? "";
5155
+ anchors++;
5156
+ out.push(lastIndent + bare);
5157
+ }
5158
+ return anchors > 0 ? out.join("\n") : null;
5159
+ };
5160
+ applyOneEditToContent = (normalizedContent, oldStr, newStr, replaceAll) => {
5161
+ const normalizedNew = newStr.replace(/\r\n/g, "\n");
5162
+ const normalizedOldRaw = oldStr.replace(/\r\n/g, "\n");
5163
+ const lnStripped = stripReadFileLineNumbers(normalizedOldRaw);
5164
+ const candidates = [
5165
+ { old: normalizedOldRaw, note: "" },
5166
+ { old: stripEdgeBlankLines(normalizedOldRaw), note: "\uFF08\u5DF2\u5BB9\u9519\u9996\u5C3E\u7A7A\u884C\uFF09" }
5167
+ ];
5168
+ if (lnStripped !== normalizedOldRaw) candidates.push({ old: lnStripped, note: "\uFF08\u5DF2\u5265\u79BB read_file \u884C\u53F7\u524D\u7F00\uFF09" });
5169
+ let normalizedOld = null;
5170
+ let note = "";
5171
+ for (const c of candidates) {
5172
+ if (c.old.length > 0 && normalizedContent.includes(c.old)) {
5173
+ normalizedOld = c.old;
5174
+ note = c.note;
5175
+ break;
5176
+ }
5177
+ }
5178
+ if (normalizedOld == null) {
5179
+ const base = lnStripped !== normalizedOldRaw ? lnStripped : normalizedOldRaw;
5180
+ const norms = [
5181
+ // 行尾空白归一:old_str 前导缩进与文件一致(可信)→ 只对齐基线(anchor=false)
5182
+ { norm: (l) => l.replace(/[ \t]+$/, ""), tag: "\u9010\u884C\u5C3E\u7A7A\u767D\u5BB9\u9519", anchor: false },
5183
+ // 全空白归一:模型前导缩进已证明不符(不可信)→ 逐行锚定文件真实缩进(anchor=true)
5184
+ { norm: (l) => l.trim(), tag: "\u9010\u884C\u5168\u7A7A\u767D\u5BB9\u9519\uFF08\u524D\u5BFC Tab/\u7A7A\u683C\uFF09", anchor: true }
5185
+ ];
5186
+ for (const { norm, tag, anchor } of norms) {
5187
+ const lm = matchLineBlockWith(normalizedContent, base, normalizedNew, replaceAll, norm, anchor);
5188
+ if (lm.ok) {
5189
+ return {
5190
+ ok: true,
5191
+ content: lm.content,
5192
+ summary: replaceAll ? `\u5DF2\u6279\u91CF\u66FF\u6362\u5168\u90E8 ${lm.count} \u5904\u5339\u914D\uFF08${tag}\uFF09\u3002` : `\u5DF2\u6210\u529F\u5B8C\u6210\u5C40\u90E8\u91CD\u6784\uFF08${tag}\uFF09\u3002`
5193
+ };
5194
+ }
5195
+ if (lm.reason === "conflict") {
5196
+ return { ok: false, error: `\u274C [\u4EE3\u7801\u4FEE\u8865\u5931\u8D25]\uFF1A\u4EE3\u7801\u51B2\u7A81\uFF01old_str\uFF08${tag}\u5F52\u4E00\u540E\uFF09\u5728\u5168\u6587\u4E2D\u4E0D\u552F\u4E00\uFF08\u5171 ${lm.count} \u5904\uFF09\u3002\u8BF7\u591A\u5305\u88F9\u51E0\u884C\u4E0A\u4E0B\u6587\uFF0C\u6216\u663E\u5F0F\u8BBE replace_all=true \u6279\u91CF\u66FF\u6362\u3002` };
5197
+ }
5198
+ }
5199
+ const diag = diagnoseOldStr(normalizedContent, normalizedOldRaw);
5200
+ return { ok: false, error: `\u274C [\u4EE3\u7801\u4FEE\u8865\u5931\u8D25]\uFF1A\u672A\u80FD\u5728\u6587\u4EF6\u4E2D\u627E\u5230\u6307\u5B9A\u7684 old_str \u65E7\u4EE3\u7801\u5757\u3002${diag}\u5E38\u89C1\u539F\u56E0\uFF1A\u2460 \u8BEF\u5E26\u4E86 read_file \u7684\u300C<\u884C\u53F7>: \u300D\u524D\u7F00\uFF1B\u2461 \u7F29\u8FDB\uFF08Tab/\u7A7A\u683C\uFF09\u4E0D\u4E00\u81F4\uFF1B\u2462 \u884C\u5C3E\u591A\u4F59\u7A7A\u683C\uFF1B\u2463 \u6587\u4EF6\u5DF2\u88AB\u6539\u52A8/old_str \u975E\u8FDE\u7EED\u6574\u6BB5\u3002\u8BF7\u7528 read_file \u91CD\u65B0\u6838\u5BF9\u8BE5\u5904\u7247\u6BB5\uFF08\u53BB\u6389\u300C<\u884C\u53F7>: \u300D\u524D\u7F00\u3001\u4FDD\u7559\u539F\u59CB Tab/\u7A7A\u683C\u7F29\u8FDB\uFF09\u540E\u91CD\u8BD5\u3002\u26A0\uFE0F \u4E25\u7981\u6539\u7528 run_command \u8C03\u7528 python/node/sed/awk \u7B49\u811A\u672C\u7ED5\u8FC7\u672C\u5DE5\u5177\u4FEE\u6539\u6587\u4EF6\u3002` };
5201
+ }
5202
+ const matchCount = normalizedContent.split(normalizedOld).length - 1;
5203
+ if (!replaceAll && matchCount > 1) {
5204
+ return { ok: false, error: `\u274C [\u4EE3\u7801\u4FEE\u8865\u5931\u8D25]\uFF1A\u4EE3\u7801\u51B2\u7A81\uFF01old_str \u5728\u5168\u6587\u4E2D\u4E0D\u552F\u4E00\uFF08\u5171\u53D1\u73B0\u4E86 ${matchCount} \u5904\uFF09\u3002\u8BF7\u5411\u4E0A\u6216\u5411\u4E0B\u591A\u5305\u88F9\u51E0\u884C\u4E0A\u4E0B\u6587\u518D\u63D0\u8BF7\u4FEE\u6539\uFF0C\u6216\u663E\u5F0F\u8BBE replace_all=true \u6279\u91CF\u66FF\u6362\u3002` };
5205
+ }
5206
+ const oldFirstNonBlank = normalizedOld.split("\n").find((l) => l.trim() !== "") ?? "";
5207
+ const baseIndent = oldFirstNonBlank.match(/^[ \t]*/)?.[0] ?? "";
5208
+ const alignedNew = baseIndent ? reindentToBase(normalizedNew, baseIndent) : normalizedNew;
5209
+ const updatedContent = replaceAll ? normalizedContent.split(normalizedOld).join(alignedNew) : normalizedContent.replace(normalizedOld, () => alignedNew);
5210
+ return {
5211
+ ok: true,
5212
+ content: updatedContent,
5213
+ summary: replaceAll ? `\u5DF2\u6279\u91CF\u66FF\u6362\u5168\u90E8 ${matchCount} \u5904\u5339\u914D\u3002${note}` : `\u5DF2\u6210\u529F\u5B8C\u6210\u552F\u4E00\u6027\u5C40\u90E8\u91CD\u6784\u3002${note}`
5214
+ };
5215
+ };
5072
5216
  fsTools = [
5073
5217
  {
5074
5218
  type: "function",
@@ -5159,8 +5303,8 @@ ${formattedCode}${hasMore ? `
5159
5303
  const entries = await fs12.readdir(currentPath, { withFileTypes: true });
5160
5304
  const validEntries = entries.filter((entry) => {
5161
5305
  if (entry.isSymbolicLink()) return false;
5162
- const fullPath = path15.join(currentPath, entry.name);
5163
- const relPath = path15.relative(getActiveWorkspaceRoot(), fullPath).replace(/\\/g, "/");
5306
+ const fullPath = path16.join(currentPath, entry.name);
5307
+ const relPath = path16.relative(getActiveWorkspaceRoot(), fullPath).replace(/\\/g, "/");
5164
5308
  return !checkIsPathIgnored(entry.isDirectory() ? `${relPath}/` : relPath);
5165
5309
  });
5166
5310
  let output = "";
@@ -5179,7 +5323,7 @@ ${formattedCode}${hasMore ? `
5179
5323
  `;
5180
5324
  if (entry.isDirectory()) {
5181
5325
  const nextPrefix = prefix + (isLast ? " " : "\u2502 ");
5182
- const fullPath = path15.join(currentPath, entry.name);
5326
+ const fullPath = path16.join(currentPath, entry.name);
5183
5327
  const subTree = await buildTreeText(fullPath, currentDepth + 1, nextPrefix);
5184
5328
  output += subTree;
5185
5329
  }
@@ -5200,78 +5344,65 @@ ${treeResult}`;
5200
5344
  type: "function",
5201
5345
  function: {
5202
5346
  name: "edit_file",
5203
- description: "\u9488\u5BF9\u6307\u5B9A\u7684\u6587\u4EF6\u8FDB\u884C\u5C40\u90E8\u7CBE\u51C6\u4FEE\u6539\u3002old_str \u5FC5\u987B\u4E0E\u6587\u4EF6\u4E2D\u7684\u539F\u59CB\u4EE3\u7801\u9010\u5B57\u7B26\u4E00\u81F4\uFF1A\u8BF7\u53BB\u6389 read_file \u8FD4\u56DE\u7684\u300C<\u884C\u53F7>: \u300D\u524D\u7F00\uFF0C\u5E76\u4FDD\u7559\u539F\u6709\u7F29\u8FDB\uFF08Tab/\u7A7A\u683C\uFF09\u4E0E\u884C\u5C3E\u7A7A\u767D\uFF1B\u9ED8\u8BA4\u8981\u6C42\u5728\u5168\u6587\u4E2D\u552F\u4E00\uFF0C\u82E5\u8BBE replace_all=true \u5219\u66FF\u6362\u5168\u90E8\u5339\u914D\u5904\uFF08\u9002\u5408\u6279\u91CF\u91CD\u547D\u540D/\u7EDF\u4E00\u6539\u5199\uFF09\u3002",
5347
+ description: "\u9488\u5BF9\u6307\u5B9A\u7684\u6587\u4EF6\u8FDB\u884C\u5C40\u90E8\u7CBE\u51C6\u4FEE\u6539\u3002\u2605 \u540C\u4E00\u6587\u4EF6\u6709\u591A\u5904\u8981\u6539\u65F6\uFF0C\u52A1\u5FC5\u4E00\u6B21\u8C03\u7528\u4F20 edits \u6570\u7EC4\u5168\u90E8\u5B8C\u6210\uFF08\u6309\u5E8F\u5E94\u7528\u3001\u6574\u4F53\u539F\u5B50\uFF1A\u4EFB\u4E00\u5904\u5931\u8D25\u5219\u5168\u90E8\u4E0D\u5199\u5165\uFF09\uFF0C\u52FF\u9010\u5904\u591A\u6B21\u8C03\u7528\u3002old_str \u5FC5\u987B\u4E0E\u6587\u4EF6\u4E2D\u7684\u539F\u59CB\u4EE3\u7801\u9010\u5B57\u7B26\u4E00\u81F4\uFF1A\u8BF7\u53BB\u6389 read_file \u8FD4\u56DE\u7684\u300C<\u884C\u53F7>: \u300D\u524D\u7F00\uFF0C\u5E76\u4FDD\u7559\u539F\u6709\u7F29\u8FDB\uFF08Tab/\u7A7A\u683C\uFF09\u4E0E\u884C\u5C3E\u7A7A\u767D\uFF1B\u9ED8\u8BA4\u8981\u6C42\u5728\u5168\u6587\u4E2D\u552F\u4E00\uFF0C\u82E5\u8BBE replace_all=true \u5219\u66FF\u6362\u5168\u90E8\u5339\u914D\u5904\uFF08\u9002\u5408\u6279\u91CF\u91CD\u547D\u540D/\u7EDF\u4E00\u6539\u5199\uFF09\u3002",
5204
5348
  parameters: {
5205
5349
  type: "object",
5206
5350
  properties: {
5207
5351
  path: { type: "string", description: "\u51C6\u5907\u4FEE\u6539\u7684\u6587\u4EF6\u76F8\u5BF9\u8DEF\u5F84" },
5208
- old_str: { type: "string", description: "\u6587\u4EF6\u4E2D\u73B0\u6709\u7684\u5B8C\u6574\u65E7\u4EE3\u7801\u5757" },
5209
- new_str: { type: "string", description: "\u51C6\u5907\u66FF\u6362\u8FDB\u53BB\u7684\u65B0\u4EE3\u7801\u5757" },
5210
- replace_all: { type: "boolean", description: "\u662F\u5426\u66FF\u6362\u5168\u6587\u6240\u6709\u5339\u914D\u5904\uFF08\u9ED8\u8BA4 false \u4EC5\u66FF\u6362\u552F\u4E00\u5339\u914D\uFF1B\u6279\u91CF\u91CD\u547D\u540D/\u7EDF\u4E00\u6539\u5199\u65F6\u8BBE true\uFF09" }
5352
+ old_str: { type: "string", description: "\u6587\u4EF6\u4E2D\u73B0\u6709\u7684\u5B8C\u6574\u65E7\u4EE3\u7801\u5757\uFF08\u5355\u5904\u4FEE\u6539\u7528\uFF1B\u591A\u5904\u4FEE\u6539\u8BF7\u6539\u7528 edits \u6570\u7EC4\u4E00\u6B21\u5B8C\u6210\uFF09" },
5353
+ new_str: { type: "string", description: "\u51C6\u5907\u66FF\u6362\u8FDB\u53BB\u7684\u65B0\u4EE3\u7801\u5757\uFF08\u5355\u5904\u4FEE\u6539\u7528\uFF09" },
5354
+ replace_all: { type: "boolean", description: "\u662F\u5426\u66FF\u6362\u5168\u6587\u6240\u6709\u5339\u914D\u5904\uFF08\u9ED8\u8BA4 false \u4EC5\u66FF\u6362\u552F\u4E00\u5339\u914D\uFF1B\u6279\u91CF\u91CD\u547D\u540D/\u7EDF\u4E00\u6539\u5199\u65F6\u8BBE true\uFF09\u3002\u9876\u5C42\u53C2\u6570\u4EC5\u4F5C\u7528\u4E8E\u5355\u6761 old_str/new_str\uFF1Bedits \u5185\u6BCF\u6761\u53EF\u72EC\u7ACB\u8BBE\u7F6E" },
5355
+ edits: {
5356
+ type: "array",
5357
+ description: "\u2605 \u540C\u4E00\u6587\u4EF6\u591A\u5904\u4FEE\u6539\u65F6\u4F18\u5148\u4F7F\u7528\uFF1A\u4E00\u6B21\u8C03\u7528\u6309\u5E8F\u5B8C\u6210\u5168\u90E8\u66FF\u6362\uFF0C\u7701\u53BB\u9010\u5904\u5F80\u8FD4\u3002\u7B2C N \u6761\u7684 old_str \u987B\u57FA\u4E8E\u524D N-1 \u6761\u5E94\u7528\u540E\u7684\u6587\u4EF6\u5185\u5BB9\u6784\u9020\uFF1B\u4EFB\u4E00\u6761\u672A\u547D\u4E2D\u5219\u6574\u4F53\u4E0D\u5199\u5165\uFF08\u539F\u5B50\uFF09\uFF0C\u4FEE\u6B63\u8BE5\u6761\u540E\u6574\u7EC4\u91CD\u8BD5",
5358
+ items: {
5359
+ type: "object",
5360
+ properties: {
5361
+ old_str: { type: "string", description: "\u6587\u4EF6\u4E2D\u73B0\u6709\u7684\u5B8C\u6574\u65E7\u4EE3\u7801\u5757" },
5362
+ new_str: { type: "string", description: "\u51C6\u5907\u66FF\u6362\u8FDB\u53BB\u7684\u65B0\u4EE3\u7801\u5757" },
5363
+ replace_all: { type: "boolean", description: "\u8BE5\u6761\u662F\u5426\u66FF\u6362\u5168\u6587\u6240\u6709\u5339\u914D\u5904\uFF08\u9ED8\u8BA4 false\uFF09" }
5364
+ },
5365
+ required: ["old_str", "new_str"]
5366
+ }
5367
+ }
5211
5368
  },
5212
- required: ["path", "old_str", "new_str"]
5369
+ required: ["path"]
5213
5370
  },
5214
5371
  safetyLevel: "mutation" /* MUTATION */,
5215
5372
  isSync: true,
5216
- requireApproval: (args) => `\u7533\u8BF7\u4FEE\u6539\u6587\u4EF6 [${args.path}]${args.replace_all ? "\uFF08\u{1F525} \u6279\u91CF\u66FF\u6362\u5168\u90E8\u5339\u914D\u5904\uFF09" : ""}
5373
+ requireApproval: (args) => {
5374
+ const list = args.edits && args.edits.length > 0 ? args.edits : [{ old_str: args.old_str ?? "", new_str: args.new_str ?? "", replace_all: args.replace_all }];
5375
+ const patches = list.map((e, i) => `\u2014\u2014 \u7B2C ${i + 1} \u5904${e.replace_all ? "\uFF08\u{1F525} \u6279\u91CF\u66FF\u6362\u5168\u90E8\u5339\u914D\u5904\uFF09" : ""} \u2014\u2014
5217
5376
  \u3010\u51CF\u5C11\u3011:
5218
- ${args.old_str}
5377
+ ${e.old_str}
5219
5378
  \u3010\u589E\u52A0\u3011:
5220
- ${args.new_str}`,
5379
+ ${e.new_str}`).join("\n\n");
5380
+ return `\u7533\u8BF7\u4FEE\u6539\u6587\u4EF6 [${args.path}]\uFF08\u5171 ${list.length} \u5904\u4FEE\u6539\uFF0C\u4EFB\u4E00\u5904\u5931\u8D25\u5C06\u6574\u4F53\u4E0D\u5199\u5165\uFF09
5381
+ ${patches}`;
5382
+ },
5221
5383
  async execute(args) {
5222
5384
  try {
5385
+ const editList = args.edits && args.edits.length > 0 ? args.edits : [{ old_str: args.old_str ?? "", new_str: args.new_str ?? "", replace_all: args.replace_all }];
5386
+ if (editList.length === 0 || editList.some((e) => typeof e.old_str !== "string" || e.old_str.length === 0)) {
5387
+ 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`;
5388
+ }
5223
5389
  const absPath = resolveSafePath(args.path);
5224
5390
  const rawContent = await fs12.readFile(absPath, "utf-8");
5225
5391
  const isCRLF = rawContent.includes("\r\n");
5226
- const normalizedContent = rawContent.replace(/\r\n/g, "\n");
5227
- const normalizedNew = args.new_str.replace(/\r\n/g, "\n");
5228
- const normalizedOldRaw = args.old_str.replace(/\r\n/g, "\n");
5229
- const lnStripped = stripReadFileLineNumbers(normalizedOldRaw);
5230
- const candidates = [
5231
- { old: normalizedOldRaw, note: "" },
5232
- { old: stripEdgeBlankLines(normalizedOldRaw), note: "\uFF08\u5DF2\u5BB9\u9519\u9996\u5C3E\u7A7A\u884C\uFF09" }
5233
- ];
5234
- if (lnStripped !== normalizedOldRaw) candidates.push({ old: lnStripped, note: "\uFF08\u5DF2\u5265\u79BB read_file \u884C\u53F7\u524D\u7F00\uFF09" });
5235
- let normalizedOld = null;
5236
- let note = "";
5237
- for (const c of candidates) {
5238
- if (c.old.length > 0 && normalizedContent.includes(c.old)) {
5239
- normalizedOld = c.old;
5240
- note = c.note;
5241
- break;
5242
- }
5243
- }
5244
- if (normalizedOld == null) {
5245
- const base = lnStripped !== normalizedOldRaw ? lnStripped : normalizedOldRaw;
5246
- const norms = [
5247
- { norm: (l) => l.replace(/[ \t]+$/, ""), tag: "\u9010\u884C\u5C3E\u7A7A\u767D\u5BB9\u9519" },
5248
- { norm: (l) => l.trim(), tag: "\u9010\u884C\u5168\u7A7A\u767D\u5BB9\u9519\uFF08\u524D\u5BFC Tab/\u7A7A\u683C\uFF09" }
5249
- ];
5250
- for (const { norm, tag } of norms) {
5251
- const lm = matchLineBlockWith(normalizedContent, base, normalizedNew, !!args.replace_all, norm);
5252
- if (lm.ok) {
5253
- assertWithinWorkspace(absPath);
5254
- await fs12.writeFile(absPath, isCRLF ? lm.content.replace(/\n/g, "\r\n") : lm.content, "utf-8");
5255
- return args.replace_all ? `\u2705 [\u4EE3\u7801\u4FEE\u8865\u6210\u529F]\uFF1A\u6587\u4EF6 [${args.path}] \u5DF2\u6279\u91CF\u66FF\u6362\u5168\u90E8 ${lm.count} \u5904\u5339\u914D\uFF08${tag}\uFF09\u3002` : `\u2705 [\u4EE3\u7801\u4FEE\u8865\u6210\u529F]\uFF1A\u6587\u4EF6 [${args.path}] \u5DF2\u6210\u529F\u5B8C\u6210\u5C40\u90E8\u91CD\u6784\uFF08${tag}\uFF09\u3002`;
5256
- }
5257
- if (lm.reason === "conflict") {
5258
- return `\u274C [\u4EE3\u7801\u4FEE\u8865\u5931\u8D25]\uFF1A\u4EE3\u7801\u51B2\u7A81\uFF01old_str\uFF08${tag}\u5F52\u4E00\u540E\uFF09\u5728\u5168\u6587\u4E2D\u4E0D\u552F\u4E00\uFF08\u5171 ${lm.count} \u5904\uFF09\u3002\u8BF7\u591A\u5305\u88F9\u51E0\u884C\u4E0A\u4E0B\u6587\uFF0C\u6216\u663E\u5F0F\u8BBE replace_all=true \u6279\u91CF\u66FF\u6362\u3002`;
5259
- }
5392
+ let content = rawContent.replace(/\r\n/g, "\n");
5393
+ const summaries = [];
5394
+ for (let i = 0; i < editList.length; i++) {
5395
+ const r = applyOneEditToContent(content, editList[i].old_str, editList[i].new_str ?? "", !!editList[i].replace_all);
5396
+ if (!r.ok) {
5397
+ return editList.length === 1 ? r.error : `\u274C [\u4EE3\u7801\u4FEE\u8865\u5931\u8D25]\uFF1Aedits \u7B2C ${i + 1}/${editList.length} \u6761\u672A\u547D\u4E2D\uFF0C\u5DF2\u6574\u4F53\u653E\u5F03\uFF08\u6587\u4EF6\u672A\u505A\u4EFB\u4F55\u6539\u52A8\uFF0C\u53EF\u4FEE\u6B63\u8BE5\u6761\u540E\u6574\u7EC4\u91CD\u8BD5\uFF09\u3002${r.error.replace(/^❌ \[代码修补失败\]:/, "")}`;
5260
5398
  }
5261
- const diag = diagnoseOldStr(normalizedContent, normalizedOldRaw);
5262
- return `\u274C [\u4EE3\u7801\u4FEE\u8865\u5931\u8D25]\uFF1A\u672A\u80FD\u5728\u6587\u4EF6\u4E2D\u627E\u5230\u6307\u5B9A\u7684 old_str \u65E7\u4EE3\u7801\u5757\u3002${diag}\u5E38\u89C1\u539F\u56E0\uFF1A\u2460 \u8BEF\u5E26\u4E86 read_file \u7684\u300C<\u884C\u53F7>: \u300D\u524D\u7F00\uFF1B\u2461 \u7F29\u8FDB\uFF08Tab/\u7A7A\u683C\uFF09\u4E0D\u4E00\u81F4\uFF1B\u2462 \u884C\u5C3E\u591A\u4F59\u7A7A\u683C\uFF1B\u2463 \u6587\u4EF6\u5DF2\u88AB\u6539\u52A8/old_str \u975E\u8FDE\u7EED\u6574\u6BB5\u3002\u8BF7\u7528 read_file \u91CD\u65B0\u6838\u5BF9\u5E94\u8D34\u7247\u6BB5\u3002\u26A0\uFE0F \u4E25\u7981\u6539\u7528 run_command \u8C03\u7528 python/node/sed/awk \u7B49\u811A\u672C\u7ED5\u8FC7\u672C\u5DE5\u5177\u4FEE\u6539\u6587\u4EF6\u2014\u2014\u8BF7\u7528 read_file \u91CD\u65B0\u8BFB\u53D6\u76EE\u6807\u7247\u6BB5\uFF08\u53BB\u6389\u300C<\u884C\u53F7>: \u300D\u524D\u7F00\u3001\u4FDD\u7559\u539F\u59CB Tab/\u7A7A\u683C\u7F29\u8FDB\uFF09\uFF0C\u518D\u6B21\u8C03\u7528 edit_file \u91CD\u8BD5\u3002`;
5399
+ content = r.content;
5400
+ summaries.push(editList.length === 1 ? r.summary : ` ${i + 1}. ${r.summary}`);
5263
5401
  }
5264
- const matchCount = normalizedContent.split(normalizedOld).length - 1;
5265
- if (!args.replace_all && matchCount > 1) {
5266
- return `\u274C [\u4EE3\u7801\u4FEE\u8865\u5931\u8D25]\uFF1A\u4EE3\u7801\u51B2\u7A81\uFF01old_str \u5728\u5168\u6587\u4E2D\u4E0D\u552F\u4E00\uFF08\u5171\u53D1\u73B0\u4E86 ${matchCount} \u5904\uFF09\u3002\u8BF7\u5411\u4E0A\u6216\u5411\u4E0B\u591A\u5305\u88F9\u51E0\u884C\u4E0A\u4E0B\u6587\u518D\u63D0\u8BF7\u4FEE\u6539\uFF0C\u6216\u663E\u5F0F\u8BBE replace_all=true \u6279\u91CF\u66FF\u6362\u3002`;
5267
- }
5268
- const oldFirstNonBlank = normalizedOld.split("\n").find((l) => l.trim() !== "") ?? "";
5269
- const baseIndent = oldFirstNonBlank.match(/^[ \t]*/)?.[0] ?? "";
5270
- const alignedNew = baseIndent ? reindentToBase(normalizedNew, baseIndent) : normalizedNew;
5271
- const updatedContent = args.replace_all ? normalizedContent.split(normalizedOld).join(alignedNew) : normalizedContent.replace(normalizedOld, () => alignedNew);
5272
5402
  assertWithinWorkspace(absPath);
5273
- await fs12.writeFile(absPath, isCRLF ? updatedContent.replace(/\n/g, "\r\n") : updatedContent, "utf-8");
5274
- return args.replace_all ? `\u2705 [\u4EE3\u7801\u4FEE\u8865\u6210\u529F]\uFF1A\u6587\u4EF6 [${args.path}] \u5DF2\u6279\u91CF\u66FF\u6362\u5168\u90E8 ${matchCount} \u5904\u5339\u914D\u3002${note}` : `\u2705 [\u4EE3\u7801\u4FEE\u8865\u6210\u529F]\uFF1A\u6587\u4EF6 [${args.path}] \u5DF2\u6210\u529F\u5B8C\u6210\u552F\u4E00\u6027\u5C40\u90E8\u91CD\u6784\u3002${note}`;
5403
+ await fs12.writeFile(absPath, isCRLF ? content.replace(/\n/g, "\r\n") : content, "utf-8");
5404
+ 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
5405
+ ${summaries.join("\n")}`;
5275
5406
  } catch (error) {
5276
5407
  return `\u64CD\u4F5C\u5931\u8D25: ${error.message}`;
5277
5408
  }
@@ -5306,7 +5437,7 @@ ${args.new_str}`,
5306
5437
  }
5307
5438
  const content = args.content ?? "";
5308
5439
  assertWithinWorkspace(absPath);
5309
- await fs12.mkdir(path15.dirname(absPath), { recursive: true });
5440
+ await fs12.mkdir(path16.dirname(absPath), { recursive: true });
5310
5441
  tmpPath = makeTmpPath(absPath);
5311
5442
  await fs12.writeFile(tmpPath, content, "utf-8");
5312
5443
  await fs12.rename(tmpPath, absPath);
@@ -5345,7 +5476,7 @@ ${args.new_str}`,
5345
5476
  }
5346
5477
  let rel = "";
5347
5478
  try {
5348
- rel = path15.relative(getActiveWorkspaceRoot(), resolveSafePath(cleanPath));
5479
+ rel = path16.relative(getActiveWorkspaceRoot(), resolveSafePath(cleanPath));
5349
5480
  } catch {
5350
5481
  }
5351
5482
  if (rel === "" || rel === "src") {
@@ -5366,8 +5497,8 @@ ${args.new_str}`,
5366
5497
  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`;
5367
5498
  }
5368
5499
  const absPath = resolveSafePath(cleanPath);
5369
- const rel = path15.relative(getActiveWorkspaceRoot(), absPath);
5370
- if (!rel || rel === "" || rel === "src" || rel.startsWith("..") || path15.isAbsolute(rel)) {
5500
+ const rel = path16.relative(getActiveWorkspaceRoot(), absPath);
5501
+ if (!rel || rel === "" || rel === "src" || rel.startsWith("..") || path16.isAbsolute(rel)) {
5371
5502
  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`;
5372
5503
  }
5373
5504
  let stat;
@@ -5412,7 +5543,7 @@ ${args.new_str}`,
5412
5543
  try {
5413
5544
  const absPath = resolveSafePath(args.path);
5414
5545
  assertWithinWorkspace(absPath);
5415
- await fs12.mkdir(path15.dirname(absPath), { recursive: true });
5546
+ await fs12.mkdir(path16.dirname(absPath), { recursive: true });
5416
5547
  tmpPath = makeTmpPath(absPath);
5417
5548
  await fs12.writeFile(tmpPath, args.content, "utf-8");
5418
5549
  await fs12.rename(tmpPath, absPath);
@@ -5546,7 +5677,7 @@ ${args.new_str}`,
5546
5677
  }
5547
5678
  assertWithinWorkspace(srcAbs);
5548
5679
  assertWithinWorkspace(dstAbs);
5549
- await fs12.mkdir(path15.dirname(dstAbs), { recursive: true });
5680
+ await fs12.mkdir(path16.dirname(dstAbs), { recursive: true });
5550
5681
  await fs12.rename(srcAbs, dstAbs);
5551
5682
  return `\u2705 [\u79FB\u52A8\u6210\u529F]\uFF1A[${args.source}] \u2192 [${args.destination}]\u3002`;
5552
5683
  } catch (error) {
@@ -5561,7 +5692,7 @@ ${args.new_str}`,
5561
5692
 
5562
5693
  // ../core/src/tool/registry/search.ts
5563
5694
  import { rgPath } from "vscode-ripgrep";
5564
- import path16 from "path";
5695
+ import path17 from "path";
5565
5696
  import fs13 from "fs/promises";
5566
5697
  function escapeRegExp(string) {
5567
5698
  return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -5579,13 +5710,14 @@ var init_search = __esm({
5579
5710
  type: "function",
5580
5711
  function: {
5581
5712
  name: "search_grep",
5582
- description: "\u5728\u5DE5\u4F5C\u533A\u7684\u6240\u6709\u6587\u4EF6\u4E2D\u68C0\u7D22\u5339\u914D\u7684\u4EE3\u7801\u884C\uFF0C\u6BCF\u4E2A\u547D\u4E2D\u5E26\u524D\u540E\u5404 2 \u884C\u4E0A\u4E0B\u6587\uFF08\u53EF\u76F4\u63A5\u5224\u65AD\u7528\u6CD5\u3001\u514D\u7D27\u8DDF\u4E00\u6B21 read_file\uFF09\uFF1B\u9ED8\u8BA4\u6309\u5B57\u9762\u91CF\u5173\u952E\u8BCD\u5339\u914D\uFF0C\u5982\u9700\u6B63\u5219\u4F20 is_regex=true\u3002\u591A\u6839\u5DE5\u4F5C\u533A\u4E0B\u7528 path \u9650\u5B9A\u641C\u7D22\u76EE\u5F55\uFF1A\u53EF\u4F20\u9879\u76EE\u76EE\u5F55\u540D\uFF08\u5982 'frontend'\uFF09\u81EA\u52A8\u5339\u914D\u5DE5\u4F5C\u533A\u6839\uFF0C\u6216\u4F20\u7EDD\u5BF9\u8DEF\u5F84 / \u76F8\u5BF9\u9ED8\u8BA4\u6839\u7684 ../\u5144\u5F1F\u76EE\u5F55\u3002\u2605 \u5F53\u7528\u6237\u5728\u5BF9\u8BDD\u91CC\u6307\u660E\u4E86\u67D0\u4E2A\u9879\u76EE\u65F6\uFF0C\u52A1\u5FC5\u628A\u8BE5\u9879\u76EE\u4F5C\u4E3A path \u4F20\u5165\u2014\u2014\u5426\u5219\u53EA\u4F1A\u641C\u7D22 IDE \u5934\u90E8\u6240\u793A\u7684\u6D3B\u52A8\u6839\uFF0C\u5E38\u4E0E\u7528\u6237\u610F\u56FE\u4E0D\u7B26\u3002",
5713
+ description: "\u5728\u5DE5\u4F5C\u533A\u7684\u6240\u6709\u6587\u4EF6\u4E2D\u68C0\u7D22\u5339\u914D\u7684\u4EE3\u7801\u884C\uFF0C\u6BCF\u4E2A\u547D\u4E2D\u9ED8\u8BA4\u5E26\u524D\u540E\u5404 2 \u884C\u4E0A\u4E0B\u6587\uFF08\u53EF\u76F4\u63A5\u5224\u65AD\u7528\u6CD5\u3001\u514D\u7D27\u8DDF\u4E00\u6B21 read_file\uFF1B\u6784\u9020 edit_file \u7684 old_str \u524D\u53EF\u7528 context \u53C2\u6570\u8C03\u5927\u4E00\u6B21\u62FF\u8DB3\uFF09\uFF1B\u9ED8\u8BA4\u6309\u5B57\u9762\u91CF\u5173\u952E\u8BCD\u5339\u914D\uFF0C\u5982\u9700\u6B63\u5219\u4F20 is_regex=true\u3002\u2605 \u68C0\u7D22\u591A\u4E2A\u5173\u952E\u8BCD\u65F6\uFF0C\u7528 is_regex=true \u4EE5 | \u5408\u5E76\uFF08\u5982 'uploadVisible|uploadTip'\uFF09\u4E00\u6B21\u67E5\u5B8C\uFF0C\u52FF\u9010\u4E2A\u5173\u952E\u8BCD\u591A\u6B21\u8C03\u7528\u3002path \u53EF\u9650\u5B9A\u5230\u76EE\u5F55\u6216\u5177\u4F53\u6587\u4EF6\uFF08\u5728\u5355\u4E2A\u5927\u6587\u4EF6\u5185\u591A\u5904\u5B9A\u4F4D\u65F6\u4F20\u6587\u4EF6\u8DEF\u5F84\u6700\u9AD8\u6548\uFF09\u3002\u591A\u6839\u5DE5\u4F5C\u533A\u4E0B\uFF1A\u53EF\u4F20\u9879\u76EE\u76EE\u5F55\u540D\uFF08\u5982 'frontend'\uFF09\u81EA\u52A8\u5339\u914D\u5DE5\u4F5C\u533A\u6839\uFF0C\u6216\u4F20\u7EDD\u5BF9\u8DEF\u5F84 / \u76F8\u5BF9\u9ED8\u8BA4\u6839\u7684 ../\u5144\u5F1F\u76EE\u5F55\u3002\u2605 \u5F53\u7528\u6237\u5728\u5BF9\u8BDD\u91CC\u6307\u660E\u4E86\u67D0\u4E2A\u9879\u76EE\u65F6\uFF0C\u52A1\u5FC5\u628A\u8BE5\u9879\u76EE\u4F5C\u4E3A path \u4F20\u5165\u2014\u2014\u5426\u5219\u53EA\u4F1A\u641C\u7D22 IDE \u5934\u90E8\u6240\u793A\u7684\u6D3B\u52A8\u6839\uFF0C\u5E38\u4E0E\u7528\u6237\u610F\u56FE\u4E0D\u7B26\u3002",
5583
5714
  parameters: {
5584
5715
  type: "object",
5585
5716
  properties: {
5586
- query: { type: "string", description: "\u68C0\u7D22\u5185\u5BB9\u3002\u9ED8\u8BA4\u4E3A\u5B57\u9762\u91CF\u5173\u952E\u8BCD\uFF08\u5982 'function runAgent'\uFF09\uFF1Bis_regex=true \u65F6\u6309\u6B63\u5219\u89E3\u6790\uFF08\u5982 'function\\s+runAgent'\uFF09\u3002" },
5717
+ query: { type: "string", description: "\u68C0\u7D22\u5185\u5BB9\u3002\u9ED8\u8BA4\u4E3A\u5B57\u9762\u91CF\u5173\u952E\u8BCD\uFF08\u5982 'function runAgent'\uFF09\uFF1Bis_regex=true \u65F6\u6309\u6B63\u5219\u89E3\u6790\uFF08\u5982 'function\\s+runAgent'\uFF0C\u591A\u5173\u952E\u8BCD\u7528 | \u5408\u5E76\uFF09" },
5587
5718
  is_regex: { type: "boolean", description: "\u662F\u5426\u5C06 query \u4F5C\u4E3A\u6B63\u5219\u8868\u8FBE\u5F0F\u89E3\u6790\uFF0C\u9ED8\u8BA4 false\uFF08\u5B57\u9762\u91CF\u5339\u914D\uFF0C\u81EA\u52A8\u8F6C\u4E49\u7279\u6B8A\u5B57\u7B26\uFF09" },
5588
- path: { type: "string", description: "\u9650\u5B9A\u641C\u7D22\u7684\u76EE\u5F55\uFF08\u53EF\u9009\uFF09\u3002\u9ED8\u8BA4\u641C\u7D22 IDE \u5934\u90E8\u6240\u793A\u6D3B\u52A8\u6839\u3002\u591A\u6839\u573A\u666F\u4E0B\uFF1A\u4F20\u9879\u76EE\u76EE\u5F55\u540D\uFF08\u5982 'frontend'\uFF09\u81EA\u52A8\u5339\u914D\u5DE5\u4F5C\u533A\u6839\uFF1B\u6216\u4F20\u7EDD\u5BF9\u8DEF\u5F84 / \u76F8\u5BF9\u9ED8\u8BA4\u6839\u7684 ../<\u5144\u5F1F\u76EE\u5F55>\uFF1B\u5747\u7ECF\u6C99\u7BB1\u6821\u9A8C\u3002\u7528\u6237\u63D0\u5230\u5177\u4F53\u9879\u76EE\u65F6\u5FC5\u586B\u3002" }
5719
+ path: { type: "string", description: "\u9650\u5B9A\u641C\u7D22\u7684\u76EE\u5F55\u6216\u5177\u4F53\u6587\u4EF6\uFF08\u53EF\u9009\uFF09\u3002\u4F20\u5177\u4F53\u6587\u4EF6\u8DEF\u5F84\u65F6\u76F8\u5F53\u4E8E\u8BE5\u6587\u4EF6\u5185\u5168\u6587\u68C0\u7D22\uFF08\u5927\u6587\u4EF6\u591A\u5904\u5B9A\u4F4D\u9996\u9009\uFF09\u3002\u9ED8\u8BA4\u641C\u7D22 IDE \u5934\u90E8\u6240\u793A\u6D3B\u52A8\u6839\u3002\u591A\u6839\u573A\u666F\u4E0B\uFF1A\u4F20\u9879\u76EE\u76EE\u5F55\u540D\uFF08\u5982 'frontend'\uFF09\u81EA\u52A8\u5339\u914D\u5DE5\u4F5C\u533A\u6839\uFF1B\u6216\u4F20\u7EDD\u5BF9\u8DEF\u5F84 / \u76F8\u5BF9\u9ED8\u8BA4\u6839\u7684 ../<\u5144\u5F1F\u76EE\u5F55>\uFF1B\u5747\u7ECF\u6C99\u7BB1\u6821\u9A8C\u3002\u7528\u6237\u63D0\u5230\u5177\u4F53\u9879\u76EE\u65F6\u5FC5\u586B\u3002" },
5720
+ context: { type: "number", description: "\u6BCF\u4E2A\u547D\u4E2D\u9644\u5E26\u7684\u524D\u540E\u4E0A\u4E0B\u6587\u884C\u6570\uFF080-10\uFF0C\u9ED8\u8BA4 2\uFF09\u3002\u9700\u8981\u62FF\u8DB3\u4E00\u6BB5\u5B8C\u6574\u4EE3\u7801\u4F5C edit_file \u7684 old_str \u65F6\u53EF\u8C03\u5927\uFF08\u5982 5-8\uFF09\uFF0C\u514D\u5F97\u4E8C\u6B21\u68C0\u7D22" }
5589
5721
  },
5590
5722
  required: ["query"]
5591
5723
  },
@@ -5603,10 +5735,10 @@ var init_search = __esm({
5603
5735
  const resolveSearchRoot = () => {
5604
5736
  if (!args.path) return ctx?.cwd ?? getActiveWorkspaceRoot();
5605
5737
  const p = args.path.trim();
5606
- const looksLikeBareName = !path16.isAbsolute(p) && !p.includes("/") && !p.includes("\\");
5738
+ const looksLikeBareName = !path17.isAbsolute(p) && !p.includes("/") && !p.includes("\\");
5607
5739
  if (looksLikeBareName) {
5608
5740
  const hit = getAllowedWorkspaceRoots().find((r) => {
5609
- const bn = path16.basename(r);
5741
+ const bn = path17.basename(r);
5610
5742
  return bn === p || bn.toLowerCase() === p.toLowerCase();
5611
5743
  });
5612
5744
  if (hit) return hit;
@@ -5614,6 +5746,7 @@ var init_search = __esm({
5614
5746
  return resolveReadablePath(args.path);
5615
5747
  };
5616
5748
  const searchRoot = resolveSearchRoot().replace(/\\/g, "/");
5749
+ const contextLines = Math.min(Math.max(args.context ?? 2, 0), 10);
5617
5750
  const rgArgs = [
5618
5751
  "--threads",
5619
5752
  "1",
@@ -5624,8 +5757,8 @@ var init_search = __esm({
5624
5757
  "--color",
5625
5758
  "never",
5626
5759
  "-C",
5627
- "2",
5628
- // ★ 每个命中带前后各 2 行上下文:模型一次看懂用法,免去紧跟的 read_file 往返(减调用次数的关键)
5760
+ String(contextLines),
5761
+ // ★ 每个命中带前后上下文:模型一次看懂用法,免去紧跟的 read_file 往返(减调用次数的关键)
5629
5762
  "--max-count",
5630
5763
  "10",
5631
5764
  "--glob",
@@ -5694,7 +5827,7 @@ var init_search = __esm({
5694
5827
  const GUIDE_CANDIDATES = ["CLAUDE.md", "AGENTS.md", "AGENT.md"];
5695
5828
  for (const name of GUIDE_CANDIDATES) {
5696
5829
  try {
5697
- const content = await fs13.readFile(path16.join(getActiveWorkspaceRoot(), name), "utf-8");
5830
+ const content = await fs13.readFile(path17.join(getActiveWorkspaceRoot(), name), "utf-8");
5698
5831
  return `[Project Guide via ${name}]
5699
5832
 
5700
5833
  ${content}`;
@@ -5927,49 +6060,91 @@ ${tail}`,
5927
6060
 
5928
6061
  // ../core/src/tool/registry/glob.ts
5929
6062
  import fs14 from "fs/promises";
5930
- import path17 from "path";
5931
- var globToRegex2, globTools;
6063
+ import path18 from "path";
6064
+ var findMatchingBrace, splitTopLevel, globToRegex2, globTools;
5932
6065
  var init_glob = __esm({
5933
6066
  "../core/src/tool/registry/glob.ts"() {
5934
6067
  "use strict";
5935
6068
  init_type();
5936
6069
  init_guard();
6070
+ findMatchingBrace = (s, start) => {
6071
+ let depth = 0;
6072
+ for (let i = start; i < s.length; i++) {
6073
+ if (s[i] === "{") depth++;
6074
+ else if (s[i] === "}") {
6075
+ depth--;
6076
+ if (depth === 0) return i;
6077
+ }
6078
+ }
6079
+ return -1;
6080
+ };
6081
+ splitTopLevel = (s) => {
6082
+ const parts = [];
6083
+ let depth = 0, cur = "";
6084
+ for (const ch of s) {
6085
+ if (ch === "{") depth++;
6086
+ else if (ch === "}") depth--;
6087
+ if (ch === "," && depth === 0) {
6088
+ parts.push(cur);
6089
+ cur = "";
6090
+ continue;
6091
+ }
6092
+ cur += ch;
6093
+ }
6094
+ parts.push(cur);
6095
+ return parts;
6096
+ };
5937
6097
  globToRegex2 = (pattern) => {
5938
- let re = "";
5939
- let i = 0;
5940
- while (i < pattern.length) {
5941
- const c = pattern[i];
5942
- if (c === "*" && pattern[i + 1] === "*") {
5943
- if (pattern[i + 2] === "/") {
5944
- re += "(?:.*/)?";
5945
- i += 3;
6098
+ const walk = (s) => {
6099
+ let re = "";
6100
+ let i = 0;
6101
+ while (i < s.length) {
6102
+ const c = s[i];
6103
+ if (c === "{") {
6104
+ const close = findMatchingBrace(s, i);
6105
+ if (close === -1) {
6106
+ re += "\\{";
6107
+ i++;
6108
+ continue;
6109
+ }
6110
+ const alts = splitTopLevel(s.slice(i + 1, close));
6111
+ re += `(?:${alts.map((a) => walk(a)).join("|")})`;
6112
+ i = close + 1;
6113
+ continue;
6114
+ }
6115
+ if (c === "*" && s[i + 1] === "*") {
6116
+ if (s[i + 2] === "/") {
6117
+ re += "(?:.*/)?";
6118
+ i += 3;
6119
+ } else {
6120
+ re += ".*";
6121
+ i += 2;
6122
+ }
6123
+ } else if (c === "*") {
6124
+ re += "[^/]*";
6125
+ i++;
6126
+ } else if (c === "?") {
6127
+ re += ".";
6128
+ i++;
5946
6129
  } else {
5947
- re += ".*";
5948
- i += 2;
6130
+ re += /[.+^$}()|[\]\\]/.test(c) ? "\\" + c : c;
6131
+ i++;
5949
6132
  }
5950
- } else if (c === "*") {
5951
- re += "[^/]*";
5952
- i++;
5953
- } else if (c === "?") {
5954
- re += ".";
5955
- i++;
5956
- } else {
5957
- re += /[.+^${}()|[\]\\]/.test(c) ? "\\" + c : c;
5958
- i++;
5959
6133
  }
5960
- }
5961
- return new RegExp(`^${re}$`);
6134
+ return re;
6135
+ };
6136
+ return new RegExp(`^${walk(pattern)}$`);
5962
6137
  };
5963
6138
  globTools = [
5964
6139
  {
5965
6140
  type: "function",
5966
6141
  function: {
5967
6142
  name: "glob",
5968
- description: "\u6309\u6587\u4EF6\u540D glob \u6A21\u5F0F\u5FEB\u901F\u67E5\u627E\u6587\u4EF6\uFF08\u5982 '**/*.ts'\u3001'src/**/test*'\u3001'**/*.test.ts'\uFF09\u3002\u4E0E search_grep\uFF08\u6309\u5185\u5BB9\u68C0\u7D22\uFF09\u4E92\u8865\u3002\u81EA\u52A8\u5957\u7528 .gitignore / \u901A\u7528\u9ED1\u540D\u5355\u8FC7\u6EE4\u3002",
6143
+ description: "\u6309\u6587\u4EF6\u540D glob \u6A21\u5F0F\u5FEB\u901F\u67E5\u627E\u6587\u4EF6\uFF08\u5982 '**/*.ts'\u3001'src/**/test*'\u3001'**/*.test.ts'\uFF09\u3002\u2605 \u652F\u6301\u82B1\u62EC\u53F7\u591A\u9009\uFF1A'**/*.{ts,tsx,vue}'\u3001'src/{api,components}/**' \u4E00\u6B21\u67E5\u591A\u7C7B\u578B/\u591A\u76EE\u5F55\uFF0C\u52FF\u5206\u591A\u6B21\u8C03\u7528\u3002\u4E0E search_grep\uFF08\u6309\u5185\u5BB9\u68C0\u7D22\uFF09\u4E92\u8865\u3002\u81EA\u52A8\u5957\u7528 .gitignore / \u901A\u7528\u9ED1\u540D\u5355\u8FC7\u6EE4\u3002",
5969
6144
  parameters: {
5970
6145
  type: "object",
5971
6146
  properties: {
5972
- pattern: { type: "string", description: "glob \u6A21\u5F0F\uFF0C\u5982 '**/*.ts' \u6216 'src/**/*.test.ts'" },
6147
+ pattern: { type: "string", description: "glob \u6A21\u5F0F\uFF0C\u652F\u6301 * / ** / ? \u4E0E\u82B1\u62EC\u53F7\u591A\u9009 {a,b}\uFF08\u5982 '**/*.{ts,vue}'\u3001'src/{api,components}/**'\uFF09" },
5973
6148
  path: { type: "string", description: "\u9650\u5B9A\u641C\u7D22\u7684\u8D77\u59CB\u76EE\u5F55\uFF08\u76F8\u5BF9\u8DEF\u5F84\uFF0C\u53EF\u9009\uFF0C\u9ED8\u8BA4\u5DE5\u4F5C\u533A\u6839\uFF09" }
5974
6149
  },
5975
6150
  required: ["pattern"]
@@ -5991,16 +6166,16 @@ var init_glob = __esm({
5991
6166
  if (scannedCount > MAX_SCAN_LIMIT) return;
5992
6167
  const entries = await fs14.readdir(dir, { withFileTypes: true });
5993
6168
  const validEntries = entries.filter((e) => {
5994
- const full = path17.join(dir, e.name);
5995
- const rel = path17.relative(activeRoot, full).replace(/\\/g, "/");
6169
+ const full = path18.join(dir, e.name);
6170
+ const rel = path18.relative(activeRoot, full).replace(/\\/g, "/");
5996
6171
  return !checkIsPathIgnored(e.isDirectory() ? `${rel}/` : rel);
5997
6172
  });
5998
6173
  for (const e of validEntries) {
5999
6174
  scannedCount++;
6000
6175
  if (scannedCount > MAX_SCAN_LIMIT) break;
6001
6176
  if (e.isSymbolicLink()) continue;
6002
- const full = path17.join(dir, e.name);
6003
- const rel = path17.relative(activeRoot, full).replace(/\\/g, "/");
6177
+ const full = path18.join(dir, e.name);
6178
+ const rel = path18.relative(activeRoot, full).replace(/\\/g, "/");
6004
6179
  if (e.isDirectory()) {
6005
6180
  if (cleanPattern.endsWith("/") && re.test(`${rel}/`)) {
6006
6181
  hits.push(`${rel}/`);
@@ -6217,7 +6392,7 @@ ${summary}`;
6217
6392
 
6218
6393
  // ../core/src/tool/registry/inspect_dependencies.ts
6219
6394
  import * as fs15 from "fs/promises";
6220
- import * as path18 from "path";
6395
+ import * as path19 from "path";
6221
6396
  var dependencyTools;
6222
6397
  var init_inspect_dependencies = __esm({
6223
6398
  "../core/src/tool/registry/inspect_dependencies.ts"() {
@@ -6238,7 +6413,7 @@ var init_inspect_dependencies = __esm({
6238
6413
  isSync: true,
6239
6414
  async execute() {
6240
6415
  try {
6241
- const pjsPath = path18.join(getActiveWorkspaceRoot(), "package.json");
6416
+ const pjsPath = path19.join(getActiveWorkspaceRoot(), "package.json");
6242
6417
  const raw = await fs15.readFile(pjsPath, "utf-8");
6243
6418
  const pjs = JSON.parse(raw);
6244
6419
  const result = {
@@ -6540,13 +6715,13 @@ async function safeFetchFollow(startUrl, baseHeaders, signals, allowPrivate = fa
6540
6715
  return res;
6541
6716
  }
6542
6717
  }
6543
- var FETCH_TIMEOUT_MS, SEARCH_TIMEOUT_MS, DEFAULT_MAX_CHARS, USER_AGENT, BROWSER_UA, TAVILY_ENDPOINT, formatHostBlockMessage, MAX_REDIRECTS, pinnedSsrfDispatcher, pinnedMetadataGuardDispatcher, readBodyCapped, webTools;
6718
+ var FETCH_TIMEOUT_MS2, SEARCH_TIMEOUT_MS, DEFAULT_MAX_CHARS, USER_AGENT, BROWSER_UA, TAVILY_ENDPOINT, formatHostBlockMessage, MAX_REDIRECTS, pinnedSsrfDispatcher, pinnedMetadataGuardDispatcher, readBodyCapped, webTools;
6544
6719
  var init_web = __esm({
6545
6720
  "../core/src/tool/registry/web.ts"() {
6546
6721
  "use strict";
6547
6722
  init_type();
6548
6723
  init_config();
6549
- FETCH_TIMEOUT_MS = 15e3;
6724
+ FETCH_TIMEOUT_MS2 = 15e3;
6550
6725
  SEARCH_TIMEOUT_MS = 2e4;
6551
6726
  DEFAULT_MAX_CHARS = 16e3;
6552
6727
  USER_AGENT = "DeepSeeker-Code-Agent/1.0 (+web_fetch tool)";
@@ -6676,7 +6851,7 @@ var init_web = __esm({
6676
6851
  if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
6677
6852
  return `\u274C [\u5B89\u5168\u7194\u65AD]\uFF1A\u4EC5\u5141\u8BB8 http/https \u534F\u8BAE\uFF0C\u62D2\u7EDD ${parsed.protocol}`;
6678
6853
  }
6679
- const signals = [AbortSignal.timeout(FETCH_TIMEOUT_MS)];
6854
+ const signals = [AbortSignal.timeout(FETCH_TIMEOUT_MS2)];
6680
6855
  if (ctx?.abortSignal) signals.push(ctx.abortSignal);
6681
6856
  try {
6682
6857
  const res = await safeFetchFollow(parsed.href, {
@@ -6713,7 +6888,7 @@ var init_web = __esm({
6713
6888
  ${body}${truncNote}`;
6714
6889
  } catch (error) {
6715
6890
  if (error?.name === "TimeoutError") {
6716
- return `\u274C [\u6293\u53D6\u8D85\u65F6]\uFF1A${FETCH_TIMEOUT_MS / 1e3}s \u5185\u672A\u54CD\u5E94\uFF1A${parsed.href}`;
6891
+ return `\u274C [\u6293\u53D6\u8D85\u65F6]\uFF1A${FETCH_TIMEOUT_MS2 / 1e3}s \u5185\u672A\u54CD\u5E94\uFF1A${parsed.href}`;
6717
6892
  }
6718
6893
  if (error?.name === "AbortError") {
6719
6894
  return `\u23F9\uFE0F [\u5DF2\u4E2D\u6B62]\uFF1A\u7528\u6237\u4E2D\u65AD\u4E86\u6293\u53D6\uFF1A${parsed.href}`;
@@ -6882,8 +7057,8 @@ var init_http = __esm({
6882
7057
 
6883
7058
  // ../core/src/tool/registry/typescript.ts
6884
7059
  import fs16 from "fs/promises";
6885
- import path19 from "path";
6886
- var MAX_FILE_BYTES, toDisplayPath, precheck, MAX_DIAG_ENTRIES, typescriptTools;
7060
+ import path20 from "path";
7061
+ var MAX_FILE_BYTES, toDisplayPath, precheck, MAX_DIAG_ENTRIES, MAX_DIAG_FILES, diagnoseOneFile, typescriptTools;
6887
7062
  var init_typescript = __esm({
6888
7063
  "../core/src/tool/registry/typescript.ts"() {
6889
7064
  "use strict";
@@ -6893,8 +7068,8 @@ var init_typescript = __esm({
6893
7068
  init_fs();
6894
7069
  MAX_FILE_BYTES = 1024 * 1024;
6895
7070
  toDisplayPath = (wsRoot, abs) => {
6896
- const rel = path19.relative(wsRoot, abs);
6897
- if (rel && !rel.startsWith("..") && !path19.isAbsolute(rel)) return rel.replace(/\\/g, "/");
7071
+ const rel = path20.relative(wsRoot, abs);
7072
+ if (rel && !rel.startsWith("..") && !path20.isAbsolute(rel)) return rel.replace(/\\/g, "/");
6898
7073
  return abs.replace(/\\/g, "/").split("/").slice(-3).join("/");
6899
7074
  };
6900
7075
  precheck = async (displayPath, absPath) => {
@@ -6907,74 +7082,108 @@ var init_typescript = __esm({
6907
7082
  return null;
6908
7083
  };
6909
7084
  MAX_DIAG_ENTRIES = 300;
7085
+ MAX_DIAG_FILES = 20;
7086
+ diagnoseOneFile = async (TS, displayPath, checkJs) => {
7087
+ try {
7088
+ const absPath = realpathNative(resolveReadablePath(displayPath));
7089
+ const block = await precheck(displayPath, absPath);
7090
+ if (block) return { ok: false, text: block };
7091
+ const { ls } = await getLanguageService(TS, absPath, { checkJs });
7092
+ const syntactic = ls.getSyntacticDiagnostics(absPath);
7093
+ const semantic = ls.getSemanticDiagnostics(absPath);
7094
+ const all = [...syntactic, ...semantic];
7095
+ if (all.length === 0) return { ok: true, errors: 0, warnings: 0, text: `\u2713 No diagnostics (0 errors, 0 warnings) for ${displayPath}` };
7096
+ const entries = [];
7097
+ let errors = 0, warnings = 0;
7098
+ for (const d of all) {
7099
+ const cat = d.category;
7100
+ let label;
7101
+ if (cat === TS.DiagnosticCategory.Error) {
7102
+ label = "error";
7103
+ errors++;
7104
+ } else if (cat === TS.DiagnosticCategory.Warning) {
7105
+ label = "warning";
7106
+ warnings++;
7107
+ } else if (cat === TS.DiagnosticCategory.Suggestion) label = "suggestion";
7108
+ else label = "info";
7109
+ let line = 0, column = 0;
7110
+ if (d.file && typeof d.start === "number") {
7111
+ ({ line, column } = posToLineCol(TS, d.file, d.start));
7112
+ }
7113
+ entries.push({
7114
+ line,
7115
+ column,
7116
+ label,
7117
+ code: typeof d.code === "number" ? `TS${d.code}` : "",
7118
+ msg: TS.flattenDiagnosticMessageText(d.messageText, "\n")
7119
+ });
7120
+ }
7121
+ entries.sort((a, b) => a.line - b.line || a.column - b.column);
7122
+ const overflow = entries.length > MAX_DIAG_ENTRIES ? entries.length - MAX_DIAG_ENTRIES : 0;
7123
+ const shown = overflow ? entries.slice(0, MAX_DIAG_ENTRIES) : entries;
7124
+ const body = shown.map(
7125
+ (e) => `${displayPath}:${e.line}:${e.column} ${e.label}${e.code ? " " + e.code : ""} ${e.msg}`
7126
+ ).join("\n");
7127
+ const tail = overflow ? `
7128
+ \u2026(\u53E6\u6709 ${overflow} \u6761\u8BCA\u65AD\u672A\u663E\u793A\uFF0C\u8BF7\u7F29\u5C0F\u8303\u56F4\u6216\u7528 run_command \u8DD1 tsc \u770B\u5168\u91CF)\u2026` : "";
7129
+ return { ok: true, errors, warnings, text: `[Diagnostics: ${displayPath}] ${errors} error(s), ${warnings} warning(s)
7130
+ ${body}${tail}` };
7131
+ } catch (e) {
7132
+ return { ok: false, text: `\u274C \u7C7B\u578B\u8BCA\u65AD\u5931\u8D25 [${displayPath}]: ${e?.message ?? e}` };
7133
+ }
7134
+ };
6910
7135
  typescriptTools = [
6911
7136
  {
6912
7137
  type: "function",
6913
7138
  function: {
6914
7139
  name: "get_diagnostics",
6915
- description: "\u5BF9\u5355\u4E2A TS/JS \u6587\u4EF6\u53D6 TypeScript \u8BED\u6CD5 + \u8BED\u4E49\u8BCA\u65AD\uFF08\u7C7B\u578B\u9519\u8BEF\u3001\u672A\u7528\u53D8\u91CF\u3001\u4E0D\u53EF\u8FBE\u4EE3\u7801\u7B49\uFF09\uFF0C\u8F93\u51FA\u5E26\u884C\u53F7/\u5217/\u4E25\u91CD\u5EA6/TS \u9519\u8BEF\u7801\uFF0C\u683C\u5F0F\u5BF9\u9F50 tsc\u3002\u7528\u4E8E\u7CBE\u51C6\u5B9A\u4F4D\u7F16\u8BD1/\u7C7B\u578B\u95EE\u9898\uFF0C\u66FF\u4EE3\u624B\u52A8\u8DD1 tsc \u518D\u89E3\u6790\u8F93\u51FA\u3002\u652F\u6301 .ts/.tsx/.js/.jsx/.mjs/.cjs\uFF1B.vue SFC \u4E0D\u652F\u6301\uFF08\u9700 vue-tsc\uFF09\u3002\u9879\u76EE\u7EA7\u5168\u91CF\u8BCA\u65AD\u8BF7\u7528 run_command \u8DD1 `tsc --noEmit`\u3002\u4F9D\u8D56 typescript \u6A21\u5757\uFF08VSCode \u6269\u5C55\u5185\u53EF\u7528\uFF1B\u7F3A\u5931\u5219\u672C\u5DE5\u5177\u81EA\u52A8\u9690\u85CF\uFF09\u3002",
7140
+ description: "\u5BF9\u4E00\u4E2A\u6216\u591A\u4E2A TS/JS \u6587\u4EF6\u53D6 TypeScript \u8BED\u6CD5 + \u8BED\u4E49\u8BCA\u65AD\uFF08\u7C7B\u578B\u9519\u8BEF\u3001\u672A\u7528\u53D8\u91CF\u3001\u4E0D\u53EF\u8FBE\u4EE3\u7801\u7B49\uFF09\uFF0C\u8F93\u51FA\u5E26\u884C\u53F7/\u5217/\u4E25\u91CD\u5EA6/TS \u9519\u8BEF\u7801\uFF0C\u683C\u5F0F\u5BF9\u9F50 tsc\u3002\u7528\u4E8E\u7CBE\u51C6\u5B9A\u4F4D\u7F16\u8BD1/\u7C7B\u578B\u95EE\u9898\uFF0C\u66FF\u4EE3\u624B\u52A8\u8DD1 tsc \u518D\u89E3\u6790\u8F93\u51FA\u3002\u2605 \u6539\u5B8C\u591A\u4E2A\u6587\u4EF6\u540E\u9A8C\u8BC1\uFF1A\u4F20 paths \u6570\u7EC4\u4E00\u6B21\u8BCA\u65AD\u5168\u90E8\uFF08\u6700\u591A 20 \u4E2A\uFF09\uFF0C\u52FF\u9010\u6587\u4EF6\u591A\u6B21\u8C03\u7528\u3002\u652F\u6301 .ts/.tsx/.js/.jsx/.mjs/.cjs\uFF1B.vue SFC \u4E0D\u652F\u6301\uFF08\u9700 vue-tsc\uFF09\u3002\u9879\u76EE\u7EA7\u5168\u91CF\u8BCA\u65AD\u8BF7\u7528 run_command \u8DD1 `tsc --noEmit`\u3002\u4F9D\u8D56 typescript \u6A21\u5757\uFF08VSCode \u6269\u5C55\u5185\u53EF\u7528\uFF1B\u7F3A\u5931\u5219\u672C\u5DE5\u5177\u81EA\u52A8\u9690\u85CF\uFF09\u3002",
6916
7141
  parameters: {
6917
7142
  type: "object",
6918
7143
  properties: {
6919
- path: { type: "string", description: "\u76EE\u6807\u6587\u4EF6\u76F8\u5BF9\u8DEF\u5F84\uFF08\u5982 'src/services/user.ts'\uFF09" },
7144
+ path: { type: "string", description: "\u76EE\u6807\u6587\u4EF6\u76F8\u5BF9\u8DEF\u5F84\uFF08\u5982 'src/services/user.ts'\uFF09\u3002\u5355\u6587\u4EF6\u8BCA\u65AD\u7528\uFF1B\u6279\u91CF\u8BF7\u6539\u7528 paths" },
7145
+ paths: { type: "array", items: { type: "string" }, description: "\u2605 \u6279\u91CF\u8BCA\u65AD\uFF1A\u591A\u4E2A\u6587\u4EF6\u4E00\u6B21\u9A8C\u8BC1\uFF08\u5355\u6B21\u6700\u591A 20 \u4E2A\uFF0C\u8D85\u51FA\u4F1A\u62D2\u7EDD\uFF09\u3002\u4F20\u4E86 paths \u5219\u5FFD\u7565 path" },
6920
7146
  check_js: { type: "boolean", description: "\u5BF9 .js/.jsx \u6587\u4EF6\u5F00\u542F\u8BED\u4E49\u68C0\u67E5\uFF08\u9ED8\u8BA4\u9075 tsconfig \u7684 checkJs\uFF1B\u76EE\u6807\u4E3A JS \u4E14\u60F3\u8981\u7C7B\u578B\u8BCA\u65AD\u65F6\u6309\u9700\u7F6E true\uFF09" }
6921
7147
  },
6922
- required: ["path"]
7148
+ required: []
6923
7149
  },
6924
7150
  safetyLevel: "safe" /* SAFE */,
6925
7151
  isSync: true,
6926
- maxOutputCharacters: 24e3,
7152
+ maxOutputCharacters: 48e3,
7153
+ // ★ 批量多文件后上调(原单文件 24K;中心 truncateToolResult 仍是最终兜底)
6927
7154
  privacyMaskingRules: maskSecretsInContent,
6928
7155
  validateEnvironment: async () => !!await getTs(),
6929
7156
  async execute(args, _ctx) {
6930
7157
  try {
6931
7158
  const TS = await getTs();
6932
7159
  if (!TS) return `\u26A0\uFE0F [\u7C7B\u578B\u8BCA\u65AD\u4E0D\u53EF\u7528]\uFF1Atypescript \u6A21\u5757\u672A\u52A0\u8F7D\uFF08VSCode \u6269\u5C55\u5185\u53EF\u7528\uFF1BCLI \u73AF\u5883\u672A\u5FC5\u5B89\u88C5 typescript\uFF09\u3002\u53EF\u6539\u7528 run_command \u8DD1 \`tsc --noEmit\`\u3002`;
6933
- const absPath = realpathNative(resolveReadablePath(args.path));
6934
- const block = await precheck(args.path, absPath);
6935
- if (block) return block;
6936
- const { ls } = await getLanguageService(TS, absPath, { checkJs: args.check_js });
6937
- const syntactic = ls.getSyntacticDiagnostics(absPath);
6938
- const semantic = ls.getSemanticDiagnostics(absPath);
6939
- const all = [...syntactic, ...semantic];
6940
- if (all.length === 0) return `\u2713 No diagnostics (0 errors, 0 warnings) for ${args.path}`;
6941
- const entries = [];
6942
- let errors = 0, warnings = 0;
6943
- for (const d of all) {
6944
- const cat = d.category;
6945
- let label;
6946
- if (cat === TS.DiagnosticCategory.Error) {
6947
- label = "error";
6948
- errors++;
6949
- } else if (cat === TS.DiagnosticCategory.Warning) {
6950
- label = "warning";
6951
- warnings++;
6952
- } else if (cat === TS.DiagnosticCategory.Suggestion) label = "suggestion";
6953
- else label = "info";
6954
- let line = 0, column = 0;
6955
- if (d.file && typeof d.start === "number") {
6956
- ({ line, column } = posToLineCol(TS, d.file, d.start));
7160
+ const targets = args.paths && args.paths.length > 0 ? args.paths : args.path ? [args.path] : [];
7161
+ if (targets.length === 0) return `\u274C [\u53C2\u6570\u7F3A\u5931]\uFF1A\u8BF7\u4F20 path\uFF08\u5355\u6587\u4EF6\uFF09\u6216 paths\uFF08\u6279\u91CF\uFF0C\u6539\u5B8C\u591A\u4E2A\u6587\u4EF6\u540E\u4E00\u6B21\u9A8C\u8BC1\uFF09\u3002`;
7162
+ if (targets.length > MAX_DIAG_FILES) return `\u274C [\u53C2\u6570\u8D85\u9650]\uFF1A\u5355\u6B21\u6279\u91CF\u8BCA\u65AD\u6700\u591A ${MAX_DIAG_FILES} \u4E2A\u6587\u4EF6\uFF08\u6536\u5230 ${targets.length} \u4E2A\uFF09\u3002\u8BF7\u5206\u6279\u8C03\u7528\uFF0C\u6216\u7528 run_command \u8DD1 \`tsc --noEmit\` \u505A\u9879\u76EE\u7EA7\u5168\u91CF\u8BCA\u65AD\u3002`;
7163
+ const results = [];
7164
+ for (const p of targets) results.push(await diagnoseOneFile(TS, p, args.check_js));
7165
+ if (results.length === 1) return results[0].text;
7166
+ let totalErr = 0, totalWarn = 0, clean = 0, failed = 0;
7167
+ const sections = [];
7168
+ for (let i = 0; i < results.length; i++) {
7169
+ const r = results[i];
7170
+ if (!r.ok) {
7171
+ failed++;
7172
+ sections.push(`\u2014\u2014 ${targets[i]}\uFF08\u8BCA\u65AD\u672A\u4EA7\u51FA\uFF09\u2014\u2014
7173
+ ${r.text}`);
7174
+ continue;
6957
7175
  }
6958
- entries.push({
6959
- line,
6960
- column,
6961
- label,
6962
- code: typeof d.code === "number" ? `TS${d.code}` : "",
6963
- msg: TS.flattenDiagnosticMessageText(d.messageText, "\n")
6964
- });
7176
+ totalErr += r.errors;
7177
+ totalWarn += r.warnings;
7178
+ if (r.errors === 0 && r.warnings === 0) clean++;
7179
+ sections.push(`\u2014\u2014 ${targets[i]} \u2014\u2014
7180
+ ${r.text}`);
6965
7181
  }
6966
- entries.sort((a, b) => a.line - b.line || a.column - b.column);
6967
- const overflow = entries.length > MAX_DIAG_ENTRIES ? entries.length - MAX_DIAG_ENTRIES : 0;
6968
- const shown = overflow ? entries.slice(0, MAX_DIAG_ENTRIES) : entries;
6969
- const body = shown.map(
6970
- (e) => `${args.path}:${e.line}:${e.column} ${e.label}${e.code ? " " + e.code : ""} ${e.msg}`
6971
- ).join("\n");
6972
- const tail = overflow ? `
6973
- \u2026(\u53E6\u6709 ${overflow} \u6761\u8BCA\u65AD\u672A\u663E\u793A\uFF0C\u8BF7\u7F29\u5C0F\u8303\u56F4\u6216\u7528 run_command \u8DD1 tsc \u770B\u5168\u91CF)\u2026` : "";
6974
- return `[Diagnostics: ${args.path}] ${errors} error(s), ${warnings} warning(s)
6975
- ${body}${tail}`;
7182
+ return `[\u6279\u91CF\u8BCA\u65AD: ${targets.length} \u4E2A\u6587\u4EF6] \u5171 ${totalErr} error(s), ${totalWarn} warning(s)\uFF1B${clean} \u4E2A\u6587\u4EF6\u5E72\u51C0${failed ? `\uFF0C${failed} \u4E2A\u8BCA\u65AD\u5931\u8D25` : ""}
7183
+
7184
+ ${sections.join("\n\n")}`;
6976
7185
  } catch (e) {
6977
- return `\u274C \u7C7B\u578B\u8BCA\u65AD\u5931\u8D25 [${args.path}]: ${e?.message ?? e}`;
7186
+ return `\u274C \u7C7B\u578B\u8BCA\u65AD\u5931\u8D25: ${e?.message ?? e}`;
6978
7187
  }
6979
7188
  }
6980
7189
  }
@@ -7119,7 +7328,7 @@ var init_todo = __esm({
7119
7328
 
7120
7329
  // ../core/src/observability/traceCalculate.ts
7121
7330
  import fs17 from "fs/promises";
7122
- import path20 from "path";
7331
+ import path21 from "path";
7123
7332
  var getDirBytes, getTodayDateString;
7124
7333
  var init_traceCalculate = __esm({
7125
7334
  "../core/src/observability/traceCalculate.ts"() {
@@ -7136,7 +7345,7 @@ var init_traceCalculate = __esm({
7136
7345
  continue;
7137
7346
  }
7138
7347
  for (const e of entries) {
7139
- const p = path20.join(cur, e.name);
7348
+ const p = path21.join(cur, e.name);
7140
7349
  if (e.isDirectory()) {
7141
7350
  stack.push(p);
7142
7351
  } else {
@@ -7160,7 +7369,7 @@ var init_traceCalculate = __esm({
7160
7369
  });
7161
7370
 
7162
7371
  // ../core/src/tool/undo/store.ts
7163
- import path21 from "path";
7372
+ import path22 from "path";
7164
7373
  import fs18 from "fs/promises";
7165
7374
  var getUndoRootPath, getUndoClockPath, getUndoDirPath, getUndoBackupRoot, ensureUndoDir, getUndoIndexPath;
7166
7375
  var init_store2 = __esm({
@@ -7169,14 +7378,14 @@ var init_store2 = __esm({
7169
7378
  init_config();
7170
7379
  init_common();
7171
7380
  init_traceCalculate();
7172
- getUndoRootPath = () => path21.join(appConfig.dataDir, "undo");
7173
- getUndoClockPath = () => path21.join(getUndoRootPath(), "undo-cleanup-clock.json");
7381
+ getUndoRootPath = () => path22.join(appConfig.dataDir, "undo");
7382
+ getUndoClockPath = () => path22.join(getUndoRootPath(), "undo-cleanup-clock.json");
7174
7383
  getUndoDirPath = (mainSessionId) => {
7175
7384
  const rootId = getFileName(mainSessionId);
7176
7385
  assertSafeSessionId(rootId, "undoSessionId");
7177
- return path21.join(getUndoRootPath(), appConfig.userWorkspaceDir, rootId);
7386
+ return path22.join(getUndoRootPath(), appConfig.userWorkspaceDir, rootId);
7178
7387
  };
7179
- getUndoBackupRoot = (mainSessionId) => path21.join(getUndoDirPath(mainSessionId), "backups");
7388
+ getUndoBackupRoot = (mainSessionId) => path22.join(getUndoDirPath(mainSessionId), "backups");
7180
7389
  ensureUndoDir = async (mainSessionId) => {
7181
7390
  await fs18.mkdir(getUndoDirPath(mainSessionId), { recursive: true, mode: 448 });
7182
7391
  };
@@ -7188,14 +7397,14 @@ var init_store2 = __esm({
7188
7397
  const files = await fs18.readdir(dir);
7189
7398
  const existedFile = files.find((f) => f.endsWith(`__${rootId}.jsonl`));
7190
7399
  const fileName = existedFile ?? `undo-${getTodayDateString()}__${rootId}.jsonl`;
7191
- return path21.join(dir, fileName);
7400
+ return path22.join(dir, fileName);
7192
7401
  };
7193
7402
  }
7194
7403
  });
7195
7404
 
7196
7405
  // ../core/src/tool/undo/index.ts
7197
7406
  import fs19 from "fs/promises";
7198
- import path22 from "path";
7407
+ import path23 from "path";
7199
7408
  var undoLocks, withUndoLock, appendUndoRecord, readUndoIndex, markRestored;
7200
7409
  var init_undo = __esm({
7201
7410
  "../core/src/tool/undo/index.ts"() {
@@ -7245,7 +7454,7 @@ var init_undo = __esm({
7245
7454
  for (const f of files) {
7246
7455
  if (!f.startsWith("undo-") || !f.endsWith(".jsonl")) continue;
7247
7456
  try {
7248
- const raw = await fs19.readFile(path22.join(dir, f), "utf-8");
7457
+ const raw = await fs19.readFile(path23.join(dir, f), "utf-8");
7249
7458
  for (const line of raw.split("\n")) {
7250
7459
  const trimmed = line.trim();
7251
7460
  if (!trimmed) continue;
@@ -7276,7 +7485,7 @@ var init_undo = __esm({
7276
7485
  }
7277
7486
  for (const f of files) {
7278
7487
  if (!f.startsWith("undo-") || !f.endsWith(".jsonl")) continue;
7279
- const fp = path22.join(dir, f);
7488
+ const fp = path23.join(dir, f);
7280
7489
  let raw;
7281
7490
  try {
7282
7491
  raw = await fs19.readFile(fp, "utf-8");
@@ -7314,7 +7523,7 @@ var init_undo = __esm({
7314
7523
 
7315
7524
  // ../core/src/tool/undo/cleanup.ts
7316
7525
  import fs20 from "fs/promises";
7317
- import path23 from "path";
7526
+ import path24 from "path";
7318
7527
  async function maybeCleanupAfterUndoAppend(_sessionId) {
7319
7528
  if (cleanupInProgress) return;
7320
7529
  cleanupInProgress = true;
@@ -7340,7 +7549,7 @@ async function maybeCleanupAfterUndoAppend(_sessionId) {
7340
7549
  lastSizeCleanupAt = now;
7341
7550
  diskLastCleanupAt = now;
7342
7551
  const clockPath = getUndoClockPath();
7343
- await fs20.mkdir(path23.dirname(clockPath), { recursive: true });
7552
+ await fs20.mkdir(path24.dirname(clockPath), { recursive: true });
7344
7553
  await fs20.writeFile(clockPath, JSON.stringify({ lastCleanupAt: now, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2), "utf-8");
7345
7554
  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`);
7346
7555
  } catch (e) {
@@ -7365,12 +7574,12 @@ async function cleanupOldUndoFiles() {
7365
7574
  const re = /^undo-(\d{4}-\d{2}-\d{2})__([\w-]+)\.jsonl$/;
7366
7575
  let deleted = 0;
7367
7576
  for (const rp of relativePaths) {
7368
- const fileName = path23.basename(rp);
7577
+ const fileName = path24.basename(rp);
7369
7578
  const m = fileName.match(re);
7370
7579
  if (!m) continue;
7371
7580
  const fileBornDay = /* @__PURE__ */ new Date(`${m[1]}T00:00:00`);
7372
7581
  if (fileBornDay >= cutoff) continue;
7373
- const fullPath = path23.join(dir, rp);
7582
+ const fullPath = path24.join(dir, rp);
7374
7583
  try {
7375
7584
  const st = await fs20.stat(fullPath);
7376
7585
  if (now - st.mtimeMs < ACTIVE_GRACE_MS) continue;
@@ -7392,10 +7601,10 @@ async function evictOldestForSize(targetBytes) {
7392
7601
  const re = /^undo-(\d{4}-\d{2}-\d{2})__([\w-]+)\.jsonl$/;
7393
7602
  const candidates = [];
7394
7603
  for (const rp of relativePaths) {
7395
- if (!re.test(path23.basename(rp))) continue;
7604
+ if (!re.test(path24.basename(rp))) continue;
7396
7605
  try {
7397
- const st = await fs20.stat(path23.join(dir, rp));
7398
- candidates.push({ mtime: st.mtimeMs, fullPath: path23.join(dir, rp), size: st.size });
7606
+ const st = await fs20.stat(path24.join(dir, rp));
7607
+ candidates.push({ mtime: st.mtimeMs, fullPath: path24.join(dir, rp), size: st.size });
7399
7608
  } catch {
7400
7609
  }
7401
7610
  }
@@ -7424,7 +7633,7 @@ async function gcOrphanBackups() {
7424
7633
  return 0;
7425
7634
  }
7426
7635
  for (const ws of workspaces) {
7427
- const wsDir = path23.join(root, ws);
7636
+ const wsDir = path24.join(root, ws);
7428
7637
  let stWs;
7429
7638
  try {
7430
7639
  stWs = await fs20.stat(wsDir);
@@ -7439,7 +7648,7 @@ async function gcOrphanBackups() {
7439
7648
  continue;
7440
7649
  }
7441
7650
  for (const sess of sessions2) {
7442
- const sessDir = path23.join(wsDir, sess);
7651
+ const sessDir = path24.join(wsDir, sess);
7443
7652
  const liveIds = /* @__PURE__ */ new Set();
7444
7653
  let files;
7445
7654
  try {
@@ -7450,7 +7659,7 @@ async function gcOrphanBackups() {
7450
7659
  for (const f of files) {
7451
7660
  if (!f.startsWith("undo-") || !f.endsWith(".jsonl")) continue;
7452
7661
  try {
7453
- const raw = await fs20.readFile(path23.join(sessDir, f), "utf-8");
7662
+ const raw = await fs20.readFile(path24.join(sessDir, f), "utf-8");
7454
7663
  for (const line of raw.split("\n")) {
7455
7664
  const t = line.trim();
7456
7665
  if (!t) continue;
@@ -7463,7 +7672,7 @@ async function gcOrphanBackups() {
7463
7672
  } catch {
7464
7673
  }
7465
7674
  }
7466
- const backupsDir = path23.join(sessDir, "backups");
7675
+ const backupsDir = path24.join(sessDir, "backups");
7467
7676
  let undoDirs;
7468
7677
  try {
7469
7678
  undoDirs = await fs20.readdir(backupsDir);
@@ -7473,7 +7682,7 @@ async function gcOrphanBackups() {
7473
7682
  for (const ud of undoDirs) {
7474
7683
  if (liveIds.has(ud)) continue;
7475
7684
  try {
7476
- await fs20.rm(path23.join(backupsDir, ud), { recursive: true, force: true });
7685
+ await fs20.rm(path24.join(backupsDir, ud), { recursive: true, force: true });
7477
7686
  deleted += 1;
7478
7687
  } catch {
7479
7688
  }
@@ -7516,7 +7725,7 @@ var init_cleanup = __esm({
7516
7725
  return 0;
7517
7726
  }
7518
7727
  for (const e of entries) {
7519
- const full = path23.join(dir, e.name);
7728
+ const full = path24.join(dir, e.name);
7520
7729
  if (e.isDirectory()) {
7521
7730
  total += await getDirBytesRecursive(full);
7522
7731
  } else if (e.isFile()) {
@@ -7533,7 +7742,7 @@ var init_cleanup = __esm({
7533
7742
 
7534
7743
  // ../core/src/tool/undo/backup.ts
7535
7744
  import fs21 from "fs/promises";
7536
- import path24 from "path";
7745
+ import path25 from "path";
7537
7746
  import crypto from "crypto";
7538
7747
  async function beforeMutationBackup(toolName, args, toolCallId, sessionId) {
7539
7748
  if (appConfig.undoEnabled === false) return null;
@@ -7548,7 +7757,7 @@ async function beforeMutationBackup(toolName, args, toolCallId, sessionId) {
7548
7757
  }
7549
7758
  await ensureUndoDir(sessionId);
7550
7759
  const undoId = createUUID();
7551
- const undoDir = path24.join(getUndoBackupRoot(sessionId), undoId);
7760
+ const undoDir = path25.join(getUndoBackupRoot(sessionId), undoId);
7552
7761
  const now = /* @__PURE__ */ new Date();
7553
7762
  const common = {
7554
7763
  undoId,
@@ -7598,7 +7807,7 @@ async function backupFileOverwrite(common, undoDir, args) {
7598
7807
  }
7599
7808
  const content = await fs21.readFile(absPath);
7600
7809
  await fs21.mkdir(undoDir, { recursive: true, mode: 448 });
7601
- const contentPath = path24.join(undoDir, "content");
7810
+ const contentPath = path25.join(undoDir, "content");
7602
7811
  await fs21.writeFile(contentPath, content, { mode: 384 });
7603
7812
  return {
7604
7813
  ...common,
@@ -7635,7 +7844,7 @@ async function backupDelete(common, undoDir, relativePath) {
7635
7844
  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`);
7636
7845
  }
7637
7846
  }
7638
- const treeDest = path24.join(undoDir, "tree");
7847
+ const treeDest = path25.join(undoDir, "tree");
7639
7848
  const sensitiveSet = new Set(sensitiveInTree);
7640
7849
  await fs21.cp(absPath, treeDest, {
7641
7850
  recursive: true,
@@ -7643,7 +7852,7 @@ async function backupDelete(common, undoDir, relativePath) {
7643
7852
  preserveTimestamps: true,
7644
7853
  filter: (src) => {
7645
7854
  if (src === absPath) return true;
7646
- const relWithin = path24.relative(absPath, src).replace(/\\/g, "/");
7855
+ const relWithin = path25.relative(absPath, src).replace(/\\/g, "/");
7647
7856
  return !sensitiveSet.has(relWithin);
7648
7857
  }
7649
7858
  });
@@ -7660,7 +7869,7 @@ async function backupDelete(common, undoDir, relativePath) {
7660
7869
  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`);
7661
7870
  }
7662
7871
  const content = await fs21.readFile(absPath);
7663
- const contentPath = path24.join(undoDir, "content");
7872
+ const contentPath = path25.join(undoDir, "content");
7664
7873
  await fs21.writeFile(contentPath, content, { mode: 384 });
7665
7874
  return {
7666
7875
  ...common,
@@ -7712,8 +7921,8 @@ var init_backup = __esm({
7712
7921
  }
7713
7922
  entries.sort((a, b) => a.name.localeCompare(b.name));
7714
7923
  for (const e of entries) {
7715
- const full = path24.join(d, e.name);
7716
- const rel = path24.relative(dir, full).replace(/\\/g, "/");
7924
+ const full = path25.join(d, e.name);
7925
+ const rel = path25.relative(dir, full).replace(/\\/g, "/");
7717
7926
  if (e.isDirectory()) {
7718
7927
  h.update(`D ${rel}
7719
7928
  `);
@@ -7739,7 +7948,7 @@ var init_backup = __esm({
7739
7948
  return 0;
7740
7949
  }
7741
7950
  for (const e of entries) {
7742
- const full = path24.join(dir, e.name);
7951
+ const full = path25.join(dir, e.name);
7743
7952
  if (e.isDirectory()) total += await getDirTreeBytes(full);
7744
7953
  else if (e.isFile()) {
7745
7954
  try {
@@ -7760,11 +7969,11 @@ var init_backup = __esm({
7760
7969
  return;
7761
7970
  }
7762
7971
  for (const e of entries) {
7763
- const full = path24.join(d, e.name);
7972
+ const full = path25.join(d, e.name);
7764
7973
  if (e.isDirectory()) {
7765
7974
  await walk(full);
7766
7975
  } else if (e.isFile()) {
7767
- const relWithin = path24.relative(dir, full).replace(/\\/g, "/");
7976
+ const relWithin = path25.relative(dir, full).replace(/\\/g, "/");
7768
7977
  if (isSensitivePath(`${wsRelDir}/${relWithin}`)) found.push(relWithin);
7769
7978
  }
7770
7979
  }
@@ -7777,7 +7986,7 @@ var init_backup = __esm({
7777
7986
 
7778
7987
  // ../core/src/tool/undo/restore.ts
7779
7988
  import fs22 from "fs/promises";
7780
- import path25 from "path";
7989
+ import path26 from "path";
7781
7990
  import crypto2 from "crypto";
7782
7991
  async function doRestore(target, sessionId) {
7783
7992
  if (target.backupKind === "directory_tree") {
@@ -7835,16 +8044,16 @@ async function ensureReverseBackup(target, sessionId) {
7835
8044
  }
7836
8045
  }
7837
8046
  const reverseId = createUUID();
7838
- const reverseDir = path25.join(getUndoBackupRoot(sessionId), reverseId);
8047
+ const reverseDir = path26.join(getUndoBackupRoot(sessionId), reverseId);
7839
8048
  await fs22.mkdir(reverseDir, { recursive: true, mode: 448 });
7840
8049
  assertWithinWorkspace(absPath);
7841
8050
  const st = await fs22.stat(absPath);
7842
8051
  if (st.isDirectory()) {
7843
- const dest2 = path25.join(reverseDir, "tree");
8052
+ const dest2 = path26.join(reverseDir, "tree");
7844
8053
  await fs22.cp(absPath, dest2, { recursive: true, force: true, preserveTimestamps: true });
7845
8054
  return { reverseId, backupKind: "directory_tree", backupPath: dest2 };
7846
8055
  }
7847
- const dest = path25.join(reverseDir, "content");
8056
+ const dest = path26.join(reverseDir, "content");
7848
8057
  await fs22.writeFile(dest, await fs22.readFile(absPath));
7849
8058
  return { reverseId, backupKind: "file_content", backupPath: dest };
7850
8059
  }
@@ -7857,15 +8066,15 @@ async function dispatchRestore(r) {
7857
8066
  return `\u5DF2\u5220\u9664\u65B0\u5EFA\u6587\u4EF6 [${r.relativePath}]`;
7858
8067
  }
7859
8068
  case "file_content": {
7860
- await fs22.mkdir(path25.dirname(absPath), { recursive: true });
7861
- const backupAbs = path25.join(getUndoBackupRoot(r.sessionId), r.undoId, "content");
8069
+ await fs22.mkdir(path26.dirname(absPath), { recursive: true });
8070
+ const backupAbs = path26.join(getUndoBackupRoot(r.sessionId), r.undoId, "content");
7862
8071
  const content = await fs22.readFile(backupAbs);
7863
8072
  await fs22.writeFile(absPath, content);
7864
8073
  return `\u5DF2\u6062\u590D [${r.relativePath}] \u81F3\u5907\u4EFD\u524D\u5185\u5BB9\uFF08${r.fileSizeBefore ?? content.byteLength} \u5B57\u8282\uFF09`;
7865
8074
  }
7866
8075
  case "directory_tree": {
7867
- await fs22.mkdir(path25.dirname(absPath), { recursive: true });
7868
- const src = path25.join(getUndoBackupRoot(r.sessionId), r.undoId, "tree");
8076
+ await fs22.mkdir(path26.dirname(absPath), { recursive: true });
8077
+ const src = path26.join(getUndoBackupRoot(r.sessionId), r.undoId, "tree");
7869
8078
  await fs22.cp(src, absPath, { recursive: true, force: true, preserveTimestamps: true });
7870
8079
  return `\u5DF2\u6062\u590D\u76EE\u5F55\u6811 [${r.relativePath}]\uFF08\u7EA6 ${r.fileSizeBefore ?? 0} \u5B57\u8282\uFF09`;
7871
8080
  }
@@ -8349,7 +8558,7 @@ var init_frontmatter = __esm({
8349
8558
 
8350
8559
  // ../core/src/memory/loader.ts
8351
8560
  import fs24 from "fs/promises";
8352
- import path26 from "path";
8561
+ import path27 from "path";
8353
8562
  var GLOBAL_MEMORY_DIR, SOURCES, VALID_TYPES, parseMemoryAt, loadMemories, initMemories;
8354
8563
  var init_loader3 = __esm({
8355
8564
  "../core/src/memory/loader.ts"() {
@@ -8358,10 +8567,10 @@ var init_loader3 = __esm({
8358
8567
  init_frontmatter();
8359
8568
  init_registry6();
8360
8569
  init_registry2();
8361
- GLOBAL_MEMORY_DIR = path26.join(appConfig.dataDir, "memory");
8570
+ GLOBAL_MEMORY_DIR = path27.join(appConfig.dataDir, "memory");
8362
8571
  SOURCES = [
8363
8572
  { dir: GLOBAL_MEMORY_DIR, source: "global" },
8364
- { dir: path26.join(process.cwd(), ".deepseeker-code", "memory"), source: "project" }
8573
+ { dir: path27.join(process.cwd(), ".deepseeker-code", "memory"), source: "project" }
8365
8574
  ];
8366
8575
  VALID_TYPES = ["user", "feedback", "project", "reference"];
8367
8576
  parseMemoryAt = async (file, _dir, source) => {
@@ -8401,7 +8610,7 @@ var init_loader3 = __esm({
8401
8610
  clearMemories();
8402
8611
  const picked = await scanSources(
8403
8612
  filterSources(SOURCES, includeProject),
8404
- (e, dir) => e.isFile() && e.name.endsWith(".md") ? path26.join(dir, e.name) : void 0,
8613
+ (e, dir) => e.isFile() && e.name.endsWith(".md") ? path27.join(dir, e.name) : void 0,
8405
8614
  parseMemoryAt
8406
8615
  );
8407
8616
  for (const { item } of picked) registerMemory(item);
@@ -8420,7 +8629,7 @@ var init_loader3 = __esm({
8420
8629
 
8421
8630
  // ../core/src/tool/registry/memory.ts
8422
8631
  import fs25 from "fs/promises";
8423
- import path27 from "path";
8632
+ import path28 from "path";
8424
8633
  var MAX_BODY_BYTES, NAME_RE, VALID_TYPES2, memoryFilePath, sanitizeLine, buildMemoryMd, writeAndRegister, memoryTools;
8425
8634
  var init_memory = __esm({
8426
8635
  "../core/src/tool/registry/memory.ts"() {
@@ -8432,7 +8641,7 @@ var init_memory = __esm({
8432
8641
  MAX_BODY_BYTES = 64 * 1024;
8433
8642
  NAME_RE = /^[a-z0-9-]+$/;
8434
8643
  VALID_TYPES2 = ["user", "feedback", "project", "reference"];
8435
- memoryFilePath = (name, project) => project ? path27.join(process.cwd(), ".deepseeker-code", "memory", `${name}.md`) : path27.join(GLOBAL_MEMORY_DIR, `${name}.md`);
8644
+ memoryFilePath = (name, project) => project ? path28.join(process.cwd(), ".deepseeker-code", "memory", `${name}.md`) : path28.join(GLOBAL_MEMORY_DIR, `${name}.md`);
8436
8645
  sanitizeLine = (s) => String(s ?? "").replace(/[\r\n]+/g, " ").trim();
8437
8646
  buildMemoryMd = (name, description, type, body) => `---
8438
8647
  name: ${name}
@@ -8444,7 +8653,7 @@ ${body.trim()}
8444
8653
  `;
8445
8654
  writeAndRegister = async (name, description, type, body, project) => {
8446
8655
  const file = memoryFilePath(name, project);
8447
- await fs25.mkdir(path27.dirname(file), { recursive: true });
8656
+ await fs25.mkdir(path28.dirname(file), { recursive: true });
8448
8657
  const tmp = makeTmpPath(file);
8449
8658
  await fs25.writeFile(tmp, buildMemoryMd(name, description, type, body), "utf-8");
8450
8659
  await fs25.rename(tmp, file);
@@ -8818,7 +9027,6 @@ var agentTools, agentSubTools, workflowTools;
8818
9027
  var init_tool = __esm({
8819
9028
  "../core/src/tool/index.ts"() {
8820
9029
  "use strict";
8821
- init_system();
8822
9030
  init_agent();
8823
9031
  init_workflow();
8824
9032
  init_fs();
@@ -8844,7 +9052,6 @@ var init_tool = __esm({
8844
9052
  agentSubTools = createAgentTools(() => agentTools);
8845
9053
  workflowTools = createWorkflowTools(() => agentTools);
8846
9054
  agentTools.push(
8847
- ...systemTools,
8848
9055
  ...agentSubTools,
8849
9056
  ...workflowTools,
8850
9057
  ...fsTools,
@@ -8986,7 +9193,7 @@ var init_backgroundTool = __esm({
8986
9193
  });
8987
9194
 
8988
9195
  // ../core/src/tool/autoPermission.ts
8989
- import path28 from "path";
9196
+ import path29 from "path";
8990
9197
  var AUTO_SCOPE, AUTO_DEFAULT_EXTRA, AUTO_AGGRESSIVE_EXTRA, isMcpTool, BUILTIN_AUTO_DENY, matchBuiltinDeny, COMMAND_DENY, matchCommandDeny, hasShellMetachars, READONLY_HEADS, hasWriteModifier, SENSITIVE_FILE_ARG_RE, hasSensitiveFileArg, isReadOnlyCommand, isWithinWorkspace, runAutoCheck;
8991
9198
  var init_autoPermission = __esm({
8992
9199
  "../core/src/tool/autoPermission.ts"() {
@@ -9121,9 +9328,9 @@ var init_autoPermission = __esm({
9121
9328
  isWithinWorkspace = (p, cwd) => {
9122
9329
  if (!p || !cwd) return false;
9123
9330
  try {
9124
- const abs = path28.isAbsolute(p) ? p : path28.resolve(cwd, p);
9125
- const rel = path28.relative(cwd, abs);
9126
- return rel === "" || !rel.startsWith("..") && !path28.isAbsolute(rel);
9331
+ const abs = path29.isAbsolute(p) ? p : path29.resolve(cwd, p);
9332
+ const rel = path29.relative(cwd, abs);
9333
+ return rel === "" || !rel.startsWith("..") && !path29.isAbsolute(rel);
9127
9334
  } catch {
9128
9335
  return false;
9129
9336
  }
@@ -10415,7 +10622,7 @@ var init_subagent = __esm({
10415
10622
 
10416
10623
  // ../core/src/hooks/loader.ts
10417
10624
  import fs27 from "fs/promises";
10418
- import path29 from "path";
10625
+ import path30 from "path";
10419
10626
  var readHooksConfig, appendValidated, validateRule, parseStdoutDecision, parseAgentDecision, compileRule2, loadHooks, initHooks;
10420
10627
  var init_loader4 = __esm({
10421
10628
  "../core/src/hooks/loader.ts"() {
@@ -10430,9 +10637,9 @@ var init_loader4 = __esm({
10430
10637
  readHooksConfig = async (includeProject) => {
10431
10638
  const merged = {};
10432
10639
  const paths = [
10433
- path29.join(appConfig.dataDir, "settings.json"),
10640
+ path30.join(appConfig.dataDir, "settings.json"),
10434
10641
  // 全局用户级
10435
- ...includeProject ? [path29.join(process.cwd(), ".deepseeker-code", "settings.json")] : []
10642
+ ...includeProject ? [path30.join(process.cwd(), ".deepseeker-code", "settings.json")] : []
10436
10643
  // 项目级(叠加);未信任时省略
10437
10644
  ];
10438
10645
  for (const configPath of paths) {
@@ -10769,8 +10976,8 @@ ${m.context}`;
10769
10976
 
10770
10977
  // ../core/src/skills/loader.ts
10771
10978
  import fs28 from "fs/promises";
10772
- import path30 from "path";
10773
- import { fileURLToPath } from "url";
10979
+ import path31 from "path";
10980
+ import { fileURLToPath as fileURLToPath2 } from "url";
10774
10981
  var BUILTIN_DIR, SOURCES2, MAX_SKILL_BODY_BYTES, splitList, parseSkillAt, loadSkills, initSkills;
10775
10982
  var init_loader5 = __esm({
10776
10983
  "../core/src/skills/loader.ts"() {
@@ -10780,11 +10987,11 @@ var init_loader5 = __esm({
10780
10987
  init_registry3();
10781
10988
  init_skill();
10782
10989
  init_registry2();
10783
- BUILTIN_DIR = path30.join(path30.dirname(fileURLToPath(import.meta.url)), "builtin");
10990
+ BUILTIN_DIR = path31.join(path31.dirname(fileURLToPath2(import.meta.url)), "builtin");
10784
10991
  SOURCES2 = [
10785
10992
  { dir: BUILTIN_DIR, source: "builtin" },
10786
- { dir: path30.join(appConfig.dataDir, "skills"), source: "global" },
10787
- { dir: path30.join(process.cwd(), ".deepseeker-code", "skills"), source: "project" }
10993
+ { dir: path31.join(appConfig.dataDir, "skills"), source: "global" },
10994
+ { dir: path31.join(process.cwd(), ".deepseeker-code", "skills"), source: "project" }
10788
10995
  ];
10789
10996
  MAX_SKILL_BODY_BYTES = 64 * 1024;
10790
10997
  splitList = (raw) => (raw ?? "").split(",").map((s) => s.trim()).filter(Boolean);
@@ -10830,7 +11037,7 @@ var init_loader5 = __esm({
10830
11037
  loadSkills = async (includeProject) => {
10831
11038
  const picked = await scanSources(
10832
11039
  filterSources(SOURCES2, includeProject),
10833
- (e, dir) => e.isDirectory() ? path30.join(dir, e.name, "SKILL.md") : void 0,
11040
+ (e, dir) => e.isDirectory() ? path31.join(dir, e.name, "SKILL.md") : void 0,
10834
11041
  parseSkillAt
10835
11042
  );
10836
11043
  for (const { item } of picked) registerSkill(item);
@@ -10862,8 +11069,8 @@ var init_loader5 = __esm({
10862
11069
 
10863
11070
  // ../core/src/agents/loader.ts
10864
11071
  import fs29 from "fs/promises";
10865
- import path31 from "path";
10866
- import { fileURLToPath as fileURLToPath2 } from "url";
11072
+ import path32 from "path";
11073
+ import { fileURLToPath as fileURLToPath3 } from "url";
10867
11074
  var BUILTIN_DIR2, SOURCES3, parseAgentAt, initAgents;
10868
11075
  var init_loader6 = __esm({
10869
11076
  "../core/src/agents/loader.ts"() {
@@ -10872,11 +11079,11 @@ var init_loader6 = __esm({
10872
11079
  init_frontmatter();
10873
11080
  init_registry4();
10874
11081
  init_registry2();
10875
- BUILTIN_DIR2 = path31.join(path31.dirname(fileURLToPath2(import.meta.url)), "builtin");
11082
+ BUILTIN_DIR2 = path32.join(path32.dirname(fileURLToPath3(import.meta.url)), "builtin");
10876
11083
  SOURCES3 = [
10877
11084
  { dir: BUILTIN_DIR2, source: "builtin" },
10878
- { dir: path31.join(appConfig.dataDir, "agents"), source: "global" },
10879
- { dir: path31.join(process.cwd(), ".deepseeker-code", "agents"), source: "project" }
11085
+ { dir: path32.join(appConfig.dataDir, "agents"), source: "global" },
11086
+ { dir: path32.join(process.cwd(), ".deepseeker-code", "agents"), source: "project" }
10880
11087
  ];
10881
11088
  parseAgentAt = async (file, dir, source) => {
10882
11089
  let raw;
@@ -10916,7 +11123,7 @@ var init_loader6 = __esm({
10916
11123
  const known = new Set(into.map((t) => t.function.name));
10917
11124
  const picked = await scanSources(
10918
11125
  filterSources(SOURCES3, includeProject),
10919
- (e, dir) => e.isFile() && e.name.endsWith(".agent.md") ? path31.join(dir, e.name) : void 0,
11126
+ (e, dir) => e.isFile() && e.name.endsWith(".agent.md") ? path32.join(dir, e.name) : void 0,
10920
11127
  parseAgentAt
10921
11128
  );
10922
11129
  for (const { item: m, file, source } of picked) {
@@ -10954,8 +11161,8 @@ var init_registry7 = __esm({
10954
11161
 
10955
11162
  // ../core/src/commands/loader.ts
10956
11163
  import fs30 from "fs/promises";
10957
- import path32 from "path";
10958
- import { fileURLToPath as fileURLToPath3 } from "url";
11164
+ import path33 from "path";
11165
+ import { fileURLToPath as fileURLToPath4 } from "url";
10959
11166
  var BUILTIN_DIR3, SOURCES4, MAX_COMMAND_BODY_BYTES, parseCommandAt, loadCommands, initCommands;
10960
11167
  var init_loader7 = __esm({
10961
11168
  "../core/src/commands/loader.ts"() {
@@ -10964,11 +11171,11 @@ var init_loader7 = __esm({
10964
11171
  init_frontmatter();
10965
11172
  init_registry7();
10966
11173
  init_registry2();
10967
- BUILTIN_DIR3 = path32.join(path32.dirname(fileURLToPath3(import.meta.url)), "builtin");
11174
+ BUILTIN_DIR3 = path33.join(path33.dirname(fileURLToPath4(import.meta.url)), "builtin");
10968
11175
  SOURCES4 = [
10969
11176
  { dir: BUILTIN_DIR3, source: "builtin" },
10970
- { dir: path32.join(appConfig.dataDir, "commands"), source: "global" },
10971
- { dir: path32.join(process.cwd(), ".deepseeker-code", "commands"), source: "project" }
11177
+ { dir: path33.join(appConfig.dataDir, "commands"), source: "global" },
11178
+ { dir: path33.join(process.cwd(), ".deepseeker-code", "commands"), source: "project" }
10972
11179
  ];
10973
11180
  MAX_COMMAND_BODY_BYTES = 64 * 1024;
10974
11181
  parseCommandAt = async (file, _dir, source) => {
@@ -10985,7 +11192,7 @@ var init_loader7 = __esm({
10985
11192
  }
10986
11193
  const name = parsed.frontmatter.name;
10987
11194
  const description = parsed.frontmatter.description;
10988
- const fallbackName = path32.basename(file, ".md");
11195
+ const fallbackName = path33.basename(file, ".md");
10989
11196
  const finalName = name || fallbackName;
10990
11197
  if (!description) {
10991
11198
  console.warn(`\u26A0\uFE0F [commands] \u7F3A\u5C11 description\uFF08${file}\uFF09\uFF0C\u5DF2\u8DF3\u8FC7`);
@@ -11011,7 +11218,7 @@ var init_loader7 = __esm({
11011
11218
  loadCommands = async (includeProject) => {
11012
11219
  const picked = await scanSources(
11013
11220
  filterSources(SOURCES4, includeProject),
11014
- (e, dir) => e.isFile() && e.name.endsWith(".md") ? path32.join(dir, e.name) : void 0,
11221
+ (e, dir) => e.isFile() && e.name.endsWith(".md") ? path33.join(dir, e.name) : void 0,
11015
11222
  parseCommandAt
11016
11223
  );
11017
11224
  for (const { item } of picked) registerCommand(item);
@@ -11030,8 +11237,8 @@ var init_loader7 = __esm({
11030
11237
 
11031
11238
  // ../core/src/outputStyles/loader.ts
11032
11239
  import fs31 from "fs/promises";
11033
- import path33 from "path";
11034
- import { fileURLToPath as fileURLToPath4 } from "url";
11240
+ import path34 from "path";
11241
+ import { fileURLToPath as fileURLToPath5 } from "url";
11035
11242
  var BUILTIN_DIR4, MAX_STYLE_BODY_BYTES, SOURCES5, parseStyleAt, loadOutputStyles, initOutputStyles;
11036
11243
  var init_loader8 = __esm({
11037
11244
  "../core/src/outputStyles/loader.ts"() {
@@ -11040,12 +11247,12 @@ var init_loader8 = __esm({
11040
11247
  init_frontmatter();
11041
11248
  init_registry5();
11042
11249
  init_registry2();
11043
- BUILTIN_DIR4 = path33.join(path33.dirname(fileURLToPath4(import.meta.url)), "builtin");
11250
+ BUILTIN_DIR4 = path34.join(path34.dirname(fileURLToPath5(import.meta.url)), "builtin");
11044
11251
  MAX_STYLE_BODY_BYTES = 64 * 1024;
11045
11252
  SOURCES5 = [
11046
11253
  { dir: BUILTIN_DIR4, source: "builtin" },
11047
- { dir: path33.join(appConfig.dataDir, "output-styles"), source: "global" },
11048
- { dir: path33.join(process.cwd(), ".deepseeker-code", "output-styles"), source: "project" }
11254
+ { dir: path34.join(appConfig.dataDir, "output-styles"), source: "global" },
11255
+ { dir: path34.join(process.cwd(), ".deepseeker-code", "output-styles"), source: "project" }
11049
11256
  ];
11050
11257
  parseStyleAt = async (file, _dir, source) => {
11051
11258
  let raw;
@@ -11082,7 +11289,7 @@ var init_loader8 = __esm({
11082
11289
  loadOutputStyles = async (includeProject) => {
11083
11290
  const picked = await scanSources(
11084
11291
  filterSources(SOURCES5, includeProject),
11085
- (e, dir) => e.isFile() && e.name.endsWith(".md") ? path33.join(dir, e.name) : void 0,
11292
+ (e, dir) => e.isFile() && e.name.endsWith(".md") ? path34.join(dir, e.name) : void 0,
11086
11293
  parseStyleAt
11087
11294
  );
11088
11295
  for (const { item } of picked) registerOutputStyle(item);
@@ -11164,7 +11371,7 @@ var init_bootstrap = __esm({
11164
11371
 
11165
11372
  // ../core/src/statusLine/config.ts
11166
11373
  import fs32 from "fs/promises";
11167
- import path34 from "path";
11374
+ import path35 from "path";
11168
11375
  var parseBlock, readStatusLineConfig;
11169
11376
  var init_config2 = __esm({
11170
11377
  "../core/src/statusLine/config.ts"() {
@@ -11180,9 +11387,9 @@ var init_config2 = __esm({
11180
11387
  };
11181
11388
  readStatusLineConfig = async (includeProject) => {
11182
11389
  const paths = [
11183
- path34.join(appConfig.dataDir, "settings.json"),
11390
+ path35.join(appConfig.dataDir, "settings.json"),
11184
11391
  // 全局用户级
11185
- ...includeProject ? [path34.join(process.cwd(), ".deepseeker-code", "settings.json")] : []
11392
+ ...includeProject ? [path35.join(process.cwd(), ".deepseeker-code", "settings.json")] : []
11186
11393
  // 项目级(覆盖);未信任时省略
11187
11394
  ];
11188
11395
  let result = null;
@@ -11210,8 +11417,8 @@ var init_config2 = __esm({
11210
11417
  // ../core/src/statusLine/runner.ts
11211
11418
  import { spawn as spawn5 } from "child_process";
11212
11419
  import fs33 from "fs";
11213
- import path35 from "path";
11214
- import { fileURLToPath as fileURLToPath5 } from "url";
11420
+ import path36 from "path";
11421
+ import { fileURLToPath as fileURLToPath6 } from "url";
11215
11422
  var STATUSLINE_TIMEOUT_MS, cachedVersion, runStatusLine;
11216
11423
  var init_runner = __esm({
11217
11424
  "../core/src/statusLine/runner.ts"() {
@@ -11219,11 +11426,11 @@ var init_runner = __esm({
11219
11426
  init_guard();
11220
11427
  STATUSLINE_TIMEOUT_MS = 3e3;
11221
11428
  try {
11222
- const here = path35.dirname(fileURLToPath5(import.meta.url));
11429
+ const here = path36.dirname(fileURLToPath6(import.meta.url));
11223
11430
  const candidates = [
11224
- path35.join(here, "../../../package.json"),
11431
+ path36.join(here, "../../../package.json"),
11225
11432
  // src/core/package.json
11226
- path35.join(here, "../../../../package.json")
11433
+ path36.join(here, "../../../../package.json")
11227
11434
  // 仓库根 package.json
11228
11435
  ];
11229
11436
  for (const p of candidates) {
@@ -11287,7 +11494,7 @@ var init_createModel = __esm({
11287
11494
  });
11288
11495
 
11289
11496
  // ../core/src/observability/store.ts
11290
- import path36 from "path";
11497
+ import path37 from "path";
11291
11498
  import fs34 from "fs/promises";
11292
11499
  var getTraceDirPath, getTracePath, tracePathCache, ensuredTraceDirs, ensureTraceDir, getGlobalClockPath, getTraceStorePath;
11293
11500
  var init_store3 = __esm({
@@ -11298,10 +11505,10 @@ var init_store3 = __esm({
11298
11505
  init_common();
11299
11506
  getTraceDirPath = (mainTraceId) => {
11300
11507
  assertSafeSessionId(mainTraceId, "traceId");
11301
- return path36.join(appConfig.dataDir, "trace", appConfig.userWorkspaceDir, getFileName(mainTraceId));
11508
+ return path37.join(appConfig.dataDir, "trace", appConfig.userWorkspaceDir, getFileName(mainTraceId));
11302
11509
  };
11303
11510
  getTracePath = () => {
11304
- return path36.join(appConfig.dataDir, "trace");
11511
+ return path37.join(appConfig.dataDir, "trace");
11305
11512
  };
11306
11513
  tracePathCache = /* @__PURE__ */ new Map();
11307
11514
  ensuredTraceDirs = /* @__PURE__ */ new Set();
@@ -11312,7 +11519,7 @@ var init_store3 = __esm({
11312
11519
  ensuredTraceDirs.add(dir);
11313
11520
  };
11314
11521
  getGlobalClockPath = () => {
11315
- return path36.join(getTracePath(), "trace-cleanup-clock.json");
11522
+ return path37.join(getTracePath(), "trace-cleanup-clock.json");
11316
11523
  };
11317
11524
  getTraceStorePath = async (mainTraceId) => {
11318
11525
  assertSafeSessionId(mainTraceId, "traceId");
@@ -11330,7 +11537,7 @@ var init_store3 = __esm({
11330
11537
  const todayStr = getTodayDateString();
11331
11538
  fileName = `trace-${todayStr}__${rootId}.jsonl`;
11332
11539
  }
11333
- const resolved = path36.join(dir, fileName);
11540
+ const resolved = path37.join(dir, fileName);
11334
11541
  tracePathCache.set(rootId, resolved);
11335
11542
  return resolved;
11336
11543
  };
@@ -11339,7 +11546,7 @@ var init_store3 = __esm({
11339
11546
 
11340
11547
  // ../core/src/observability/trace.ts
11341
11548
  import fs35 from "fs/promises";
11342
- import path37 from "path";
11549
+ import path38 from "path";
11343
11550
  async function emitTrace(base) {
11344
11551
  const event = {
11345
11552
  sessionId: base.sessionId,
@@ -11393,7 +11600,7 @@ async function maybeCleanupAfterAppend(sessionId) {
11393
11600
  lastSizeCleanupAt2 = now;
11394
11601
  diskLastCleanupAt2 = now;
11395
11602
  const clockPath = getGlobalClockPath();
11396
- await fs35.mkdir(path37.dirname(clockPath), { recursive: true });
11603
+ await fs35.mkdir(path38.dirname(clockPath), { recursive: true });
11397
11604
  await fs35.writeFile(clockPath, JSON.stringify({ lastCleanupAt: now, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2), "utf-8");
11398
11605
  if (deletedCount > 0) {
11399
11606
  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`);
@@ -11420,12 +11627,12 @@ async function cleanupOldTraceFiles() {
11420
11627
  }
11421
11628
  const re = /^trace-(\d{4}-\d{2}-\d{2})__([\w-]+)\.jsonl$/;
11422
11629
  for (const relativePath of relativePaths) {
11423
- const fileName = path37.basename(relativePath);
11630
+ const fileName = path38.basename(relativePath);
11424
11631
  const m = fileName.match(re);
11425
11632
  if (!m) continue;
11426
11633
  const fileBornDay = /* @__PURE__ */ new Date(`${m[1]}T00:00:00`);
11427
11634
  if (fileBornDay >= cutoff) continue;
11428
- const fullPath = path37.join(dir, relativePath);
11635
+ const fullPath = path38.join(dir, relativePath);
11429
11636
  try {
11430
11637
  const st = await fs35.stat(fullPath);
11431
11638
  if (now - st.mtimeMs < ACTIVE_GRACE_MS2) continue;
@@ -11447,11 +11654,11 @@ async function evictOldestForSize2(targetBytes) {
11447
11654
  const re = /^trace-(\d{4}-\d{2}-\d{2})__([\w-]+)\.jsonl$/;
11448
11655
  const candidates = [];
11449
11656
  for (const relativePath of relativePaths) {
11450
- const fileName = path37.basename(relativePath);
11657
+ const fileName = path38.basename(relativePath);
11451
11658
  if (!re.test(fileName)) continue;
11452
11659
  try {
11453
- const st = await fs35.stat(path37.join(dir, relativePath));
11454
- candidates.push({ mtime: st.mtimeMs, fullPath: path37.join(dir, relativePath), size: st.size });
11660
+ const st = await fs35.stat(path38.join(dir, relativePath));
11661
+ candidates.push({ mtime: st.mtimeMs, fullPath: path38.join(dir, relativePath), size: st.size });
11455
11662
  } catch {
11456
11663
  }
11457
11664
  }
@@ -11638,7 +11845,7 @@ ${PLAN_MODE_AUTO_ENTER_HINT}
11638
11845
  });
11639
11846
 
11640
11847
  // ../core/src/serve/chatProcessing.ts
11641
- import path38 from "path";
11848
+ import path39 from "path";
11642
11849
  import fs36 from "fs";
11643
11850
  var handleUnifiedChat;
11644
11851
  var init_chatProcessing = __esm({
@@ -11696,14 +11903,14 @@ ${inject}`;
11696
11903
  activeReal = fs36.realpathSync(activeReal);
11697
11904
  } catch {
11698
11905
  }
11699
- const lines = roots.map((r) => `- ${path38.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"}`);
11906
+ const lines = roots.map((r) => `- ${path39.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"}`);
11700
11907
  sysPrompt = sysPrompt + `
11701
11908
 
11702
11909
  \u3010\u5DE5\u4F5C\u533A\uFF08\u591A\u9879\u76EE\uFF09\u3011
11703
11910
  \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>:
11704
11911
  ${lines.join("\n")}
11705
- \u2605 \u8DEF\u5F84\u951A\u5B9A\u94C1\u5F8B\uFF1A\u5DE5\u5177\u7F3A\u7701\u53EA\u4F5C\u7528\u4E8E\u9ED8\u8BA4\u6839\uFF08${path38.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
11706
- \u6CE8\u610F\uFF1A\u9879\u76EE\u7EA7\u914D\u7F6E\uFF08.deepseeker-code/\uFF09\u4EC5\u5728\u9ED8\u8BA4\u6839 ${path38.basename(activeReal) || activeReal} \u751F\u6548\u3002`;
11912
+ \u2605 \u8DEF\u5F84\u951A\u5B9A\u94C1\u5F8B\uFF1A\u5DE5\u5177\u7F3A\u7701\u53EA\u4F5C\u7528\u4E8E\u9ED8\u8BA4\u6839\uFF08${path39.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
11913
+ \u6CE8\u610F\uFF1A\u9879\u76EE\u7EA7\u914D\u7F6E\uFF08.deepseeker-code/\uFF09\u4EC5\u5728\u9ED8\u8BA4\u6839 ${path39.basename(activeReal) || activeReal} \u751F\u6548\u3002`;
11707
11914
  }
11708
11915
  let replyText = "";
11709
11916
  try {
@@ -12442,14 +12649,17 @@ var init_useChatState = __esm({
12442
12649
  await runOnce(sid, `\uFF08\u7528\u6237\u5DF2\u6279\u51C6\u4EE5\u4E0B\u65B9\u6848\uFF0C\u8BF7\u4E25\u683C\u6309\u65B9\u6848\u5F00\u59CB\u5B9E\u73B0\uFF09\uFF1A
12443
12650
 
12444
12651
  ${finalPlan}`, false, res.autoExecute);
12445
- } else {
12446
- pushInfo(S.planRejected);
12652
+ return true;
12447
12653
  }
12654
+ planModeRef.current = true;
12655
+ pushInfo(S.planKeepPlanning);
12656
+ return false;
12448
12657
  }, [runOnce, setPlan, pushInfo]);
12449
12658
  const runPlanStage = useCallback(async (sid, researchPrompt) => {
12450
12659
  await runOnce(sid, researchPrompt, true);
12451
12660
  const plan = takeProposedPlan();
12452
- if (plan != null) await approveAndImplement(sid, plan);
12661
+ if (plan == null) return false;
12662
+ return await approveAndImplement(sid, plan);
12453
12663
  }, [runOnce, takeProposedPlan, approveAndImplement]);
12454
12664
  const queueInput = useCallback((content) => {
12455
12665
  const text = content.trim();
@@ -12472,7 +12682,8 @@ ${finalPlan}`, false, res.autoExecute);
12472
12682
  const sid = sessionIdRef.current;
12473
12683
  pushUser(text);
12474
12684
  if (planModeRef.current) {
12475
- await runPlanStage(sid, text);
12685
+ const kept = await runPlanStage(sid, text);
12686
+ if (kept) planModeRef.current = false;
12476
12687
  } else {
12477
12688
  await runOnce(sid, text, false);
12478
12689
  const proposedPlan = takeProposedPlan();
@@ -12483,8 +12694,8 @@ ${finalPlan}`, false, res.autoExecute);
12483
12694
  if (enterReason != null) {
12484
12695
  pushInfo(`\u{1F4CB} \u6A21\u578B\u8BF7\u6C42\u8FDB\u5165\u8BA1\u5212\u6A21\u5F0F${enterReason ? `\uFF1A${enterReason}` : ""}\uFF0C\u5DF2\u5207\u6362\u2026`);
12485
12696
  planModeRef.current = true;
12486
- await runPlanStage(sid, ENTER_PLAN_RESEARCH_PROMPT);
12487
- planModeRef.current = false;
12697
+ const kept = await runPlanStage(sid, ENTER_PLAN_RESEARCH_PROMPT);
12698
+ if (kept) planModeRef.current = false;
12488
12699
  }
12489
12700
  }
12490
12701
  }
@@ -12748,6 +12959,8 @@ var init_MessageBlock = __esm({
12748
12959
  return { bullet: `${m[2]} `, rest: m[3] };
12749
12960
  };
12750
12961
  AssistantLine = ({ line }) => {
12962
+ const heading = line.match(/^#{1,6}\s+(.*)$/);
12963
+ if (heading) return /* @__PURE__ */ jsx3(Text3, { bold: true, color: "#ffffff", children: heading[1] });
12751
12964
  const list = listPrefix(line);
12752
12965
  if (list) {
12753
12966
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
@@ -12897,6 +13110,149 @@ var init_ThinkingBlock = __esm({
12897
13110
  }
12898
13111
  });
12899
13112
 
13113
+ // src/lineDiff.ts
13114
+ var splitLines, lineDiff, collapseContext;
13115
+ var init_lineDiff = __esm({
13116
+ "src/lineDiff.ts"() {
13117
+ "use strict";
13118
+ splitLines = (s) => {
13119
+ const t = String(s ?? "").replace(/\r\n/g, "\n");
13120
+ return t === "" ? [] : t.split("\n");
13121
+ };
13122
+ lineDiff = (oldStr, newStr) => {
13123
+ const a = splitLines(oldStr);
13124
+ const b = splitLines(newStr);
13125
+ let s = 0;
13126
+ while (s < a.length && s < b.length && a[s] === b[s]) s++;
13127
+ let e = 0;
13128
+ while (e < a.length - s && e < b.length - s && a[a.length - 1 - e] === b[b.length - 1 - e]) e++;
13129
+ const m1 = a.slice(s, a.length - e);
13130
+ const m2 = b.slice(s, b.length - e);
13131
+ const rows = [];
13132
+ for (let i = 0; i < s; i++) rows.push({ t: "ctx", s: a[i] });
13133
+ const n = m1.length, m = m2.length;
13134
+ if (n === 0 && m === 0) {
13135
+ } else if (n * m > 4e6) {
13136
+ for (const l of m1) rows.push({ t: "del", s: l });
13137
+ for (const l of m2) rows.push({ t: "add", s: l });
13138
+ } else {
13139
+ const w = m + 1;
13140
+ const dp = new Uint32Array((n + 1) * w);
13141
+ for (let i2 = n - 1; i2 >= 0; i2--) {
13142
+ for (let j2 = m - 1; j2 >= 0; j2--) {
13143
+ dp[i2 * w + j2] = m1[i2] === m2[j2] ? dp[(i2 + 1) * w + j2 + 1] + 1 : Math.max(dp[(i2 + 1) * w + j2], dp[i2 * w + j2 + 1]);
13144
+ }
13145
+ }
13146
+ let i = 0, j = 0;
13147
+ while (i < n && j < m) {
13148
+ if (m1[i] === m2[j]) {
13149
+ rows.push({ t: "ctx", s: m1[i] });
13150
+ i++;
13151
+ j++;
13152
+ } else if (dp[(i + 1) * w + j] >= dp[i * w + j + 1]) {
13153
+ rows.push({ t: "del", s: m1[i] });
13154
+ i++;
13155
+ } else {
13156
+ rows.push({ t: "add", s: m2[j] });
13157
+ j++;
13158
+ }
13159
+ }
13160
+ while (i < n) {
13161
+ rows.push({ t: "del", s: m1[i] });
13162
+ i++;
13163
+ }
13164
+ while (j < m) {
13165
+ rows.push({ t: "add", s: m2[j] });
13166
+ j++;
13167
+ }
13168
+ }
13169
+ for (let k = 0; k < e; k++) rows.push({ t: "ctx", s: a[a.length - e + k] });
13170
+ return rows;
13171
+ };
13172
+ collapseContext = (rows, keep = 2) => {
13173
+ const out = [];
13174
+ let i = 0;
13175
+ while (i < rows.length) {
13176
+ if (rows[i].t !== "ctx") {
13177
+ out.push(rows[i]);
13178
+ i++;
13179
+ continue;
13180
+ }
13181
+ let j = i;
13182
+ while (j < rows.length && rows[j].t === "ctx") j++;
13183
+ const run = j - i;
13184
+ if (run > keep * 2 + 1) {
13185
+ for (let k = 0; k < keep; k++) out.push(rows[i + k]);
13186
+ out.push({ t: "ellip", n: run - keep * 2 });
13187
+ for (let k = run - keep; k < run; k++) out.push(rows[i + k]);
13188
+ } else {
13189
+ for (let k = 0; k < run; k++) out.push(rows[i + k]);
13190
+ }
13191
+ i = j;
13192
+ }
13193
+ return out;
13194
+ };
13195
+ }
13196
+ });
13197
+
13198
+ // src/diffView.ts
13199
+ var EDIT_TOOL_NAMES, extractEditPairs, pairsToDisplayRows, parseApprovalDiff;
13200
+ var init_diffView = __esm({
13201
+ "src/diffView.ts"() {
13202
+ "use strict";
13203
+ init_lineDiff();
13204
+ EDIT_TOOL_NAMES = ["edit_file", "create_file", "write_file"];
13205
+ extractEditPairs = (toolName, args) => {
13206
+ if (args == null || typeof args !== "object") return null;
13207
+ const o = args;
13208
+ if (toolName === "edit_file") {
13209
+ const list = Array.isArray(o.edits) && o.edits.length > 0 ? o.edits : [o];
13210
+ const pairs = list.filter((e) => typeof e.old_str === "string" && e.old_str.length > 0);
13211
+ if (pairs.length === 0) return null;
13212
+ return pairs.map((e, i) => ({
13213
+ label: pairs.length > 1 ? `\u7B2C ${i + 1} \u5904${e.replace_all ? "\uFF08\u6279\u91CF\u66FF\u6362\u5168\u90E8\u5339\u914D\uFF09" : ""}` : "",
13214
+ old: e.old_str,
13215
+ new: typeof e.new_str === "string" ? e.new_str : ""
13216
+ }));
13217
+ }
13218
+ if (toolName === "create_file" || toolName === "write_file") {
13219
+ return typeof o.content === "string" && o.content.length > 0 ? [{ label: "", old: "", new: o.content }] : null;
13220
+ }
13221
+ return null;
13222
+ };
13223
+ pairsToDisplayRows = (pairs, keep = 2) => {
13224
+ const out = [];
13225
+ let changed = false;
13226
+ for (const p of pairs) {
13227
+ const collapsed = collapseContext(lineDiff(p.old, p.new), keep);
13228
+ if (!collapsed.some((r) => r.t !== "ctx" && r.t !== "ellip")) continue;
13229
+ changed = true;
13230
+ if (p.label) {
13231
+ if (out.length > 0) out.push({ t: "ellip", n: 0 });
13232
+ out.push({ t: "ctx", s: `\u2014\u2014 ${p.label} \u2014\u2014` });
13233
+ }
13234
+ out.push(...collapsed);
13235
+ }
13236
+ return changed ? out : null;
13237
+ };
13238
+ parseApprovalDiff = (detail, toolName) => {
13239
+ if (toolName !== "edit_file" || !detail.includes("\u3010\u51CF\u5C11\u3011:")) return null;
13240
+ const parts = detail.split(/\n(?=—— 第 )/);
13241
+ const sections = [];
13242
+ for (const part of parts.slice(1)) {
13243
+ const label = (part.match(/^—— (第 \d+ 处[^\n]*)——/)?.[1] ?? "").trim();
13244
+ const rIdx = part.indexOf("\u3010\u51CF\u5C11\u3011:");
13245
+ const aIdx = part.indexOf("\u3010\u589E\u52A0\u3011:");
13246
+ if (rIdx < 0 || aIdx < 0 || aIdx < rIdx) continue;
13247
+ const old = part.slice(rIdx + "\u3010\u51CF\u5C11\u3011:".length, aIdx).replace(/^\n+|\n+$/g, "");
13248
+ const neu = part.slice(aIdx + "\u3010\u589E\u52A0\u3011:".length).replace(/^\n+|\n+$/g, "");
13249
+ sections.push({ label, old, new: neu });
13250
+ }
13251
+ return sections.length > 0 ? { header: parts[0], sections } : null;
13252
+ };
13253
+ }
13254
+ });
13255
+
12900
13256
  // src/components/ToolCard.tsx
12901
13257
  import { Box as Box3, Text as Text5 } from "ink";
12902
13258
  import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
@@ -12906,6 +13262,7 @@ var init_ToolCard = __esm({
12906
13262
  "use strict";
12907
13263
  init_theme();
12908
13264
  init_util();
13265
+ init_diffView();
12909
13266
  ToolCard = ({ toolName, args, result, ok, status, progress, wrapW }) => {
12910
13267
  const tool = findTool(toolName);
12911
13268
  const level = tool?.function?.safetyLevel;
@@ -12922,6 +13279,15 @@ var init_ToolCard = __esm({
12922
13279
  const last = progress.replace(/\r/g, "").split("\n").map((s) => s.trim()).filter(Boolean).pop() ?? "";
12923
13280
  return truncateMiddle(last, Math.max(20, wrapW - 6));
12924
13281
  })();
13282
+ const MAX_DIFF_LINES2 = 14;
13283
+ const diffAll = (() => {
13284
+ if (status !== "done" || !ok) return null;
13285
+ if (!EDIT_TOOL_NAMES.includes(toolName)) return null;
13286
+ const pairs = extractEditPairs(toolName, args);
13287
+ return pairs ? pairsToDisplayRows(pairs) : null;
13288
+ })();
13289
+ const diffRows = diffAll ? diffAll.slice(0, MAX_DIFF_LINES2) : null;
13290
+ const diffHidden = diffAll ? Math.max(0, diffAll.length - MAX_DIFF_LINES2) : 0;
12925
13291
  return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginTop: 0.3, marginBottom: 0.3, children: [
12926
13292
  /* @__PURE__ */ jsxs3(Box3, { flexDirection: "row", flexShrink: 0, children: [
12927
13293
  /* @__PURE__ */ jsx5(Text5, { color: markerColor, bold: true, children: "\u23FA " }),
@@ -12935,6 +13301,14 @@ var init_ToolCard = __esm({
12935
13301
  ] }, i)) : status === "running" ? /* @__PURE__ */ jsxs3(Box3, { flexDirection: "row", flexShrink: 0, children: [
12936
13302
  /* @__PURE__ */ jsx5(Text5, { color: THEME.grayDim, children: " \u23BF " }),
12937
13303
  /* @__PURE__ */ jsx5(Text5, { color: THEME.gray, children: runningLine || "\u8FD0\u884C\u4E2D\u2026" })
13304
+ ] }) : null,
13305
+ diffRows && diffRows.length > 0 ? diffRows.map((r, i) => /* @__PURE__ */ jsxs3(Box3, { flexDirection: "row", flexShrink: 0, children: [
13306
+ /* @__PURE__ */ jsx5(Text5, { color: THEME.grayDim, children: " " }),
13307
+ r.t === "ellip" ? /* @__PURE__ */ jsx5(Text5, { color: THEME.grayDim, children: r.n > 0 ? ` \u22EF ${r.n} \u884C\u672A\u53D8` : " \u22EF" }) : /* @__PURE__ */ jsx5(Text5, { color: r.t === "del" ? THEME.danger : r.t === "add" ? THEME.ok : THEME.grayDim, children: `${r.t === "del" ? "- " : r.t === "add" ? "+ " : " "}${truncateMiddle(r.s, Math.max(20, wrapW - 8))}` })
13308
+ ] }, `diff-${i}`)) : null,
13309
+ diffHidden > 0 ? /* @__PURE__ */ jsxs3(Box3, { flexDirection: "row", flexShrink: 0, children: [
13310
+ /* @__PURE__ */ jsx5(Text5, { color: THEME.grayDim, children: " " }),
13311
+ /* @__PURE__ */ jsx5(Text5, { color: THEME.grayDim, children: ` \u2026\uFF08\u53E6\u6709 ${diffHidden} \u884C\u6539\u52A8\u672A\u663E\u793A\uFF09` })
12938
13312
  ] }) : null
12939
13313
  ] });
12940
13314
  };
@@ -12978,28 +13352,36 @@ var init_TodosPanel = __esm({
12978
13352
 
12979
13353
  // src/components/ApprovalModal.tsx
12980
13354
  import { Box as Box5, Text as Text7 } from "ink";
12981
- import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
12982
- var OPTIONS, ApprovalModal;
13355
+ import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
13356
+ var OPTIONS, MAX_DIFF_LINES, ApprovalModal;
12983
13357
  var init_ApprovalModal = __esm({
12984
13358
  "src/components/ApprovalModal.tsx"() {
12985
13359
  "use strict";
12986
13360
  init_theme();
12987
13361
  init_strings();
12988
13362
  init_util();
13363
+ init_diffView();
12989
13364
  OPTIONS = [
12990
13365
  { label: S.approvalAllow, value: "allow-once", color: THEME.ok },
12991
13366
  { label: S.approvalAllowAlways, value: "allow-always", color: THEME.warn },
12992
13367
  { label: S.approvalDeny, value: "deny", color: THEME.danger }
12993
13368
  ];
13369
+ MAX_DIFF_LINES = 18;
12994
13370
  ApprovalModal = ({ toolName, detail, selectedIndex, wrapW }) => {
12995
13371
  const contentW = Math.max(16, wrapW);
13372
+ const parsed = parseApprovalDiff(detail, toolName);
13373
+ const diffRows = parsed ? pairsToDisplayRows(parsed.sections) : null;
12996
13374
  return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", borderStyle: "round", borderColor: THEME.warn, paddingX: 1, paddingY: 1, marginTop: 1, children: [
12997
13375
  /* @__PURE__ */ jsxs5(Text7, { color: THEME.warn, bold: true, children: [
12998
13376
  S.approvalTitle,
12999
13377
  " \xB7 ",
13000
13378
  toolName
13001
13379
  ] }),
13002
- /* @__PURE__ */ jsx7(Box5, { flexDirection: "column", marginTop: 0.5, marginBottom: 0.5, children: wrapText(detail || "(\u65E0\u8BF4\u660E)", contentW).map((line, j) => /* @__PURE__ */ jsx7(Text7, { color: THEME.white, children: line }, j)) }),
13380
+ /* @__PURE__ */ jsx7(Box5, { flexDirection: "column", marginTop: 0.5, marginBottom: 0.5, children: parsed && diffRows ? /* @__PURE__ */ jsxs5(Fragment2, { children: [
13381
+ wrapText(parsed.header, contentW).map((line, j) => /* @__PURE__ */ jsx7(Text7, { color: THEME.white, children: line }, `h-${j}`)),
13382
+ diffRows.slice(0, MAX_DIFF_LINES).map((r, i) => /* @__PURE__ */ jsx7(Text7, { color: r.t === "del" ? THEME.danger : r.t === "add" ? THEME.ok : THEME.grayDim, children: r.t === "ellip" ? r.n > 0 ? ` \u22EF ${r.n} \u884C\u672A\u53D8` : " \u22EF" : `${r.t === "del" ? "- " : r.t === "add" ? "+ " : " "}${truncateMiddle(r.s, Math.max(20, contentW - 2))}` }, `d-${i}`)),
13383
+ diffRows.length > MAX_DIFF_LINES ? /* @__PURE__ */ jsx7(Text7, { color: THEME.grayDim, children: ` \u2026\uFF08\u53E6\u6709 ${diffRows.length - MAX_DIFF_LINES} \u884C\u672A\u663E\u793A\uFF09` }) : null
13384
+ ] }) : wrapText(detail || "(\u65E0\u8BF4\u660E)", contentW).map((line, j) => /* @__PURE__ */ jsx7(Text7, { color: THEME.white, children: line }, j)) }),
13003
13385
  /* @__PURE__ */ jsx7(Text7, { color: THEME.grayDim, children: S.approvalPrompt }),
13004
13386
  OPTIONS.map((opt, i) => {
13005
13387
  const active = i === selectedIndex;
@@ -13539,7 +13921,7 @@ __export(App_exports, {
13539
13921
  });
13540
13922
  import { useCallback as useCallback2, useEffect as useEffect4, useMemo, useRef as useRef2, useState as useState4 } from "react";
13541
13923
  import { Box as Box15, Static, Text as Text17, useApp, useInput as useInput2, useStdout } from "ink";
13542
- import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
13924
+ import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
13543
13925
  var KNOWN_MODELS, CWD2, RowView, isDynamicRow, App;
13544
13926
  var init_App = __esm({
13545
13927
  "src/App.tsx"() {
@@ -14068,9 +14450,10 @@ ${listText}`);
14068
14450
  state.pendingFork ? /* @__PURE__ */ jsx17(ForkPicker, { anchors: state.pendingFork.anchors, selectedIndex: selectIdx, wrapW }) : null,
14069
14451
  slashVisible ? /* @__PURE__ */ jsx17(SlashMenu, { entries: filteredCommands, selectedIndex: selectIdx, cols }) : null
14070
14452
  ] }),
14071
- /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", paddingX: 1, marginTop: 1, flexShrink: 0, children: [
14072
- /* @__PURE__ */ jsx17(Text17, { dimColor: true, color: THEME.gray, children: dimRule(cols) }),
14073
- /* @__PURE__ */ jsx17(
14453
+ /* @__PURE__ */ jsx17(Box15, { flexDirection: "column", paddingX: 1, marginTop: 1, flexShrink: 0, children: (() => {
14454
+ const planOn = state.getPlanMode();
14455
+ const autoOn = !planOn && state.getAutoMode();
14456
+ const inputEl = /* @__PURE__ */ jsx17(
14074
14457
  MultilineInput,
14075
14458
  {
14076
14459
  value: input,
@@ -14086,8 +14469,18 @@ ${listText}`);
14086
14469
  suppressSubmit: slashVisible,
14087
14470
  placeholder: S.placeholder
14088
14471
  }
14089
- )
14090
- ] }),
14472
+ );
14473
+ if (planOn || autoOn) {
14474
+ return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: planOn ? THEME.thinking : THEME.warn, paddingX: 1, children: [
14475
+ /* @__PURE__ */ jsx17(Text17, { color: planOn ? THEME.thinking : THEME.warn, children: planOn ? S.inputBadgePlan : S.inputBadgeAuto }),
14476
+ inputEl
14477
+ ] });
14478
+ }
14479
+ return /* @__PURE__ */ jsxs15(Fragment3, { children: [
14480
+ /* @__PURE__ */ jsx17(Text17, { dimColor: true, color: THEME.gray, children: dimRule(cols) }),
14481
+ inputEl
14482
+ ] });
14483
+ })() }),
14091
14484
  /* @__PURE__ */ jsx17(Box15, { paddingX: 1, marginTop: 1, flexShrink: 0, children: /* @__PURE__ */ jsx17(StatusStrip, { model: modelDisplay, busy: state.busy, aborting: state.aborting, planMode: state.getPlanMode(), autoMode: state.getAutoMode(), sessionShort, cols, customLine: statusLineText }) })
14092
14485
  ] })
14093
14486
  ] });
@@ -14095,81 +14488,6 @@ ${listText}`);
14095
14488
  }
14096
14489
  });
14097
14490
 
14098
- // src/updateCheck.ts
14099
- var updateCheck_exports = {};
14100
- __export(updateCheck_exports, {
14101
- getCachedLatestIfNewer: () => getCachedLatestIfNewer,
14102
- readLocalVersion: () => readLocalVersion,
14103
- refreshUpdateCache: () => refreshUpdateCache
14104
- });
14105
- import { readFileSync as readFileSync4, writeFileSync, mkdirSync } from "node:fs";
14106
- import path39 from "node:path";
14107
- import os4 from "os";
14108
- import { fileURLToPath as fileURLToPath6 } from "node:url";
14109
- var PKG_NAME, REGISTRY, CACHE_TTL_MS, FETCH_TIMEOUT_MS2, cacheFile, readLocalVersion, parseSemver, compareVersion, readCache, writeCache, getCachedLatestIfNewer, refreshUpdateCache;
14110
- var init_updateCheck = __esm({
14111
- "src/updateCheck.ts"() {
14112
- "use strict";
14113
- PKG_NAME = "deepseeker-code";
14114
- REGISTRY = "https://registry.npmjs.org";
14115
- CACHE_TTL_MS = 6 * 60 * 60 * 1e3;
14116
- FETCH_TIMEOUT_MS2 = 3e3;
14117
- cacheFile = () => path39.join(os4.homedir(), ".deepseeker-code", "update-check.json");
14118
- readLocalVersion = () => {
14119
- try {
14120
- const here = path39.dirname(fileURLToPath6(import.meta.url));
14121
- return JSON.parse(readFileSync4(path39.join(here, "..", "package.json"), "utf8")).version ?? "0.0.0";
14122
- } catch {
14123
- return "0.0.0";
14124
- }
14125
- };
14126
- parseSemver = (v) => {
14127
- const m = String(v ?? "").match(/^(\d+)\.(\d+)\.(\d+)/);
14128
- return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : [0, 0, 0];
14129
- };
14130
- compareVersion = (a, b) => {
14131
- const [a1, a2, a3] = parseSemver(a);
14132
- const [b1, b2, b3] = parseSemver(b);
14133
- return a1 - b1 || a2 - b2 || a3 - b3;
14134
- };
14135
- readCache = () => {
14136
- try {
14137
- const obj = JSON.parse(readFileSync4(cacheFile(), "utf8"));
14138
- return typeof obj.latestVersion === "string" && typeof obj.lastCheck === "number" ? obj : null;
14139
- } catch {
14140
- return null;
14141
- }
14142
- };
14143
- writeCache = (latestVersion) => {
14144
- try {
14145
- mkdirSync(path39.dirname(cacheFile()), { recursive: true });
14146
- writeFileSync(cacheFile(), JSON.stringify({ lastCheck: Date.now(), latestVersion }), "utf8");
14147
- } catch {
14148
- }
14149
- };
14150
- getCachedLatestIfNewer = (currentVersion) => {
14151
- const cache = readCache();
14152
- if (!cache) return null;
14153
- return compareVersion(cache.latestVersion, currentVersion) > 0 ? cache.latestVersion : null;
14154
- };
14155
- refreshUpdateCache = () => {
14156
- const cache = readCache();
14157
- if (cache && Date.now() - cache.lastCheck < CACHE_TTL_MS) return;
14158
- void (async () => {
14159
- try {
14160
- const res = await fetch(`${REGISTRY}/${PKG_NAME}/latest`, {
14161
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS2)
14162
- });
14163
- if (!res.ok) return;
14164
- const info = await res.json();
14165
- if (info.version) writeCache(info.version);
14166
- } catch {
14167
- }
14168
- })();
14169
- };
14170
- }
14171
- });
14172
-
14173
14491
  // src/preload-config.ts
14174
14492
  import { readFileSync } from "node:fs";
14175
14493
  import path from "node:path";
@@ -14217,6 +14535,7 @@ applyConfigToEnv(loadConfigFile());
14217
14535
  // src/main.tsx
14218
14536
  init_strings();
14219
14537
  init_prefs();
14538
+ init_updateCheck();
14220
14539
  init_trust();
14221
14540
  import { render } from "ink";
14222
14541
  import os5 from "os";
@@ -14233,6 +14552,7 @@ var parseArgs = (argv) => {
14233
14552
  else if (a === "--continue" || a === "-c") out.continue = true;
14234
14553
  else if (a === "--trust") out.trust = true;
14235
14554
  else if (a === "--no-update-check") out.noUpdateCheck = true;
14555
+ else if (a === "--version" || a === "-v") out.version = true;
14236
14556
  }
14237
14557
  return out;
14238
14558
  };
@@ -14293,6 +14613,11 @@ var main = async () => {
14293
14613
  console.debug = silence;
14294
14614
  console.warn = silence;
14295
14615
  const args = parseArgs(process.argv.slice(2));
14616
+ if (args.version) {
14617
+ process.stdout.write(`deepseeker-code v${readLocalVersion()}
14618
+ `);
14619
+ process.exit(0);
14620
+ }
14296
14621
  if (!process.env.DEEP_SEEK_API_KEY) {
14297
14622
  console.error(S.noApiKey("DEEP_SEEK_API_KEY"));
14298
14623
  process.exit(1);