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.
- package/README.md +1 -1
- package/dist/cli.mjs +805 -480
- 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
|
-
|
|
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: "\
|
|
38
|
-
planPrompt: "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u786E\u8BA4\uFF08\
|
|
39
|
-
planAcceptAuto: "\
|
|
40
|
-
planAcceptManual: "\
|
|
41
|
-
planEdit: "\
|
|
42
|
-
planReject: "\
|
|
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
|
-
|
|
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: "
|
|
253
|
+
planTitle: "Ready to code?",
|
|
176
254
|
planPrompt: "\u2191\u2193 then Enter (edit opens the editor: Enter to save / Esc to cancel).",
|
|
177
|
-
planAcceptAuto: "
|
|
178
|
-
planAcceptManual: "
|
|
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: "
|
|
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
|
-
|
|
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
|
|
317
|
-
import
|
|
318
|
-
import { readFileSync as
|
|
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 ?
|
|
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 =
|
|
352
|
-
const parentFolder =
|
|
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:
|
|
530
|
+
{ scope: "settings.global", configPath: path3.join(cfg.dataDir, "settings.json") },
|
|
451
531
|
// 全局用户级
|
|
452
|
-
{ scope: "settings.project", configPath:
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
712
|
+
TRUSTED_FILE = path5.join(appConfig.dataDir, "trusted_dirs.json");
|
|
633
713
|
normalizeDir = (dir) => {
|
|
634
|
-
let d =
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
1239
|
+
return path6.join(appConfig.dataDir, "sessions", appConfig.userWorkspaceDir, fileName);
|
|
1160
1240
|
};
|
|
1161
|
-
getWorkspaceSessionsDir = () =>
|
|
1241
|
+
getWorkspaceSessionsDir = () => path6.join(appConfig.dataDir, "sessions", appConfig.userWorkspaceDir);
|
|
1162
1242
|
getStatePath = (sessionId) => {
|
|
1163
1243
|
assertSafeSessionId(sessionId);
|
|
1164
|
-
return
|
|
1244
|
+
return path6.join(getSessionsDirPath(sessionId), `${sessionId}.state.json`);
|
|
1165
1245
|
};
|
|
1166
1246
|
getTranscriptPath = (sessionId) => {
|
|
1167
1247
|
assertSafeSessionId(sessionId);
|
|
1168
|
-
return
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
1850
|
+
roots.add(path8.resolve(appConfig.userWorkspaceDir));
|
|
1771
1851
|
for (const r of getFileAccessRoots()) {
|
|
1772
1852
|
try {
|
|
1773
|
-
roots.add(
|
|
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
|
|
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
|
-
|
|
2182
|
+
path9.join(appConfig.dataDir, "settings.json"),
|
|
2103
2183
|
// 全局用户级
|
|
2104
|
-
...includeProject ? [
|
|
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" ?
|
|
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(
|
|
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
|
|
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 =
|
|
2304
|
-
if (!rel.startsWith("..") && !
|
|
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 =
|
|
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 =
|
|
2407
|
+
const parentDir = path10.dirname(candidateAbsPath);
|
|
2328
2408
|
if (fsSync.existsSync(parentDir)) {
|
|
2329
2409
|
const trueParentDir = fsSync.realpathSync(parentDir);
|
|
2330
|
-
truePhysicalPath =
|
|
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 =
|
|
2345
|
-
return rel0.startsWith("..") ||
|
|
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 =
|
|
2434
|
+
const absPath = path10.resolve(root, rel);
|
|
2355
2435
|
if (!fsSync.existsSync(absPath)) {
|
|
2356
|
-
const rootName =
|
|
2436
|
+
const rootName = path10.basename(root);
|
|
2357
2437
|
const firstSeg = rel.split(/[\\/]/)[0];
|
|
2358
2438
|
if (rootName && firstSeg === rootName) {
|
|
2359
|
-
const alt =
|
|
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 =
|
|
2452
|
+
const parentDir = path10.dirname(absPath);
|
|
2373
2453
|
if (fsSync.existsSync(parentDir)) {
|
|
2374
|
-
truePhysicalPath =
|
|
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 =
|
|
2389
|
-
return rel0.startsWith("..") ||
|
|
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 =
|
|
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 =
|
|
2511
|
+
const fullPath = path10.join(dirPath, entry.name);
|
|
2427
2512
|
const content = await fs7.readFile(fullPath, "utf-8");
|
|
2428
|
-
const relDir =
|
|
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(
|
|
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
|
|
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) =>
|
|
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 =
|
|
2581
|
-
const root =
|
|
2582
|
-
candidates.push(
|
|
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
|
|
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 ||
|
|
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
|
|
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(
|
|
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
|
|
4375
|
-
import
|
|
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 = () =>
|
|
4388
|
-
worktreeDir = (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(
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
4798
|
-
let dir =
|
|
4851
|
+
const root = path15.resolve(getContainingRoot(absPath));
|
|
4852
|
+
let dir = path15.dirname(absPath);
|
|
4799
4853
|
while (true) {
|
|
4800
|
-
const candidate =
|
|
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 (
|
|
4806
|
-
const parent =
|
|
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 =
|
|
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(
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
5163
|
-
const relPath =
|
|
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 =
|
|
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"
|
|
5369
|
+
required: ["path"]
|
|
5213
5370
|
},
|
|
5214
5371
|
safetyLevel: "mutation" /* MUTATION */,
|
|
5215
5372
|
isSync: true,
|
|
5216
|
-
requireApproval: (args) =>
|
|
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
|
-
${
|
|
5377
|
+
${e.old_str}
|
|
5219
5378
|
\u3010\u589E\u52A0\u3011:
|
|
5220
|
-
${
|
|
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
|
-
|
|
5227
|
-
const
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
|
|
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
|
-
|
|
5262
|
-
|
|
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 ?
|
|
5274
|
-
return
|
|
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(
|
|
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 =
|
|
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 =
|
|
5370
|
-
if (!rel || rel === "" || rel === "src" || rel.startsWith("..") ||
|
|
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(
|
|
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(
|
|
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
|
|
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\
|
|
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
|
|
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 = !
|
|
5738
|
+
const looksLikeBareName = !path17.isAbsolute(p) && !p.includes("/") && !p.includes("\\");
|
|
5607
5739
|
if (looksLikeBareName) {
|
|
5608
5740
|
const hit = getAllowedWorkspaceRoots().find((r) => {
|
|
5609
|
-
const bn =
|
|
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
|
-
|
|
5628
|
-
// ★
|
|
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(
|
|
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
|
|
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
|
-
|
|
5939
|
-
|
|
5940
|
-
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
if (
|
|
5944
|
-
|
|
5945
|
-
|
|
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
|
|
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
|
-
|
|
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'
|
|
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 =
|
|
5995
|
-
const rel =
|
|
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 =
|
|
6003
|
-
const rel =
|
|
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
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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(
|
|
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${
|
|
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
|
|
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 =
|
|
6897
|
-
if (rel && !rel.startsWith("..") && !
|
|
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\
|
|
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: [
|
|
7148
|
+
required: []
|
|
6923
7149
|
},
|
|
6924
7150
|
safetyLevel: "safe" /* SAFE */,
|
|
6925
7151
|
isSync: true,
|
|
6926
|
-
maxOutputCharacters:
|
|
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
|
|
6934
|
-
|
|
6935
|
-
if (
|
|
6936
|
-
const
|
|
6937
|
-
const
|
|
6938
|
-
|
|
6939
|
-
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
6943
|
-
|
|
6944
|
-
|
|
6945
|
-
|
|
6946
|
-
|
|
6947
|
-
|
|
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
|
-
|
|
6959
|
-
|
|
6960
|
-
|
|
6961
|
-
|
|
6962
|
-
|
|
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
|
-
|
|
6967
|
-
|
|
6968
|
-
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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 = () =>
|
|
7173
|
-
getUndoClockPath = () =>
|
|
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
|
|
7386
|
+
return path22.join(getUndoRootPath(), appConfig.userWorkspaceDir, rootId);
|
|
7178
7387
|
};
|
|
7179
|
-
getUndoBackupRoot = (mainSessionId) =>
|
|
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
|
|
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
|
|
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(
|
|
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 =
|
|
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
|
|
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(
|
|
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 =
|
|
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 =
|
|
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(
|
|
7604
|
+
if (!re.test(path24.basename(rp))) continue;
|
|
7396
7605
|
try {
|
|
7397
|
-
const st = await fs20.stat(
|
|
7398
|
-
candidates.push({ mtime: st.mtimeMs, fullPath:
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 =
|
|
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(
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
7716
|
-
const rel =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
7861
|
-
const backupAbs =
|
|
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(
|
|
7868
|
-
const src =
|
|
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
|
|
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 =
|
|
8570
|
+
GLOBAL_MEMORY_DIR = path27.join(appConfig.dataDir, "memory");
|
|
8362
8571
|
SOURCES = [
|
|
8363
8572
|
{ dir: GLOBAL_MEMORY_DIR, source: "global" },
|
|
8364
|
-
{ dir:
|
|
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") ?
|
|
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
|
|
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 ?
|
|
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(
|
|
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
|
|
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 =
|
|
9125
|
-
const rel =
|
|
9126
|
-
return rel === "" || !rel.startsWith("..") && !
|
|
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
|
|
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
|
-
|
|
10640
|
+
path30.join(appConfig.dataDir, "settings.json"),
|
|
10434
10641
|
// 全局用户级
|
|
10435
|
-
...includeProject ? [
|
|
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
|
|
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 =
|
|
10990
|
+
BUILTIN_DIR = path31.join(path31.dirname(fileURLToPath2(import.meta.url)), "builtin");
|
|
10784
10991
|
SOURCES2 = [
|
|
10785
10992
|
{ dir: BUILTIN_DIR, source: "builtin" },
|
|
10786
|
-
{ dir:
|
|
10787
|
-
{ dir:
|
|
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() ?
|
|
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
|
|
10866
|
-
import { fileURLToPath as
|
|
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 =
|
|
11082
|
+
BUILTIN_DIR2 = path32.join(path32.dirname(fileURLToPath3(import.meta.url)), "builtin");
|
|
10876
11083
|
SOURCES3 = [
|
|
10877
11084
|
{ dir: BUILTIN_DIR2, source: "builtin" },
|
|
10878
|
-
{ dir:
|
|
10879
|
-
{ dir:
|
|
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") ?
|
|
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
|
|
10958
|
-
import { fileURLToPath as
|
|
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 =
|
|
11174
|
+
BUILTIN_DIR3 = path33.join(path33.dirname(fileURLToPath4(import.meta.url)), "builtin");
|
|
10968
11175
|
SOURCES4 = [
|
|
10969
11176
|
{ dir: BUILTIN_DIR3, source: "builtin" },
|
|
10970
|
-
{ dir:
|
|
10971
|
-
{ dir:
|
|
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 =
|
|
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") ?
|
|
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
|
|
11034
|
-
import { fileURLToPath as
|
|
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 =
|
|
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:
|
|
11048
|
-
{ dir:
|
|
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") ?
|
|
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
|
|
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
|
-
|
|
11390
|
+
path35.join(appConfig.dataDir, "settings.json"),
|
|
11184
11391
|
// 全局用户级
|
|
11185
|
-
...includeProject ? [
|
|
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
|
|
11214
|
-
import { fileURLToPath as
|
|
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 =
|
|
11429
|
+
const here = path36.dirname(fileURLToPath6(import.meta.url));
|
|
11223
11430
|
const candidates = [
|
|
11224
|
-
|
|
11431
|
+
path36.join(here, "../../../package.json"),
|
|
11225
11432
|
// src/core/package.json
|
|
11226
|
-
|
|
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
|
|
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
|
|
11508
|
+
return path37.join(appConfig.dataDir, "trace", appConfig.userWorkspaceDir, getFileName(mainTraceId));
|
|
11302
11509
|
};
|
|
11303
11510
|
getTracePath = () => {
|
|
11304
|
-
return
|
|
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
|
|
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 =
|
|
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
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
11657
|
+
const fileName = path38.basename(relativePath);
|
|
11451
11658
|
if (!re.test(fileName)) continue;
|
|
11452
11659
|
try {
|
|
11453
|
-
const st = await fs35.stat(
|
|
11454
|
-
candidates.push({ mtime: st.mtimeMs, fullPath:
|
|
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
|
|
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) => `- ${
|
|
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${
|
|
11706
|
-
\u6CE8\u610F\uFF1A\u9879\u76EE\u7EA7\u914D\u7F6E\uFF08.deepseeker-code/\uFF09\u4EC5\u5728\u9ED8\u8BA4\u6839 ${
|
|
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
|
-
|
|
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
|
|
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:
|
|
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__ */
|
|
14072
|
-
|
|
14073
|
-
|
|
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);
|