@zqagent/core 0.2.5 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/README.oss.en.md +5 -0
- package/README.oss.md +5 -0
- package/README.oss.zh-TW.md +5 -0
- package/dist/cli/index.cjs +1135 -599
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +1141 -605
- package/dist/cli/index.js.map +1 -1
- package/dist/{explore-D4lCKXbA.d.ts → explore-B_bIPzmB.d.ts} +49 -1
- package/dist/{explore-Dj1j_GyN.d.cts → explore-COqHKDoK.d.cts} +49 -1
- package/dist/index.cjs +654 -258
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -2
- package/dist/index.d.ts +12 -2
- package/dist/index.js +654 -258
- package/dist/index.js.map +1 -1
- package/dist/server/index.cjs +974 -442
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.js +980 -448
- package/dist/server/index.js.map +1 -1
- package/dist/tools/explore.cjs +528 -141
- package/dist/tools/explore.cjs.map +1 -1
- package/dist/tools/explore.d.cts +1 -1
- package/dist/tools/explore.d.ts +1 -1
- package/dist/tools/explore.js +528 -141
- package/dist/tools/explore.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.cjs
CHANGED
|
@@ -569,9 +569,9 @@ var init_wire = __esm({
|
|
|
569
569
|
// src/cli/index.ts
|
|
570
570
|
init_cjs_shims();
|
|
571
571
|
var import_config = require("dotenv/config");
|
|
572
|
-
var
|
|
572
|
+
var fs33 = __toESM(require("fs"), 1);
|
|
573
573
|
var readline2 = __toESM(require("readline"), 1);
|
|
574
|
-
var
|
|
574
|
+
var path42 = __toESM(require("path"), 1);
|
|
575
575
|
var import_child_process = require("child_process");
|
|
576
576
|
var import_util = require("util");
|
|
577
577
|
|
|
@@ -937,8 +937,11 @@ function formatTokens(tokens) {
|
|
|
937
937
|
return `${tokens}`;
|
|
938
938
|
}
|
|
939
939
|
var KEEP_RECENT_FRACTION = 0.25;
|
|
940
|
-
var
|
|
941
|
-
var
|
|
940
|
+
var SOFT_THRESHOLD_RATIO = 0.75;
|
|
941
|
+
var ELIDE_KEEP_FRACTION = 0.15;
|
|
942
|
+
var SUMMARY_MAX_TOKENS = 3e3;
|
|
943
|
+
var SPAN_TOOL_RESULT_CLIP = 200;
|
|
944
|
+
var SPAN_BUDGET_CHARS = 8e4;
|
|
942
945
|
var USER_MESSAGE_CLIP = 600;
|
|
943
946
|
var USER_MESSAGES_MAX = 40;
|
|
944
947
|
var TRIM_FRACTION = 0.1;
|
|
@@ -961,9 +964,22 @@ function triggerTokens(contextWindow, thresholdPct = DEFAULT_THRESHOLD_PCT, capT
|
|
|
961
964
|
}
|
|
962
965
|
return base;
|
|
963
966
|
}
|
|
967
|
+
function softTriggerTokens(contextWindow, thresholdPct = DEFAULT_THRESHOLD_PCT, capTokens, softThresholdPct) {
|
|
968
|
+
const hard = triggerTokens(contextWindow, thresholdPct, capTokens);
|
|
969
|
+
if (softThresholdPct != null && Number.isFinite(softThresholdPct) && softThresholdPct > 0) {
|
|
970
|
+
return Math.min(
|
|
971
|
+
triggerTokens(contextWindow, softThresholdPct, capTokens),
|
|
972
|
+
Math.floor(hard * 0.95)
|
|
973
|
+
);
|
|
974
|
+
}
|
|
975
|
+
return Math.floor(hard * SOFT_THRESHOLD_RATIO);
|
|
976
|
+
}
|
|
964
977
|
function shouldCompact(signal, contextWindow, thresholdPct, capTokens) {
|
|
965
978
|
return signal >= triggerTokens(contextWindow, thresholdPct, capTokens);
|
|
966
979
|
}
|
|
980
|
+
function elisionKeepChars(hardTriggerTokens, fraction = ELIDE_KEEP_FRACTION) {
|
|
981
|
+
return Math.max(4e3, Math.floor(hardTriggerTokens * fraction * 4));
|
|
982
|
+
}
|
|
967
983
|
function turnStarts(messages, start) {
|
|
968
984
|
const users = [];
|
|
969
985
|
const assistants = [];
|
|
@@ -1113,10 +1129,11 @@ var SUMMARY_SYSTEM_PROMPT = `\u4F60\u6B63\u5728\u538B\u7F29\u4E00\u4E2A AI \u534
|
|
|
1113
1129
|
|
|
1114
1130
|
\u89C4\u5219\uFF1A
|
|
1115
1131
|
- \u4E0D\u8981\u5C06\u5B8C\u6574\u7684\u6587\u4EF6\u5185\u5BB9\u5F53\u4F5C\u771F\u7406\u3002\u53EA\u8BB0\u5F55\u67D0\u4E2A\u6587\u4EF6\u88AB\u8BFB\u53D6/\u7F16\u8F91\u8FC7\u8FD9\u4E00\u4E8B\u5B9E\uFF1B\u534F\u4F5C\u8005\u5982\u679C\u9700\u8981\u518D\u6B21\u83B7\u53D6\u5185\u5BB9\u4F1A\u91CD\u65B0\u8BFB\u53D6\u3002\u9648\u65E7\u7684\u6587\u4EF6\u8BB0\u5FC6\u6BD4\u6CA1\u6709\u8BB0\u5FC6\u66F4\u7CDF\u7CD5\u3002
|
|
1132
|
+
- \u82E5\u63D0\u4F9B\u4E86\u4E0A\u4E00\u7248\u6458\u8981\uFF1A\u53EA\u628A\u5B83\u4ECD\u7136\u6709\u6548\u7684\u7ED3\u8BBA\u5E76\u5165\u5BF9\u5E94\u7AE0\u8282\uFF0C\u4E0D\u8981\u6574\u6BB5\u590D\u8FF0\u6216\u9010\u6761\u8F6C\u6284\u3002
|
|
1116
1133
|
- \u8981\u5177\u4F53\uFF1A\u8DEF\u5F84\u3001\u540D\u79F0\u3001\u547D\u4EE4\u3001id\u2014\u2014\u800C\u4E0D\u662F\u6A21\u7CCA\u7684\u5F15\u7528\u3002
|
|
1117
1134
|
- \u4EC5\u8F93\u51FA\u6458\u8981\u7AE0\u8282\uFF0C\u4E0D\u9644\u52A0\u524D\u8A00\u3002`;
|
|
1118
1135
|
var CONTINUATION_CONTRACT = "\u4ECE\u4F60\u4E4B\u524D\u4E2D\u65AD\u7684\u5730\u65B9\u7EE7\u7EED\uFF1A\u5B8C\u5168\u6309\u7167\u63CF\u8FF0\u63A5\u7EED\u5F53\u524D\u5DE5\u4F5C\u548C\u4E0B\u4E00\u6B65\u3002\u4E0D\u8981\u91CD\u65B0\u8BE2\u95EE\u5DF2\u56DE\u7B54\u7684\u95EE\u9898\uFF0C\u4E0D\u8981\u56DE\u987E\uFF0C\u4E0D\u8981\u63D0\u53CA\u4E0A\u4E0B\u6587\u5DF2\u88AB\u538B\u7F29\u3002\u5982\u679C\u4F60\u9700\u8981\u4E0A\u8FF0\u63D0\u5230\u7684\u6587\u4EF6\u7684\u5185\u5BB9\uFF0C\u8BF7\u91CD\u65B0\u8BFB\u53D6\u5B83\u3002";
|
|
1119
|
-
function renderSpan(span,
|
|
1136
|
+
function renderSpan(span, budgetChars2 = SPAN_BUDGET_CHARS) {
|
|
1120
1137
|
const lines = [];
|
|
1121
1138
|
for (const m of span) {
|
|
1122
1139
|
const role = m.role;
|
|
@@ -1140,8 +1157,8 @@ function renderSpan(span, budgetChars = SPAN_BUDGET_CHARS) {
|
|
|
1140
1157
|
if (text) lines.push(`[${role}] ${text}`);
|
|
1141
1158
|
}
|
|
1142
1159
|
let rendered = lines.join("\n");
|
|
1143
|
-
if (rendered.length >
|
|
1144
|
-
rendered = "(\u2026oldest turns elided\u2026)\n" + rendered.slice(-
|
|
1160
|
+
if (rendered.length > budgetChars2) {
|
|
1161
|
+
rendered = "(\u2026oldest turns elided\u2026)\n" + rendered.slice(-budgetChars2);
|
|
1145
1162
|
}
|
|
1146
1163
|
return rendered;
|
|
1147
1164
|
}
|
|
@@ -1155,9 +1172,17 @@ function summarizerMessages(span, priorSummary = "") {
|
|
|
1155
1172
|
{ role: "user", content: body }
|
|
1156
1173
|
];
|
|
1157
1174
|
}
|
|
1175
|
+
function summarizerReasoningEffort() {
|
|
1176
|
+
const v = process.env.COMPACTION_REASONING_EFFORT?.toLowerCase();
|
|
1177
|
+
if (v === "low" || v === "medium" || v === "high") return v;
|
|
1178
|
+
return "low";
|
|
1179
|
+
}
|
|
1158
1180
|
async function summarizeSpan(provider, model, span, priorSummary = "", opts) {
|
|
1159
1181
|
const msgs = summarizerMessages(span, priorSummary);
|
|
1160
|
-
const chunks = await provider.stream(model, msgs, [],
|
|
1182
|
+
const chunks = await provider.stream(model, msgs, [], {
|
|
1183
|
+
...opts,
|
|
1184
|
+
maxTokens: SUMMARY_MAX_TOKENS
|
|
1185
|
+
});
|
|
1161
1186
|
let text = "";
|
|
1162
1187
|
for await (const chunk of chunks) {
|
|
1163
1188
|
if (chunk.content) text += chunk.content;
|
|
@@ -1268,6 +1293,166 @@ function applyToOutbound(messages, state) {
|
|
|
1268
1293
|
head.push({ role: "user", content: compactedBlock(state) });
|
|
1269
1294
|
return [...head, ...messages.slice(boundary)];
|
|
1270
1295
|
}
|
|
1296
|
+
var ELIDE_EXEMPT_TOOLS = /* @__PURE__ */ new Set([
|
|
1297
|
+
"explore",
|
|
1298
|
+
"ask_user",
|
|
1299
|
+
"propose_plan",
|
|
1300
|
+
"request_directory",
|
|
1301
|
+
"todo_write"
|
|
1302
|
+
]);
|
|
1303
|
+
function elidedToolContent(m) {
|
|
1304
|
+
const name = m.tool_call_name || "tool";
|
|
1305
|
+
const size = m.content.length;
|
|
1306
|
+
const saved = /full output saved to ([^\]]+)/.exec(m.content)?.[1]?.trim();
|
|
1307
|
+
return saved ? `[old tool result elided: ${name}, ${size} chars; full output saved to ${saved}]` : `[old tool result elided: ${name}, ${size} chars; re-run the tool if its content is still needed]`;
|
|
1308
|
+
}
|
|
1309
|
+
function isPlaceholder(content) {
|
|
1310
|
+
return content.startsWith("[old tool result elided") || content.startsWith("[superseded by a later read_file");
|
|
1311
|
+
}
|
|
1312
|
+
var ONE_SHOT_TOOLS = /* @__PURE__ */ new Set(["git_diff"]);
|
|
1313
|
+
var ONE_SHOT_KEEP_RECENT = 1;
|
|
1314
|
+
function applyOneShotElision(messages, keepRecent = ONE_SHOT_KEEP_RECENT, tools = ONE_SHOT_TOOLS) {
|
|
1315
|
+
const out = [...messages];
|
|
1316
|
+
let seen = 0;
|
|
1317
|
+
let elided = 0;
|
|
1318
|
+
let freed = 0;
|
|
1319
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1320
|
+
const m = messages[i];
|
|
1321
|
+
if (m.role !== "tool" || !tools.has(m.tool_call_name ?? "")) continue;
|
|
1322
|
+
if (isPlaceholder(m.content)) continue;
|
|
1323
|
+
seen++;
|
|
1324
|
+
if (seen <= keepRecent) continue;
|
|
1325
|
+
const placeholder = elidedToolContent(m);
|
|
1326
|
+
freed += m.content.length - placeholder.length;
|
|
1327
|
+
out[i] = { ...m, content: placeholder };
|
|
1328
|
+
elided++;
|
|
1329
|
+
}
|
|
1330
|
+
return elided > 0 ? { messages: out, elided, freedChars: freed } : { messages, elided: 0, freedChars: 0 };
|
|
1331
|
+
}
|
|
1332
|
+
function applyToolResultElision(messages, keepChars, exempt = ELIDE_EXEMPT_TOOLS) {
|
|
1333
|
+
let total = 0;
|
|
1334
|
+
for (const m of messages) {
|
|
1335
|
+
if (m.role === "tool" && !exempt.has(m.tool_call_name ?? "")) {
|
|
1336
|
+
total += m.content.length;
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
if (total <= keepChars) return { messages, elided: 0, freedChars: 0 };
|
|
1340
|
+
const out = [...messages];
|
|
1341
|
+
let budget = 0;
|
|
1342
|
+
let elided = 0;
|
|
1343
|
+
let freed = 0;
|
|
1344
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1345
|
+
const m = messages[i];
|
|
1346
|
+
if (m.role !== "tool") continue;
|
|
1347
|
+
if (exempt.has(m.tool_call_name ?? "")) continue;
|
|
1348
|
+
if (elided === 0 && budget === 0 && m.content.length > keepChars) {
|
|
1349
|
+
const kept = m.content.slice(0, keepChars) + "\n\u2026(truncated)";
|
|
1350
|
+
freed += m.content.length - kept.length;
|
|
1351
|
+
out[i] = { ...m, content: kept };
|
|
1352
|
+
budget = keepChars;
|
|
1353
|
+
continue;
|
|
1354
|
+
}
|
|
1355
|
+
if (budget + m.content.length <= keepChars) {
|
|
1356
|
+
budget += m.content.length;
|
|
1357
|
+
continue;
|
|
1358
|
+
}
|
|
1359
|
+
const placeholder = elidedToolContent(m);
|
|
1360
|
+
freed += m.content.length - placeholder.length;
|
|
1361
|
+
out[i] = { ...m, content: placeholder };
|
|
1362
|
+
elided++;
|
|
1363
|
+
}
|
|
1364
|
+
return { messages: out, elided, freedChars: freed };
|
|
1365
|
+
}
|
|
1366
|
+
function normalizeToolPath(p) {
|
|
1367
|
+
let s = p.trim().replace(/\\/g, "/");
|
|
1368
|
+
while (s.startsWith("./")) s = s.slice(2);
|
|
1369
|
+
return s.replace(/\/{2,}/g, "/");
|
|
1370
|
+
}
|
|
1371
|
+
var MUTATING_TOOLS = /* @__PURE__ */ new Set([
|
|
1372
|
+
"write_file",
|
|
1373
|
+
"replace_in_file",
|
|
1374
|
+
"apply_patch",
|
|
1375
|
+
"apply_unified_diff",
|
|
1376
|
+
"run_shell"
|
|
1377
|
+
]);
|
|
1378
|
+
function parseReadFileSpan(content) {
|
|
1379
|
+
const body = content.replace(/^\[tool output truncated:[^\n]*\]\n\n/, "");
|
|
1380
|
+
let path43;
|
|
1381
|
+
let start;
|
|
1382
|
+
let end;
|
|
1383
|
+
try {
|
|
1384
|
+
const obj = JSON.parse(body);
|
|
1385
|
+
path43 = obj.path;
|
|
1386
|
+
start = obj.start_line;
|
|
1387
|
+
end = obj.end_line;
|
|
1388
|
+
} catch {
|
|
1389
|
+
const str2 = (key) => new RegExp(`"${key}"\\s*:\\s*"((?:[^"\\\\]|\\\\.)*)"`).exec(body)?.[1];
|
|
1390
|
+
const num2 = (key) => {
|
|
1391
|
+
const m = new RegExp(`"${key}"\\s*:\\s*(\\d+)`).exec(body);
|
|
1392
|
+
return m ? Number(m[1]) : void 0;
|
|
1393
|
+
};
|
|
1394
|
+
path43 = str2("path");
|
|
1395
|
+
start = num2("start_line");
|
|
1396
|
+
end = num2("end_line");
|
|
1397
|
+
}
|
|
1398
|
+
if (typeof path43 !== "string" || !path43) return null;
|
|
1399
|
+
if (typeof start !== "number" || typeof end !== "number") return null;
|
|
1400
|
+
if (!Number.isFinite(start) || !Number.isFinite(end)) return null;
|
|
1401
|
+
return { path: path43, start, end };
|
|
1402
|
+
}
|
|
1403
|
+
function addSpan(spans, start, end) {
|
|
1404
|
+
spans.push([start, end]);
|
|
1405
|
+
spans.sort((a, b) => a[0] - b[0]);
|
|
1406
|
+
const merged = [];
|
|
1407
|
+
for (const cur of spans) {
|
|
1408
|
+
const last = merged[merged.length - 1];
|
|
1409
|
+
if (last && cur[0] <= last[1] + 1) {
|
|
1410
|
+
last[1] = Math.max(last[1], cur[1]);
|
|
1411
|
+
} else {
|
|
1412
|
+
merged.push([...cur]);
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
spans.length = 0;
|
|
1416
|
+
spans.push(...merged);
|
|
1417
|
+
}
|
|
1418
|
+
function coversSpans(spans, start, end) {
|
|
1419
|
+
return spans.some(([a, b]) => a <= start && b >= end);
|
|
1420
|
+
}
|
|
1421
|
+
function applyReadFileDedup(messages) {
|
|
1422
|
+
let candidates = 0;
|
|
1423
|
+
for (const m of messages) {
|
|
1424
|
+
if (m.role === "tool" && m.tool_call_name === "read_file") candidates++;
|
|
1425
|
+
}
|
|
1426
|
+
if (candidates < 2) return { messages, elided: 0 };
|
|
1427
|
+
const out = [...messages];
|
|
1428
|
+
const covered = /* @__PURE__ */ new Map();
|
|
1429
|
+
let elided = 0;
|
|
1430
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1431
|
+
const m = messages[i];
|
|
1432
|
+
if (m.role === "assistant") {
|
|
1433
|
+
if (m.tool_calls?.some((tc) => MUTATING_TOOLS.has(tc.function.name))) {
|
|
1434
|
+
covered.clear();
|
|
1435
|
+
}
|
|
1436
|
+
continue;
|
|
1437
|
+
}
|
|
1438
|
+
if (m.role !== "tool" || m.tool_call_name !== "read_file") continue;
|
|
1439
|
+
const span = parseReadFileSpan(m.content);
|
|
1440
|
+
if (!span) continue;
|
|
1441
|
+
const key = normalizeToolPath(span.path);
|
|
1442
|
+
const seen = covered.get(key) ?? [];
|
|
1443
|
+
if (coversSpans(seen, span.start, span.end)) {
|
|
1444
|
+
out[i] = {
|
|
1445
|
+
...m,
|
|
1446
|
+
content: `[superseded by a later read_file of ${span.path} (lines ${span.start}-${span.end})]`
|
|
1447
|
+
};
|
|
1448
|
+
elided++;
|
|
1449
|
+
continue;
|
|
1450
|
+
}
|
|
1451
|
+
addSpan(seen, span.start, span.end);
|
|
1452
|
+
covered.set(key, seen);
|
|
1453
|
+
}
|
|
1454
|
+
return { messages: elided > 0 ? out : messages, elided };
|
|
1455
|
+
}
|
|
1271
1456
|
var OVERFLOW_MARKERS = [
|
|
1272
1457
|
"context_length_exceeded",
|
|
1273
1458
|
"maximum context length",
|
|
@@ -1283,9 +1468,116 @@ function isContextOverflow(exc) {
|
|
|
1283
1468
|
return OVERFLOW_MARKERS.some((m) => text.includes(m));
|
|
1284
1469
|
}
|
|
1285
1470
|
|
|
1471
|
+
// src/engine/toolResultBudget.ts
|
|
1472
|
+
init_cjs_shims();
|
|
1473
|
+
var fs = __toESM(require("fs"), 1);
|
|
1474
|
+
var path2 = __toESM(require("path"), 1);
|
|
1475
|
+
|
|
1476
|
+
// src/paths.ts
|
|
1477
|
+
init_cjs_shims();
|
|
1478
|
+
var os = __toESM(require("os"), 1);
|
|
1479
|
+
var path = __toESM(require("path"), 1);
|
|
1480
|
+
var APP_DIR_NAME = "zqagent";
|
|
1481
|
+
var DEFAULT_DATA_DIR = ".zqagent_data";
|
|
1482
|
+
var DEFAULT_HUB_URL = "https://hub.cd-zq.com";
|
|
1483
|
+
var IS_WINDOWS = process.platform === "win32";
|
|
1484
|
+
function homeDir() {
|
|
1485
|
+
return process.env.HOME || process.env.USERPROFILE || os.homedir() || os.tmpdir();
|
|
1486
|
+
}
|
|
1487
|
+
function configDir() {
|
|
1488
|
+
const base = process.env.XDG_CONFIG_HOME || (IS_WINDOWS ? process.env.APPDATA : void 0) || path.join(homeDir(), ".config");
|
|
1489
|
+
return path.join(base, APP_DIR_NAME);
|
|
1490
|
+
}
|
|
1491
|
+
function stateDir() {
|
|
1492
|
+
const base = process.env.XDG_STATE_HOME || (IS_WINDOWS ? process.env.LOCALAPPDATA : void 0) || path.join(homeDir(), ".local", "state");
|
|
1493
|
+
return path.join(base, APP_DIR_NAME);
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
// src/engine/toolResultBudget.ts
|
|
1497
|
+
var DEFAULT_TOOL_RESULT_MAX_CHARS = 24e3;
|
|
1498
|
+
var HEAD_RATIO = 0.6;
|
|
1499
|
+
function budgetChars() {
|
|
1500
|
+
const n = Number(process.env.TOOL_RESULT_MAX_CHARS);
|
|
1501
|
+
return Number.isFinite(n) && n > 0 ? Math.floor(n) : DEFAULT_TOOL_RESULT_MAX_CHARS;
|
|
1502
|
+
}
|
|
1503
|
+
function toolResultDir() {
|
|
1504
|
+
const env3 = process.env.TOOL_RESULT_DIR?.trim();
|
|
1505
|
+
return env3 || path2.join(stateDir(), "tool-results");
|
|
1506
|
+
}
|
|
1507
|
+
function clipText(text, budget) {
|
|
1508
|
+
if (text.length <= budget) return text;
|
|
1509
|
+
const room = Math.max(
|
|
1510
|
+
0,
|
|
1511
|
+
budget - `
|
|
1512
|
+
|
|
1513
|
+
\u2026 [${text.length} characters omitted] \u2026
|
|
1514
|
+
|
|
1515
|
+
`.length
|
|
1516
|
+
);
|
|
1517
|
+
const headLen = Math.floor(room * HEAD_RATIO);
|
|
1518
|
+
const tailLen = room - headLen;
|
|
1519
|
+
const omitted = text.length - headLen - tailLen;
|
|
1520
|
+
return text.slice(0, headLen) + `
|
|
1521
|
+
|
|
1522
|
+
\u2026 [${omitted} characters omitted] \u2026
|
|
1523
|
+
|
|
1524
|
+
` + text.slice(-tailLen);
|
|
1525
|
+
}
|
|
1526
|
+
function clipDeep(value, perField) {
|
|
1527
|
+
if (typeof value === "string") {
|
|
1528
|
+
return value.length <= perField ? value : clipText(value, perField);
|
|
1529
|
+
}
|
|
1530
|
+
if (Array.isArray(value)) {
|
|
1531
|
+
return value.map((v) => clipDeep(v, perField));
|
|
1532
|
+
}
|
|
1533
|
+
if (value && typeof value === "object") {
|
|
1534
|
+
const out = {};
|
|
1535
|
+
for (const [k, v] of Object.entries(value)) out[k] = clipDeep(v, perField);
|
|
1536
|
+
return out;
|
|
1537
|
+
}
|
|
1538
|
+
return value;
|
|
1539
|
+
}
|
|
1540
|
+
function saveRaw(tool, raw, dir) {
|
|
1541
|
+
try {
|
|
1542
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
1543
|
+
const safe2 = tool.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 40) || "tool";
|
|
1544
|
+
const name = `${Date.now()}-${process.pid}-${Math.random().toString(36).slice(2, 8)}-${safe2}.txt`;
|
|
1545
|
+
const file = path2.join(dir, name);
|
|
1546
|
+
fs.writeFileSync(file, raw, "utf-8");
|
|
1547
|
+
return file;
|
|
1548
|
+
} catch {
|
|
1549
|
+
return void 0;
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
function applyToolResultBudget(tool, result, opts = {}) {
|
|
1553
|
+
const budget = opts.maxChars ?? budgetChars();
|
|
1554
|
+
const raw = typeof result === "string" ? result : JSON.stringify(result, null, 2) ?? String(result);
|
|
1555
|
+
if (raw.length <= budget) {
|
|
1556
|
+
return { content: raw, truncated: false };
|
|
1557
|
+
}
|
|
1558
|
+
let content = raw;
|
|
1559
|
+
if (typeof result === "object" && result !== null) {
|
|
1560
|
+
let perField = Math.floor(budget * 0.7);
|
|
1561
|
+
let clipped = JSON.stringify(clipDeep(result, perField), null, 2);
|
|
1562
|
+
for (let i = 0; i < 6 && clipped && clipped.length > budget && perField > 128; i++) {
|
|
1563
|
+
perField = Math.floor(perField / 2);
|
|
1564
|
+
clipped = JSON.stringify(clipDeep(result, perField), null, 2);
|
|
1565
|
+
}
|
|
1566
|
+
if (clipped && clipped.length <= budget) content = clipped;
|
|
1567
|
+
}
|
|
1568
|
+
if (content.length > budget) content = clipText(content, budget);
|
|
1569
|
+
const savedPath = saveRaw(tool, raw, opts.dir ?? toolResultDir());
|
|
1570
|
+
if (savedPath) {
|
|
1571
|
+
content = `[tool output truncated: ${raw.length} chars, full output saved to ${savedPath}]
|
|
1572
|
+
|
|
1573
|
+
` + content;
|
|
1574
|
+
}
|
|
1575
|
+
return { content, truncated: true, savedPath };
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1286
1578
|
// src/engine/TurnEngine.ts
|
|
1287
1579
|
var crypto = __toESM(require("crypto"), 1);
|
|
1288
|
-
var
|
|
1580
|
+
var fs2 = __toESM(require("fs"), 1);
|
|
1289
1581
|
var _path = __toESM(require("path"), 1);
|
|
1290
1582
|
|
|
1291
1583
|
// src/prompts/index.ts
|
|
@@ -1411,13 +1703,17 @@ var INTERACTIVE_TOOLS = /* @__PURE__ */ new Set([
|
|
|
1411
1703
|
"propose_plan",
|
|
1412
1704
|
"request_directory"
|
|
1413
1705
|
]);
|
|
1414
|
-
|
|
1415
|
-
|
|
1706
|
+
var MAX_COMPACT_ROUNDS = 4;
|
|
1707
|
+
var OVERFLOW_TARGET_RATIO = 0.5;
|
|
1708
|
+
var OVERFLOW_TRIM_FRACTION = 0.5;
|
|
1709
|
+
var COMPACT_STALL_RETRY_DELTA = 20;
|
|
1710
|
+
function toolResultMessage(tc, result, taskId, toolResultDir2) {
|
|
1711
|
+
const budgeted = applyToolResultBudget(tc.name, result, { dir: toolResultDir2 });
|
|
1416
1712
|
return {
|
|
1417
1713
|
role: "tool",
|
|
1418
1714
|
tool_call_id: tc.id,
|
|
1419
1715
|
tool_call_name: tc.name,
|
|
1420
|
-
content,
|
|
1716
|
+
content: budgeted.content,
|
|
1421
1717
|
taskId
|
|
1422
1718
|
};
|
|
1423
1719
|
}
|
|
@@ -1528,12 +1824,22 @@ var TurnEngine = class _TurnEngine {
|
|
|
1528
1824
|
// 上下文压缩
|
|
1529
1825
|
compactionState = null;
|
|
1530
1826
|
_lastContextTokens = null;
|
|
1827
|
+
/** 压缩无进展时的消息条数快照;-1 表示无冷却 */
|
|
1828
|
+
_compactStalledAt = -1;
|
|
1531
1829
|
/** 显式配置的上下文窗口大小(token 数),未设置时为 undefined(走自动检测) */
|
|
1532
1830
|
_contextWindow;
|
|
1533
1831
|
/** 压缩触发阈值比例(默认 0.8) */
|
|
1534
1832
|
_thresholdPct;
|
|
1833
|
+
/** 软阈值比例(undefined = 取硬阈值的 75%) */
|
|
1834
|
+
_softThresholdPct;
|
|
1835
|
+
/** 是否启用软阈值淘汰(COMPACTION_ELIDE=0 可关闭) */
|
|
1836
|
+
_elisionEnabled;
|
|
1837
|
+
/** 是否启用重复读取去重(COMPACTION_DEDUP=0 可关闭) */
|
|
1838
|
+
_dedupEnabled;
|
|
1535
1839
|
/** 压缩触发阈值绝对上限(null = 不限制) */
|
|
1536
1840
|
_capTokens;
|
|
1841
|
+
/** 超预算工具结果的落盘目录(undefined = 使用默认状态目录) */
|
|
1842
|
+
_toolResultDir;
|
|
1537
1843
|
// 产出文件追踪(本轮 Turn 中成功写入的文件)
|
|
1538
1844
|
_producedFiles = [];
|
|
1539
1845
|
_turnStartTime = 0;
|
|
@@ -1585,7 +1891,15 @@ var TurnEngine = class _TurnEngine {
|
|
|
1585
1891
|
this._hook = opts.hook;
|
|
1586
1892
|
this._contextWindow = opts.contextWindow;
|
|
1587
1893
|
this._thresholdPct = opts.thresholdPct ?? DEFAULT_THRESHOLD_PCT;
|
|
1894
|
+
this._softThresholdPct = opts.softThresholdPct;
|
|
1895
|
+
this._elisionEnabled = !/^(0|false|off|no)$/i.test(
|
|
1896
|
+
(process.env.COMPACTION_ELIDE ?? "").trim()
|
|
1897
|
+
);
|
|
1898
|
+
this._dedupEnabled = !/^(0|false|off|no)$/i.test(
|
|
1899
|
+
(process.env.COMPACTION_DEDUP ?? "").trim()
|
|
1900
|
+
);
|
|
1588
1901
|
this._capTokens = opts.capTokens ?? null;
|
|
1902
|
+
this._toolResultDir = opts.toolResultDir;
|
|
1589
1903
|
this._reasoningEffort = opts.reasoningEffort;
|
|
1590
1904
|
if (this.messages.length === 0 || this.messages[0].role !== "system") {
|
|
1591
1905
|
this.messages.unshift({ role: "system", content: this.instructions });
|
|
@@ -1641,6 +1955,7 @@ var TurnEngine = class _TurnEngine {
|
|
|
1641
1955
|
this._cancel = false;
|
|
1642
1956
|
this._producedFiles = [];
|
|
1643
1957
|
this._turnStartTime = Date.now();
|
|
1958
|
+
this._compactStalledAt = -1;
|
|
1644
1959
|
this._emitHook((h) => h.onTurnStart?.(userInput));
|
|
1645
1960
|
yield {
|
|
1646
1961
|
type: "turn_start" /* TURN_START */,
|
|
@@ -2357,7 +2672,9 @@ var TurnEngine = class _TurnEngine {
|
|
|
2357
2672
|
for (let i = 0; i < concurrent.length; i++) {
|
|
2358
2673
|
const tc = concurrent[i];
|
|
2359
2674
|
const { result, status } = results[i];
|
|
2360
|
-
this.messages.push(
|
|
2675
|
+
this.messages.push(
|
|
2676
|
+
toolResultMessage(tc, result, this.taskId, this._toolResultDir)
|
|
2677
|
+
);
|
|
2361
2678
|
this._trackProducedFile(
|
|
2362
2679
|
tc,
|
|
2363
2680
|
result,
|
|
@@ -2420,7 +2737,9 @@ var TurnEngine = class _TurnEngine {
|
|
|
2420
2737
|
};
|
|
2421
2738
|
status = "error";
|
|
2422
2739
|
}
|
|
2423
|
-
this.messages.push(
|
|
2740
|
+
this.messages.push(
|
|
2741
|
+
toolResultMessage(tc, result, this.taskId, this._toolResultDir)
|
|
2742
|
+
);
|
|
2424
2743
|
this._trackProducedFile(
|
|
2425
2744
|
tc,
|
|
2426
2745
|
result,
|
|
@@ -2455,13 +2774,41 @@ var TurnEngine = class _TurnEngine {
|
|
|
2455
2774
|
* 过滤 notice 消息;tool 消息只保留必要字段;
|
|
2456
2775
|
* 其余消息剥离 display-only sidecar 字段(source/_display/ts/
|
|
2457
2776
|
* reasoning/usage),避免污染模型上下文。
|
|
2777
|
+
*
|
|
2778
|
+
* 达到软阈值时先淘汰旧工具结果(零 LLM 成本),再产出最终视图。
|
|
2458
2779
|
*/
|
|
2459
2780
|
_outboundMessages() {
|
|
2460
|
-
const
|
|
2461
|
-
const
|
|
2462
|
-
|
|
2463
|
-
|
|
2781
|
+
const base = applyToOutbound(this.messages, this.compactionState);
|
|
2782
|
+
const deduped = this._dedupEnabled ? applyReadFileDedup(base).messages : base;
|
|
2783
|
+
let view = this._finalizeOutbound(deduped);
|
|
2784
|
+
if (!this._elisionEnabled) return view;
|
|
2785
|
+
if (estimateTokens(view) < this._softTriggerTokens()) {
|
|
2786
|
+
return view;
|
|
2787
|
+
}
|
|
2788
|
+
const oneShot = applyOneShotElision(deduped);
|
|
2789
|
+
if (oneShot.freedChars > 0) {
|
|
2790
|
+
view = this._finalizeOutbound(oneShot.messages);
|
|
2791
|
+
if (estimateTokens(view) < this._softTriggerTokens()) {
|
|
2792
|
+
return view;
|
|
2793
|
+
}
|
|
2794
|
+
}
|
|
2795
|
+
const keepChars = elisionKeepChars(
|
|
2796
|
+
triggerTokens(
|
|
2797
|
+
this._getContextWindow(),
|
|
2798
|
+
this._thresholdPct,
|
|
2799
|
+
this._capTokens
|
|
2800
|
+
)
|
|
2801
|
+
);
|
|
2802
|
+
const elided = applyToolResultElision(
|
|
2803
|
+
oneShot.messages,
|
|
2804
|
+
keepChars
|
|
2464
2805
|
);
|
|
2806
|
+
if (elided.freedChars === 0) return view;
|
|
2807
|
+
return this._finalizeOutbound(elided.messages);
|
|
2808
|
+
}
|
|
2809
|
+
/** 过滤 notice + 剥离 display-only 字段,得到最终发送视图 */
|
|
2810
|
+
_finalizeOutbound(sourceMessages) {
|
|
2811
|
+
const _STRIP = /* @__PURE__ */ new Set(["source", "_display", "ts", "reasoning", "usage"]);
|
|
2465
2812
|
return sourceMessages.filter((m) => m.role !== "notice").map((m) => {
|
|
2466
2813
|
if (m.role === "tool") {
|
|
2467
2814
|
return {
|
|
@@ -2479,6 +2826,15 @@ var TurnEngine = class _TurnEngine {
|
|
|
2479
2826
|
return stripped;
|
|
2480
2827
|
});
|
|
2481
2828
|
}
|
|
2829
|
+
/** 软阈值(token 数):达到它只淘汰旧工具结果 */
|
|
2830
|
+
_softTriggerTokens() {
|
|
2831
|
+
return softTriggerTokens(
|
|
2832
|
+
this._getContextWindow(),
|
|
2833
|
+
this._thresholdPct,
|
|
2834
|
+
this._capTokens,
|
|
2835
|
+
this._softThresholdPct
|
|
2836
|
+
);
|
|
2837
|
+
}
|
|
2482
2838
|
/** 通知消息:仅用于日志/展示,不发给模型 */
|
|
2483
2839
|
_appendNotice(kind, text) {
|
|
2484
2840
|
this.messages.push({
|
|
@@ -2520,18 +2876,36 @@ var TurnEngine = class _TurnEngine {
|
|
|
2520
2876
|
return false;
|
|
2521
2877
|
}
|
|
2522
2878
|
// ===================== 自动压缩 =====================
|
|
2523
|
-
/**
|
|
2879
|
+
/**
|
|
2880
|
+
* 当前上下文 token 用量。
|
|
2881
|
+
*
|
|
2882
|
+
* API 返回的 `usage.input` 是精确值,但反映的是「上一次请求」——工具结果
|
|
2883
|
+
* 与淘汰/压缩都会让它过时。因此同时估算当前 outbound 视图,取较大者:
|
|
2884
|
+
* 宁可早一点压缩,也不要漏判导致溢出。
|
|
2885
|
+
*/
|
|
2524
2886
|
_compactionTokens() {
|
|
2525
|
-
|
|
2526
|
-
|
|
2887
|
+
const estimated = estimateTokens(this._outboundMessages());
|
|
2888
|
+
if (this._lastContextTokens == null) {
|
|
2889
|
+
return { tokens: estimated, estimated: true };
|
|
2527
2890
|
}
|
|
2528
|
-
|
|
2529
|
-
tokens:
|
|
2530
|
-
|
|
2531
|
-
};
|
|
2891
|
+
if (estimated > this._lastContextTokens) {
|
|
2892
|
+
return { tokens: estimated, estimated: true };
|
|
2893
|
+
}
|
|
2894
|
+
return { tokens: this._lastContextTokens, estimated: false };
|
|
2895
|
+
}
|
|
2896
|
+
/** 压缩后重置精确计数:后续按估算值判断 */
|
|
2897
|
+
_resetContextTokens() {
|
|
2898
|
+
this._lastContextTokens = null;
|
|
2899
|
+
}
|
|
2900
|
+
/** 当前 outbound 视图的估算 token 数 */
|
|
2901
|
+
_estimateContextTokens() {
|
|
2902
|
+
return estimateTokens(this._outboundMessages());
|
|
2532
2903
|
}
|
|
2533
2904
|
/** 检查是否需要压缩(每轮 LLM 调用前) */
|
|
2534
2905
|
_compactionDue() {
|
|
2906
|
+
if (this._compactStalledAt >= 0 && this.messages.length < this._compactStalledAt + COMPACT_STALL_RETRY_DELTA) {
|
|
2907
|
+
return false;
|
|
2908
|
+
}
|
|
2535
2909
|
const { tokens } = this._compactionTokens();
|
|
2536
2910
|
return shouldCompact(
|
|
2537
2911
|
tokens,
|
|
@@ -2578,63 +2952,82 @@ var TurnEngine = class _TurnEngine {
|
|
|
2578
2952
|
async _compactNow(reqId, force = false) {
|
|
2579
2953
|
const contextWindow = this._getContextWindow();
|
|
2580
2954
|
const messagesBefore = this._outboundMessages().length;
|
|
2581
|
-
const
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
this._capTokens
|
|
2586
|
-
)
|
|
2955
|
+
const trigger = triggerTokens(
|
|
2956
|
+
contextWindow,
|
|
2957
|
+
this._thresholdPct,
|
|
2958
|
+
this._capTokens
|
|
2587
2959
|
);
|
|
2588
|
-
const
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2960
|
+
const target = Math.floor(
|
|
2961
|
+
trigger * (force ? OVERFLOW_TARGET_RATIO : 0.9)
|
|
2962
|
+
);
|
|
2963
|
+
const model = process.env.COMPACTION_MODEL?.trim() || this.model;
|
|
2964
|
+
const reasoningEffort = summarizerReasoningEffort();
|
|
2965
|
+
let keep = Math.floor(KEEP_RECENT_FRACTION * trigger);
|
|
2966
|
+
let method = null;
|
|
2967
|
+
let lastState = null;
|
|
2968
|
+
let progressed = false;
|
|
2969
|
+
for (let round = 0; round < MAX_COMPACT_ROUNDS; round++) {
|
|
2970
|
+
if (round > 0 && this._estimateContextTokens() <= target) break;
|
|
2971
|
+
let state = null;
|
|
2972
|
+
for (let attempt = 0; attempt < 2 && !state; attempt++) {
|
|
2973
|
+
try {
|
|
2974
|
+
const logTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
2975
|
+
state = await buildState(
|
|
2976
|
+
this.messages,
|
|
2977
|
+
this.provider,
|
|
2978
|
+
model,
|
|
2979
|
+
keep,
|
|
2980
|
+
this.compactionState,
|
|
2981
|
+
{ reqId, logTime, reasoningEffort }
|
|
2982
|
+
);
|
|
2983
|
+
} catch {
|
|
2984
|
+
}
|
|
2985
|
+
}
|
|
2986
|
+
if (state) {
|
|
2987
|
+
this.compactionState = state;
|
|
2988
|
+
lastState = state;
|
|
2989
|
+
method = "summarized";
|
|
2990
|
+
progressed = true;
|
|
2991
|
+
} else {
|
|
2992
|
+
const trimmed = trimState(
|
|
2595
2993
|
this.messages,
|
|
2596
|
-
this.provider,
|
|
2597
|
-
model,
|
|
2598
|
-
keep,
|
|
2599
2994
|
this.compactionState,
|
|
2600
|
-
|
|
2995
|
+
force ? OVERFLOW_TRIM_FRACTION : 0.25
|
|
2601
2996
|
);
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
this.
|
|
2610
|
-
|
|
2997
|
+
if (!trimmed) break;
|
|
2998
|
+
this.compactionState = trimmed;
|
|
2999
|
+
lastState = trimmed;
|
|
3000
|
+
method = "trimmed";
|
|
3001
|
+
progressed = true;
|
|
3002
|
+
}
|
|
3003
|
+
this._resetContextTokens();
|
|
3004
|
+
if (this._estimateContextTokens() <= trigger) break;
|
|
3005
|
+
keep = Math.max(Math.floor(trigger * 0.05), Math.floor(keep / 2));
|
|
3006
|
+
}
|
|
3007
|
+
if (!progressed || !lastState) return { notice: null, method: null };
|
|
3008
|
+
this._compactStalledAt = this._estimateContextTokens() >= trigger ? this.messages.length : -1;
|
|
3009
|
+
const messagesAfter = this._outboundMessages().length;
|
|
3010
|
+
const common = {
|
|
3011
|
+
boundaryIndex: lastState.boundaryIndex,
|
|
3012
|
+
messagesBefore,
|
|
3013
|
+
messagesAfter
|
|
3014
|
+
};
|
|
3015
|
+
if (method === "summarized") {
|
|
2611
3016
|
return {
|
|
2612
3017
|
notice: "\u4E0A\u4E0B\u6587\u5DF2\u538B\u7F29 \u2014 \u65E9\u671F\u8F6E\u6B21\u5DF2\u6458\u8981",
|
|
2613
3018
|
method: "summarized",
|
|
2614
|
-
modelUsed:
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
messagesBefore,
|
|
2620
|
-
messagesAfter: this._outboundMessages().length
|
|
3019
|
+
modelUsed: lastState.modelUsed,
|
|
3020
|
+
summaryPreview: lastState.summaryText.slice(0, 200),
|
|
3021
|
+
keptUserMessages: lastState.userMessages.length,
|
|
3022
|
+
droppedUserMessages: lastState.userMessagesDropped,
|
|
3023
|
+
...common
|
|
2621
3024
|
};
|
|
2622
3025
|
}
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
return {
|
|
2629
|
-
notice: "\u4E0A\u4E0B\u6587\u5DF2\u88C1\u526A \u2014 \u6700\u65E7\u7684\u8F6E\u6B21\u5DF2\u4E22\u5F03\uFF08\u6458\u8981\u4E0D\u53EF\u7528\uFF09",
|
|
2630
|
-
method: "trimmed",
|
|
2631
|
-
boundaryIndex: trimmed.boundaryIndex,
|
|
2632
|
-
messagesBefore,
|
|
2633
|
-
messagesAfter: this._outboundMessages().length
|
|
2634
|
-
};
|
|
2635
|
-
}
|
|
2636
|
-
}
|
|
2637
|
-
return { notice: null, method: null };
|
|
3026
|
+
return {
|
|
3027
|
+
notice: "\u4E0A\u4E0B\u6587\u5DF2\u88C1\u526A \u2014 \u6700\u65E7\u7684\u8F6E\u6B21\u5DF2\u4E22\u5F03\uFF08\u6458\u8981\u4E0D\u53EF\u7528\uFF09",
|
|
3028
|
+
method: "trimmed",
|
|
3029
|
+
...common
|
|
3030
|
+
};
|
|
2638
3031
|
}
|
|
2639
3032
|
/** 追踪文件写入工具成功产生的文件 */
|
|
2640
3033
|
_trackProducedFile(tc, result, status) {
|
|
@@ -2644,9 +3037,9 @@ var TurnEngine = class _TurnEngine {
|
|
|
2644
3037
|
return;
|
|
2645
3038
|
}
|
|
2646
3039
|
if (result && typeof result === "object") {
|
|
2647
|
-
const
|
|
2648
|
-
if (
|
|
2649
|
-
this._producedFiles.push(
|
|
3040
|
+
const path43 = result.path;
|
|
3041
|
+
if (path43) {
|
|
3042
|
+
this._producedFiles.push(path43);
|
|
2650
3043
|
return;
|
|
2651
3044
|
}
|
|
2652
3045
|
const changed = result.changed_files;
|
|
@@ -2670,7 +3063,7 @@ var TurnEngine = class _TurnEngine {
|
|
|
2670
3063
|
_fileExists(f, ws) {
|
|
2671
3064
|
if (!ws && !_path.isAbsolute(f)) return true;
|
|
2672
3065
|
try {
|
|
2673
|
-
return
|
|
3066
|
+
return fs2.existsSync(_path.isAbsolute(f) ? f : _path.join(ws, f));
|
|
2674
3067
|
} catch {
|
|
2675
3068
|
return false;
|
|
2676
3069
|
}
|
|
@@ -2693,7 +3086,7 @@ var TurnEngine = class _TurnEngine {
|
|
|
2693
3086
|
if (depth > 4 || results.length >= 50) return;
|
|
2694
3087
|
let entries;
|
|
2695
3088
|
try {
|
|
2696
|
-
entries =
|
|
3089
|
+
entries = fs2.readdirSync(dir, { withFileTypes: true });
|
|
2697
3090
|
} catch {
|
|
2698
3091
|
return;
|
|
2699
3092
|
}
|
|
@@ -2708,7 +3101,7 @@ var TurnEngine = class _TurnEngine {
|
|
|
2708
3101
|
const ext = dotIdx !== -1 ? e.name.slice(dotIdx).toLowerCase() : "";
|
|
2709
3102
|
if (!_TurnEngine.SCAN_SUFFIXES.has(ext)) continue;
|
|
2710
3103
|
try {
|
|
2711
|
-
const st =
|
|
3104
|
+
const st = fs2.statSync(full);
|
|
2712
3105
|
if (st.mtimeMs >= since) {
|
|
2713
3106
|
results.push(
|
|
2714
3107
|
_path.relative(_path.resolve(ws), _path.resolve(full))
|
|
@@ -2730,8 +3123,8 @@ var TurnEngine = class _TurnEngine {
|
|
|
2730
3123
|
|
|
2731
3124
|
// src/providers/OpenAIProvider.ts
|
|
2732
3125
|
init_cjs_shims();
|
|
2733
|
-
var
|
|
2734
|
-
var
|
|
3126
|
+
var fs3 = __toESM(require("fs"), 1);
|
|
3127
|
+
var path3 = __toESM(require("path"), 1);
|
|
2735
3128
|
var import_openai = __toESM(require("openai"), 1);
|
|
2736
3129
|
|
|
2737
3130
|
// src/terminal.ts
|
|
@@ -2917,7 +3310,7 @@ var OpenAIProvider = class {
|
|
|
2917
3310
|
});
|
|
2918
3311
|
if (opts.logDir) {
|
|
2919
3312
|
this._logDir = opts.logDir;
|
|
2920
|
-
|
|
3313
|
+
fs3.mkdirSync(opts.logDir, { recursive: true });
|
|
2921
3314
|
}
|
|
2922
3315
|
}
|
|
2923
3316
|
// =====================================================================
|
|
@@ -3070,6 +3463,8 @@ var OpenAIProvider = class {
|
|
|
3070
3463
|
tools: this._toResponsesTools(tools, model),
|
|
3071
3464
|
// 推理强度:DeepSeek 不支持,跳过
|
|
3072
3465
|
...opts.reasoningEffort && !this._isDeepSeek(model) ? { reasoning: { effort: opts.reasoningEffort } } : {},
|
|
3466
|
+
// 限制输出长度(摘要器等轻量请求)
|
|
3467
|
+
...opts.maxTokens ? { max_output_tokens: opts.maxTokens } : {},
|
|
3073
3468
|
stream: true
|
|
3074
3469
|
}, requestOptions);
|
|
3075
3470
|
return this._responsesStream(reqId, startTime, rawStream, {
|
|
@@ -3168,6 +3563,8 @@ var OpenAIProvider = class {
|
|
|
3168
3563
|
})),
|
|
3169
3564
|
// 推理强度:DeepSeek 不支持,跳过
|
|
3170
3565
|
...opts.reasoningEffort && !this._isDeepSeek(model) ? { reasoning_effort: opts.reasoningEffort } : {},
|
|
3566
|
+
// 限制输出长度:o 系列 / gpt-5 推理模型仅支持 max_completion_tokens
|
|
3567
|
+
...opts.maxTokens ? isReasoningModel(model) ? { max_completion_tokens: opts.maxTokens } : { max_tokens: opts.maxTokens } : {},
|
|
3171
3568
|
stream: true,
|
|
3172
3569
|
// 要求返回 Token 用量统计(在流结束前的一个 chunk 中携带)
|
|
3173
3570
|
stream_options: { include_usage: true }
|
|
@@ -3281,8 +3678,8 @@ var OpenAIProvider = class {
|
|
|
3281
3678
|
if (!this._logDir) return;
|
|
3282
3679
|
try {
|
|
3283
3680
|
const today = logTime?.split("T")[0];
|
|
3284
|
-
const dir =
|
|
3285
|
-
|
|
3681
|
+
const dir = path3.join(this._logDir, today);
|
|
3682
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
3286
3683
|
const entry = {
|
|
3287
3684
|
reqId,
|
|
3288
3685
|
ts: logTime,
|
|
@@ -3294,8 +3691,8 @@ var OpenAIProvider = class {
|
|
|
3294
3691
|
toolNames: tools?.map((t) => t.function.name) ?? []
|
|
3295
3692
|
}
|
|
3296
3693
|
};
|
|
3297
|
-
|
|
3298
|
-
|
|
3694
|
+
fs3.writeFileSync(
|
|
3695
|
+
path3.join(dir, `${reqId}.json`),
|
|
3299
3696
|
JSON.stringify(entry, null, 2),
|
|
3300
3697
|
"utf-8"
|
|
3301
3698
|
);
|
|
@@ -3314,9 +3711,9 @@ var OpenAIProvider = class {
|
|
|
3314
3711
|
if (!this._logDir) return;
|
|
3315
3712
|
try {
|
|
3316
3713
|
const today = logTime?.split("T")[0];
|
|
3317
|
-
const filePath =
|
|
3318
|
-
if (!
|
|
3319
|
-
const entry = JSON.parse(
|
|
3714
|
+
const filePath = path3.join(this._logDir, today, `${reqId}.json`);
|
|
3715
|
+
if (!fs3.existsSync(filePath)) return;
|
|
3716
|
+
const entry = JSON.parse(fs3.readFileSync(filePath, "utf-8"));
|
|
3320
3717
|
entry.elapsedMs = Date.now() - startTime;
|
|
3321
3718
|
if (data.response) {
|
|
3322
3719
|
entry.response = data.response;
|
|
@@ -3324,7 +3721,7 @@ var OpenAIProvider = class {
|
|
|
3324
3721
|
if (data.error) {
|
|
3325
3722
|
entry.error = data.error;
|
|
3326
3723
|
}
|
|
3327
|
-
|
|
3724
|
+
fs3.writeFileSync(filePath, JSON.stringify(entry, null, 2), "utf-8");
|
|
3328
3725
|
} catch (e) {
|
|
3329
3726
|
console.error(e);
|
|
3330
3727
|
}
|
|
@@ -3787,62 +4184,62 @@ init_cjs_shims();
|
|
|
3787
4184
|
|
|
3788
4185
|
// src/tools/pathSafety.ts
|
|
3789
4186
|
init_cjs_shims();
|
|
3790
|
-
var
|
|
3791
|
-
var
|
|
4187
|
+
var fs4 = __toESM(require("fs"), 1);
|
|
4188
|
+
var path4 = __toESM(require("path"), 1);
|
|
3792
4189
|
function isInsideRelative(rel) {
|
|
3793
|
-
return !
|
|
4190
|
+
return !path4.isAbsolute(rel) && rel !== ".." && !rel.startsWith(`..${path4.sep}`);
|
|
3794
4191
|
}
|
|
3795
4192
|
function isFilesystemRoot(p) {
|
|
3796
|
-
return
|
|
4193
|
+
return path4.parse(p).root === p;
|
|
3797
4194
|
}
|
|
3798
4195
|
function resolveWithinRoot(workspace, target) {
|
|
3799
|
-
const abs =
|
|
4196
|
+
const abs = path4.resolve(workspace, target);
|
|
3800
4197
|
let rootReal;
|
|
3801
4198
|
try {
|
|
3802
|
-
rootReal =
|
|
4199
|
+
rootReal = fs4.realpathSync(workspace);
|
|
3803
4200
|
} catch {
|
|
3804
|
-
const rootAbs =
|
|
3805
|
-
if (!isInsideRelative(
|
|
4201
|
+
const rootAbs = path4.resolve(workspace);
|
|
4202
|
+
if (!isInsideRelative(path4.relative(rootAbs, abs))) return null;
|
|
3806
4203
|
return { root: rootAbs, real: abs };
|
|
3807
4204
|
}
|
|
3808
4205
|
if (isFilesystemRoot(rootReal)) return null;
|
|
3809
4206
|
let real;
|
|
3810
4207
|
try {
|
|
3811
|
-
real =
|
|
4208
|
+
real = fs4.realpathSync(abs);
|
|
3812
4209
|
} catch {
|
|
3813
4210
|
let probe = abs;
|
|
3814
4211
|
const tail = [];
|
|
3815
4212
|
for (; ; ) {
|
|
3816
|
-
const exists =
|
|
4213
|
+
const exists = fs4.existsSync(probe) || fs4.lstatSync(probe, { throwIfNoEntry: false }) !== void 0;
|
|
3817
4214
|
if (exists) {
|
|
3818
4215
|
try {
|
|
3819
|
-
real =
|
|
4216
|
+
real = path4.join(fs4.realpathSync(probe), ...tail);
|
|
3820
4217
|
break;
|
|
3821
4218
|
} catch {
|
|
3822
4219
|
return null;
|
|
3823
4220
|
}
|
|
3824
4221
|
}
|
|
3825
|
-
tail.unshift(
|
|
3826
|
-
const parent =
|
|
4222
|
+
tail.unshift(path4.basename(probe));
|
|
4223
|
+
const parent = path4.dirname(probe);
|
|
3827
4224
|
if (parent === probe) return null;
|
|
3828
4225
|
probe = parent;
|
|
3829
4226
|
}
|
|
3830
4227
|
}
|
|
3831
|
-
if (!isInsideRelative(
|
|
4228
|
+
if (!isInsideRelative(path4.relative(rootReal, real))) return null;
|
|
3832
4229
|
return { root: rootReal, real };
|
|
3833
4230
|
}
|
|
3834
4231
|
function isWithinRoot(workspace, target) {
|
|
3835
4232
|
return resolveWithinRoot(workspace, target) !== null;
|
|
3836
4233
|
}
|
|
3837
4234
|
function resolveEntryWithinRoot(workspace, target) {
|
|
3838
|
-
const abs =
|
|
3839
|
-
const parent = resolveWithinRoot(workspace,
|
|
4235
|
+
const abs = path4.resolve(workspace, target);
|
|
4236
|
+
const parent = resolveWithinRoot(workspace, path4.dirname(abs));
|
|
3840
4237
|
if (!parent) return null;
|
|
3841
|
-
return { root: parent.root, real:
|
|
4238
|
+
return { root: parent.root, real: path4.join(parent.real, path4.basename(abs)) };
|
|
3842
4239
|
}
|
|
3843
4240
|
|
|
3844
4241
|
// src/permissions/PermissionEngine.ts
|
|
3845
|
-
var
|
|
4242
|
+
var path5 = __toESM(require("path"), 1);
|
|
3846
4243
|
var READ_ONLY_MODES = /* @__PURE__ */ new Set(["discuss" /* DISCUSS */, "plan" /* PLAN */]);
|
|
3847
4244
|
var WRITE_TOOLS = /* @__PURE__ */ new Set([
|
|
3848
4245
|
"write_file",
|
|
@@ -3892,7 +4289,7 @@ var PermissionEngine = class {
|
|
|
3892
4289
|
/** 会话级「总是允许此命令」集合 */
|
|
3893
4290
|
sessionAllowCommands;
|
|
3894
4291
|
constructor(opts) {
|
|
3895
|
-
this.workspaceRoot =
|
|
4292
|
+
this.workspaceRoot = path5.resolve(opts.workspaceRoot);
|
|
3896
4293
|
this.mode = opts.mode;
|
|
3897
4294
|
this.allowedCommands = Array.isArray(opts.allowedCommands) ? opts.allowedCommands : [];
|
|
3898
4295
|
this.sessionAllowTools = /* @__PURE__ */ new Set();
|
|
@@ -4818,14 +5215,14 @@ function approvalToHtmlTable(input, maxLen = APPROVAL_VALUE_MAX) {
|
|
|
4818
5215
|
|
|
4819
5216
|
// src/engine/FileLogHook.ts
|
|
4820
5217
|
init_cjs_shims();
|
|
4821
|
-
var
|
|
4822
|
-
var
|
|
5218
|
+
var fs5 = __toESM(require("fs"), 1);
|
|
5219
|
+
var path6 = __toESM(require("path"), 1);
|
|
4823
5220
|
var FileLogHook = class {
|
|
4824
5221
|
constructor(sessionId, stateDir2) {
|
|
4825
5222
|
this.sessionId = sessionId;
|
|
4826
|
-
|
|
4827
|
-
this._logPath =
|
|
4828
|
-
this._statePath =
|
|
5223
|
+
fs5.mkdirSync(stateDir2, { recursive: true });
|
|
5224
|
+
this._logPath = path6.join(stateDir2, `${sessionId}.jsonl`);
|
|
5225
|
+
this._statePath = path6.join(stateDir2, `${sessionId}_state.json`);
|
|
4829
5226
|
}
|
|
4830
5227
|
sessionId;
|
|
4831
5228
|
_logPath;
|
|
@@ -4919,13 +5316,13 @@ var FileLogHook = class {
|
|
|
4919
5316
|
...meta?.nameSource !== void 0 ? { nameSource: meta.nameSource } : {},
|
|
4920
5317
|
...meta?.taskCount !== void 0 ? { taskCount: meta.taskCount } : {}
|
|
4921
5318
|
};
|
|
4922
|
-
|
|
5319
|
+
fs5.writeFileSync(this._statePath, JSON.stringify(state, null, 2), "utf-8");
|
|
4923
5320
|
}
|
|
4924
5321
|
/** 读取保存的引擎状态 */
|
|
4925
5322
|
static loadState(sessionId, stateDir2) {
|
|
4926
|
-
const p =
|
|
5323
|
+
const p = path6.join(stateDir2, `${sessionId}_state.json`);
|
|
4927
5324
|
try {
|
|
4928
|
-
const raw =
|
|
5325
|
+
const raw = fs5.readFileSync(p, "utf-8");
|
|
4929
5326
|
return JSON.parse(raw);
|
|
4930
5327
|
} catch (e) {
|
|
4931
5328
|
console.error(e);
|
|
@@ -4934,9 +5331,9 @@ var FileLogHook = class {
|
|
|
4934
5331
|
}
|
|
4935
5332
|
/** 读取事件日志 */
|
|
4936
5333
|
static loadEvents(sessionId, stateDir2) {
|
|
4937
|
-
const p =
|
|
5334
|
+
const p = path6.join(stateDir2, `${sessionId}.jsonl`);
|
|
4938
5335
|
try {
|
|
4939
|
-
const raw =
|
|
5336
|
+
const raw = fs5.readFileSync(p, "utf-8");
|
|
4940
5337
|
return raw.trim().split("\n").filter(Boolean).map((line) => JSON.parse(line));
|
|
4941
5338
|
} catch (e) {
|
|
4942
5339
|
console.error(e);
|
|
@@ -4947,7 +5344,7 @@ var FileLogHook = class {
|
|
|
4947
5344
|
_append(entry) {
|
|
4948
5345
|
entry["ts"] = (/* @__PURE__ */ new Date()).toISOString();
|
|
4949
5346
|
try {
|
|
4950
|
-
|
|
5347
|
+
fs5.appendFileSync(this._logPath, JSON.stringify(entry) + "\n", "utf-8");
|
|
4951
5348
|
} catch (e) {
|
|
4952
5349
|
console.error(e);
|
|
4953
5350
|
}
|
|
@@ -5375,12 +5772,12 @@ var McpManager = class {
|
|
|
5375
5772
|
|
|
5376
5773
|
// src/tools/files.ts
|
|
5377
5774
|
init_cjs_shims();
|
|
5378
|
-
var
|
|
5379
|
-
var
|
|
5775
|
+
var fs6 = __toESM(require("fs"), 1);
|
|
5776
|
+
var path7 = __toESM(require("path"), 1);
|
|
5380
5777
|
var DEFAULT_MAX_LINES = 2e3;
|
|
5381
5778
|
var MAX_LINE_CHARS = 500;
|
|
5382
5779
|
function makeReadFile(workspace) {
|
|
5383
|
-
const root =
|
|
5780
|
+
const root = path7.resolve(workspace);
|
|
5384
5781
|
return function read_file(args) {
|
|
5385
5782
|
const filePath = String(args.path ?? "");
|
|
5386
5783
|
const startLine = Math.max(1, Number(args.start_line ?? 1));
|
|
@@ -5390,13 +5787,13 @@ function makeReadFile(workspace) {
|
|
|
5390
5787
|
return { error: "\u8DEF\u5F84\u5728\u5DE5\u4F5C\u533A\u4E4B\u5916" };
|
|
5391
5788
|
}
|
|
5392
5789
|
const target = resolved.real;
|
|
5393
|
-
if (!
|
|
5790
|
+
if (!fs6.existsSync(target) || !fs6.statSync(target).isFile()) {
|
|
5394
5791
|
return { error: `\u4E0D\u662F\u6587\u4EF6: ${filePath}` };
|
|
5395
5792
|
}
|
|
5396
5793
|
const selected = [];
|
|
5397
5794
|
let total = 0;
|
|
5398
5795
|
try {
|
|
5399
|
-
const content =
|
|
5796
|
+
const content = fs6.readFileSync(target, "utf-8");
|
|
5400
5797
|
const lines = content.split("\n");
|
|
5401
5798
|
total = lines.length;
|
|
5402
5799
|
for (let i = startLine - 1; i < Math.min(startLine - 1 + maxLines, lines.length); i++) {
|
|
@@ -5411,7 +5808,7 @@ function makeReadFile(workspace) {
|
|
|
5411
5808
|
}
|
|
5412
5809
|
const end = startLine + selected.length - 1;
|
|
5413
5810
|
const result = {
|
|
5414
|
-
path:
|
|
5811
|
+
path: path7.relative(resolved.root, target),
|
|
5415
5812
|
start_line: startLine,
|
|
5416
5813
|
end_line: end,
|
|
5417
5814
|
total_lines: total,
|
|
@@ -5424,7 +5821,7 @@ function makeReadFile(workspace) {
|
|
|
5424
5821
|
};
|
|
5425
5822
|
}
|
|
5426
5823
|
function makeWriteFile(workspace) {
|
|
5427
|
-
const root =
|
|
5824
|
+
const root = path7.resolve(workspace);
|
|
5428
5825
|
return function write_file(args) {
|
|
5429
5826
|
const filePath = String(args.path ?? "");
|
|
5430
5827
|
const content = String(args.content ?? "");
|
|
@@ -5434,34 +5831,34 @@ function makeWriteFile(workspace) {
|
|
|
5434
5831
|
return { error: "\u8DEF\u5F84\u5728\u5DE5\u4F5C\u533A\u4E4B\u5916" };
|
|
5435
5832
|
}
|
|
5436
5833
|
const target = resolved.real;
|
|
5437
|
-
if (
|
|
5834
|
+
if (fs6.existsSync(target) && fs6.statSync(target).isDirectory()) {
|
|
5438
5835
|
return { error: "\u8DEF\u5F84\u662F\u76EE\u5F55\uFF0C\u4E0D\u662F\u6587\u4EF6" };
|
|
5439
5836
|
}
|
|
5440
|
-
if (
|
|
5837
|
+
if (fs6.existsSync(target) && !overwrite) {
|
|
5441
5838
|
return { error: "\u6587\u4EF6\u5DF2\u5B58\u5728 (overwrite=false)" };
|
|
5442
5839
|
}
|
|
5443
5840
|
try {
|
|
5444
|
-
|
|
5445
|
-
|
|
5841
|
+
fs6.mkdirSync(path7.dirname(target), { recursive: true });
|
|
5842
|
+
fs6.writeFileSync(target, content, "utf-8");
|
|
5446
5843
|
} catch (exc) {
|
|
5447
5844
|
return { error: `\u5199\u5165\u5931\u8D25: ${String(exc)}` };
|
|
5448
5845
|
}
|
|
5449
|
-
return
|
|
5846
|
+
return path7.relative(resolved.root, target);
|
|
5450
5847
|
};
|
|
5451
5848
|
}
|
|
5452
5849
|
function makeListFiles(workspace) {
|
|
5453
|
-
const root =
|
|
5850
|
+
const root = path7.resolve(workspace);
|
|
5454
5851
|
return function list_files(args) {
|
|
5455
5852
|
const dirPath = String(args.path ?? ".");
|
|
5456
5853
|
const maxResults = Math.min(Number(args.max_results ?? 100), 100);
|
|
5457
5854
|
const resolved = resolveWithinRoot(root, dirPath);
|
|
5458
5855
|
if (!resolved) return { error: "\u8DEF\u5F84\u5728\u5DE5\u4F5C\u533A\u4E4B\u5916" };
|
|
5459
5856
|
const target = resolved.real;
|
|
5460
|
-
if (!
|
|
5857
|
+
if (!fs6.existsSync(target) || !fs6.statSync(target).isDirectory()) {
|
|
5461
5858
|
return { error: `\u4E0D\u662F\u76EE\u5F55: ${dirPath}` };
|
|
5462
5859
|
}
|
|
5463
5860
|
try {
|
|
5464
|
-
const entries =
|
|
5861
|
+
const entries = fs6.readdirSync(target, { withFileTypes: true });
|
|
5465
5862
|
const results = [];
|
|
5466
5863
|
for (const e of entries) {
|
|
5467
5864
|
if (results.length >= maxResults) break;
|
|
@@ -5470,14 +5867,14 @@ function makeListFiles(workspace) {
|
|
|
5470
5867
|
results.push(e.isDirectory() ? `${e.name}/` : e.name);
|
|
5471
5868
|
}
|
|
5472
5869
|
results.sort();
|
|
5473
|
-
return { path:
|
|
5870
|
+
return { path: path7.relative(resolved.root, target), entries: results.slice(0, maxResults) };
|
|
5474
5871
|
} catch (exc) {
|
|
5475
5872
|
return { error: `\u5217\u51FA\u6587\u4EF6\u5931\u8D25: ${String(exc)}` };
|
|
5476
5873
|
}
|
|
5477
5874
|
};
|
|
5478
5875
|
}
|
|
5479
5876
|
function makeReplaceInFile(workspace) {
|
|
5480
|
-
const root =
|
|
5877
|
+
const root = path7.resolve(workspace);
|
|
5481
5878
|
return function replace_in_file(args) {
|
|
5482
5879
|
const filePath = String(args.path ?? "");
|
|
5483
5880
|
const oldStr = String(args.old ?? "");
|
|
@@ -5487,19 +5884,19 @@ function makeReplaceInFile(workspace) {
|
|
|
5487
5884
|
const resolved = resolveWithinRoot(root, filePath);
|
|
5488
5885
|
if (!resolved) return { error: "\u8DEF\u5F84\u5728\u5DE5\u4F5C\u533A\u4E4B\u5916" };
|
|
5489
5886
|
const target = resolved.real;
|
|
5490
|
-
if (!
|
|
5887
|
+
if (!fs6.existsSync(target) || !fs6.statSync(target).isFile()) {
|
|
5491
5888
|
return { error: `\u4E0D\u662F\u6587\u4EF6: ${filePath}` };
|
|
5492
5889
|
}
|
|
5493
5890
|
try {
|
|
5494
|
-
const content =
|
|
5891
|
+
const content = fs6.readFileSync(target, "utf-8");
|
|
5495
5892
|
const count = content.split(oldStr).length - 1;
|
|
5496
5893
|
if (count !== expectedReplacements) {
|
|
5497
5894
|
return { error: `\u671F\u671B ${expectedReplacements} \u5904\u66FF\u6362\uFF0C\u5B9E\u9645\u627E\u5230 ${count} \u5904: ${filePath}` };
|
|
5498
5895
|
}
|
|
5499
5896
|
const updated = content.replaceAll(oldStr, newStr);
|
|
5500
|
-
|
|
5897
|
+
fs6.writeFileSync(target, updated, "utf-8");
|
|
5501
5898
|
return {
|
|
5502
|
-
path:
|
|
5899
|
+
path: path7.relative(resolved.root, target),
|
|
5503
5900
|
replacements: count,
|
|
5504
5901
|
chars_before: content.length,
|
|
5505
5902
|
chars_after: updated.length
|
|
@@ -5600,8 +5997,8 @@ function registerFileTools(registry, workspace) {
|
|
|
5600
5997
|
|
|
5601
5998
|
// src/tools/shell.ts
|
|
5602
5999
|
init_cjs_shims();
|
|
5603
|
-
var
|
|
5604
|
-
var
|
|
6000
|
+
var fs8 = __toESM(require("fs"), 1);
|
|
6001
|
+
var path9 = __toESM(require("path"), 1);
|
|
5605
6002
|
|
|
5606
6003
|
// src/tools/execAsync.ts
|
|
5607
6004
|
init_cjs_shims();
|
|
@@ -5766,15 +6163,15 @@ function execAsync(file, argv, opts = {}) {
|
|
|
5766
6163
|
|
|
5767
6164
|
// src/tools/shellRuntime.ts
|
|
5768
6165
|
init_cjs_shims();
|
|
5769
|
-
var
|
|
5770
|
-
var
|
|
6166
|
+
var fs7 = __toESM(require("fs"), 1);
|
|
6167
|
+
var path8 = __toESM(require("path"), 1);
|
|
5771
6168
|
var WINDOWS_SUFFIXES = [".exe", ".cmd", ".bat", ".com", ""];
|
|
5772
6169
|
function pathApi(platform) {
|
|
5773
|
-
return platform === "win32" ?
|
|
6170
|
+
return platform === "win32" ? path8.win32 : path8.posix;
|
|
5774
6171
|
}
|
|
5775
6172
|
function defaultFileExists(p) {
|
|
5776
6173
|
try {
|
|
5777
|
-
return
|
|
6174
|
+
return fs7.statSync(p).isFile();
|
|
5778
6175
|
} catch {
|
|
5779
6176
|
return false;
|
|
5780
6177
|
}
|
|
@@ -5805,7 +6202,7 @@ function kindFromBasename(base) {
|
|
|
5805
6202
|
return "sh";
|
|
5806
6203
|
}
|
|
5807
6204
|
function busyboxArgs(file, command) {
|
|
5808
|
-
const base = (file ?
|
|
6205
|
+
const base = (file ? path8.win32.basename(file) : "busybox").toLowerCase().replace(/\.(exe|cmd|bat|com)$/, "");
|
|
5809
6206
|
return base === "busybox" ? ["sh", "-c", command] : ["-c", command];
|
|
5810
6207
|
}
|
|
5811
6208
|
function argsFor(kind, command) {
|
|
@@ -6072,7 +6469,7 @@ var MAX_STDERR = 5e3;
|
|
|
6072
6469
|
var MAX_BUFFER = 1024 * 1024 * 5;
|
|
6073
6470
|
var shellSessions = /* @__PURE__ */ new Map();
|
|
6074
6471
|
function sessionFor(workspace) {
|
|
6075
|
-
const key =
|
|
6472
|
+
const key = path9.resolve(workspace);
|
|
6076
6473
|
let s = shellSessions.get(key);
|
|
6077
6474
|
if (!s) {
|
|
6078
6475
|
s = { cwd: key };
|
|
@@ -6129,8 +6526,8 @@ function makeRunShell(workspace, spec, tasks, scope) {
|
|
|
6129
6526
|
let toRun = command;
|
|
6130
6527
|
if (target) {
|
|
6131
6528
|
try {
|
|
6132
|
-
const resolved =
|
|
6133
|
-
if (
|
|
6529
|
+
const resolved = path9.resolve(session.cwd, target);
|
|
6530
|
+
if (fs8.existsSync(resolved) && fs8.statSync(resolved).isDirectory()) {
|
|
6134
6531
|
session.cwd = resolved;
|
|
6135
6532
|
}
|
|
6136
6533
|
} catch {
|
|
@@ -6265,8 +6662,8 @@ init_cjs_shims();
|
|
|
6265
6662
|
|
|
6266
6663
|
// src/tools/nodeGrep.ts
|
|
6267
6664
|
init_cjs_shims();
|
|
6268
|
-
var
|
|
6269
|
-
var
|
|
6665
|
+
var fs9 = __toESM(require("fs"), 1);
|
|
6666
|
+
var path10 = __toESM(require("path"), 1);
|
|
6270
6667
|
var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
6271
6668
|
".git",
|
|
6272
6669
|
"node_modules",
|
|
@@ -6291,27 +6688,27 @@ function nodeGrep(opts) {
|
|
|
6291
6688
|
} catch (err) {
|
|
6292
6689
|
throw new Error(`\u65E0\u6548\u7684\u6B63\u5219\u8868\u8FBE\u5F0F: ${opts.pattern}\uFF08${String(err)}\uFF09`);
|
|
6293
6690
|
}
|
|
6294
|
-
const target =
|
|
6295
|
-
if (!
|
|
6691
|
+
const target = path10.resolve(opts.workspace, opts.target);
|
|
6692
|
+
if (!fs9.existsSync(target)) {
|
|
6296
6693
|
throw new Error(`\u641C\u7D22\u8DEF\u5F84\u4E0D\u5B58\u5728: ${opts.target}`);
|
|
6297
6694
|
}
|
|
6298
6695
|
const matches = [];
|
|
6299
6696
|
const scanFile = (file) => {
|
|
6300
6697
|
let stat2;
|
|
6301
6698
|
try {
|
|
6302
|
-
stat2 =
|
|
6699
|
+
stat2 = fs9.statSync(file);
|
|
6303
6700
|
} catch {
|
|
6304
6701
|
return false;
|
|
6305
6702
|
}
|
|
6306
6703
|
if (!stat2.isFile() || stat2.size > maxFileBytes) return false;
|
|
6307
6704
|
let buf;
|
|
6308
6705
|
try {
|
|
6309
|
-
buf =
|
|
6706
|
+
buf = fs9.readFileSync(file);
|
|
6310
6707
|
} catch {
|
|
6311
6708
|
return false;
|
|
6312
6709
|
}
|
|
6313
6710
|
if (looksBinary(buf)) return false;
|
|
6314
|
-
const rel =
|
|
6711
|
+
const rel = path10.relative(opts.workspace, file) || path10.basename(file);
|
|
6315
6712
|
const lines = buf.toString("utf-8").split("\n");
|
|
6316
6713
|
for (let i = 0; i < lines.length; i++) {
|
|
6317
6714
|
const raw = lines[i].replace(/\r$/, "");
|
|
@@ -6322,7 +6719,7 @@ function nodeGrep(opts) {
|
|
|
6322
6719
|
}
|
|
6323
6720
|
return false;
|
|
6324
6721
|
};
|
|
6325
|
-
const stat =
|
|
6722
|
+
const stat = fs9.statSync(target);
|
|
6326
6723
|
if (stat.isFile()) {
|
|
6327
6724
|
scanFile(target);
|
|
6328
6725
|
return matches;
|
|
@@ -6332,12 +6729,12 @@ function nodeGrep(opts) {
|
|
|
6332
6729
|
const dir = stack.pop();
|
|
6333
6730
|
let entries;
|
|
6334
6731
|
try {
|
|
6335
|
-
entries =
|
|
6732
|
+
entries = fs9.readdirSync(dir, { withFileTypes: true });
|
|
6336
6733
|
} catch {
|
|
6337
6734
|
continue;
|
|
6338
6735
|
}
|
|
6339
6736
|
for (const entry of entries) {
|
|
6340
|
-
const full =
|
|
6737
|
+
const full = path10.join(dir, entry.name);
|
|
6341
6738
|
if (entry.isDirectory()) {
|
|
6342
6739
|
if (!SKIP_DIRS.has(entry.name)) stack.push(full);
|
|
6343
6740
|
} else if (entry.isFile()) {
|
|
@@ -6350,22 +6747,22 @@ function nodeGrep(opts) {
|
|
|
6350
6747
|
|
|
6351
6748
|
// src/tools/ripgrep.ts
|
|
6352
6749
|
init_cjs_shims();
|
|
6353
|
-
var
|
|
6354
|
-
var
|
|
6355
|
-
var
|
|
6750
|
+
var fs10 = __toESM(require("fs"), 1);
|
|
6751
|
+
var os2 = __toESM(require("os"), 1);
|
|
6752
|
+
var path11 = __toESM(require("path"), 1);
|
|
6356
6753
|
var import_node_module = require("module");
|
|
6357
6754
|
var cached2;
|
|
6358
6755
|
function extractBundledRipgrep() {
|
|
6359
6756
|
try {
|
|
6360
|
-
const req2 = typeof require === "function" ? require : (0, import_node_module.createRequire)(
|
|
6757
|
+
const req2 = typeof require === "function" ? require : (0, import_node_module.createRequire)(path11.join(process.cwd(), "__zqagent__.js"));
|
|
6361
6758
|
const sea = req2("node:sea");
|
|
6362
6759
|
if (!sea?.isSea?.() || typeof sea.getAsset !== "function") return null;
|
|
6363
6760
|
const asset = sea.getAsset("rg");
|
|
6364
6761
|
if (!asset) return null;
|
|
6365
|
-
const dir =
|
|
6366
|
-
const file =
|
|
6367
|
-
|
|
6368
|
-
|
|
6762
|
+
const dir = fs10.mkdtempSync(path11.join(os2.tmpdir(), "zqagent-rg-"));
|
|
6763
|
+
const file = path11.join(dir, process.platform === "win32" ? "rg.exe" : "rg");
|
|
6764
|
+
fs10.writeFileSync(file, Buffer.from(asset));
|
|
6765
|
+
fs10.chmodSync(file, 493);
|
|
6369
6766
|
return file;
|
|
6370
6767
|
} catch {
|
|
6371
6768
|
return null;
|
|
@@ -6374,7 +6771,7 @@ function extractBundledRipgrep() {
|
|
|
6374
6771
|
function resolveRipgrep() {
|
|
6375
6772
|
if (cached2 !== void 0) return cached2;
|
|
6376
6773
|
const explicit = (process.env.ZQAGENT_RG ?? "").trim();
|
|
6377
|
-
if (explicit &&
|
|
6774
|
+
if (explicit && fs10.existsSync(explicit)) {
|
|
6378
6775
|
cached2 = explicit;
|
|
6379
6776
|
return cached2;
|
|
6380
6777
|
}
|
|
@@ -6388,7 +6785,7 @@ function resolveRipgrep() {
|
|
|
6388
6785
|
env: process.env,
|
|
6389
6786
|
fileExists: (p) => {
|
|
6390
6787
|
try {
|
|
6391
|
-
return
|
|
6788
|
+
return fs10.statSync(p).isFile();
|
|
6392
6789
|
} catch {
|
|
6393
6790
|
return false;
|
|
6394
6791
|
}
|
|
@@ -6937,8 +7334,8 @@ function registerWebTools(registry) {
|
|
|
6937
7334
|
|
|
6938
7335
|
// src/tools/git.ts
|
|
6939
7336
|
init_cjs_shims();
|
|
6940
|
-
var
|
|
6941
|
-
var
|
|
7337
|
+
var fs11 = __toESM(require("fs"), 1);
|
|
7338
|
+
var path12 = __toESM(require("path"), 1);
|
|
6942
7339
|
async function runGit(repoDir, args, timeout = 15e3) {
|
|
6943
7340
|
const res = await execAsync("git", ["-c", "core.quotepath=false", ...args], {
|
|
6944
7341
|
cwd: repoDir,
|
|
@@ -6955,9 +7352,9 @@ async function runGit(repoDir, args, timeout = 15e3) {
|
|
|
6955
7352
|
async function resolveRepoRoot(workspace, pathArg) {
|
|
6956
7353
|
let dir = workspace;
|
|
6957
7354
|
if (pathArg) {
|
|
6958
|
-
const abs =
|
|
7355
|
+
const abs = path12.resolve(workspace, pathArg);
|
|
6959
7356
|
try {
|
|
6960
|
-
dir =
|
|
7357
|
+
dir = fs11.statSync(abs).isDirectory() ? abs : path12.dirname(abs);
|
|
6961
7358
|
} catch {
|
|
6962
7359
|
dir = abs;
|
|
6963
7360
|
}
|
|
@@ -6970,24 +7367,24 @@ function repoDirArg(workspace, raw) {
|
|
|
6970
7367
|
if (typeof raw !== "string") return void 0;
|
|
6971
7368
|
const v = raw.trim();
|
|
6972
7369
|
if (!v) return void 0;
|
|
6973
|
-
const base =
|
|
6974
|
-
const abs =
|
|
6975
|
-
const rel =
|
|
6976
|
-
if (rel.startsWith("..") ||
|
|
7370
|
+
const base = path12.resolve(workspace);
|
|
7371
|
+
const abs = path12.resolve(base, v);
|
|
7372
|
+
const rel = path12.relative(base, abs);
|
|
7373
|
+
if (rel.startsWith("..") || path12.isAbsolute(rel)) return void 0;
|
|
6977
7374
|
return abs;
|
|
6978
7375
|
}
|
|
6979
7376
|
function toPathspec(repoRoot, workspace, pathArg) {
|
|
6980
7377
|
if (!pathArg) return null;
|
|
6981
|
-
const abs =
|
|
6982
|
-
let rel =
|
|
7378
|
+
const abs = path12.resolve(workspace, pathArg);
|
|
7379
|
+
let rel = path12.relative(repoRoot, abs);
|
|
6983
7380
|
if (rel === "") return ".";
|
|
6984
|
-
if (rel.startsWith("..") ||
|
|
7381
|
+
if (rel.startsWith("..") || path12.isAbsolute(rel)) {
|
|
6985
7382
|
try {
|
|
6986
|
-
const realRepo =
|
|
6987
|
-
const realAbs =
|
|
6988
|
-
const rel2 =
|
|
7383
|
+
const realRepo = fs11.realpathSync(repoRoot);
|
|
7384
|
+
const realAbs = fs11.realpathSync(abs);
|
|
7385
|
+
const rel2 = path12.relative(realRepo, realAbs);
|
|
6989
7386
|
if (rel2 === "") return ".";
|
|
6990
|
-
if (!rel2.startsWith("..") && !
|
|
7387
|
+
if (!rel2.startsWith("..") && !path12.isAbsolute(rel2)) return rel2;
|
|
6991
7388
|
} catch {
|
|
6992
7389
|
}
|
|
6993
7390
|
return null;
|
|
@@ -7413,18 +7810,18 @@ var SCAN_SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", ".hg", ".s
|
|
|
7413
7810
|
var SCAN_DEFAULT_DEPTH = 3;
|
|
7414
7811
|
var SCAN_MAX_DIRS = 2e3;
|
|
7415
7812
|
function readRepoHead(repoDir) {
|
|
7416
|
-
const dotGit =
|
|
7813
|
+
const dotGit = path12.join(repoDir, ".git");
|
|
7417
7814
|
try {
|
|
7418
7815
|
let headFile;
|
|
7419
|
-
if (
|
|
7420
|
-
headFile =
|
|
7816
|
+
if (fs11.statSync(dotGit).isDirectory()) {
|
|
7817
|
+
headFile = path12.join(dotGit, "HEAD");
|
|
7421
7818
|
} else {
|
|
7422
|
-
const raw =
|
|
7819
|
+
const raw = fs11.readFileSync(dotGit, "utf-8");
|
|
7423
7820
|
const m = /^gitdir:\s*(.+)$/m.exec(raw);
|
|
7424
7821
|
if (!m) return {};
|
|
7425
|
-
headFile =
|
|
7822
|
+
headFile = path12.join(path12.resolve(repoDir, m[1].trim()), "HEAD");
|
|
7426
7823
|
}
|
|
7427
|
-
const head =
|
|
7824
|
+
const head = fs11.readFileSync(headFile, "utf-8").trim();
|
|
7428
7825
|
const prefix = "ref: refs/heads/";
|
|
7429
7826
|
if (head.startsWith(prefix)) return { branch: head.slice(prefix.length), detached: false };
|
|
7430
7827
|
if (/^[0-9a-f]{7,40}$/i.test(head)) return { branch: head.slice(0, 7), detached: true };
|
|
@@ -7433,7 +7830,7 @@ function readRepoHead(repoDir) {
|
|
|
7433
7830
|
return {};
|
|
7434
7831
|
}
|
|
7435
7832
|
function scanGitRepos(workspace, depth = SCAN_DEFAULT_DEPTH) {
|
|
7436
|
-
const root =
|
|
7833
|
+
const root = path12.resolve(workspace);
|
|
7437
7834
|
const maxDepth = Number.isFinite(depth) ? Math.min(Math.max(Math.floor(depth), 0), 6) : SCAN_DEFAULT_DEPTH;
|
|
7438
7835
|
const repos = [];
|
|
7439
7836
|
const stack = [{ dir: root, depth: 0 }];
|
|
@@ -7446,24 +7843,24 @@ function scanGitRepos(workspace, depth = SCAN_DEFAULT_DEPTH) {
|
|
|
7446
7843
|
truncated = true;
|
|
7447
7844
|
break;
|
|
7448
7845
|
}
|
|
7449
|
-
const rel =
|
|
7450
|
-
if (
|
|
7846
|
+
const rel = path12.relative(root, dir).split(path12.sep).join("/");
|
|
7847
|
+
if (fs11.existsSync(path12.join(dir, ".git"))) {
|
|
7451
7848
|
repos.push({
|
|
7452
7849
|
path: rel,
|
|
7453
|
-
name: rel ?
|
|
7850
|
+
name: rel ? path12.basename(dir) : path12.basename(root),
|
|
7454
7851
|
...readRepoHead(dir)
|
|
7455
7852
|
});
|
|
7456
7853
|
}
|
|
7457
7854
|
if (d >= maxDepth) continue;
|
|
7458
7855
|
let entries;
|
|
7459
7856
|
try {
|
|
7460
|
-
entries =
|
|
7857
|
+
entries = fs11.readdirSync(dir, { withFileTypes: true });
|
|
7461
7858
|
} catch {
|
|
7462
7859
|
continue;
|
|
7463
7860
|
}
|
|
7464
7861
|
for (const e of entries) {
|
|
7465
7862
|
if (!e.isDirectory() || SCAN_SKIP_DIRS.has(e.name)) continue;
|
|
7466
|
-
stack.push({ dir:
|
|
7863
|
+
stack.push({ dir: path12.join(dir, e.name), depth: d + 1 });
|
|
7467
7864
|
}
|
|
7468
7865
|
}
|
|
7469
7866
|
repos.sort(
|
|
@@ -7473,9 +7870,9 @@ function scanGitRepos(workspace, depth = SCAN_DEFAULT_DEPTH) {
|
|
|
7473
7870
|
}
|
|
7474
7871
|
function makeGitRepos(workspace) {
|
|
7475
7872
|
return async function git_repos(args) {
|
|
7476
|
-
const root =
|
|
7873
|
+
const root = path12.resolve(workspace);
|
|
7477
7874
|
try {
|
|
7478
|
-
if (!
|
|
7875
|
+
if (!fs11.statSync(root).isDirectory()) return { root, repos: [], error: "\u5DE5\u4F5C\u533A\u4E0D\u662F\u76EE\u5F55" };
|
|
7479
7876
|
} catch {
|
|
7480
7877
|
return { root, repos: [], error: "\u5DE5\u4F5C\u533A\u76EE\u5F55\u4E0D\u5B58\u5728" };
|
|
7481
7878
|
}
|
|
@@ -7487,10 +7884,10 @@ function makeGitRepos(workspace) {
|
|
|
7487
7884
|
|
|
7488
7885
|
// src/tools/diff.ts
|
|
7489
7886
|
init_cjs_shims();
|
|
7490
|
-
var
|
|
7491
|
-
var
|
|
7887
|
+
var fs12 = __toESM(require("fs"), 1);
|
|
7888
|
+
var path13 = __toESM(require("path"), 1);
|
|
7492
7889
|
function makeApplyPatch(workspace) {
|
|
7493
|
-
const root =
|
|
7890
|
+
const root = path13.resolve(workspace);
|
|
7494
7891
|
return function apply_patch(args) {
|
|
7495
7892
|
const patch = String(args.patch ?? "");
|
|
7496
7893
|
if (!patch.trim()) return { error: "\u8865\u4E01\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A" };
|
|
@@ -7529,12 +7926,12 @@ function makeApplyPatch(workspace) {
|
|
|
7529
7926
|
contentLines.push(current.slice(1));
|
|
7530
7927
|
i++;
|
|
7531
7928
|
}
|
|
7532
|
-
if (
|
|
7929
|
+
if (fs12.existsSync(target)) {
|
|
7533
7930
|
return { error: `\u6587\u4EF6\u5DF2\u5B58\u5728: ${filePath}` };
|
|
7534
7931
|
}
|
|
7535
|
-
|
|
7536
|
-
|
|
7537
|
-
const rel =
|
|
7932
|
+
fs12.mkdirSync(path13.dirname(target), { recursive: true });
|
|
7933
|
+
fs12.writeFileSync(target, contentLines.join("\n") + "\n", "utf-8");
|
|
7934
|
+
const rel = path13.relative(resolved.root, target);
|
|
7538
7935
|
changedFiles.push(rel);
|
|
7539
7936
|
addedFiles.push(rel);
|
|
7540
7937
|
fileCount++;
|
|
@@ -7547,11 +7944,11 @@ function makeApplyPatch(workspace) {
|
|
|
7547
7944
|
return { error: `\u8DEF\u5F84\u5728\u5DE5\u4F5C\u533A\u4E4B\u5916: ${filePath}` };
|
|
7548
7945
|
}
|
|
7549
7946
|
const target = entry.real;
|
|
7550
|
-
if (!
|
|
7947
|
+
if (!fs12.existsSync(target)) {
|
|
7551
7948
|
return { error: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}` };
|
|
7552
7949
|
}
|
|
7553
|
-
|
|
7554
|
-
deletedFiles.push(
|
|
7950
|
+
fs12.unlinkSync(target);
|
|
7951
|
+
deletedFiles.push(path13.relative(entry.root, target));
|
|
7555
7952
|
fileCount++;
|
|
7556
7953
|
i++;
|
|
7557
7954
|
continue;
|
|
@@ -7587,10 +7984,10 @@ function makeApplyPatch(workspace) {
|
|
|
7587
7984
|
if (!chunkLines.length) {
|
|
7588
7985
|
return { error: `\u8865\u4E01\u66F4\u65B0\u6CA1\u6709 hunks: ${filePath}` };
|
|
7589
7986
|
}
|
|
7590
|
-
if (!
|
|
7987
|
+
if (!fs12.existsSync(target)) {
|
|
7591
7988
|
return { error: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}` };
|
|
7592
7989
|
}
|
|
7593
|
-
const oldLines =
|
|
7990
|
+
const oldLines = fs12.readFileSync(target, "utf-8").split("\n");
|
|
7594
7991
|
const newLines = applyPatchHunks(oldLines, chunkLines, filePath);
|
|
7595
7992
|
let finalResolved = resolved;
|
|
7596
7993
|
if (moveTo) {
|
|
@@ -7601,20 +7998,20 @@ function makeApplyPatch(workspace) {
|
|
|
7601
7998
|
finalResolved = moved;
|
|
7602
7999
|
}
|
|
7603
8000
|
const finalTarget = finalResolved.real;
|
|
7604
|
-
if (moveTo &&
|
|
8001
|
+
if (moveTo && fs12.existsSync(finalTarget) && finalTarget !== target) {
|
|
7605
8002
|
return { error: `\u6587\u4EF6\u5DF2\u5B58\u5728: ${moveTo}` };
|
|
7606
8003
|
}
|
|
7607
|
-
|
|
7608
|
-
|
|
8004
|
+
fs12.mkdirSync(path13.dirname(finalTarget), { recursive: true });
|
|
8005
|
+
fs12.writeFileSync(finalTarget, newLines.join("\n"), "utf-8");
|
|
7609
8006
|
if (moveTo && finalTarget !== target) {
|
|
7610
8007
|
const entry = resolveEntryWithinRoot(root, filePath);
|
|
7611
8008
|
if (!entry) {
|
|
7612
8009
|
return { error: `\u8DEF\u5F84\u5728\u5DE5\u4F5C\u533A\u4E4B\u5916: ${filePath}` };
|
|
7613
8010
|
}
|
|
7614
|
-
|
|
7615
|
-
deletedFiles.push(
|
|
8011
|
+
fs12.unlinkSync(entry.real);
|
|
8012
|
+
deletedFiles.push(path13.relative(resolved.root, target));
|
|
7616
8013
|
}
|
|
7617
|
-
changedFiles.push(
|
|
8014
|
+
changedFiles.push(path13.relative(finalResolved.root, finalTarget));
|
|
7618
8015
|
fileCount++;
|
|
7619
8016
|
continue;
|
|
7620
8017
|
}
|
|
@@ -7626,18 +8023,18 @@ function makeApplyPatch(workspace) {
|
|
|
7626
8023
|
return { changed_files: changedFiles, added_files: addedFiles, deleted_files: deletedFiles, file_count: fileCount };
|
|
7627
8024
|
};
|
|
7628
8025
|
}
|
|
7629
|
-
function applyPatchHunks(oldLines, chunks,
|
|
8026
|
+
function applyPatchHunks(oldLines, chunks, path43) {
|
|
7630
8027
|
let newLines = [...oldLines];
|
|
7631
8028
|
let cursor = 0;
|
|
7632
8029
|
for (const chunk of chunks) {
|
|
7633
8030
|
const oldBlock = chunk.filter((l) => l[0] === " " || l[0] === "-").map((l) => l.slice(1));
|
|
7634
8031
|
const newBlock = chunk.filter((l) => l[0] === " " || l[0] === "+").map((l) => l.slice(1));
|
|
7635
8032
|
if (!oldBlock.length) {
|
|
7636
|
-
throw new Error(`\u8865\u4E01 hunk \u5FC5\u987B\u5305\u542B\u4E0A\u4E0B\u6587\u6216\u5220\u9664\u884C: ${
|
|
8033
|
+
throw new Error(`\u8865\u4E01 hunk \u5FC5\u987B\u5305\u542B\u4E0A\u4E0B\u6587\u6216\u5220\u9664\u884C: ${path43}`);
|
|
7637
8034
|
}
|
|
7638
8035
|
const matchStart = findBlockMatch(newLines, oldBlock, cursor);
|
|
7639
8036
|
if (matchStart === -1) {
|
|
7640
|
-
throw new Error(`\u8865\u4E01\u4E0A\u4E0B\u6587\u4E0D\u5339\u914D: ${
|
|
8037
|
+
throw new Error(`\u8865\u4E01\u4E0A\u4E0B\u6587\u4E0D\u5339\u914D: ${path43}`);
|
|
7641
8038
|
}
|
|
7642
8039
|
const matchEnd = matchStart + oldBlock.length;
|
|
7643
8040
|
newLines.splice(matchStart, oldBlock.length, ...newBlock);
|
|
@@ -7654,7 +8051,7 @@ function findBlockMatch(lines, block, start) {
|
|
|
7654
8051
|
return -1;
|
|
7655
8052
|
}
|
|
7656
8053
|
function makeApplyUnifiedDiff(workspace) {
|
|
7657
|
-
const root =
|
|
8054
|
+
const root = path13.resolve(workspace);
|
|
7658
8055
|
return function apply_unified_diff(args) {
|
|
7659
8056
|
const diff = String(args.diff ?? "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
7660
8057
|
if (!diff.trim()) return { error: "diff \u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A" };
|
|
@@ -7673,26 +8070,26 @@ function makeApplyUnifiedDiff(workspace) {
|
|
|
7673
8070
|
return { error: `\u8DEF\u5F84\u5728\u5DE5\u4F5C\u533A\u4E4B\u5916: ${targetPath}` };
|
|
7674
8071
|
}
|
|
7675
8072
|
const target = resolved.real;
|
|
7676
|
-
const oldLines = oldIsDevNull ? [] :
|
|
8073
|
+
const oldLines = oldIsDevNull ? [] : fs12.existsSync(target) ? fs12.readFileSync(target, "utf-8").split("\n") : [];
|
|
7677
8074
|
const newLines = applyDiffHunks(oldLines, patch.hunks, targetPath);
|
|
7678
8075
|
hunkCount += patch.hunks.length;
|
|
7679
8076
|
if (newIsDevNull) {
|
|
7680
|
-
if (
|
|
7681
|
-
if (!
|
|
8077
|
+
if (fs12.existsSync(target)) {
|
|
8078
|
+
if (!fs12.statSync(target).isFile()) {
|
|
7682
8079
|
return { error: `\u8DEF\u5F84\u4E0D\u662F\u6587\u4EF6: ${targetPath}` };
|
|
7683
8080
|
}
|
|
7684
8081
|
const entry = resolveEntryWithinRoot(root, targetPath);
|
|
7685
8082
|
if (!entry) {
|
|
7686
8083
|
return { error: `\u8DEF\u5F84\u5728\u5DE5\u4F5C\u533A\u4E4B\u5916: ${targetPath}` };
|
|
7687
8084
|
}
|
|
7688
|
-
|
|
8085
|
+
fs12.unlinkSync(entry.real);
|
|
7689
8086
|
}
|
|
7690
|
-
deletedFiles.push(
|
|
8087
|
+
deletedFiles.push(path13.relative(resolved.root, target));
|
|
7691
8088
|
continue;
|
|
7692
8089
|
}
|
|
7693
|
-
|
|
7694
|
-
|
|
7695
|
-
const rel =
|
|
8090
|
+
fs12.mkdirSync(path13.dirname(target), { recursive: true });
|
|
8091
|
+
fs12.writeFileSync(target, newLines.join("\n"), "utf-8");
|
|
8092
|
+
const rel = path13.relative(resolved.root, target);
|
|
7696
8093
|
changedFiles.push(rel);
|
|
7697
8094
|
if (oldIsDevNull) addedFiles.push(rel);
|
|
7698
8095
|
}
|
|
@@ -7956,7 +8353,8 @@ function buildExplorerEngine(opts) {
|
|
|
7956
8353
|
model: opts.model,
|
|
7957
8354
|
instructions: EXPLORER_INSTRUCTIONS,
|
|
7958
8355
|
maxIterations: parseMaxIterations(process.env.EXPLORE_MAX_ITERATIONS, 30),
|
|
7959
|
-
hook: opts.hook
|
|
8356
|
+
hook: opts.hook,
|
|
8357
|
+
toolResultDir: opts.toolResultDir
|
|
7960
8358
|
});
|
|
7961
8359
|
}
|
|
7962
8360
|
function makeExploreTool(opts) {
|
|
@@ -7968,7 +8366,8 @@ function makeExploreTool(opts) {
|
|
|
7968
8366
|
provider: opts.provider,
|
|
7969
8367
|
model: opts.model,
|
|
7970
8368
|
readonlyRegistrars: opts.readonlyRegistrars,
|
|
7971
|
-
hook: opts.hookFactory?.()
|
|
8369
|
+
hook: opts.hookFactory?.(),
|
|
8370
|
+
toolResultDir: opts.toolResultDir
|
|
7972
8371
|
});
|
|
7973
8372
|
let report = "";
|
|
7974
8373
|
let status = "unknown";
|
|
@@ -8029,14 +8428,14 @@ function registerExploreTool(registry, opts) {
|
|
|
8029
8428
|
|
|
8030
8429
|
// src/tools/media.ts
|
|
8031
8430
|
init_cjs_shims();
|
|
8032
|
-
var
|
|
8033
|
-
var
|
|
8431
|
+
var fs14 = __toESM(require("fs"), 1);
|
|
8432
|
+
var path15 = __toESM(require("path"), 1);
|
|
8034
8433
|
|
|
8035
8434
|
// src/tools/ffmpegRuntime.ts
|
|
8036
8435
|
init_cjs_shims();
|
|
8037
|
-
var
|
|
8038
|
-
var
|
|
8039
|
-
var
|
|
8436
|
+
var fs13 = __toESM(require("fs"), 1);
|
|
8437
|
+
var os3 = __toESM(require("os"), 1);
|
|
8438
|
+
var path14 = __toESM(require("path"), 1);
|
|
8040
8439
|
var import_node_module2 = require("module");
|
|
8041
8440
|
var import_node_crypto = require("crypto");
|
|
8042
8441
|
var import_promises = require("stream/promises");
|
|
@@ -8059,29 +8458,29 @@ if (PROXY_ENV2) {
|
|
|
8059
8458
|
}
|
|
8060
8459
|
var DOWNLOAD_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
8061
8460
|
function agentBinDir(workspace) {
|
|
8062
|
-
return
|
|
8461
|
+
return path14.join(path14.resolve(workspace), ".agent", "bin");
|
|
8063
8462
|
}
|
|
8064
8463
|
function exeName(name, platform) {
|
|
8065
8464
|
return platform === "win32" ? `${name}.exe` : name;
|
|
8066
8465
|
}
|
|
8067
8466
|
function defaultFileExists2(p) {
|
|
8068
8467
|
try {
|
|
8069
|
-
return
|
|
8468
|
+
return fs13.statSync(p).isFile();
|
|
8070
8469
|
} catch {
|
|
8071
8470
|
return false;
|
|
8072
8471
|
}
|
|
8073
8472
|
}
|
|
8074
8473
|
function extractBundled(name, platform) {
|
|
8075
8474
|
try {
|
|
8076
|
-
const req2 = typeof require === "function" ? require : (0, import_node_module2.createRequire)(
|
|
8475
|
+
const req2 = typeof require === "function" ? require : (0, import_node_module2.createRequire)(path14.join(process.cwd(), "__zqagent__.js"));
|
|
8077
8476
|
const sea = req2("node:sea");
|
|
8078
8477
|
if (!sea?.isSea?.() || typeof sea.getAsset !== "function") return null;
|
|
8079
8478
|
const asset = sea.getAsset(name);
|
|
8080
8479
|
if (!asset) return null;
|
|
8081
|
-
const dir =
|
|
8082
|
-
const file =
|
|
8083
|
-
|
|
8084
|
-
|
|
8480
|
+
const dir = fs13.mkdtempSync(path14.join(os3.tmpdir(), `zqagent-${name}-`));
|
|
8481
|
+
const file = path14.join(dir, exeName(name, platform));
|
|
8482
|
+
fs13.writeFileSync(file, Buffer.from(asset));
|
|
8483
|
+
fs13.chmodSync(file, 493);
|
|
8085
8484
|
return file;
|
|
8086
8485
|
} catch {
|
|
8087
8486
|
return null;
|
|
@@ -8091,7 +8490,7 @@ function resolveOne(name, workspace, o) {
|
|
|
8091
8490
|
const envKey = name === "ffmpeg" ? ENV_FFMPEG : ENV_FFPROBE;
|
|
8092
8491
|
const explicit = (o.env[envKey] ?? "").trim();
|
|
8093
8492
|
if (explicit && o.fileExists(explicit)) return { path: explicit, source: "env" };
|
|
8094
|
-
const local =
|
|
8493
|
+
const local = path14.join(agentBinDir(workspace), exeName(name, o.platform));
|
|
8095
8494
|
if (o.fileExists(local)) return { path: local, source: "agent-bin" };
|
|
8096
8495
|
const bundled = extractBundled(name, o.platform);
|
|
8097
8496
|
if (bundled) return { path: bundled, source: "bundled" };
|
|
@@ -8105,7 +8504,7 @@ function resolveOne(name, workspace, o) {
|
|
|
8105
8504
|
var cache = /* @__PURE__ */ new Map();
|
|
8106
8505
|
function resolveMedia(workspace, opts = {}) {
|
|
8107
8506
|
const platform = opts.platform ?? process.platform;
|
|
8108
|
-
const key = `${platform}:${
|
|
8507
|
+
const key = `${platform}:${path14.resolve(workspace)}`;
|
|
8109
8508
|
const hit = cache.get(key);
|
|
8110
8509
|
if (hit) return hit;
|
|
8111
8510
|
const ctx = {
|
|
@@ -8211,7 +8610,7 @@ function parseChecksumFile(text, filename) {
|
|
|
8211
8610
|
if (!m) continue;
|
|
8212
8611
|
const hash = m[1].toLowerCase();
|
|
8213
8612
|
const name = m[2]?.trim() ?? "";
|
|
8214
|
-
if (!name || name === filename ||
|
|
8613
|
+
if (!name || name === filename || path14.basename(name) === filename) return hash;
|
|
8215
8614
|
}
|
|
8216
8615
|
const single = lines[0]?.trim();
|
|
8217
8616
|
if (lines.length === 1 && single && /^[0-9a-f]{32,128}$/i.test(single)) {
|
|
@@ -8221,7 +8620,7 @@ function parseChecksumFile(text, filename) {
|
|
|
8221
8620
|
}
|
|
8222
8621
|
async function computeChecksum(file, algo) {
|
|
8223
8622
|
const hash = (0, import_node_crypto.createHash)(algo);
|
|
8224
|
-
await (0, import_promises.pipeline)(
|
|
8623
|
+
await (0, import_promises.pipeline)(fs13.createReadStream(file), hash);
|
|
8225
8624
|
return hash.digest("hex");
|
|
8226
8625
|
}
|
|
8227
8626
|
function fetchInit() {
|
|
@@ -8236,7 +8635,7 @@ async function downloadToFile(url, dest) {
|
|
|
8236
8635
|
const resp = await (0, import_node_fetch3.default)(url, fetchInit());
|
|
8237
8636
|
if (!resp.ok) throw new Error(`HTTP ${resp.status} ${resp.statusText}`);
|
|
8238
8637
|
if (!resp.body) throw new Error("\u54CD\u5E94\u6CA1\u6709\u5185\u5BB9");
|
|
8239
|
-
await (0, import_promises.pipeline)(resp.body,
|
|
8638
|
+
await (0, import_promises.pipeline)(resp.body, fs13.createWriteStream(dest));
|
|
8240
8639
|
}
|
|
8241
8640
|
async function resolveComponentUrl(c) {
|
|
8242
8641
|
if (c.url) return c.url;
|
|
@@ -8253,12 +8652,12 @@ function findBinaryInTree(dir, names) {
|
|
|
8253
8652
|
const cur = stack.pop();
|
|
8254
8653
|
let entries;
|
|
8255
8654
|
try {
|
|
8256
|
-
entries =
|
|
8655
|
+
entries = fs13.readdirSync(cur, { withFileTypes: true });
|
|
8257
8656
|
} catch {
|
|
8258
8657
|
continue;
|
|
8259
8658
|
}
|
|
8260
8659
|
for (const e of entries) {
|
|
8261
|
-
const full =
|
|
8660
|
+
const full = path14.join(cur, e.name);
|
|
8262
8661
|
if (e.isDirectory()) {
|
|
8263
8662
|
stack.push(full);
|
|
8264
8663
|
} else if (names.includes(e.name)) {
|
|
@@ -8269,7 +8668,7 @@ function findBinaryInTree(dir, names) {
|
|
|
8269
8668
|
return null;
|
|
8270
8669
|
}
|
|
8271
8670
|
async function extractArchive(archive, dest, kind, platform) {
|
|
8272
|
-
|
|
8671
|
+
fs13.mkdirSync(dest, { recursive: true });
|
|
8273
8672
|
let res;
|
|
8274
8673
|
if (kind === "tar.xz") {
|
|
8275
8674
|
res = await execAsync("tar", ["-xJf", archive, "-C", dest]);
|
|
@@ -8305,7 +8704,7 @@ async function downloadFfmpeg(workspace, opts = {}) {
|
|
|
8305
8704
|
error: `\u6682\u4E0D\u652F\u6301\u81EA\u52A8\u4E0B\u8F7D\u7684\u5E73\u53F0: ${platform}/${arch}`
|
|
8306
8705
|
};
|
|
8307
8706
|
}
|
|
8308
|
-
const tmp =
|
|
8707
|
+
const tmp = fs13.mkdtempSync(path14.join(os3.tmpdir(), "zqagent-ffmpeg-"));
|
|
8309
8708
|
const binDir = agentBinDir(workspace);
|
|
8310
8709
|
const installed = {};
|
|
8311
8710
|
try {
|
|
@@ -8319,7 +8718,7 @@ async function downloadFfmpeg(workspace, opts = {}) {
|
|
|
8319
8718
|
}
|
|
8320
8719
|
let archive = fetched.get(url);
|
|
8321
8720
|
if (!archive) {
|
|
8322
|
-
const archivePath =
|
|
8721
|
+
const archivePath = path14.join(tmp, path14.basename(new URL(url).pathname) || `${c.name}.${c.archive}`);
|
|
8323
8722
|
log(`\u4E0B\u8F7D ${url}`);
|
|
8324
8723
|
try {
|
|
8325
8724
|
await downloadToFile(url, archivePath);
|
|
@@ -8329,7 +8728,7 @@ async function downloadFfmpeg(workspace, opts = {}) {
|
|
|
8329
8728
|
if (c.checksumUrl) {
|
|
8330
8729
|
const algo = c.checksumAlgo ?? "sha256";
|
|
8331
8730
|
try {
|
|
8332
|
-
const expected = parseChecksumFile(await fetchText(c.checksumUrl),
|
|
8731
|
+
const expected = parseChecksumFile(await fetchText(c.checksumUrl), path14.basename(archivePath));
|
|
8333
8732
|
if (!expected) {
|
|
8334
8733
|
notes.push(`\u672A\u80FD\u4ECE ${c.checksumUrl} \u89E3\u6790\u51FA\u6821\u9A8C\u548C\uFF0C\u5DF2\u8DF3\u8FC7\u6821\u9A8C`);
|
|
8335
8734
|
} else {
|
|
@@ -8346,24 +8745,24 @@ async function downloadFfmpeg(workspace, opts = {}) {
|
|
|
8346
8745
|
notes.push(`\u6821\u9A8C\u548C\u83B7\u53D6\u5931\u8D25 (${c.checksumUrl}): ${String(e instanceof Error ? e.message : e)}`);
|
|
8347
8746
|
}
|
|
8348
8747
|
} else {
|
|
8349
|
-
notes.push(`${
|
|
8748
|
+
notes.push(`${path14.basename(archivePath)} \u672A\u63D0\u4F9B\u6821\u9A8C\u548C\uFF08\u4EC5 HTTPS \u4F20\u8F93\u4FDD\u62A4\uFF09`);
|
|
8350
8749
|
}
|
|
8351
8750
|
archive = { file: archivePath, kind: c.archive };
|
|
8352
8751
|
fetched.set(url, archive);
|
|
8353
8752
|
}
|
|
8354
|
-
const extractDir =
|
|
8753
|
+
const extractDir = fs13.mkdtempSync(path14.join(tmp, "x-"));
|
|
8355
8754
|
const err = await extractArchive(archive.file, extractDir, archive.kind, platform);
|
|
8356
8755
|
if (err) return { ok: false, error: err };
|
|
8357
8756
|
const found = findBinaryInTree(extractDir, [exeName(c.name, platform), c.name]);
|
|
8358
8757
|
if (!found) {
|
|
8359
|
-
return { ok: false, error: `\u5F52\u6863\u5185\u672A\u627E\u5230 ${c.name}: ${
|
|
8758
|
+
return { ok: false, error: `\u5F52\u6863\u5185\u672A\u627E\u5230 ${c.name}: ${path14.basename(archive.file)}` };
|
|
8360
8759
|
}
|
|
8361
|
-
|
|
8362
|
-
const target =
|
|
8760
|
+
fs13.mkdirSync(binDir, { recursive: true });
|
|
8761
|
+
const target = path14.join(binDir, exeName(c.name, platform));
|
|
8363
8762
|
const staging = `${target}.tmp-${process.pid}`;
|
|
8364
|
-
|
|
8365
|
-
|
|
8366
|
-
|
|
8763
|
+
fs13.copyFileSync(found, staging);
|
|
8764
|
+
fs13.chmodSync(staging, 493);
|
|
8765
|
+
fs13.renameSync(staging, target);
|
|
8367
8766
|
installed[c.name] = target;
|
|
8368
8767
|
}
|
|
8369
8768
|
resetFfmpegCache();
|
|
@@ -8372,7 +8771,7 @@ async function downloadFfmpeg(workspace, opts = {}) {
|
|
|
8372
8771
|
} catch (e) {
|
|
8373
8772
|
return { ok: false, error: `\u5B89\u88C5\u5931\u8D25: ${String(e instanceof Error ? e.message : e)}` };
|
|
8374
8773
|
} finally {
|
|
8375
|
-
|
|
8774
|
+
fs13.rmSync(tmp, { recursive: true, force: true });
|
|
8376
8775
|
}
|
|
8377
8776
|
}
|
|
8378
8777
|
function canAutoDownload(platform, arch) {
|
|
@@ -8637,13 +9036,13 @@ function resolveTarget(workspace, value) {
|
|
|
8637
9036
|
return { abs: resolved.real, root: resolved.root };
|
|
8638
9037
|
}
|
|
8639
9038
|
function relOut(workspace, abs) {
|
|
8640
|
-
return
|
|
9039
|
+
return path15.relative(workspace, abs) || abs;
|
|
8641
9040
|
}
|
|
8642
9041
|
function registerMediaTool(registry, workspace, opts = {}) {
|
|
8643
9042
|
const platform = opts.platform ?? process.platform;
|
|
8644
9043
|
const arch = process.arch;
|
|
8645
9044
|
const media = async (args) => {
|
|
8646
|
-
const root =
|
|
9045
|
+
const root = path15.resolve(workspace);
|
|
8647
9046
|
const op = str(args["op"]);
|
|
8648
9047
|
if (!op) {
|
|
8649
9048
|
return { error: `\u7F3A\u5C11\u53C2\u6570 op\u3002\u53EF\u9009\u503C\uFF1A${OPS.join(" / ")}` };
|
|
@@ -8688,7 +9087,7 @@ function registerMediaTool(registry, workspace, opts = {}) {
|
|
|
8688
9087
|
if (!input) return { error: `\u64CD\u4F5C ${op} \u9700\u8981\u53C2\u6570 input\uFF08\u5DE5\u4F5C\u533A\u5185\u76F8\u5BF9\u8DEF\u5F84\uFF09` };
|
|
8689
9088
|
const r = resolveTarget(root, input);
|
|
8690
9089
|
if ("error" in r) return { error: r.error };
|
|
8691
|
-
if (!
|
|
9090
|
+
if (!fs14.existsSync(r.abs) || !fs14.statSync(r.abs).isFile()) {
|
|
8692
9091
|
return { error: `\u8F93\u5165\u6587\u4EF6\u4E0D\u5B58\u5728: ${input}` };
|
|
8693
9092
|
}
|
|
8694
9093
|
inputAbs = r.abs;
|
|
@@ -8700,7 +9099,7 @@ function registerMediaTool(registry, workspace, opts = {}) {
|
|
|
8700
9099
|
if (!output) return { error: `\u64CD\u4F5C ${op} \u9700\u8981\u53C2\u6570 output\uFF08\u5DE5\u4F5C\u533A\u5185\u76F8\u5BF9\u8DEF\u5F84\uFF09` };
|
|
8701
9100
|
const r = resolveTarget(root, output);
|
|
8702
9101
|
if ("error" in r) return { error: r.error };
|
|
8703
|
-
|
|
9102
|
+
fs14.mkdirSync(path15.dirname(r.abs), { recursive: true });
|
|
8704
9103
|
outputAbs = r.abs;
|
|
8705
9104
|
relRoot = r.root;
|
|
8706
9105
|
}
|
|
@@ -8750,7 +9149,7 @@ function registerMediaTool(registry, workspace, opts = {}) {
|
|
|
8750
9149
|
};
|
|
8751
9150
|
if (outputAbs) {
|
|
8752
9151
|
try {
|
|
8753
|
-
result["size_bytes"] =
|
|
9152
|
+
result["size_bytes"] = fs14.statSync(outputAbs).size;
|
|
8754
9153
|
} catch {
|
|
8755
9154
|
}
|
|
8756
9155
|
}
|
|
@@ -8993,7 +9392,9 @@ function createDefaultEngine(opts) {
|
|
|
8993
9392
|
subagentHookFactory,
|
|
8994
9393
|
contextWindow,
|
|
8995
9394
|
thresholdPct,
|
|
9395
|
+
softThresholdPct,
|
|
8996
9396
|
capTokens,
|
|
9397
|
+
toolResultDir: toolResultDir2,
|
|
8997
9398
|
logDir
|
|
8998
9399
|
} = opts;
|
|
8999
9400
|
const envEffort = process.env.OPENAI_REASONING_EFFORT?.toLowerCase();
|
|
@@ -9016,7 +9417,8 @@ function createDefaultEngine(opts) {
|
|
|
9016
9417
|
workspace,
|
|
9017
9418
|
provider: effectiveProvider,
|
|
9018
9419
|
model,
|
|
9019
|
-
hookFactory: subagentHookFactory
|
|
9420
|
+
hookFactory: subagentHookFactory,
|
|
9421
|
+
toolResultDir: toolResultDir2
|
|
9020
9422
|
});
|
|
9021
9423
|
const permissions = new PermissionEngine({
|
|
9022
9424
|
workspaceRoot: workspace,
|
|
@@ -9038,7 +9440,9 @@ function createDefaultEngine(opts) {
|
|
|
9038
9440
|
hook,
|
|
9039
9441
|
contextWindow,
|
|
9040
9442
|
thresholdPct,
|
|
9041
|
-
|
|
9443
|
+
softThresholdPct,
|
|
9444
|
+
capTokens,
|
|
9445
|
+
toolResultDir: toolResultDir2
|
|
9042
9446
|
});
|
|
9043
9447
|
return engine;
|
|
9044
9448
|
}
|
|
@@ -9048,8 +9452,8 @@ init_cjs_shims();
|
|
|
9048
9452
|
|
|
9049
9453
|
// src/llmConfig.ts
|
|
9050
9454
|
init_cjs_shims();
|
|
9051
|
-
var
|
|
9052
|
-
var
|
|
9455
|
+
var fs16 = __toESM(require("fs"), 1);
|
|
9456
|
+
var path17 = __toESM(require("path"), 1);
|
|
9053
9457
|
var crypto3 = __toESM(require("crypto"), 1);
|
|
9054
9458
|
|
|
9055
9459
|
// src/crypto/secrets.ts
|
|
@@ -9058,8 +9462,8 @@ init_cjs_shims();
|
|
|
9058
9462
|
// ../shared/src/secrets.ts
|
|
9059
9463
|
init_cjs_shims();
|
|
9060
9464
|
var crypto2 = __toESM(require("crypto"), 1);
|
|
9061
|
-
var
|
|
9062
|
-
var
|
|
9465
|
+
var fs15 = __toESM(require("fs"), 1);
|
|
9466
|
+
var path16 = __toESM(require("path"), 1);
|
|
9063
9467
|
function encryptWithKey(key, plain) {
|
|
9064
9468
|
const iv = crypto2.randomBytes(12);
|
|
9065
9469
|
const cipher = crypto2.createCipheriv("aes-256-gcm", key, iv);
|
|
@@ -9090,16 +9494,16 @@ function decryptWithKey(key, payload) {
|
|
|
9090
9494
|
}
|
|
9091
9495
|
}
|
|
9092
9496
|
function loadOrCreateMasterKey(masterKeyFile) {
|
|
9093
|
-
if (
|
|
9094
|
-
const hex =
|
|
9497
|
+
if (fs15.existsSync(masterKeyFile)) {
|
|
9498
|
+
const hex = fs15.readFileSync(masterKeyFile, "utf8").trim();
|
|
9095
9499
|
if (/^[0-9a-f]{64}$/i.test(hex)) {
|
|
9096
9500
|
return Buffer.from(hex, "hex");
|
|
9097
9501
|
}
|
|
9098
9502
|
console.warn(`\u26A0\uFE0F \u4E3B\u5BC6\u94A5\u6587\u4EF6\u635F\u574F\uFF0C\u5DF2\u91CD\u65B0\u751F\u6210\uFF08\u65E7\u5BC6\u6587\u5C06\u65E0\u6CD5\u89E3\u5BC6\uFF09`);
|
|
9099
9503
|
}
|
|
9100
9504
|
const key = crypto2.randomBytes(32);
|
|
9101
|
-
|
|
9102
|
-
|
|
9505
|
+
fs15.mkdirSync(path16.dirname(masterKeyFile), { recursive: true, mode: 448 });
|
|
9506
|
+
fs15.writeFileSync(masterKeyFile, key.toString("hex"), {
|
|
9103
9507
|
mode: 384,
|
|
9104
9508
|
encoding: "utf8"
|
|
9105
9509
|
});
|
|
@@ -9317,26 +9721,6 @@ async function probeModel(baseURL, apiKey, model) {
|
|
|
9317
9721
|
}
|
|
9318
9722
|
}
|
|
9319
9723
|
|
|
9320
|
-
// src/paths.ts
|
|
9321
|
-
init_cjs_shims();
|
|
9322
|
-
var os3 = __toESM(require("os"), 1);
|
|
9323
|
-
var path15 = __toESM(require("path"), 1);
|
|
9324
|
-
var APP_DIR_NAME = "zqagent";
|
|
9325
|
-
var DEFAULT_DATA_DIR = ".zqagent_data";
|
|
9326
|
-
var DEFAULT_HUB_URL = "https://hub.cd-zq.com";
|
|
9327
|
-
var IS_WINDOWS = process.platform === "win32";
|
|
9328
|
-
function homeDir() {
|
|
9329
|
-
return process.env.HOME || process.env.USERPROFILE || os3.homedir() || os3.tmpdir();
|
|
9330
|
-
}
|
|
9331
|
-
function configDir() {
|
|
9332
|
-
const base = process.env.XDG_CONFIG_HOME || (IS_WINDOWS ? process.env.APPDATA : void 0) || path15.join(homeDir(), ".config");
|
|
9333
|
-
return path15.join(base, APP_DIR_NAME);
|
|
9334
|
-
}
|
|
9335
|
-
function stateDir() {
|
|
9336
|
-
const base = process.env.XDG_STATE_HOME || (IS_WINDOWS ? process.env.LOCALAPPDATA : void 0) || path15.join(homeDir(), ".local", "state");
|
|
9337
|
-
return path15.join(base, APP_DIR_NAME);
|
|
9338
|
-
}
|
|
9339
|
-
|
|
9340
9724
|
// ../shared/src/llm-presets.ts
|
|
9341
9725
|
init_cjs_shims();
|
|
9342
9726
|
var LLM_PRESETS = [
|
|
@@ -9401,11 +9785,11 @@ function llmPreset(id) {
|
|
|
9401
9785
|
function llmConfigFile() {
|
|
9402
9786
|
const override = process.env.ZQAGENT_LLM_CONFIG_FILE?.trim();
|
|
9403
9787
|
if (override) return override;
|
|
9404
|
-
return
|
|
9788
|
+
return path17.join(configDir(), "connections.json");
|
|
9405
9789
|
}
|
|
9406
9790
|
var keyCache = /* @__PURE__ */ new Map();
|
|
9407
9791
|
function masterKeyFileFor(file) {
|
|
9408
|
-
return
|
|
9792
|
+
return path17.join(path17.dirname(file), "secret.key");
|
|
9409
9793
|
}
|
|
9410
9794
|
function getMasterKey(file) {
|
|
9411
9795
|
const keyFile = masterKeyFileFor(file);
|
|
@@ -9510,10 +9894,10 @@ function normalize(f) {
|
|
|
9510
9894
|
return { ...f, providers, activeId };
|
|
9511
9895
|
}
|
|
9512
9896
|
function readRaw(file, keyFile = file) {
|
|
9513
|
-
if (!
|
|
9897
|
+
if (!fs16.existsSync(file)) return null;
|
|
9514
9898
|
let raw;
|
|
9515
9899
|
try {
|
|
9516
|
-
raw = JSON.parse(
|
|
9900
|
+
raw = JSON.parse(fs16.readFileSync(file, "utf8"));
|
|
9517
9901
|
} catch {
|
|
9518
9902
|
return null;
|
|
9519
9903
|
}
|
|
@@ -9561,19 +9945,19 @@ function readLlmConfig(opts = {}) {
|
|
|
9561
9945
|
f = r.config;
|
|
9562
9946
|
changed = changed || r.changed;
|
|
9563
9947
|
}
|
|
9564
|
-
if (changed || !
|
|
9948
|
+
if (changed || !fs16.existsSync(file)) writeLlmConfig(f, file);
|
|
9565
9949
|
return f;
|
|
9566
9950
|
}
|
|
9567
9951
|
function writeLlmConfig(f, file = llmConfigFile()) {
|
|
9568
9952
|
const next = normalize(f);
|
|
9569
|
-
|
|
9570
|
-
|
|
9953
|
+
fs16.mkdirSync(path17.dirname(file), { recursive: true, mode: 448 });
|
|
9954
|
+
fs16.writeFileSync(file, JSON.stringify(next, null, 2) + "\n", {
|
|
9571
9955
|
mode: 384,
|
|
9572
9956
|
encoding: "utf8"
|
|
9573
9957
|
});
|
|
9574
9958
|
}
|
|
9575
9959
|
function commonLegacyFiles() {
|
|
9576
|
-
return [
|
|
9960
|
+
return [path17.join(stateDir(), "data", "node-llm.json")];
|
|
9577
9961
|
}
|
|
9578
9962
|
|
|
9579
9963
|
// src/cli/connection.ts
|
|
@@ -10006,17 +10390,17 @@ function renderBanner(opts = {}) {
|
|
|
10006
10390
|
// src/cli/terminalSetup.ts
|
|
10007
10391
|
init_cjs_shims();
|
|
10008
10392
|
var import_fs = require("fs");
|
|
10009
|
-
var
|
|
10393
|
+
var path18 = __toESM(require("path"), 1);
|
|
10010
10394
|
var TERM_SETUP_ENV = "ZQAGENT_TERM_SETUP";
|
|
10011
10395
|
var FALSE_FLAGS = ["0", "false", "no", "off"];
|
|
10012
10396
|
var TRUE_FLAGS = ["1", "true", "yes", "on"];
|
|
10013
10397
|
function hasWindowsTerminal(env3 = process.env, fileExists = import_fs.existsSync) {
|
|
10014
10398
|
const raw = env3.PATH ?? env3.Path ?? "";
|
|
10015
|
-
const dirs = raw.split(
|
|
10399
|
+
const dirs = raw.split(path18.delimiter).filter(Boolean);
|
|
10016
10400
|
if (env3.LOCALAPPDATA) {
|
|
10017
|
-
dirs.push(
|
|
10401
|
+
dirs.push(path18.join(env3.LOCALAPPDATA, "Microsoft", "WindowsApps"));
|
|
10018
10402
|
}
|
|
10019
|
-
return dirs.some((dir) => fileExists(
|
|
10403
|
+
return dirs.some((dir) => fileExists(path18.join(dir, "wt.exe")));
|
|
10020
10404
|
}
|
|
10021
10405
|
function detectTerminalSetup(input = {}) {
|
|
10022
10406
|
const env3 = input.env ?? process.env;
|
|
@@ -10097,13 +10481,13 @@ function renderTerminalTutorial() {
|
|
|
10097
10481
|
|
|
10098
10482
|
// src/cli/link.ts
|
|
10099
10483
|
init_cjs_shims();
|
|
10100
|
-
var
|
|
10484
|
+
var path21 = __toESM(require("path"), 1);
|
|
10101
10485
|
|
|
10102
10486
|
// src/server/store.ts
|
|
10103
10487
|
init_cjs_shims();
|
|
10104
|
-
var
|
|
10488
|
+
var fs17 = __toESM(require("fs"), 1);
|
|
10105
10489
|
var fsp = __toESM(require("fs/promises"), 1);
|
|
10106
|
-
var
|
|
10490
|
+
var path19 = __toESM(require("path"), 1);
|
|
10107
10491
|
var import_crypto = require("crypto");
|
|
10108
10492
|
|
|
10109
10493
|
// src/server/dbgTrace.ts
|
|
@@ -10157,57 +10541,57 @@ var Store = class {
|
|
|
10157
10541
|
sessionCache = /* @__PURE__ */ new Map();
|
|
10158
10542
|
// ===================== 租户 =====================
|
|
10159
10543
|
tenantDir(tenantId) {
|
|
10160
|
-
return
|
|
10544
|
+
return path19.join(this.root, "tenants", tenantId);
|
|
10161
10545
|
}
|
|
10162
10546
|
listTenants() {
|
|
10163
|
-
const dir =
|
|
10547
|
+
const dir = path19.join(this.root, "tenants");
|
|
10164
10548
|
try {
|
|
10165
|
-
return
|
|
10549
|
+
return fs17.readdirSync(dir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
10166
10550
|
} catch {
|
|
10167
10551
|
return [];
|
|
10168
10552
|
}
|
|
10169
10553
|
}
|
|
10170
10554
|
loadTenant(tenantId) {
|
|
10171
|
-
return this._readJson(
|
|
10555
|
+
return this._readJson(path19.join(this.tenantDir(tenantId), "config.json"));
|
|
10172
10556
|
}
|
|
10173
10557
|
saveTenant(config) {
|
|
10174
10558
|
const dir = this.tenantDir(config.id);
|
|
10175
|
-
|
|
10176
|
-
|
|
10559
|
+
fs17.mkdirSync(dir, { recursive: true });
|
|
10560
|
+
fs17.writeFileSync(path19.join(dir, "config.json"), JSON.stringify(config, null, 2), "utf-8");
|
|
10177
10561
|
}
|
|
10178
10562
|
deleteTenant(tenantId) {
|
|
10179
|
-
|
|
10563
|
+
fs17.rmSync(this.tenantDir(tenantId), { recursive: true, force: true });
|
|
10180
10564
|
}
|
|
10181
10565
|
// ===================== 会话 =====================
|
|
10182
10566
|
workspaceDir(tenantId, sessionId) {
|
|
10183
|
-
return
|
|
10567
|
+
return path19.join(this.tenantDir(tenantId), "workspaces", sessionId);
|
|
10184
10568
|
}
|
|
10185
10569
|
/** 创建(或复用)会话工作区沙箱目录 */
|
|
10186
10570
|
ensureWorkspace(tenantId, sessionId) {
|
|
10187
10571
|
const dir = this.workspaceDir(tenantId, sessionId);
|
|
10188
|
-
|
|
10572
|
+
fs17.mkdirSync(dir, { recursive: true });
|
|
10189
10573
|
return dir;
|
|
10190
10574
|
}
|
|
10191
10575
|
sessionDir(tenantId, sessionId) {
|
|
10192
|
-
return
|
|
10576
|
+
return path19.join(this.tenantDir(tenantId), "sessions", sessionId);
|
|
10193
10577
|
}
|
|
10194
10578
|
listSessions(tenantId) {
|
|
10195
|
-
const dir =
|
|
10579
|
+
const dir = path19.join(this.tenantDir(tenantId), "sessions");
|
|
10196
10580
|
try {
|
|
10197
|
-
return
|
|
10581
|
+
return fs17.readdirSync(dir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
10198
10582
|
} catch {
|
|
10199
10583
|
return [];
|
|
10200
10584
|
}
|
|
10201
10585
|
}
|
|
10202
10586
|
loadSession(tenantId, sessionId) {
|
|
10203
|
-
const p =
|
|
10587
|
+
const p = path19.join(this.sessionDir(tenantId, sessionId), "session.json");
|
|
10204
10588
|
try {
|
|
10205
|
-
const st =
|
|
10589
|
+
const st = fs17.statSync(p);
|
|
10206
10590
|
const key = `${st.mtimeMs}:${st.size}`;
|
|
10207
10591
|
const hit = this.sessionCache.get(p);
|
|
10208
10592
|
if (hit && hit.key === key) return hit.rec;
|
|
10209
10593
|
const __t0 = dbgNow();
|
|
10210
|
-
const rec = JSON.parse(
|
|
10594
|
+
const rec = JSON.parse(fs17.readFileSync(p, "utf-8"));
|
|
10211
10595
|
dbgMs("store.loadSession(\u89E3\u6790)", __t0, `bytes=${st.size}`);
|
|
10212
10596
|
this.sessionCache.set(p, { key, rec });
|
|
10213
10597
|
if (this.sessionCache.size > 300) {
|
|
@@ -10223,8 +10607,8 @@ var Store = class {
|
|
|
10223
10607
|
saveSession(record) {
|
|
10224
10608
|
record.savedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
10225
10609
|
const dir = this.sessionDir(record.tenantId, record.sessionId);
|
|
10226
|
-
|
|
10227
|
-
const file =
|
|
10610
|
+
fs17.mkdirSync(dir, { recursive: true });
|
|
10611
|
+
const file = path19.join(dir, "session.json");
|
|
10228
10612
|
const snapshot = JSON.stringify(record, null, 2);
|
|
10229
10613
|
const tmp = `${file}.${(0, import_crypto.randomUUID)()}.tmp`;
|
|
10230
10614
|
const prev = this.writeChains.get(file) ?? Promise.resolve();
|
|
@@ -10239,34 +10623,34 @@ var Store = class {
|
|
|
10239
10623
|
saveSessionSync(record) {
|
|
10240
10624
|
record.savedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
10241
10625
|
const dir = this.sessionDir(record.tenantId, record.sessionId);
|
|
10242
|
-
|
|
10243
|
-
|
|
10244
|
-
|
|
10626
|
+
fs17.mkdirSync(dir, { recursive: true });
|
|
10627
|
+
fs17.writeFileSync(
|
|
10628
|
+
path19.join(dir, "session.json"),
|
|
10245
10629
|
JSON.stringify(record, null, 2),
|
|
10246
10630
|
"utf-8"
|
|
10247
10631
|
);
|
|
10248
10632
|
}
|
|
10249
10633
|
deleteSession(tenantId, sessionId) {
|
|
10250
|
-
this.sessionCache.delete(
|
|
10251
|
-
|
|
10252
|
-
|
|
10634
|
+
this.sessionCache.delete(path19.join(this.sessionDir(tenantId, sessionId), "session.json"));
|
|
10635
|
+
fs17.rmSync(this.sessionDir(tenantId, sessionId), { recursive: true, force: true });
|
|
10636
|
+
fs17.rmSync(this.workspaceDir(tenantId, sessionId), { recursive: true, force: true });
|
|
10253
10637
|
}
|
|
10254
10638
|
// ===================== 事件日志 =====================
|
|
10255
10639
|
appendEvent(tenantId, sessionId, entry) {
|
|
10256
10640
|
const dir = this.sessionDir(tenantId, sessionId);
|
|
10257
|
-
|
|
10641
|
+
fs17.mkdirSync(dir, { recursive: true });
|
|
10258
10642
|
return fsp.appendFile(
|
|
10259
|
-
|
|
10643
|
+
path19.join(dir, "events.jsonl"),
|
|
10260
10644
|
JSON.stringify(entry) + "\n",
|
|
10261
10645
|
"utf-8"
|
|
10262
10646
|
).catch(() => {
|
|
10263
10647
|
});
|
|
10264
10648
|
}
|
|
10265
10649
|
loadEvents(tenantId, sessionId) {
|
|
10266
|
-
const p =
|
|
10650
|
+
const p = path19.join(this.sessionDir(tenantId, sessionId), "events.jsonl");
|
|
10267
10651
|
const __t0 = dbgNow();
|
|
10268
10652
|
try {
|
|
10269
|
-
const raw =
|
|
10653
|
+
const raw = fs17.readFileSync(p, "utf-8");
|
|
10270
10654
|
const out = raw.trim().split("\n").filter(Boolean).map((l) => JSON.parse(l));
|
|
10271
10655
|
dbgMs("store.loadEvents(\u6574\u6587\u4EF6)", __t0, `bytes=${raw.length} evts=${out.length}`);
|
|
10272
10656
|
return out;
|
|
@@ -10284,15 +10668,15 @@ var Store = class {
|
|
|
10284
10668
|
* 窗口内一条完整记录都没有时回退为整文件读取。
|
|
10285
10669
|
*/
|
|
10286
10670
|
loadEventsTail(tenantId, sessionId, maxBytes = 1024 * 1024) {
|
|
10287
|
-
const p =
|
|
10671
|
+
const p = path19.join(this.sessionDir(tenantId, sessionId), "events.jsonl");
|
|
10288
10672
|
const __t0 = dbgNow();
|
|
10289
10673
|
let fd = null;
|
|
10290
10674
|
try {
|
|
10291
|
-
const size =
|
|
10675
|
+
const size = fs17.statSync(p).size;
|
|
10292
10676
|
if (size <= maxBytes) return this.loadEvents(tenantId, sessionId);
|
|
10293
|
-
fd =
|
|
10677
|
+
fd = fs17.openSync(p, "r");
|
|
10294
10678
|
const buf = Buffer.allocUnsafe(maxBytes);
|
|
10295
|
-
const read2 =
|
|
10679
|
+
const read2 = fs17.readSync(fd, buf, 0, maxBytes, size - maxBytes);
|
|
10296
10680
|
let text = buf.subarray(0, read2).toString("utf-8");
|
|
10297
10681
|
const nl = text.indexOf("\n");
|
|
10298
10682
|
if (nl < 0) return this.loadEvents(tenantId, sessionId);
|
|
@@ -10317,7 +10701,7 @@ var Store = class {
|
|
|
10317
10701
|
} finally {
|
|
10318
10702
|
if (fd !== null) {
|
|
10319
10703
|
try {
|
|
10320
|
-
|
|
10704
|
+
fs17.closeSync(fd);
|
|
10321
10705
|
} catch {
|
|
10322
10706
|
}
|
|
10323
10707
|
}
|
|
@@ -10326,26 +10710,26 @@ var Store = class {
|
|
|
10326
10710
|
// ===================== 节点身份 & 管理员密钥 =====================
|
|
10327
10711
|
/** 节点稳定标识:{root}/node.json(首次启动生成后长期固定) */
|
|
10328
10712
|
loadNodeId() {
|
|
10329
|
-
const v = this._readJson(
|
|
10713
|
+
const v = this._readJson(path19.join(this.root, "node.json"));
|
|
10330
10714
|
return v?.id && typeof v.id === "string" ? v.id : null;
|
|
10331
10715
|
}
|
|
10332
10716
|
saveNodeId(id) {
|
|
10333
|
-
|
|
10334
|
-
const file =
|
|
10717
|
+
fs17.mkdirSync(this.root, { recursive: true });
|
|
10718
|
+
const file = path19.join(this.root, "node.json");
|
|
10335
10719
|
const cur = this._readJson(file) ?? {};
|
|
10336
|
-
|
|
10720
|
+
fs17.writeFileSync(file, JSON.stringify({ ...cur, id }, null, 2), "utf-8");
|
|
10337
10721
|
}
|
|
10338
10722
|
/** 节点展示名:{root}/node.json 的 label(Hub 下发或本地设置) */
|
|
10339
10723
|
loadNodeLabel() {
|
|
10340
|
-
const v = this._readJson(
|
|
10724
|
+
const v = this._readJson(path19.join(this.root, "node.json"));
|
|
10341
10725
|
return v?.label && typeof v.label === "string" ? v.label : null;
|
|
10342
10726
|
}
|
|
10343
10727
|
/** 写入/更新节点展示名(保留 id 等既有字段) */
|
|
10344
10728
|
saveNodeLabel(label) {
|
|
10345
|
-
|
|
10346
|
-
const file =
|
|
10729
|
+
fs17.mkdirSync(this.root, { recursive: true });
|
|
10730
|
+
const file = path19.join(this.root, "node.json");
|
|
10347
10731
|
const cur = this._readJson(file) ?? {};
|
|
10348
|
-
|
|
10732
|
+
fs17.writeFileSync(file, JSON.stringify({ ...cur, label }, null, 2), "utf-8");
|
|
10349
10733
|
}
|
|
10350
10734
|
/**
|
|
10351
10735
|
* 节点级 LLM 配置:统一存放于本机 `~/.config/zqagent/connections.json`
|
|
@@ -10356,7 +10740,7 @@ var Store = class {
|
|
|
10356
10740
|
const file = this.llmFile();
|
|
10357
10741
|
const cfg = readLlmConfig({
|
|
10358
10742
|
file,
|
|
10359
|
-
legacyFiles: [
|
|
10743
|
+
legacyFiles: [path19.join(this.root, "node-llm.json")]
|
|
10360
10744
|
});
|
|
10361
10745
|
return {
|
|
10362
10746
|
providers: cfg.providers.map((p) => ({
|
|
@@ -10378,7 +10762,7 @@ var Store = class {
|
|
|
10378
10762
|
const file = this.llmFile();
|
|
10379
10763
|
const cur = readLlmConfig({
|
|
10380
10764
|
file,
|
|
10381
|
-
legacyFiles: [
|
|
10765
|
+
legacyFiles: [path19.join(this.root, "node-llm.json")]
|
|
10382
10766
|
});
|
|
10383
10767
|
const old = new Map(cur.providers.map((p) => [p.id, p]));
|
|
10384
10768
|
const providers = cfg.providers.map((p) => {
|
|
@@ -10410,13 +10794,13 @@ var Store = class {
|
|
|
10410
10794
|
}
|
|
10411
10795
|
/** 管理员密钥:{root}/admin.json(可跨项目操作;桌面外壳注入) */
|
|
10412
10796
|
loadAdminKey() {
|
|
10413
|
-
const v = this._readJson(
|
|
10797
|
+
const v = this._readJson(path19.join(this.root, "admin.json"));
|
|
10414
10798
|
return v?.apiKey && typeof v.apiKey === "string" ? v.apiKey : null;
|
|
10415
10799
|
}
|
|
10416
10800
|
saveAdminKey(apiKey) {
|
|
10417
|
-
|
|
10418
|
-
|
|
10419
|
-
|
|
10801
|
+
fs17.mkdirSync(this.root, { recursive: true });
|
|
10802
|
+
fs17.writeFileSync(
|
|
10803
|
+
path19.join(this.root, "admin.json"),
|
|
10420
10804
|
JSON.stringify({ apiKey }, null, 2),
|
|
10421
10805
|
"utf-8"
|
|
10422
10806
|
);
|
|
@@ -10426,18 +10810,18 @@ var Store = class {
|
|
|
10426
10810
|
* 节点凭注册码接入后写入;启动时优先于环境变量读取。
|
|
10427
10811
|
*/
|
|
10428
10812
|
loadFleetCredential() {
|
|
10429
|
-
return this._readJson(
|
|
10813
|
+
return this._readJson(path19.join(this.root, "fleet.json"));
|
|
10430
10814
|
}
|
|
10431
10815
|
saveFleetCredential(cred) {
|
|
10432
|
-
|
|
10433
|
-
|
|
10434
|
-
|
|
10816
|
+
fs17.mkdirSync(this.root, { recursive: true });
|
|
10817
|
+
fs17.writeFileSync(
|
|
10818
|
+
path19.join(this.root, "fleet.json"),
|
|
10435
10819
|
JSON.stringify(cred, null, 2),
|
|
10436
10820
|
{ encoding: "utf-8", mode: 384 }
|
|
10437
10821
|
);
|
|
10438
10822
|
}
|
|
10439
10823
|
clearFleetCredential() {
|
|
10440
|
-
|
|
10824
|
+
fs17.rmSync(path19.join(this.root, "fleet.json"), { force: true });
|
|
10441
10825
|
}
|
|
10442
10826
|
/** 数据根目录(只读;节点管理配置等辅助文件定位用) */
|
|
10443
10827
|
get rootDir() {
|
|
@@ -10446,7 +10830,7 @@ var Store = class {
|
|
|
10446
10830
|
// ===================== 工具 =====================
|
|
10447
10831
|
_readJson(p) {
|
|
10448
10832
|
try {
|
|
10449
|
-
return JSON.parse(
|
|
10833
|
+
return JSON.parse(fs17.readFileSync(p, "utf-8"));
|
|
10450
10834
|
} catch {
|
|
10451
10835
|
return null;
|
|
10452
10836
|
}
|
|
@@ -10459,13 +10843,13 @@ var baseUrlResolver = null;
|
|
|
10459
10843
|
function resolveBase(baseUrl) {
|
|
10460
10844
|
return baseUrlResolver ? baseUrlResolver(baseUrl) : baseUrl;
|
|
10461
10845
|
}
|
|
10462
|
-
async function req(baseUrl, token,
|
|
10846
|
+
async function req(baseUrl, token, path43, init = {}) {
|
|
10463
10847
|
const headers = {
|
|
10464
10848
|
...init.body ? { "Content-Type": "application/json" } : {},
|
|
10465
10849
|
...init.headers ?? {}
|
|
10466
10850
|
};
|
|
10467
10851
|
if (token) headers.Authorization = `Bearer ${token}`;
|
|
10468
|
-
const res = await fetch(`${resolveBase(baseUrl).replace(/\/$/, "")}${
|
|
10852
|
+
const res = await fetch(`${resolveBase(baseUrl).replace(/\/$/, "")}${path43}`, {
|
|
10469
10853
|
...init,
|
|
10470
10854
|
headers
|
|
10471
10855
|
});
|
|
@@ -10508,8 +10892,8 @@ async function hubEnrollByAccount(baseUrl, input) {
|
|
|
10508
10892
|
// src/cli/serve-instances.ts
|
|
10509
10893
|
init_cjs_shims();
|
|
10510
10894
|
var import_node_child_process4 = require("child_process");
|
|
10511
|
-
var
|
|
10512
|
-
var
|
|
10895
|
+
var fs18 = __toESM(require("fs"), 1);
|
|
10896
|
+
var path20 = __toESM(require("path"), 1);
|
|
10513
10897
|
var DEFAULT_SERVE_HOST = "127.0.0.1";
|
|
10514
10898
|
var DEFAULT_SERVE_PORT = 8787;
|
|
10515
10899
|
function serveSubcommandIndex(argv) {
|
|
@@ -10547,9 +10931,9 @@ function parseServeArgs(argv) {
|
|
|
10547
10931
|
}
|
|
10548
10932
|
function buildHotCandidates(explicitDataDir, discovered, fallback) {
|
|
10549
10933
|
if (explicitDataDir) {
|
|
10550
|
-
return [{ dataDir:
|
|
10934
|
+
return [{ dataDir: path20.resolve(explicitDataDir), ...fallback }];
|
|
10551
10935
|
}
|
|
10552
|
-
const out = [{ dataDir:
|
|
10936
|
+
const out = [{ dataDir: path20.resolve(DEFAULT_DATA_DIR), ...fallback }];
|
|
10553
10937
|
for (const inst of discovered) {
|
|
10554
10938
|
if (!out.some((o) => o.dataDir === inst.dataDir)) out.push(inst);
|
|
10555
10939
|
}
|
|
@@ -10557,7 +10941,7 @@ function buildHotCandidates(explicitDataDir, discovered, fallback) {
|
|
|
10557
10941
|
}
|
|
10558
10942
|
function processCwd(pid) {
|
|
10559
10943
|
try {
|
|
10560
|
-
return
|
|
10944
|
+
return fs18.readlinkSync(`/proc/${pid}/cwd`);
|
|
10561
10945
|
} catch {
|
|
10562
10946
|
return null;
|
|
10563
10947
|
}
|
|
@@ -10565,7 +10949,7 @@ function processCwd(pid) {
|
|
|
10565
10949
|
function processEnv(pid) {
|
|
10566
10950
|
const out = {};
|
|
10567
10951
|
try {
|
|
10568
|
-
const raw =
|
|
10952
|
+
const raw = fs18.readFileSync(`/proc/${pid}/environ`, "utf-8");
|
|
10569
10953
|
for (const entry of raw.split("\0")) {
|
|
10570
10954
|
const eq = entry.indexOf("=");
|
|
10571
10955
|
if (eq > 0) out[entry.slice(0, eq)] = entry.slice(eq + 1);
|
|
@@ -10576,14 +10960,14 @@ function processEnv(pid) {
|
|
|
10576
10960
|
}
|
|
10577
10961
|
function resolveDataDir(rawDataDir, cwd, env3) {
|
|
10578
10962
|
const pick = rawDataDir ?? env3.DATA_DIR ?? null;
|
|
10579
|
-
if (pick) return
|
|
10580
|
-
return cwd ?
|
|
10963
|
+
if (pick) return path20.isAbsolute(pick) ? path20.normalize(pick) : cwd ? path20.resolve(cwd, pick) : null;
|
|
10964
|
+
return cwd ? path20.resolve(cwd, DEFAULT_DATA_DIR) : null;
|
|
10581
10965
|
}
|
|
10582
10966
|
function discoverFromProc() {
|
|
10583
10967
|
const out = [];
|
|
10584
10968
|
let pids;
|
|
10585
10969
|
try {
|
|
10586
|
-
pids =
|
|
10970
|
+
pids = fs18.readdirSync("/proc");
|
|
10587
10971
|
} catch {
|
|
10588
10972
|
return out;
|
|
10589
10973
|
}
|
|
@@ -10593,7 +10977,7 @@ function discoverFromProc() {
|
|
|
10593
10977
|
if (pid === process.pid) continue;
|
|
10594
10978
|
let argv;
|
|
10595
10979
|
try {
|
|
10596
|
-
argv =
|
|
10980
|
+
argv = fs18.readFileSync(`/proc/${pid}/cmdline`, "utf-8").split("\0").filter(Boolean);
|
|
10597
10981
|
} catch {
|
|
10598
10982
|
continue;
|
|
10599
10983
|
}
|
|
@@ -10614,11 +10998,11 @@ function discoverFromPs() {
|
|
|
10614
10998
|
const m = /--data-dir(?:=|\s+)(.+?)(?=\s+--|\s*$)/.exec(line);
|
|
10615
10999
|
if (!m) continue;
|
|
10616
11000
|
const raw = m[1].trim();
|
|
10617
|
-
if (!raw || !
|
|
11001
|
+
if (!raw || !path20.isAbsolute(raw)) continue;
|
|
10618
11002
|
const host = /--host(?:=|\s+)(\S+)/.exec(line)?.[1] ?? DEFAULT_SERVE_HOST;
|
|
10619
11003
|
const port = Number(/--port(?:=|\s+)(\d+)/.exec(line)?.[1] ?? DEFAULT_SERVE_PORT);
|
|
10620
11004
|
out.push({
|
|
10621
|
-
dataDir:
|
|
11005
|
+
dataDir: path20.normalize(raw),
|
|
10622
11006
|
host: host === "0.0.0.0" || host === "::" ? DEFAULT_SERVE_HOST : host,
|
|
10623
11007
|
port: Number.isFinite(port) && port > 0 ? port : DEFAULT_SERVE_PORT
|
|
10624
11008
|
});
|
|
@@ -10721,7 +11105,7 @@ async function linkNode(opts) {
|
|
|
10721
11105
|
const status = await enrollViaServer(inst.host, inst.port, adminKey, opts);
|
|
10722
11106
|
return { mode: "hot", ...status, dataDir: inst.dataDir };
|
|
10723
11107
|
}
|
|
10724
|
-
const dataDir =
|
|
11108
|
+
const dataDir = path21.resolve(explicitDataDir ?? DEFAULT_DATA_DIR);
|
|
10725
11109
|
const store = new Store(dataDir);
|
|
10726
11110
|
const nodeId = ensureNodeId(store);
|
|
10727
11111
|
const cred = await hubEnrollByCode(opts.hubUrl, {
|
|
@@ -10803,11 +11187,12 @@ init_cjs_shims();
|
|
|
10803
11187
|
|
|
10804
11188
|
// src/server/runtime.ts
|
|
10805
11189
|
init_cjs_shims();
|
|
10806
|
-
var
|
|
10807
|
-
var
|
|
11190
|
+
var fs30 = __toESM(require("fs"), 1);
|
|
11191
|
+
var path37 = __toESM(require("path"), 1);
|
|
10808
11192
|
|
|
10809
11193
|
// src/server/session.ts
|
|
10810
11194
|
init_cjs_shims();
|
|
11195
|
+
var path24 = __toESM(require("path"), 1);
|
|
10811
11196
|
var import_async_hooks = require("async_hooks");
|
|
10812
11197
|
|
|
10813
11198
|
// src/server/mcpConfig.ts
|
|
@@ -10988,8 +11373,8 @@ function resolveSessionProvider(store, tenant, providerId) {
|
|
|
10988
11373
|
|
|
10989
11374
|
// src/server/usage.ts
|
|
10990
11375
|
init_cjs_shims();
|
|
10991
|
-
var
|
|
10992
|
-
var
|
|
11376
|
+
var fs20 = __toESM(require("fs"), 1);
|
|
11377
|
+
var path23 = __toESM(require("path"), 1);
|
|
10993
11378
|
var LEDGER_RETENTION_MONTHS = 12;
|
|
10994
11379
|
var USAGE_SCHEMA = 1;
|
|
10995
11380
|
var DEFAULT_PRICING = {
|
|
@@ -11070,15 +11455,15 @@ function retainedMonths(now = /* @__PURE__ */ new Date()) {
|
|
|
11070
11455
|
return out;
|
|
11071
11456
|
}
|
|
11072
11457
|
function atomicWrite(file, content) {
|
|
11073
|
-
|
|
11458
|
+
fs20.mkdirSync(path23.dirname(file), { recursive: true });
|
|
11074
11459
|
const tmp = `${file}.tmp`;
|
|
11075
|
-
|
|
11076
|
-
|
|
11460
|
+
fs20.writeFileSync(tmp, content, "utf-8");
|
|
11461
|
+
fs20.renameSync(tmp, file);
|
|
11077
11462
|
}
|
|
11078
11463
|
var UsageLedger = class {
|
|
11079
11464
|
constructor(root) {
|
|
11080
11465
|
this.root = root;
|
|
11081
|
-
this.dir =
|
|
11466
|
+
this.dir = path23.join(root, "usage");
|
|
11082
11467
|
}
|
|
11083
11468
|
root;
|
|
11084
11469
|
dir;
|
|
@@ -11091,18 +11476,18 @@ var UsageLedger = class {
|
|
|
11091
11476
|
return this.dir;
|
|
11092
11477
|
}
|
|
11093
11478
|
ledgerFile(month) {
|
|
11094
|
-
return
|
|
11479
|
+
return path23.join(this.ledgerDir, `ledger-${month}.jsonl`);
|
|
11095
11480
|
}
|
|
11096
11481
|
get rollupFile() {
|
|
11097
|
-
return
|
|
11482
|
+
return path23.join(this.ledgerDir, "rollup.json");
|
|
11098
11483
|
}
|
|
11099
11484
|
get pricingFile() {
|
|
11100
|
-
return
|
|
11485
|
+
return path23.join(this.ledgerDir, "pricing.json");
|
|
11101
11486
|
}
|
|
11102
11487
|
// ===================== 初始化 =====================
|
|
11103
11488
|
init(now = /* @__PURE__ */ new Date()) {
|
|
11104
11489
|
if (this.inited) return;
|
|
11105
|
-
|
|
11490
|
+
fs20.mkdirSync(this.ledgerDir, { recursive: true });
|
|
11106
11491
|
this.pricing = this.loadPricing();
|
|
11107
11492
|
this.rollup = this.loadRollup(now);
|
|
11108
11493
|
this.pruneLedgers(now);
|
|
@@ -11110,7 +11495,7 @@ var UsageLedger = class {
|
|
|
11110
11495
|
}
|
|
11111
11496
|
loadPricing() {
|
|
11112
11497
|
try {
|
|
11113
|
-
const raw =
|
|
11498
|
+
const raw = fs20.readFileSync(this.pricingFile, "utf-8");
|
|
11114
11499
|
const parsed = JSON.parse(raw);
|
|
11115
11500
|
const vendors = {};
|
|
11116
11501
|
for (const v of /* @__PURE__ */ new Set([
|
|
@@ -11139,7 +11524,7 @@ var UsageLedger = class {
|
|
|
11139
11524
|
}
|
|
11140
11525
|
loadRollup(now) {
|
|
11141
11526
|
try {
|
|
11142
|
-
const raw =
|
|
11527
|
+
const raw = fs20.readFileSync(this.rollupFile, "utf-8");
|
|
11143
11528
|
const parsed = JSON.parse(raw);
|
|
11144
11529
|
return {
|
|
11145
11530
|
schema: USAGE_SCHEMA,
|
|
@@ -11166,10 +11551,10 @@ var UsageLedger = class {
|
|
|
11166
11551
|
const keep = retainedMonths(now);
|
|
11167
11552
|
let changed = false;
|
|
11168
11553
|
try {
|
|
11169
|
-
for (const f of
|
|
11554
|
+
for (const f of fs20.readdirSync(this.ledgerDir)) {
|
|
11170
11555
|
const m = /^ledger-(\d{4}-\d{2})\.jsonl$/.exec(f);
|
|
11171
11556
|
if (m && !keep.has(m[1])) {
|
|
11172
|
-
|
|
11557
|
+
fs20.unlinkSync(path23.join(this.ledgerDir, f));
|
|
11173
11558
|
}
|
|
11174
11559
|
}
|
|
11175
11560
|
} catch {
|
|
@@ -11246,7 +11631,7 @@ var UsageLedger = class {
|
|
|
11246
11631
|
};
|
|
11247
11632
|
const line = JSON.stringify(rec) + "\n";
|
|
11248
11633
|
try {
|
|
11249
|
-
|
|
11634
|
+
fs20.appendFileSync(this.ledgerFile(monthOf(rec.ts)), line);
|
|
11250
11635
|
} catch (e) {
|
|
11251
11636
|
console.error(`[usage] \u5199\u8D26\u672C\u5931\u8D25: ${String(e)}`);
|
|
11252
11637
|
}
|
|
@@ -11418,10 +11803,10 @@ var UsageLedger = class {
|
|
|
11418
11803
|
const rows = [];
|
|
11419
11804
|
for (const month of months) {
|
|
11420
11805
|
const file = this.ledgerFile(month);
|
|
11421
|
-
if (!
|
|
11806
|
+
if (!fs20.existsSync(file)) continue;
|
|
11422
11807
|
let content = "";
|
|
11423
11808
|
try {
|
|
11424
|
-
content =
|
|
11809
|
+
content = fs20.readFileSync(file, "utf-8");
|
|
11425
11810
|
} catch {
|
|
11426
11811
|
continue;
|
|
11427
11812
|
}
|
|
@@ -11530,10 +11915,10 @@ var UsageLedger = class {
|
|
|
11530
11915
|
const seen = /* @__PURE__ */ new Set();
|
|
11531
11916
|
for (const month of this.monthsInRange("", "")) {
|
|
11532
11917
|
const file = this.ledgerFile(month);
|
|
11533
|
-
if (!
|
|
11918
|
+
if (!fs20.existsSync(file)) continue;
|
|
11534
11919
|
let content = "";
|
|
11535
11920
|
try {
|
|
11536
|
-
content =
|
|
11921
|
+
content = fs20.readFileSync(file, "utf-8");
|
|
11537
11922
|
} catch {
|
|
11538
11923
|
continue;
|
|
11539
11924
|
}
|
|
@@ -12841,7 +13226,10 @@ data: ${JSON.stringify(entry.data)}
|
|
|
12841
13226
|
// 上下文窗口:环境变量显式覆盖 > 供应商 /models 提供的真实长度 > 引擎内置表
|
|
12842
13227
|
contextWindow: parseOptionalPositiveNumber(process.env.CONTEXT_WINDOW) ?? modelContextWindow(eff.modelMeta, activeModel),
|
|
12843
13228
|
thresholdPct: parseRatio(process.env.COMPACTION_THRESHOLD_PCT),
|
|
12844
|
-
|
|
13229
|
+
softThresholdPct: parseRatio(process.env.COMPACTION_SOFT_THRESHOLD_PCT),
|
|
13230
|
+
capTokens: parseOptionalPositiveNumber(process.env.COMPACTION_CAP_TOKENS) ?? null,
|
|
13231
|
+
// 超预算工具结果按租户/工作区隔离落盘(多租户共用一个状态目录会混内容)
|
|
13232
|
+
toolResultDir: path24.join(workspace, ".agent", "tool-results")
|
|
12845
13233
|
});
|
|
12846
13234
|
engine.setApprover(this._makeApprover(rt));
|
|
12847
13235
|
const mcpConfigs = loadServerMcpConfigs(tenant);
|
|
@@ -13022,11 +13410,11 @@ var ApiError = class extends Error {
|
|
|
13022
13410
|
// src/server/routes.ts
|
|
13023
13411
|
init_cjs_shims();
|
|
13024
13412
|
var import_http = require("http");
|
|
13025
|
-
var
|
|
13413
|
+
var path29 = __toESM(require("path"), 1);
|
|
13026
13414
|
|
|
13027
13415
|
// src/server/projects.ts
|
|
13028
13416
|
init_cjs_shims();
|
|
13029
|
-
var
|
|
13417
|
+
var path25 = __toESM(require("path"), 1);
|
|
13030
13418
|
var DEFAULT_MODEL = () => process.env.OPENAI_MODEL || process.env.MODEL || "gpt-4o";
|
|
13031
13419
|
function toProjectSummary(store, tenant) {
|
|
13032
13420
|
return {
|
|
@@ -13159,9 +13547,9 @@ function createProject(store, input) {
|
|
|
13159
13547
|
if (store.loadTenant(id)) {
|
|
13160
13548
|
throw new ApiError(409, "project_exists", `\u9879\u76EE ${id} \u5DF2\u5B58\u5728`);
|
|
13161
13549
|
}
|
|
13162
|
-
const workspaceRoot = typeof raw.workspaceRoot === "string" && raw.workspaceRoot.trim() ?
|
|
13550
|
+
const workspaceRoot = typeof raw.workspaceRoot === "string" && raw.workspaceRoot.trim() ? path25.resolve(raw.workspaceRoot.trim()) : void 0;
|
|
13163
13551
|
const explicitName = typeof raw.name === "string" && raw.name.trim() ? raw.name.trim() : "";
|
|
13164
|
-
const defaultName = workspaceRoot ?
|
|
13552
|
+
const defaultName = workspaceRoot ? path25.basename(workspaceRoot) : id;
|
|
13165
13553
|
const tenant = {
|
|
13166
13554
|
id,
|
|
13167
13555
|
name: explicitName || defaultName,
|
|
@@ -13191,7 +13579,7 @@ function buildNodeInfo(store, opts) {
|
|
|
13191
13579
|
nodeId: opts.nodeId ?? ensureNodeId2(store),
|
|
13192
13580
|
platform: process.platform,
|
|
13193
13581
|
mode: process.env.NODE_MODE ?? "standalone",
|
|
13194
|
-
version: "0.2.
|
|
13582
|
+
version: "0.2.6",
|
|
13195
13583
|
admin: opts.admin,
|
|
13196
13584
|
projects: opts.projects
|
|
13197
13585
|
};
|
|
@@ -13275,8 +13663,8 @@ function hubProxyEnabled(host) {
|
|
|
13275
13663
|
const h = (host ?? "127.0.0.1").trim();
|
|
13276
13664
|
return h === "127.0.0.1" || h === "localhost" || h === "::1";
|
|
13277
13665
|
}
|
|
13278
|
-
function isHubProxyPath(
|
|
13279
|
-
return
|
|
13666
|
+
function isHubProxyPath(path43) {
|
|
13667
|
+
return path43.startsWith(HUB_PROXY_PREFIX);
|
|
13280
13668
|
}
|
|
13281
13669
|
function decodeTarget(enc) {
|
|
13282
13670
|
try {
|
|
@@ -13370,34 +13758,34 @@ async function handleHubProxy(req2, res) {
|
|
|
13370
13758
|
|
|
13371
13759
|
// src/server/fsBrowser.ts
|
|
13372
13760
|
init_cjs_shims();
|
|
13373
|
-
var
|
|
13761
|
+
var fs21 = __toESM(require("fs"), 1);
|
|
13374
13762
|
var os4 = __toESM(require("os"), 1);
|
|
13375
|
-
var
|
|
13763
|
+
var path26 = __toESM(require("path"), 1);
|
|
13376
13764
|
var MAX_ENTRIES = 2e3;
|
|
13377
13765
|
var DEFAULT_SEARCH_LIMIT = 200;
|
|
13378
13766
|
var MAX_SEARCH_LIMIT = 1e3;
|
|
13379
13767
|
function listDirs(input) {
|
|
13380
13768
|
const base = (input ?? "").trim() || os4.homedir();
|
|
13381
|
-
const target =
|
|
13769
|
+
const target = path26.resolve(base);
|
|
13382
13770
|
let st;
|
|
13383
13771
|
try {
|
|
13384
|
-
st =
|
|
13772
|
+
st = fs21.statSync(target);
|
|
13385
13773
|
} catch {
|
|
13386
13774
|
throw new Error(`\u8DEF\u5F84\u4E0D\u5B58\u5728: ${target}`);
|
|
13387
13775
|
}
|
|
13388
13776
|
if (!st.isDirectory()) throw new Error(`\u4E0D\u662F\u76EE\u5F55: ${target}`);
|
|
13389
13777
|
let dirents;
|
|
13390
13778
|
try {
|
|
13391
|
-
dirents =
|
|
13779
|
+
dirents = fs21.readdirSync(target, { withFileTypes: true });
|
|
13392
13780
|
} catch {
|
|
13393
13781
|
throw new Error(`\u65E0\u6CD5\u8BFB\u53D6\u76EE\u5F55\uFF08\u6743\u9650\u4E0D\u8DB3\uFF1F\uFF09: ${target}`);
|
|
13394
13782
|
}
|
|
13395
13783
|
const entries = dirents.map((d) => {
|
|
13396
|
-
const full =
|
|
13784
|
+
const full = path26.join(target, d.name);
|
|
13397
13785
|
let isDir = d.isDirectory();
|
|
13398
13786
|
if (d.isSymbolicLink()) {
|
|
13399
13787
|
try {
|
|
13400
|
-
isDir =
|
|
13788
|
+
isDir = fs21.statSync(full).isDirectory();
|
|
13401
13789
|
} catch {
|
|
13402
13790
|
}
|
|
13403
13791
|
}
|
|
@@ -13406,7 +13794,7 @@ function listDirs(input) {
|
|
|
13406
13794
|
entries.sort(
|
|
13407
13795
|
(a, b) => a.type === b.type ? a.name.localeCompare(b.name) : a.type === "dir" ? -1 : 1
|
|
13408
13796
|
);
|
|
13409
|
-
const parentDir =
|
|
13797
|
+
const parentDir = path26.dirname(target);
|
|
13410
13798
|
return {
|
|
13411
13799
|
path: target,
|
|
13412
13800
|
parent: parentDir !== target ? parentDir : null,
|
|
@@ -13437,7 +13825,7 @@ var NAME_CACHE_MAX_DIRS = 4;
|
|
|
13437
13825
|
var NAME_CACHE_MAX_ENTRIES = 5e4;
|
|
13438
13826
|
var nameCache = /* @__PURE__ */ new Map();
|
|
13439
13827
|
function invalidateDirNames(target) {
|
|
13440
|
-
nameCache.delete(
|
|
13828
|
+
nameCache.delete(path26.resolve(target));
|
|
13441
13829
|
}
|
|
13442
13830
|
async function loadDirNames(target) {
|
|
13443
13831
|
const now = Date.now();
|
|
@@ -13449,7 +13837,7 @@ async function loadDirNames(target) {
|
|
|
13449
13837
|
}
|
|
13450
13838
|
let dirents;
|
|
13451
13839
|
try {
|
|
13452
|
-
dirents = await
|
|
13840
|
+
dirents = await fs21.promises.readdir(target, { withFileTypes: true });
|
|
13453
13841
|
} catch {
|
|
13454
13842
|
throw new Error(`\u65E0\u6CD5\u8BFB\u53D6\u76EE\u5F55\uFF08\u6743\u9650\u4E0D\u8DB3\uFF1F\uFF09: ${target}`);
|
|
13455
13843
|
}
|
|
@@ -13472,11 +13860,11 @@ async function loadDirNames(target) {
|
|
|
13472
13860
|
return entries;
|
|
13473
13861
|
}
|
|
13474
13862
|
async function toDirEntry(dir, e) {
|
|
13475
|
-
const full =
|
|
13863
|
+
const full = path26.join(dir, e.name);
|
|
13476
13864
|
let isDir = e.isDir;
|
|
13477
13865
|
if (e.isLink) {
|
|
13478
13866
|
try {
|
|
13479
|
-
isDir = (await
|
|
13867
|
+
isDir = (await fs21.promises.stat(full)).isDirectory();
|
|
13480
13868
|
} catch {
|
|
13481
13869
|
}
|
|
13482
13870
|
}
|
|
@@ -13484,10 +13872,10 @@ async function toDirEntry(dir, e) {
|
|
|
13484
13872
|
}
|
|
13485
13873
|
async function searchDirs(input, query, limit) {
|
|
13486
13874
|
const base = (input ?? "").trim() || os4.homedir();
|
|
13487
|
-
const target =
|
|
13875
|
+
const target = path26.resolve(base);
|
|
13488
13876
|
let st;
|
|
13489
13877
|
try {
|
|
13490
|
-
st = await
|
|
13878
|
+
st = await fs21.promises.stat(target);
|
|
13491
13879
|
} catch {
|
|
13492
13880
|
throw new Error(`\u8DEF\u5F84\u4E0D\u5B58\u5728: ${target}`);
|
|
13493
13881
|
}
|
|
@@ -13517,7 +13905,7 @@ async function searchDirs(input, query, limit) {
|
|
|
13517
13905
|
);
|
|
13518
13906
|
const hit = scored.slice(0, max);
|
|
13519
13907
|
const entries = await Promise.all(hit.map(({ entry }) => toDirEntry(target, entry)));
|
|
13520
|
-
const parentDir =
|
|
13908
|
+
const parentDir = path26.dirname(target);
|
|
13521
13909
|
return {
|
|
13522
13910
|
path: target,
|
|
13523
13911
|
parent: parentDir !== target ? parentDir : null,
|
|
@@ -13528,52 +13916,52 @@ async function searchDirs(input, query, limit) {
|
|
|
13528
13916
|
};
|
|
13529
13917
|
}
|
|
13530
13918
|
function makeDirIn(parentInput, name) {
|
|
13531
|
-
const parent =
|
|
13919
|
+
const parent = path26.resolve((parentInput ?? "").trim() || os4.homedir());
|
|
13532
13920
|
const clean = (name ?? "").trim();
|
|
13533
13921
|
if (!clean) throw new Error("\u76EE\u5F55\u540D\u4E0D\u80FD\u4E3A\u7A7A");
|
|
13534
13922
|
if (clean === "." || clean === "..") throw new Error("\u76EE\u5F55\u540D\u975E\u6CD5");
|
|
13535
|
-
const target =
|
|
13536
|
-
const rel =
|
|
13537
|
-
if (!rel || rel.startsWith("..") ||
|
|
13923
|
+
const target = path26.resolve(parent, clean);
|
|
13924
|
+
const rel = path26.relative(parent, target);
|
|
13925
|
+
if (!rel || rel.startsWith("..") || path26.isAbsolute(rel)) {
|
|
13538
13926
|
throw new Error("\u76EE\u5F55\u540D\u4E0D\u80FD\u8D8A\u51FA\u5F53\u524D\u76EE\u5F55");
|
|
13539
13927
|
}
|
|
13540
13928
|
let st = null;
|
|
13541
13929
|
try {
|
|
13542
|
-
st =
|
|
13930
|
+
st = fs21.statSync(target);
|
|
13543
13931
|
} catch {
|
|
13544
13932
|
st = null;
|
|
13545
13933
|
}
|
|
13546
13934
|
if (st && !st.isDirectory()) throw new Error(`\u5DF2\u5B58\u5728\u540C\u540D\u6587\u4EF6: ${target}`);
|
|
13547
13935
|
try {
|
|
13548
|
-
|
|
13936
|
+
fs21.mkdirSync(target, { recursive: true });
|
|
13549
13937
|
} catch (e) {
|
|
13550
13938
|
throw new Error(`\u521B\u5EFA\u76EE\u5F55\u5931\u8D25: ${e instanceof Error ? e.message : String(e)}`);
|
|
13551
13939
|
}
|
|
13552
13940
|
invalidateDirNames(parent);
|
|
13553
|
-
return { name:
|
|
13941
|
+
return { name: path26.basename(target), path: target, type: "dir" };
|
|
13554
13942
|
}
|
|
13555
13943
|
|
|
13556
13944
|
// src/server/projectFiles.ts
|
|
13557
13945
|
init_cjs_shims();
|
|
13558
|
-
var
|
|
13559
|
-
var
|
|
13946
|
+
var fs22 = __toESM(require("fs"), 1);
|
|
13947
|
+
var path27 = __toESM(require("path"), 1);
|
|
13560
13948
|
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
13561
13949
|
var MAX_DOWNLOAD_BYTES = 16 * 1024 * 1024;
|
|
13562
13950
|
var MAX_ENTRIES2 = 2e3;
|
|
13563
13951
|
function toPosix(p) {
|
|
13564
|
-
return p.split(
|
|
13952
|
+
return p.split(path27.sep).join("/");
|
|
13565
13953
|
}
|
|
13566
13954
|
function projectRoot(workspaceRoot) {
|
|
13567
13955
|
const r = (workspaceRoot ?? "").trim();
|
|
13568
13956
|
if (!r) {
|
|
13569
13957
|
throw new Error("\u9879\u76EE\u672A\u8BBE\u7F6E\u5DE5\u4F5C\u533A\u76EE\u5F55\uFF08workspaceRoot\uFF09\uFF0C\u65E0\u6CD5\u6D4F\u89C8\u6587\u4EF6");
|
|
13570
13958
|
}
|
|
13571
|
-
const abs =
|
|
13572
|
-
if (!
|
|
13959
|
+
const abs = path27.resolve(r);
|
|
13960
|
+
if (!fs22.existsSync(abs)) {
|
|
13573
13961
|
throw new Error(`\u5DE5\u4F5C\u533A\u76EE\u5F55\u4E0D\u5B58\u5728: ${abs}`);
|
|
13574
13962
|
}
|
|
13575
13963
|
try {
|
|
13576
|
-
return
|
|
13964
|
+
return fs22.realpathSync(abs);
|
|
13577
13965
|
} catch {
|
|
13578
13966
|
return abs;
|
|
13579
13967
|
}
|
|
@@ -13591,37 +13979,37 @@ function listProjectFiles(workspaceRoot, relPath) {
|
|
|
13591
13979
|
const dir = resolveWithin(base, relPath ?? "");
|
|
13592
13980
|
let st;
|
|
13593
13981
|
try {
|
|
13594
|
-
st =
|
|
13982
|
+
st = fs22.statSync(dir);
|
|
13595
13983
|
} catch {
|
|
13596
|
-
throw new Error(`\u76EE\u5F55\u4E0D\u5B58\u5728: ${toPosix(
|
|
13984
|
+
throw new Error(`\u76EE\u5F55\u4E0D\u5B58\u5728: ${toPosix(path27.relative(base, dir)) || "/"}`);
|
|
13597
13985
|
}
|
|
13598
13986
|
if (!st.isDirectory()) throw new Error("\u76EE\u6807\u4E0D\u662F\u76EE\u5F55");
|
|
13599
13987
|
let dirents;
|
|
13600
13988
|
try {
|
|
13601
|
-
dirents =
|
|
13989
|
+
dirents = fs22.readdirSync(dir, { withFileTypes: true });
|
|
13602
13990
|
} catch {
|
|
13603
13991
|
throw new Error("\u65E0\u6CD5\u8BFB\u53D6\u76EE\u5F55\uFF08\u6743\u9650\u4E0D\u8DB3\uFF1F\uFF09");
|
|
13604
13992
|
}
|
|
13605
13993
|
const entries = dirents.map((d) => {
|
|
13606
|
-
const full =
|
|
13994
|
+
const full = path27.join(dir, d.name);
|
|
13607
13995
|
let isDir = d.isDirectory();
|
|
13608
13996
|
if (d.isSymbolicLink()) {
|
|
13609
13997
|
try {
|
|
13610
|
-
isDir =
|
|
13998
|
+
isDir = fs22.statSync(full).isDirectory();
|
|
13611
13999
|
} catch {
|
|
13612
14000
|
}
|
|
13613
14001
|
}
|
|
13614
14002
|
let size = 0;
|
|
13615
14003
|
let mtime = "";
|
|
13616
14004
|
try {
|
|
13617
|
-
const s =
|
|
14005
|
+
const s = fs22.statSync(full);
|
|
13618
14006
|
size = s.size;
|
|
13619
14007
|
mtime = s.mtime.toISOString();
|
|
13620
14008
|
} catch {
|
|
13621
14009
|
}
|
|
13622
14010
|
return {
|
|
13623
14011
|
name: d.name,
|
|
13624
|
-
path: toPosix(
|
|
14012
|
+
path: toPosix(path27.relative(base, full)),
|
|
13625
14013
|
type: isDir ? "dir" : "file",
|
|
13626
14014
|
size,
|
|
13627
14015
|
mtime
|
|
@@ -13630,12 +14018,12 @@ function listProjectFiles(workspaceRoot, relPath) {
|
|
|
13630
14018
|
entries.sort(
|
|
13631
14019
|
(a, b) => a.type === b.type ? a.name.localeCompare(b.name) : a.type === "dir" ? -1 : 1
|
|
13632
14020
|
);
|
|
13633
|
-
const relDir = toPosix(
|
|
13634
|
-
const parentAbs =
|
|
14021
|
+
const relDir = toPosix(path27.relative(base, dir));
|
|
14022
|
+
const parentAbs = path27.dirname(dir);
|
|
13635
14023
|
return {
|
|
13636
14024
|
root: base,
|
|
13637
14025
|
path: relDir,
|
|
13638
|
-
parent: isWithinRoot(base, parentAbs) ? toPosix(
|
|
14026
|
+
parent: isWithinRoot(base, parentAbs) ? toPosix(path27.relative(base, parentAbs)) : null,
|
|
13639
14027
|
entries: entries.slice(0, MAX_ENTRIES2)
|
|
13640
14028
|
};
|
|
13641
14029
|
}
|
|
@@ -13644,17 +14032,17 @@ function readProjectFile(workspaceRoot, relPath) {
|
|
|
13644
14032
|
const file = resolveWithin(base, relPath ?? "");
|
|
13645
14033
|
let st;
|
|
13646
14034
|
try {
|
|
13647
|
-
st =
|
|
14035
|
+
st = fs22.statSync(file);
|
|
13648
14036
|
} catch {
|
|
13649
14037
|
throw new Error("\u6587\u4EF6\u4E0D\u5B58\u5728");
|
|
13650
14038
|
}
|
|
13651
14039
|
if (!st.isFile()) throw new Error("\u76EE\u6807\u4E0D\u662F\u6587\u4EF6");
|
|
13652
|
-
const buf =
|
|
14040
|
+
const buf = fs22.readFileSync(file);
|
|
13653
14041
|
const binary = isBinary(buf);
|
|
13654
14042
|
const truncated = buf.length > MAX_FILE_BYTES;
|
|
13655
14043
|
const slice = truncated ? buf.subarray(0, MAX_FILE_BYTES) : buf;
|
|
13656
14044
|
return {
|
|
13657
|
-
path: toPosix(
|
|
14045
|
+
path: toPosix(path27.relative(base, file)),
|
|
13658
14046
|
size: st.size,
|
|
13659
14047
|
binary,
|
|
13660
14048
|
truncated,
|
|
@@ -13666,7 +14054,7 @@ function downloadProjectFile(workspaceRoot, relPath) {
|
|
|
13666
14054
|
const file = resolveWithin(base, relPath ?? "");
|
|
13667
14055
|
let st;
|
|
13668
14056
|
try {
|
|
13669
|
-
st =
|
|
14057
|
+
st = fs22.statSync(file);
|
|
13670
14058
|
} catch {
|
|
13671
14059
|
throw new Error("\u6587\u4EF6\u4E0D\u5B58\u5728");
|
|
13672
14060
|
}
|
|
@@ -13674,10 +14062,10 @@ function downloadProjectFile(workspaceRoot, relPath) {
|
|
|
13674
14062
|
if (st.size > MAX_DOWNLOAD_BYTES) {
|
|
13675
14063
|
throw new Error(`\u6587\u4EF6\u8D85\u8FC7\u4E0B\u8F7D\u4E0A\u9650\uFF08${MAX_DOWNLOAD_BYTES / (1024 * 1024)}MB\uFF09`);
|
|
13676
14064
|
}
|
|
13677
|
-
const buf =
|
|
14065
|
+
const buf = fs22.readFileSync(file);
|
|
13678
14066
|
return {
|
|
13679
|
-
path: toPosix(
|
|
13680
|
-
name:
|
|
14067
|
+
path: toPosix(path27.relative(base, file)),
|
|
14068
|
+
name: path27.basename(file),
|
|
13681
14069
|
size: buf.length,
|
|
13682
14070
|
base64: buf.toString("base64")
|
|
13683
14071
|
};
|
|
@@ -13699,12 +14087,12 @@ function writeProjectFile(workspaceRoot, relPath, content) {
|
|
|
13699
14087
|
throw new Error("\u5185\u5BB9\u8D85\u8FC7 2MB \u4E0A\u9650\uFF0C\u65E0\u6CD5\u4FDD\u5B58");
|
|
13700
14088
|
}
|
|
13701
14089
|
try {
|
|
13702
|
-
|
|
13703
|
-
|
|
14090
|
+
fs22.mkdirSync(path27.dirname(file), { recursive: true });
|
|
14091
|
+
fs22.writeFileSync(file, buf);
|
|
13704
14092
|
} catch (e) {
|
|
13705
14093
|
throw new Error(`\u5199\u5165\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
13706
14094
|
}
|
|
13707
|
-
return { path: toPosix(
|
|
14095
|
+
return { path: toPosix(path27.relative(base, file)), size: buf.length };
|
|
13708
14096
|
}
|
|
13709
14097
|
function createProjectDir(workspaceRoot, relPath) {
|
|
13710
14098
|
const base = projectRoot(workspaceRoot);
|
|
@@ -13712,26 +14100,26 @@ function createProjectDir(workspaceRoot, relPath) {
|
|
|
13712
14100
|
if (!rel) throw new Error("\u76EE\u5F55\u8DEF\u5F84\u4E0D\u80FD\u4E3A\u7A7A");
|
|
13713
14101
|
const dir = resolveWithin(base, rel);
|
|
13714
14102
|
try {
|
|
13715
|
-
|
|
14103
|
+
fs22.mkdirSync(dir, { recursive: true });
|
|
13716
14104
|
} catch (e) {
|
|
13717
14105
|
throw new Error(`\u521B\u5EFA\u76EE\u5F55\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
13718
14106
|
}
|
|
13719
|
-
return { path: toPosix(
|
|
14107
|
+
return { path: toPosix(path27.relative(base, dir)) };
|
|
13720
14108
|
}
|
|
13721
14109
|
function createProjectFile(workspaceRoot, relPath, content = "") {
|
|
13722
14110
|
const base = projectRoot(workspaceRoot);
|
|
13723
14111
|
const rel = (relPath ?? "").trim();
|
|
13724
14112
|
if (!rel) throw new Error("\u6587\u4EF6\u8DEF\u5F84\u4E0D\u80FD\u4E3A\u7A7A");
|
|
13725
14113
|
const file = resolveWithin(base, rel);
|
|
13726
|
-
if (
|
|
14114
|
+
if (fs22.existsSync(file)) throw new Error("\u6587\u4EF6\u5DF2\u5B58\u5728");
|
|
13727
14115
|
const buf = Buffer.from(String(content ?? ""), "utf-8");
|
|
13728
14116
|
try {
|
|
13729
|
-
|
|
13730
|
-
|
|
14117
|
+
fs22.mkdirSync(path27.dirname(file), { recursive: true });
|
|
14118
|
+
fs22.writeFileSync(file, buf);
|
|
13731
14119
|
} catch (e) {
|
|
13732
14120
|
throw new Error(`\u521B\u5EFA\u6587\u4EF6\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
13733
14121
|
}
|
|
13734
|
-
return { path: toPosix(
|
|
14122
|
+
return { path: toPosix(path27.relative(base, file)), size: buf.length };
|
|
13735
14123
|
}
|
|
13736
14124
|
function searchProjectFiles(workspaceRoot, query) {
|
|
13737
14125
|
const base = projectRoot(workspaceRoot);
|
|
@@ -13754,7 +14142,7 @@ function searchProjectFiles(workspaceRoot, query) {
|
|
|
13754
14142
|
if (out.length >= LIMIT) return;
|
|
13755
14143
|
let dirents;
|
|
13756
14144
|
try {
|
|
13757
|
-
dirents =
|
|
14145
|
+
dirents = fs22.readdirSync(dir, { withFileTypes: true });
|
|
13758
14146
|
} catch {
|
|
13759
14147
|
return;
|
|
13760
14148
|
}
|
|
@@ -13765,7 +14153,7 @@ function searchProjectFiles(workspaceRoot, query) {
|
|
|
13765
14153
|
let isDir = d.isDirectory();
|
|
13766
14154
|
if (d.isSymbolicLink()) {
|
|
13767
14155
|
try {
|
|
13768
|
-
isDir =
|
|
14156
|
+
isDir = fs22.statSync(path27.join(dir, d.name)).isDirectory();
|
|
13769
14157
|
} catch {
|
|
13770
14158
|
isDir = false;
|
|
13771
14159
|
}
|
|
@@ -13773,7 +14161,7 @@ function searchProjectFiles(workspaceRoot, query) {
|
|
|
13773
14161
|
if (d.name.toLowerCase().includes(q)) {
|
|
13774
14162
|
out.push({ path: rel, type: isDir ? "dir" : "file" });
|
|
13775
14163
|
}
|
|
13776
|
-
if (isDir) walk(
|
|
14164
|
+
if (isDir) walk(path27.join(dir, d.name), rel);
|
|
13777
14165
|
}
|
|
13778
14166
|
};
|
|
13779
14167
|
walk(base, "");
|
|
@@ -13783,7 +14171,7 @@ function searchProjectFiles(workspaceRoot, query) {
|
|
|
13783
14171
|
// src/server/projectOps.ts
|
|
13784
14172
|
init_cjs_shims();
|
|
13785
14173
|
var os5 = __toESM(require("os"), 1);
|
|
13786
|
-
var
|
|
14174
|
+
var path28 = __toESM(require("path"), 1);
|
|
13787
14175
|
var MAX_STDOUT2 = 2e4;
|
|
13788
14176
|
var MAX_STDERR2 = 1e4;
|
|
13789
14177
|
var MAX_BUFFER3 = 1024 * 1024 * 5;
|
|
@@ -13797,7 +14185,7 @@ function resolveInvocation2(spec, prepared) {
|
|
|
13797
14185
|
}
|
|
13798
14186
|
function workRoot(workspaceRoot) {
|
|
13799
14187
|
const r = (workspaceRoot ?? "").trim();
|
|
13800
|
-
return r ?
|
|
14188
|
+
return r ? path28.resolve(r) : os5.homedir();
|
|
13801
14189
|
}
|
|
13802
14190
|
async function runProjectCommand(workspaceRoot, command, timeoutSeconds) {
|
|
13803
14191
|
const cmd = String(command ?? "");
|
|
@@ -13917,6 +14305,92 @@ async function projectGitPush(workspaceRoot, repoPath) {
|
|
|
13917
14305
|
});
|
|
13918
14306
|
}
|
|
13919
14307
|
|
|
14308
|
+
// src/server/gitCommitMessage.ts
|
|
14309
|
+
init_cjs_shims();
|
|
14310
|
+
var crypto5 = __toESM(require("crypto"), 1);
|
|
14311
|
+
var MAX_DIFF_CHARS = 12e3;
|
|
14312
|
+
var MAX_MESSAGE_CHARS = 200;
|
|
14313
|
+
var GEN_COMMIT_MESSAGE_INSTRUCTIONS = `\u4F60\u662F Git \u63D0\u4EA4\u8BF4\u660E\u751F\u6210\u52A9\u624B\u3002\u6839\u636E\u7ED9\u5B9A\u7684\u4EE3\u7801\u5DEE\u5F02\uFF0C\u751F\u6210\u4E00\u6761\u51C6\u786E\u3001\u7B80\u6D01\u7684\u63D0\u4EA4\u8BF4\u660E\u3002
|
|
14314
|
+
|
|
14315
|
+
\u8981\u6C42\uFF1A
|
|
14316
|
+
1. \u4F7F\u7528 Conventional Commits \u98CE\u683C\uFF1Atype(scope): \u63CF\u8FF0\uFF08type \u5982 feat / fix / refactor / docs / test / chore / perf / build / ci\uFF09\uFF1B
|
|
14317
|
+
2. scope \u53D6\u53D8\u66F4\u6700\u96C6\u4E2D\u7684\u6A21\u5757\u6216\u76EE\u5F55\uFF0C\u65E0\u6CD5\u5224\u65AD\u65F6\u7701\u7565\uFF1B
|
|
14318
|
+
3. \u63CF\u8FF0\u4F7F\u7528\u4E2D\u6587\uFF0C\u6982\u62EC\u672C\u6B21\u53D8\u66F4\u7684\u76EE\u7684\u6216\u6548\u679C\uFF0C\u4E0D\u8981\u9010\u6587\u4EF6\u7F57\u5217\uFF1B
|
|
14319
|
+
4. \u53EA\u8F93\u51FA\u63D0\u4EA4\u8BF4\u660E\u672C\u8EAB\uFF0C\u4E0D\u8981\u5F15\u53F7\u3001\u4EE3\u7801\u5757\u3001\u6362\u884C\u6216\u4EFB\u4F55\u89E3\u91CA\uFF1B
|
|
14320
|
+
5. \u4E0D\u8D85\u8FC7 72 \u4E2A\u5B57\u7B26\u3002`;
|
|
14321
|
+
function genReqId2() {
|
|
14322
|
+
return crypto5.randomBytes(6).toString("base64url");
|
|
14323
|
+
}
|
|
14324
|
+
function cleanCommitMessage(raw) {
|
|
14325
|
+
let text = String(raw ?? "").trim();
|
|
14326
|
+
if (!text) return "";
|
|
14327
|
+
text = text.replace(/^```[^\n]*\n?/, "").replace(/\n?```$/, "").trim();
|
|
14328
|
+
const first = text.split(/\r?\n/).map((line) => line.trim()).find((line) => line.length > 0) ?? "";
|
|
14329
|
+
return first.replace(/^(commit message|提交说明|提交信息|message)\s*[::]\s*/i, "").replace(/^["'“”`]+|["'“”`]+$/g, "").replace(/\s+/g, " ").trim().slice(0, MAX_MESSAGE_CHARS);
|
|
14330
|
+
}
|
|
14331
|
+
async function collectDiff(workspaceRoot, repo) {
|
|
14332
|
+
const staged = await projectGitDiff(workspaceRoot, void 0, true, repo);
|
|
14333
|
+
if (!staged.error && String(staged.diff ?? "").trim()) {
|
|
14334
|
+
return { text: String(staged.diff), source: "staged" };
|
|
14335
|
+
}
|
|
14336
|
+
const worktree = await projectGitDiff(workspaceRoot, void 0, false, repo);
|
|
14337
|
+
if (!worktree.error && String(worktree.diff ?? "").trim()) {
|
|
14338
|
+
return { text: String(worktree.diff), source: "worktree" };
|
|
14339
|
+
}
|
|
14340
|
+
const status = await projectGitStatus(workspaceRoot, void 0, repo);
|
|
14341
|
+
if (status.error) throw new ApiError(400, "git_error", String(status.error));
|
|
14342
|
+
const entries = status.entries ?? [];
|
|
14343
|
+
if (entries.length === 0) throw new ApiError(400, "no_changes", "\u6CA1\u6709\u53EF\u63D0\u4EA4\u7684\u53D8\u66F4");
|
|
14344
|
+
return {
|
|
14345
|
+
text: entries.map((e) => `${e.status ?? ""} ${e.file ?? ""}`.trim()).join("\n"),
|
|
14346
|
+
source: "worktree"
|
|
14347
|
+
};
|
|
14348
|
+
}
|
|
14349
|
+
async function generateGitCommitMessage(opts) {
|
|
14350
|
+
const { store, tenant } = opts;
|
|
14351
|
+
const { text, source } = await collectDiff(opts.workspaceRoot, opts.repo);
|
|
14352
|
+
const truncated = text.length > MAX_DIFF_CHARS;
|
|
14353
|
+
const clipped = text.slice(0, MAX_DIFF_CHARS);
|
|
14354
|
+
const eff = resolveSessionProvider(store, tenant);
|
|
14355
|
+
const apiKey = eff.apiKey || process.env.OPENAI_API_KEY || "";
|
|
14356
|
+
const model = (eff.model || tenant.model || process.env.OPENAI_MODEL || process.env.MODEL || "").trim();
|
|
14357
|
+
if (!apiKey) {
|
|
14358
|
+
throw new ApiError(
|
|
14359
|
+
400,
|
|
14360
|
+
"llm_not_configured",
|
|
14361
|
+
"\u5F53\u524D\u8282\u70B9\u672A\u914D\u7F6E\u53EF\u7528\u7684 LLM\uFF0C\u8BF7\u5148\u5728\u8282\u70B9\u914D\u7F6E\u4E2D\u6DFB\u52A0\u6A21\u578B\u4E0E API Key"
|
|
14362
|
+
);
|
|
14363
|
+
}
|
|
14364
|
+
if (!model) {
|
|
14365
|
+
throw new ApiError(
|
|
14366
|
+
400,
|
|
14367
|
+
"llm_not_configured",
|
|
14368
|
+
"\u5F53\u524D\u8282\u70B9\u672A\u914D\u7F6E\u6A21\u578B\uFF0C\u8BF7\u5148\u5728\u8282\u70B9\u914D\u7F6E\u4E2D\u9009\u62E9\u6A21\u578B"
|
|
14369
|
+
);
|
|
14370
|
+
}
|
|
14371
|
+
const provider = new OpenAIProvider({ apiKey, baseURL: eff.baseURL });
|
|
14372
|
+
const raw = await provider.chat(
|
|
14373
|
+
model,
|
|
14374
|
+
[
|
|
14375
|
+
{ role: "system", content: GEN_COMMIT_MESSAGE_INSTRUCTIONS },
|
|
14376
|
+
{
|
|
14377
|
+
role: "user",
|
|
14378
|
+
content: `\u4EE5\u4E0B\u662F\u672C\u6B21\u5F85\u63D0\u4EA4\u7684\u53D8\u66F4${source === "staged" ? "\uFF08\u5DF2\u6682\u5B58\uFF09" : "\uFF08\u5DE5\u4F5C\u533A\uFF0C\u5C1A\u672A\u6682\u5B58\uFF09"}${truncated ? "\uFF0C\u5185\u5BB9\u8FC7\u957F\u5DF2\u622A\u65AD" : ""}\uFF1A
|
|
14379
|
+
|
|
14380
|
+
${clipped}`
|
|
14381
|
+
}
|
|
14382
|
+
],
|
|
14383
|
+
{},
|
|
14384
|
+
{ reqId: `llm_commit_${Date.now()}_${genReqId2()}`, logTime: (/* @__PURE__ */ new Date()).toISOString() },
|
|
14385
|
+
// 不设 maxTokens:推理模型的思考会占用输出配额,过小会导致 content 为空;
|
|
14386
|
+
// 提示词已约束只输出一行短说明。
|
|
14387
|
+
{}
|
|
14388
|
+
);
|
|
14389
|
+
const message = cleanCommitMessage(raw ?? "");
|
|
14390
|
+
if (!message) throw new ApiError(502, "llm_empty", "AI \u672A\u8FD4\u56DE\u6709\u6548\u7684\u63D0\u4EA4\u8BF4\u660E\uFF0C\u8BF7\u91CD\u8BD5");
|
|
14391
|
+
return message;
|
|
14392
|
+
}
|
|
14393
|
+
|
|
13920
14394
|
// src/server/toolsCatalog.ts
|
|
13921
14395
|
init_cjs_shims();
|
|
13922
14396
|
function buildToolCatalog(workspace) {
|
|
@@ -14022,11 +14496,11 @@ function projectStats(manager, tenantId) {
|
|
|
14022
14496
|
|
|
14023
14497
|
// src/server/nodeHost.ts
|
|
14024
14498
|
init_cjs_shims();
|
|
14025
|
-
var
|
|
14499
|
+
var fs23 = __toESM(require("fs"), 1);
|
|
14026
14500
|
var os6 = __toESM(require("os"), 1);
|
|
14027
14501
|
function diskInfo(pathStr) {
|
|
14028
14502
|
try {
|
|
14029
|
-
const st =
|
|
14503
|
+
const st = fs23.statfsSync(pathStr);
|
|
14030
14504
|
return {
|
|
14031
14505
|
path: pathStr,
|
|
14032
14506
|
total: Number(st.blocks) * Number(st.bsize),
|
|
@@ -14098,7 +14572,7 @@ function buildNodeHost(store, manager, diskPath) {
|
|
|
14098
14572
|
arch: process.arch,
|
|
14099
14573
|
release: os6.release(),
|
|
14100
14574
|
uptimeSec: Math.round(os6.uptime()),
|
|
14101
|
-
version: "0.2.
|
|
14575
|
+
version: "0.2.6",
|
|
14102
14576
|
mode: process.env.NODE_MODE ?? "standalone",
|
|
14103
14577
|
cpu: {
|
|
14104
14578
|
count: cpus2.length,
|
|
@@ -14673,7 +15147,7 @@ function createApp(store, manager, opts = {}) {
|
|
|
14673
15147
|
applyProvidersPatch(tenant, raw);
|
|
14674
15148
|
if (typeof raw.workspaceRoot === "string") {
|
|
14675
15149
|
const ws = raw.workspaceRoot.trim();
|
|
14676
|
-
if (ws) tenant.workspaceRoot =
|
|
15150
|
+
if (ws) tenant.workspaceRoot = path29.resolve(ws);
|
|
14677
15151
|
else delete tenant.workspaceRoot;
|
|
14678
15152
|
}
|
|
14679
15153
|
if (typeof raw.name === "string" && raw.name.trim()) {
|
|
@@ -15082,6 +15556,25 @@ function createApp(store, manager, opts = {}) {
|
|
|
15082
15556
|
}
|
|
15083
15557
|
}
|
|
15084
15558
|
},
|
|
15559
|
+
{
|
|
15560
|
+
method: "POST",
|
|
15561
|
+
pattern: ["git", "commit-message"],
|
|
15562
|
+
fn: async (_req, res, { tenant, body }) => {
|
|
15563
|
+
const raw = body ?? {};
|
|
15564
|
+
try {
|
|
15565
|
+
const message = await generateGitCommitMessage({
|
|
15566
|
+
store,
|
|
15567
|
+
tenant,
|
|
15568
|
+
workspaceRoot: tenant.workspaceRoot ?? null,
|
|
15569
|
+
repo: String(raw.repo ?? "") || void 0
|
|
15570
|
+
});
|
|
15571
|
+
ok(res, { message });
|
|
15572
|
+
} catch (e) {
|
|
15573
|
+
if (e instanceof ApiError) throw e;
|
|
15574
|
+
throw new ApiError(400, "bad_request", e instanceof Error ? e.message : String(e));
|
|
15575
|
+
}
|
|
15576
|
+
}
|
|
15577
|
+
},
|
|
15085
15578
|
{
|
|
15086
15579
|
method: "POST",
|
|
15087
15580
|
pattern: ["git", "checkout"],
|
|
@@ -15605,10 +16098,10 @@ function createApp(store, manager, opts = {}) {
|
|
|
15605
16098
|
function handle(req2, res) {
|
|
15606
16099
|
const startedAt2 = Date.now();
|
|
15607
16100
|
const url = new URL(req2.url ?? "/", "http://localhost");
|
|
15608
|
-
const
|
|
16101
|
+
const path43 = url.pathname;
|
|
15609
16102
|
const method = req2.method ?? "GET";
|
|
15610
16103
|
console.log(
|
|
15611
|
-
`[api] ${(/* @__PURE__ */ new Date()).toISOString()} \u2192 ${method} ${
|
|
16104
|
+
`[api] ${(/* @__PURE__ */ new Date()).toISOString()} \u2192 ${method} ${path43}${url.search}`
|
|
15612
16105
|
);
|
|
15613
16106
|
let tenantId = null;
|
|
15614
16107
|
let logged = false;
|
|
@@ -15616,7 +16109,7 @@ function createApp(store, manager, opts = {}) {
|
|
|
15616
16109
|
if (logged) return;
|
|
15617
16110
|
logged = true;
|
|
15618
16111
|
console.log(
|
|
15619
|
-
`[api] ${(/* @__PURE__ */ new Date()).toISOString()} \u2190 ${method} ${
|
|
16112
|
+
`[api] ${(/* @__PURE__ */ new Date()).toISOString()} \u2190 ${method} ${path43} ${extra} (${Date.now() - startedAt2}ms) tenant=${tenantId ?? "-"}`
|
|
15620
16113
|
);
|
|
15621
16114
|
};
|
|
15622
16115
|
res.on("finish", () => logDone(`HTTP ${res.statusCode}`));
|
|
@@ -15627,16 +16120,16 @@ function createApp(store, manager, opts = {}) {
|
|
|
15627
16120
|
res.end();
|
|
15628
16121
|
return;
|
|
15629
16122
|
}
|
|
15630
|
-
if (req2.method === "GET" &&
|
|
16123
|
+
if (req2.method === "GET" && path43 === "/healthz") {
|
|
15631
16124
|
json(res, 200, {
|
|
15632
16125
|
status: "ok",
|
|
15633
16126
|
// 版本让运维/探针能确认线上跑的是哪个构建(更新与回滚据此判断)
|
|
15634
|
-
version: "0.2.
|
|
16127
|
+
version: "0.2.6",
|
|
15635
16128
|
features: { mcp: hasServerMcpConfig() }
|
|
15636
16129
|
});
|
|
15637
16130
|
return;
|
|
15638
16131
|
}
|
|
15639
|
-
if (hubProxyEnabled(opts.host) && isHubProxyPath(
|
|
16132
|
+
if (hubProxyEnabled(opts.host) && isHubProxyPath(path43)) {
|
|
15640
16133
|
void handleHubProxy(req2, res).catch(() => {
|
|
15641
16134
|
if (!res.headersSent) {
|
|
15642
16135
|
res.writeHead(502, { "Content-Type": "application/json; charset=utf-8" });
|
|
@@ -15647,11 +16140,11 @@ function createApp(store, manager, opts = {}) {
|
|
|
15647
16140
|
});
|
|
15648
16141
|
return;
|
|
15649
16142
|
}
|
|
15650
|
-
if (!
|
|
16143
|
+
if (!path43.startsWith(API_PREFIX)) {
|
|
15651
16144
|
json(res, 404, { error: { code: "not_found", message: "\u672A\u77E5\u8DEF\u5F84" } });
|
|
15652
16145
|
return;
|
|
15653
16146
|
}
|
|
15654
|
-
const segs =
|
|
16147
|
+
const segs = path43.slice(API_PREFIX.length).split("/").filter(Boolean);
|
|
15655
16148
|
const apiKey = extractApiKey(req2);
|
|
15656
16149
|
if (!apiKey) {
|
|
15657
16150
|
json(res, 401, {
|
|
@@ -15716,7 +16209,7 @@ function createApp(store, manager, opts = {}) {
|
|
|
15716
16209
|
).catch((err) => {
|
|
15717
16210
|
const msg = err instanceof Error ? err.message : String(err);
|
|
15718
16211
|
console.log(
|
|
15719
|
-
`[api] ${(/* @__PURE__ */ new Date()).toISOString()} ! ${method} ${
|
|
16212
|
+
`[api] ${(/* @__PURE__ */ new Date()).toISOString()} ! ${method} ${path43} ERROR: ${msg}`
|
|
15720
16213
|
);
|
|
15721
16214
|
error(res, err);
|
|
15722
16215
|
});
|
|
@@ -16231,6 +16724,17 @@ async function dispatchFleetCommand(deps, env3) {
|
|
|
16231
16724
|
)
|
|
16232
16725
|
);
|
|
16233
16726
|
}
|
|
16727
|
+
case "git_commit_message": {
|
|
16728
|
+
const t = project();
|
|
16729
|
+
return ok2({
|
|
16730
|
+
message: await generateGitCommitMessage({
|
|
16731
|
+
store,
|
|
16732
|
+
tenant: t,
|
|
16733
|
+
workspaceRoot: t.workspaceRoot ?? null,
|
|
16734
|
+
repo: gitRepo(payload.repo)
|
|
16735
|
+
})
|
|
16736
|
+
});
|
|
16737
|
+
}
|
|
16234
16738
|
case "git_checkout": {
|
|
16235
16739
|
const t = project();
|
|
16236
16740
|
return ok2(
|
|
@@ -16871,6 +17375,18 @@ var READONLY_CMD_TYPES = /* @__PURE__ */ new Set([
|
|
|
16871
17375
|
"git_show"
|
|
16872
17376
|
]);
|
|
16873
17377
|
var CMD_CACHE_TTL_MS = 1500;
|
|
17378
|
+
var STATE_CHANGING_EVENTS = /* @__PURE__ */ new Set([
|
|
17379
|
+
"turn_start",
|
|
17380
|
+
"turn_end",
|
|
17381
|
+
"permission_required",
|
|
17382
|
+
"ask_user_question",
|
|
17383
|
+
"plan_proposed",
|
|
17384
|
+
"directory_requested",
|
|
17385
|
+
"error",
|
|
17386
|
+
"interrupted",
|
|
17387
|
+
"queue_steering",
|
|
17388
|
+
"session_named"
|
|
17389
|
+
]);
|
|
16874
17390
|
var READONLY_CONCURRENCY = 4;
|
|
16875
17391
|
var BATCH_MAX_SUBS = 64;
|
|
16876
17392
|
var BATCH_SUB_TIMEOUT_MS = 7e3;
|
|
@@ -17106,6 +17622,20 @@ var FleetNodeBridge = class {
|
|
|
17106
17622
|
this.writeEpoch += 1;
|
|
17107
17623
|
this.cmdResultCache.clear();
|
|
17108
17624
|
}
|
|
17625
|
+
/**
|
|
17626
|
+
* 会话快照缓存失效(事件/通知驱动的状态变化)。
|
|
17627
|
+
*
|
|
17628
|
+
* 与写操作不同,这些变化只影响会话相关查询;文件树 / Git 等重查询的缓存
|
|
17629
|
+
* 保持有效,避免多会话并行运行时把整个只读缓存反复清空。
|
|
17630
|
+
*/
|
|
17631
|
+
_invalidateSessionCache() {
|
|
17632
|
+
this.writeEpoch += 1;
|
|
17633
|
+
for (const key of [...this.cmdResultCache.keys()]) {
|
|
17634
|
+
if (/^(get_state|get_events|list_sessions|get_session_states)\|/.test(key)) {
|
|
17635
|
+
this.cmdResultCache.delete(key);
|
|
17636
|
+
}
|
|
17637
|
+
}
|
|
17638
|
+
}
|
|
17109
17639
|
close() {
|
|
17110
17640
|
this.closing = true;
|
|
17111
17641
|
if (this.usageTimer) {
|
|
@@ -17134,6 +17664,7 @@ var FleetNodeBridge = class {
|
|
|
17134
17664
|
}
|
|
17135
17665
|
/** 通知广播(SessionManager 注入的 notify 回调) */
|
|
17136
17666
|
notify(tenantId, ev) {
|
|
17667
|
+
this._invalidateSessionCache();
|
|
17137
17668
|
const payload = ev.kind === "approval_request" ? {
|
|
17138
17669
|
...ev,
|
|
17139
17670
|
projectId: tenantId,
|
|
@@ -17146,6 +17677,7 @@ var FleetNodeBridge = class {
|
|
|
17146
17677
|
}
|
|
17147
17678
|
/** 事件桥接(SessionManager 注入的 onEvent 回调);发布按窗口批量合并 */
|
|
17148
17679
|
onEvent(tenantId, sessionId, entry) {
|
|
17680
|
+
if (STATE_CHANGING_EVENTS.has(entry.type)) this._invalidateSessionCache();
|
|
17149
17681
|
if (entry.type === "turn_end") this.stats.turns += 1;
|
|
17150
17682
|
else if (entry.type === "tool_finished") this.stats.toolCalls += 1;
|
|
17151
17683
|
else if (entry.type === "error") this.stats.errors += 1;
|
|
@@ -17230,7 +17762,7 @@ var FleetNodeBridge = class {
|
|
|
17230
17762
|
label: this.opts.deps.store.loadNodeLabel() ?? void 0,
|
|
17231
17763
|
platform: process.platform,
|
|
17232
17764
|
mode: process.env.NODE_MODE ?? "standalone",
|
|
17233
|
-
version: "0.2.
|
|
17765
|
+
version: "0.2.6",
|
|
17234
17766
|
ip: primaryIp()
|
|
17235
17767
|
};
|
|
17236
17768
|
}
|
|
@@ -17264,7 +17796,10 @@ var FleetNodeBridge = class {
|
|
|
17264
17796
|
sessionId: s.sessionId,
|
|
17265
17797
|
name: s.name ?? null,
|
|
17266
17798
|
status: s.status,
|
|
17267
|
-
lastUserMessage: lastUserMessage(s)
|
|
17799
|
+
lastUserMessage: lastUserMessage(s),
|
|
17800
|
+
// 控制面的聚合邮件靠它判断「这台机器最近有没有在干活」;
|
|
17801
|
+
// 状态跃迁可能被 info 节流跳过,完成时间不会。
|
|
17802
|
+
lastCompletedAt: s.lastCompletedAt ?? null
|
|
17268
17803
|
});
|
|
17269
17804
|
}
|
|
17270
17805
|
} catch {
|
|
@@ -17282,7 +17817,7 @@ var FleetNodeBridge = class {
|
|
|
17282
17817
|
label: this.opts.deps.store.loadNodeLabel() ?? void 0,
|
|
17283
17818
|
platform: process.platform,
|
|
17284
17819
|
mode: process.env.NODE_MODE ?? "standalone",
|
|
17285
|
-
version: "0.2.
|
|
17820
|
+
version: "0.2.6",
|
|
17286
17821
|
ip: primaryIp(),
|
|
17287
17822
|
projects,
|
|
17288
17823
|
totals,
|
|
@@ -18051,8 +18586,8 @@ init_cjs_shims();
|
|
|
18051
18586
|
|
|
18052
18587
|
// src/server/qq/bindings.ts
|
|
18053
18588
|
init_cjs_shims();
|
|
18054
|
-
var
|
|
18055
|
-
var
|
|
18589
|
+
var fs24 = __toESM(require("fs"), 1);
|
|
18590
|
+
var path30 = __toESM(require("path"), 1);
|
|
18056
18591
|
function conversationKey(target) {
|
|
18057
18592
|
switch (target.kind) {
|
|
18058
18593
|
case "c2c":
|
|
@@ -18091,12 +18626,12 @@ var QqBindingsStore = class _QqBindingsStore {
|
|
|
18091
18626
|
cache = null;
|
|
18092
18627
|
/** 基于 DATA_DIR 构造 */
|
|
18093
18628
|
static in(dataDir) {
|
|
18094
|
-
return new _QqBindingsStore(
|
|
18629
|
+
return new _QqBindingsStore(path30.join(dataDir, "qq", "bindings.json"));
|
|
18095
18630
|
}
|
|
18096
18631
|
load() {
|
|
18097
18632
|
if (this.cache) return this.cache;
|
|
18098
18633
|
try {
|
|
18099
|
-
const raw = JSON.parse(
|
|
18634
|
+
const raw = JSON.parse(fs24.readFileSync(this.file, "utf-8"));
|
|
18100
18635
|
this.cache = {
|
|
18101
18636
|
conversations: raw.conversations ?? {}
|
|
18102
18637
|
};
|
|
@@ -18128,8 +18663,8 @@ var QqBindingsStore = class _QqBindingsStore {
|
|
|
18128
18663
|
return null;
|
|
18129
18664
|
}
|
|
18130
18665
|
persist() {
|
|
18131
|
-
|
|
18132
|
-
|
|
18666
|
+
fs24.mkdirSync(path30.dirname(this.file), { recursive: true });
|
|
18667
|
+
fs24.writeFileSync(this.file, JSON.stringify(this.cache, null, 2), "utf-8");
|
|
18133
18668
|
}
|
|
18134
18669
|
};
|
|
18135
18670
|
|
|
@@ -18541,8 +19076,8 @@ ${lines.join("\n")}`, msgId);
|
|
|
18541
19076
|
|
|
18542
19077
|
// src/server/qq/QqManager.ts
|
|
18543
19078
|
init_cjs_shims();
|
|
18544
|
-
var
|
|
18545
|
-
var
|
|
19079
|
+
var fs25 = __toESM(require("fs"), 1);
|
|
19080
|
+
var path31 = __toESM(require("path"), 1);
|
|
18546
19081
|
var QqManager = class {
|
|
18547
19082
|
constructor(opts) {
|
|
18548
19083
|
this.opts = opts;
|
|
@@ -18551,7 +19086,7 @@ var QqManager = class {
|
|
|
18551
19086
|
adapter = null;
|
|
18552
19087
|
config = null;
|
|
18553
19088
|
get configFile() {
|
|
18554
|
-
return
|
|
19089
|
+
return path31.join(this.opts.dataDir, "qq", "config.json");
|
|
18555
19090
|
}
|
|
18556
19091
|
/** 启动:读配置(env 优先,其次文件),有则建连接 */
|
|
18557
19092
|
start() {
|
|
@@ -18589,7 +19124,7 @@ var QqManager = class {
|
|
|
18589
19124
|
/** 清空配置:删除文件 + 断开 */
|
|
18590
19125
|
clearConfig() {
|
|
18591
19126
|
try {
|
|
18592
|
-
|
|
19127
|
+
fs25.rmSync(this.configFile, { force: true });
|
|
18593
19128
|
} catch {
|
|
18594
19129
|
}
|
|
18595
19130
|
this.stop();
|
|
@@ -18631,7 +19166,7 @@ var QqManager = class {
|
|
|
18631
19166
|
}
|
|
18632
19167
|
_readConfigFile() {
|
|
18633
19168
|
try {
|
|
18634
|
-
const raw = JSON.parse(
|
|
19169
|
+
const raw = JSON.parse(fs25.readFileSync(this.configFile, "utf-8"));
|
|
18635
19170
|
if (raw.appId && raw.appSecret) {
|
|
18636
19171
|
return {
|
|
18637
19172
|
appId: raw.appId,
|
|
@@ -18644,18 +19179,18 @@ var QqManager = class {
|
|
|
18644
19179
|
return null;
|
|
18645
19180
|
}
|
|
18646
19181
|
_persistConfig(cfg) {
|
|
18647
|
-
|
|
18648
|
-
|
|
19182
|
+
fs25.mkdirSync(path31.dirname(this.configFile), { recursive: true });
|
|
19183
|
+
fs25.writeFileSync(this.configFile, JSON.stringify(cfg, null, 2), "utf-8");
|
|
18649
19184
|
}
|
|
18650
19185
|
};
|
|
18651
19186
|
|
|
18652
19187
|
// src/server/qq/pairingCodes.ts
|
|
18653
19188
|
init_cjs_shims();
|
|
18654
|
-
var
|
|
19189
|
+
var crypto6 = __toESM(require("crypto"), 1);
|
|
18655
19190
|
var PAIRING_CODE_TTL_MS = 5 * 60 * 1e3;
|
|
18656
19191
|
function randomCode(len = 8) {
|
|
18657
19192
|
const alphabet = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
|
18658
|
-
const bytes =
|
|
19193
|
+
const bytes = crypto6.randomBytes(len);
|
|
18659
19194
|
let out = "";
|
|
18660
19195
|
for (let i = 0; i < len; i++) {
|
|
18661
19196
|
out += alphabet[bytes[i] % alphabet.length];
|
|
@@ -18693,17 +19228,17 @@ var PairingCodeStore = class {
|
|
|
18693
19228
|
|
|
18694
19229
|
// src/update/controller.ts
|
|
18695
19230
|
init_cjs_shims();
|
|
18696
|
-
var
|
|
18697
|
-
var
|
|
19231
|
+
var fs29 = __toESM(require("fs"), 1);
|
|
19232
|
+
var path36 = __toESM(require("path"), 1);
|
|
18698
19233
|
|
|
18699
19234
|
// src/update/downloader.ts
|
|
18700
19235
|
init_cjs_shims();
|
|
18701
19236
|
var import_node_crypto5 = require("crypto");
|
|
18702
|
-
var
|
|
19237
|
+
var fs26 = __toESM(require("fs"), 1);
|
|
18703
19238
|
var import_node_stream2 = require("stream");
|
|
18704
19239
|
var import_promises2 = require("stream/promises");
|
|
18705
19240
|
var import_node_child_process5 = require("child_process");
|
|
18706
|
-
var
|
|
19241
|
+
var path32 = __toESM(require("path"), 1);
|
|
18707
19242
|
|
|
18708
19243
|
// src/update/manifest.ts
|
|
18709
19244
|
init_cjs_shims();
|
|
@@ -18878,8 +19413,8 @@ async function fetchManifest(url, publicKey, opts = {}) {
|
|
|
18878
19413
|
async function downloadBinary(bin, destPath, log = () => {
|
|
18879
19414
|
}) {
|
|
18880
19415
|
const partPath = `${destPath}.part`;
|
|
18881
|
-
|
|
18882
|
-
|
|
19416
|
+
fs26.mkdirSync(path32.dirname(destPath), { recursive: true });
|
|
19417
|
+
fs26.rmSync(partPath, { force: true });
|
|
18883
19418
|
let res;
|
|
18884
19419
|
try {
|
|
18885
19420
|
res = await fetch(bin.url, { signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS2) });
|
|
@@ -18904,25 +19439,25 @@ async function downloadBinary(bin, destPath, log = () => {
|
|
|
18904
19439
|
yield chunk;
|
|
18905
19440
|
}
|
|
18906
19441
|
},
|
|
18907
|
-
|
|
19442
|
+
fs26.createWriteStream(partPath, { mode: 493 })
|
|
18908
19443
|
);
|
|
18909
19444
|
} catch (err) {
|
|
18910
|
-
|
|
19445
|
+
fs26.rmSync(partPath, { force: true });
|
|
18911
19446
|
return { error: `\u4E0B\u8F7D\u4E2D\u65AD\uFF1A${err.message}` };
|
|
18912
19447
|
}
|
|
18913
19448
|
const actual = hash.digest("hex");
|
|
18914
19449
|
if (actual !== bin.sha256) {
|
|
18915
|
-
|
|
19450
|
+
fs26.rmSync(partPath, { force: true });
|
|
18916
19451
|
return { error: `SHA-256 \u4E0D\u5339\u914D\uFF08\u671F\u671B ${bin.sha256.slice(0, 12)}\u2026\uFF0C\u5B9E\u9645 ${actual.slice(0, 12)}\u2026\uFF09` };
|
|
18917
19452
|
}
|
|
18918
19453
|
if (expected && bytes !== expected) {
|
|
18919
|
-
|
|
19454
|
+
fs26.rmSync(partPath, { force: true });
|
|
18920
19455
|
return { error: `\u4EA7\u7269\u5927\u5C0F\u4E0D\u5339\u914D\uFF08\u671F\u671B ${expected}\uFF0C\u5B9E\u9645 ${bytes}\uFF09` };
|
|
18921
19456
|
}
|
|
18922
|
-
|
|
18923
|
-
|
|
18924
|
-
|
|
18925
|
-
log(`\u5DF2\u4E0B\u8F7D ${
|
|
19457
|
+
fs26.rmSync(destPath, { force: true });
|
|
19458
|
+
fs26.renameSync(partPath, destPath);
|
|
19459
|
+
fs26.chmodSync(destPath, 493);
|
|
19460
|
+
log(`\u5DF2\u4E0B\u8F7D ${path32.basename(destPath)}\uFF08${Math.round(bytes / 1024 / 1024)}MB\uFF0C\u6821\u9A8C\u901A\u8FC7\uFF09`);
|
|
18926
19461
|
return { bytes };
|
|
18927
19462
|
}
|
|
18928
19463
|
function selfCheck(binPath, expectedVersion) {
|
|
@@ -18946,10 +19481,10 @@ function selfCheck(binPath, expectedVersion) {
|
|
|
18946
19481
|
|
|
18947
19482
|
// src/update/platform.ts
|
|
18948
19483
|
init_cjs_shims();
|
|
18949
|
-
var
|
|
19484
|
+
var path33 = __toESM(require("path"), 1);
|
|
18950
19485
|
var import_node_module3 = require("module");
|
|
18951
19486
|
function currentVersion() {
|
|
18952
|
-
const injected = "0.2.
|
|
19487
|
+
const injected = "0.2.6"?.trim();
|
|
18953
19488
|
if (injected) return injected;
|
|
18954
19489
|
try {
|
|
18955
19490
|
const req2 = (0, import_node_module3.createRequire)(importMetaUrl);
|
|
@@ -18961,7 +19496,7 @@ function currentVersion() {
|
|
|
18961
19496
|
}
|
|
18962
19497
|
function isSeaRuntime() {
|
|
18963
19498
|
if (process.env.ZQAGENT_SEA === "1") return true;
|
|
18964
|
-
const base =
|
|
19499
|
+
const base = path33.basename(process.execPath).toLowerCase().replace(/\.exe$/, "");
|
|
18965
19500
|
return base !== "node" && base !== "nodejs";
|
|
18966
19501
|
}
|
|
18967
19502
|
function serviceManager() {
|
|
@@ -18989,22 +19524,22 @@ function selfUpdateCapability(hasPublicKey) {
|
|
|
18989
19524
|
|
|
18990
19525
|
// src/update/installer.ts
|
|
18991
19526
|
init_cjs_shims();
|
|
18992
|
-
var
|
|
18993
|
-
var
|
|
19527
|
+
var fs28 = __toESM(require("fs"), 1);
|
|
19528
|
+
var path35 = __toESM(require("path"), 1);
|
|
18994
19529
|
|
|
18995
19530
|
// src/update/state.ts
|
|
18996
19531
|
init_cjs_shims();
|
|
18997
|
-
var
|
|
18998
|
-
var
|
|
19532
|
+
var fs27 = __toESM(require("fs"), 1);
|
|
19533
|
+
var path34 = __toESM(require("path"), 1);
|
|
18999
19534
|
function updatesDir(dataDir) {
|
|
19000
|
-
return
|
|
19535
|
+
return path34.join(dataDir, "updates");
|
|
19001
19536
|
}
|
|
19002
19537
|
function statePath(dataDir) {
|
|
19003
|
-
return
|
|
19538
|
+
return path34.join(updatesDir(dataDir), "state.json");
|
|
19004
19539
|
}
|
|
19005
19540
|
function loadState(dataDir) {
|
|
19006
19541
|
try {
|
|
19007
|
-
const raw =
|
|
19542
|
+
const raw = fs27.readFileSync(statePath(dataDir), "utf-8");
|
|
19008
19543
|
const parsed = JSON.parse(raw);
|
|
19009
19544
|
if (typeof parsed === "object" && parsed !== null) return parsed;
|
|
19010
19545
|
} catch {
|
|
@@ -19013,11 +19548,11 @@ function loadState(dataDir) {
|
|
|
19013
19548
|
}
|
|
19014
19549
|
function saveState(dataDir, state) {
|
|
19015
19550
|
const dir = updatesDir(dataDir);
|
|
19016
|
-
|
|
19551
|
+
fs27.mkdirSync(dir, { recursive: true });
|
|
19017
19552
|
const file = statePath(dataDir);
|
|
19018
19553
|
const tmp = `${file}.tmp`;
|
|
19019
|
-
|
|
19020
|
-
|
|
19554
|
+
fs27.writeFileSync(tmp, JSON.stringify(state, null, 2), "utf-8");
|
|
19555
|
+
fs27.renameSync(tmp, file);
|
|
19021
19556
|
}
|
|
19022
19557
|
function patchState(dataDir, patch) {
|
|
19023
19558
|
const next = { ...loadState(dataDir), ...patch };
|
|
@@ -19027,36 +19562,36 @@ function patchState(dataDir, patch) {
|
|
|
19027
19562
|
|
|
19028
19563
|
// src/update/installer.ts
|
|
19029
19564
|
function backupDir(dataDir) {
|
|
19030
|
-
return
|
|
19565
|
+
return path35.join(updatesDir(dataDir), "backup");
|
|
19031
19566
|
}
|
|
19032
19567
|
function backupCurrent(dataDir, execPath, version) {
|
|
19033
19568
|
const dir = backupDir(dataDir);
|
|
19034
|
-
|
|
19035
|
-
const target =
|
|
19036
|
-
|
|
19037
|
-
|
|
19569
|
+
fs28.mkdirSync(dir, { recursive: true });
|
|
19570
|
+
const target = path35.join(dir, `zqagent-${version}${process.platform === "win32" ? ".exe" : ""}`);
|
|
19571
|
+
fs28.copyFileSync(execPath, target);
|
|
19572
|
+
fs28.chmodSync(target, 493);
|
|
19038
19573
|
return target;
|
|
19039
19574
|
}
|
|
19040
19575
|
function replaceExecutable(execPath, stagedPath) {
|
|
19041
19576
|
if (process.platform === "win32") {
|
|
19042
19577
|
const oldPath = `${execPath}.old`;
|
|
19043
|
-
|
|
19044
|
-
|
|
19045
|
-
|
|
19046
|
-
|
|
19578
|
+
fs28.rmSync(oldPath, { force: true });
|
|
19579
|
+
fs28.renameSync(execPath, oldPath);
|
|
19580
|
+
fs28.copyFileSync(stagedPath, execPath);
|
|
19581
|
+
fs28.chmodSync(execPath, 493);
|
|
19047
19582
|
return;
|
|
19048
19583
|
}
|
|
19049
19584
|
const tmp = `${execPath}.new`;
|
|
19050
|
-
|
|
19585
|
+
fs28.rmSync(tmp, { force: true });
|
|
19051
19586
|
try {
|
|
19052
|
-
|
|
19053
|
-
|
|
19054
|
-
|
|
19587
|
+
fs28.copyFileSync(stagedPath, tmp);
|
|
19588
|
+
fs28.chmodSync(tmp, 493);
|
|
19589
|
+
fs28.renameSync(tmp, execPath);
|
|
19055
19590
|
} catch (err) {
|
|
19056
|
-
|
|
19591
|
+
fs28.rmSync(tmp, { force: true });
|
|
19057
19592
|
throw err;
|
|
19058
19593
|
}
|
|
19059
|
-
|
|
19594
|
+
fs28.rmSync(stagedPath, { force: true });
|
|
19060
19595
|
}
|
|
19061
19596
|
function installStaged(opts) {
|
|
19062
19597
|
const log = opts.log ?? (() => {
|
|
@@ -19064,7 +19599,7 @@ function installStaged(opts) {
|
|
|
19064
19599
|
const from = currentVersion();
|
|
19065
19600
|
log(`\u6B63\u5728\u5B89\u88C5 v${opts.version}\uFF08\u5F53\u524D v${from}\uFF09`);
|
|
19066
19601
|
const backupPath = backupCurrent(opts.dataDir, opts.execPath, from);
|
|
19067
|
-
log(`\u5DF2\u5907\u4EFD\u5F53\u524D\u7248\u672C\u5230 ${
|
|
19602
|
+
log(`\u5DF2\u5907\u4EFD\u5F53\u524D\u7248\u672C\u5230 ${path35.basename(backupPath)}`);
|
|
19068
19603
|
replaceExecutable(opts.execPath, opts.stagedPath);
|
|
19069
19604
|
return patchState(opts.dataDir, {
|
|
19070
19605
|
stagedVersion: void 0,
|
|
@@ -19083,18 +19618,18 @@ function rollback(dataDir, execPath, log = () => {
|
|
|
19083
19618
|
}) {
|
|
19084
19619
|
const state = readRollbackTarget(dataDir);
|
|
19085
19620
|
if (!state?.backupPath || !state.backupVersion) return null;
|
|
19086
|
-
if (!
|
|
19621
|
+
if (!fs28.existsSync(state.backupPath)) return null;
|
|
19087
19622
|
log(`\u6B63\u5728\u56DE\u6EDA\u5230 v${state.backupVersion}`);
|
|
19088
19623
|
if (process.platform === "win32") {
|
|
19089
|
-
|
|
19090
|
-
|
|
19091
|
-
|
|
19092
|
-
|
|
19624
|
+
fs28.rmSync(`${execPath}.old`, { force: true });
|
|
19625
|
+
fs28.renameSync(execPath, `${execPath}.old`);
|
|
19626
|
+
fs28.copyFileSync(state.backupPath, execPath);
|
|
19627
|
+
fs28.chmodSync(execPath, 493);
|
|
19093
19628
|
} else {
|
|
19094
19629
|
const tmp = `${execPath}.rollback`;
|
|
19095
|
-
|
|
19096
|
-
|
|
19097
|
-
|
|
19630
|
+
fs28.copyFileSync(state.backupPath, tmp);
|
|
19631
|
+
fs28.chmodSync(tmp, 493);
|
|
19632
|
+
fs28.renameSync(tmp, execPath);
|
|
19098
19633
|
}
|
|
19099
19634
|
patchState(dataDir, {
|
|
19100
19635
|
pendingVersion: state.backupVersion,
|
|
@@ -19108,7 +19643,7 @@ function rollback(dataDir, execPath, log = () => {
|
|
|
19108
19643
|
}
|
|
19109
19644
|
function readRollbackTarget(dataDir) {
|
|
19110
19645
|
try {
|
|
19111
|
-
const raw =
|
|
19646
|
+
const raw = fs28.readFileSync(path35.join(updatesDir(dataDir), "state.json"), "utf-8");
|
|
19112
19647
|
const s = JSON.parse(raw);
|
|
19113
19648
|
if (s.backupPath && s.backupVersion) return s;
|
|
19114
19649
|
} catch {
|
|
@@ -19191,7 +19726,7 @@ var UpdateController = class {
|
|
|
19191
19726
|
reconcile() {
|
|
19192
19727
|
const state = loadState(this.opts.dataDir);
|
|
19193
19728
|
const current = this.currentVersion;
|
|
19194
|
-
if (state.stagedPath && !
|
|
19729
|
+
if (state.stagedPath && !fs29.existsSync(state.stagedPath)) {
|
|
19195
19730
|
patchState(this.opts.dataDir, { stagedVersion: void 0, stagedPath: void 0 });
|
|
19196
19731
|
}
|
|
19197
19732
|
const patch = { runningVersion: current };
|
|
@@ -19206,7 +19741,7 @@ var UpdateController = class {
|
|
|
19206
19741
|
}
|
|
19207
19742
|
patchState(this.opts.dataDir, patch);
|
|
19208
19743
|
if (process.platform === "win32") {
|
|
19209
|
-
|
|
19744
|
+
fs29.rmSync(`${process.execPath}.old`, { force: true });
|
|
19210
19745
|
}
|
|
19211
19746
|
}
|
|
19212
19747
|
schedule(delayMs) {
|
|
@@ -19282,8 +19817,8 @@ var UpdateController = class {
|
|
|
19282
19817
|
const bin = manifest.binaries[platformKey()];
|
|
19283
19818
|
if (!bin) return `\u6E05\u5355\u6CA1\u6709\u5F53\u524D\u5E73\u53F0\uFF08${platformKey()}\uFF09\u7684\u4EA7\u7269`;
|
|
19284
19819
|
let stagedPath = state.stagedPath;
|
|
19285
|
-
if (!(state.stagedVersion === manifest.version && stagedPath &&
|
|
19286
|
-
stagedPath =
|
|
19820
|
+
if (!(state.stagedVersion === manifest.version && stagedPath && fs29.existsSync(stagedPath))) {
|
|
19821
|
+
stagedPath = path36.join(
|
|
19287
19822
|
updatesDir(this.opts.dataDir),
|
|
19288
19823
|
"staged",
|
|
19289
19824
|
`zqagent-${manifest.version}${process.platform === "win32" ? ".exe" : ""}`
|
|
@@ -19295,7 +19830,7 @@ var UpdateController = class {
|
|
|
19295
19830
|
}
|
|
19296
19831
|
const selfTest = selfCheck(stagedPath, manifest.version);
|
|
19297
19832
|
if (!selfTest.ok) {
|
|
19298
|
-
|
|
19833
|
+
fs29.rmSync(stagedPath, { force: true });
|
|
19299
19834
|
this.recordFailure(manifest.version, selfTest.error ?? "\u81EA\u68C0\u5931\u8D25");
|
|
19300
19835
|
return `\u5B89\u88C5\u5305\u81EA\u68C0\u5931\u8D25\uFF1A${selfTest.error}`;
|
|
19301
19836
|
}
|
|
@@ -19436,7 +19971,7 @@ function pemFile(key) {
|
|
|
19436
19971
|
const p = env2(key);
|
|
19437
19972
|
if (!p) return void 0;
|
|
19438
19973
|
try {
|
|
19439
|
-
return
|
|
19974
|
+
return fs30.readFileSync(p);
|
|
19440
19975
|
} catch (e) {
|
|
19441
19976
|
console.warn(`[tls] \u8BFB\u53D6 ${key}=${p} \u5931\u8D25: ${e instanceof Error ? e.message : e}`);
|
|
19442
19977
|
return void 0;
|
|
@@ -19458,7 +19993,7 @@ function seedDemoTenant(store) {
|
|
|
19458
19993
|
apiKey: env2("OPENAI_API_KEY"),
|
|
19459
19994
|
baseURL: env2("OPENAI_BASE_URL")
|
|
19460
19995
|
},
|
|
19461
|
-
workspaceRoot: workspace ?
|
|
19996
|
+
workspaceRoot: workspace ? path37.resolve(workspace) : void 0,
|
|
19462
19997
|
allowedCommands: []
|
|
19463
19998
|
};
|
|
19464
19999
|
store.saveTenant(demo);
|
|
@@ -19512,9 +20047,9 @@ function syncTenantModels(store) {
|
|
|
19512
20047
|
tenant.model = model;
|
|
19513
20048
|
changed = true;
|
|
19514
20049
|
}
|
|
19515
|
-
if (workspace && tenant.workspaceRoot !==
|
|
19516
|
-
console.log(`[sync] \u79DF\u6237 ${id} workspaceRoot \u5DF2\u540C\u6B65: ${tenant.workspaceRoot ?? "(\u6C99\u7BB1)"} \u2192 ${
|
|
19517
|
-
tenant.workspaceRoot =
|
|
20050
|
+
if (workspace && tenant.workspaceRoot !== path37.resolve(workspace)) {
|
|
20051
|
+
console.log(`[sync] \u79DF\u6237 ${id} workspaceRoot \u5DF2\u540C\u6B65: ${tenant.workspaceRoot ?? "(\u6C99\u7BB1)"} \u2192 ${path37.resolve(workspace)}`);
|
|
20052
|
+
tenant.workspaceRoot = path37.resolve(workspace);
|
|
19518
20053
|
changed = true;
|
|
19519
20054
|
}
|
|
19520
20055
|
if (apiKey && tenant.provider.apiKey !== apiKey) {
|
|
@@ -19546,7 +20081,7 @@ function exitWhenOrphaned() {
|
|
|
19546
20081
|
timer.unref();
|
|
19547
20082
|
}
|
|
19548
20083
|
function startServer(opts = {}) {
|
|
19549
|
-
const dataDir =
|
|
20084
|
+
const dataDir = path37.resolve(opts.dataDir ?? env2("DATA_DIR") ?? DEFAULT_DATA_DIR);
|
|
19550
20085
|
const port = opts.port ?? Number(env2("PORT") ?? 8787);
|
|
19551
20086
|
const host = opts.host ?? env2("HOST") ?? "127.0.0.1";
|
|
19552
20087
|
exitWhenOrphaned();
|
|
@@ -19576,7 +20111,7 @@ function startServer(opts = {}) {
|
|
|
19576
20111
|
}
|
|
19577
20112
|
const adminKey = ensureAdminKey();
|
|
19578
20113
|
const secretKey = env2("SECRET_KEY");
|
|
19579
|
-
const secretBox = secretKey ? SecretBox.fromHex(secretKey) : SecretBox.fromFile(
|
|
20114
|
+
const secretBox = secretKey ? SecretBox.fromHex(secretKey) : SecretBox.fromFile(path37.join(dataDir, "secret.key"));
|
|
19580
20115
|
if (secretKey && !secretBox) {
|
|
19581
20116
|
console.warn("[crypto] SECRET_KEY \u975E\u6CD5\uFF08\u9700 64 \u4F4D hex\uFF09\uFF0C\u901A\u77E5\u51ED\u636E\u5C06\u9000\u5316\u4E3A\u660E\u6587");
|
|
19582
20117
|
}
|
|
@@ -19805,7 +20340,7 @@ function printReady(info, qq) {
|
|
|
19805
20340
|
`zqagent server \u76D1\u542C http://${info.host}:${info.port}`,
|
|
19806
20341
|
`\u6570\u636E\u76EE\u5F55: ${info.dataDir}`,
|
|
19807
20342
|
`\u5BA1\u6279\u6302\u8D77\u8D85\u65F6: ${env2("APPROVAL_TIMEOUT_SECONDS") ?? 900}s\uFF08\u8D85\u65F6\u540E\u56DE\u6536\u5185\u5B58\u4EFB\u52A1\uFF0C\u53EF\u7ECF resume \u6062\u590D\uFF09`,
|
|
19808
|
-
env2("ZQAGENT_LOG_ADMIN_KEY") === "0" ? `\u7BA1\u7406\u5458\u5BC6\u94A5: ${maskKey(info.adminKey)}\uFF08\u5DF2\u8131\u654F\uFF0C\u5B8C\u6574\u503C\u89C1 ${
|
|
20343
|
+
env2("ZQAGENT_LOG_ADMIN_KEY") === "0" ? `\u7BA1\u7406\u5458\u5BC6\u94A5: ${maskKey(info.adminKey)}\uFF08\u5DF2\u8131\u654F\uFF0C\u5B8C\u6574\u503C\u89C1 ${path37.join(info.dataDir, "admin.json")}\uFF09` : `\u7BA1\u7406\u5458\u5BC6\u94A5: ${info.adminKey}\uFF08\u63A7\u5236\u53F0\u591A\u9879\u76EE\u5165\u53E3\uFF1A/api/v1/projects\uFF1B\u9879\u76EE\u7EA7\u63A5\u53E3\u52A0 X-Project-Id \u5934\uFF09`
|
|
19809
20344
|
];
|
|
19810
20345
|
if (info.fleetNodeId) {
|
|
19811
20346
|
lines.push(
|
|
@@ -19826,7 +20361,7 @@ function printReady(info, qq) {
|
|
|
19826
20361
|
|
|
19827
20362
|
// src/cli/account-enroll.ts
|
|
19828
20363
|
init_cjs_shims();
|
|
19829
|
-
var
|
|
20364
|
+
var path38 = __toESM(require("path"), 1);
|
|
19830
20365
|
var readline = __toESM(require("readline/promises"), 1);
|
|
19831
20366
|
var SKIP_ANSWERS = /* @__PURE__ */ new Set(["-", "skip", "none", "no"]);
|
|
19832
20367
|
function resolveDefaultHub(hubUrl, env3 = process.env) {
|
|
@@ -19838,7 +20373,7 @@ function parseHubAnswer(answer, fallback) {
|
|
|
19838
20373
|
return (a || fallback).replace(/\/$/, "");
|
|
19839
20374
|
}
|
|
19840
20375
|
function resolveDataDir2(dataDir) {
|
|
19841
|
-
return
|
|
20376
|
+
return path38.resolve(dataDir ?? process.env.DATA_DIR ?? DEFAULT_DATA_DIR);
|
|
19842
20377
|
}
|
|
19843
20378
|
async function maybeAccountEnroll(opts = {}) {
|
|
19844
20379
|
if (!process.stdin.isTTY || !process.stdout.isTTY) return;
|
|
@@ -20044,7 +20579,7 @@ async function runServeCommand(argv) {
|
|
|
20044
20579
|
|
|
20045
20580
|
// src/cli/update.ts
|
|
20046
20581
|
init_cjs_shims();
|
|
20047
|
-
var
|
|
20582
|
+
var path39 = __toESM(require("path"), 1);
|
|
20048
20583
|
function parse3(argv) {
|
|
20049
20584
|
const out = { status: false, check: false, now: false, rollback: false };
|
|
20050
20585
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -20073,7 +20608,7 @@ function restartHint() {
|
|
|
20073
20608
|
}
|
|
20074
20609
|
async function runUpdateCommand(argv) {
|
|
20075
20610
|
const args = parse3(argv);
|
|
20076
|
-
const dataDir =
|
|
20611
|
+
const dataDir = path39.resolve(args.dataDir ?? process.env.DATA_DIR ?? DEFAULT_DATA_DIR);
|
|
20077
20612
|
const controller = new UpdateController({ dataDir, isIdle: () => true });
|
|
20078
20613
|
if (args.rollback) {
|
|
20079
20614
|
const restored = controller.rollbackNow();
|
|
@@ -20121,17 +20656,17 @@ async function runUpdateCommand(argv) {
|
|
|
20121
20656
|
|
|
20122
20657
|
// src/cli/sessionMeta.ts
|
|
20123
20658
|
init_cjs_shims();
|
|
20124
|
-
var
|
|
20125
|
-
var
|
|
20659
|
+
var fs31 = __toESM(require("fs"), 1);
|
|
20660
|
+
var path40 = __toESM(require("path"), 1);
|
|
20126
20661
|
function updateSessionMetaFile(stateDir2, sessionId, patch) {
|
|
20127
|
-
const file =
|
|
20662
|
+
const file = path40.join(stateDir2, `${sessionId}_state.json`);
|
|
20128
20663
|
try {
|
|
20129
|
-
const raw =
|
|
20664
|
+
const raw = fs31.readFileSync(file, "utf8");
|
|
20130
20665
|
const state = JSON.parse(raw);
|
|
20131
20666
|
if (patch.name !== void 0) state.name = patch.name;
|
|
20132
20667
|
if (patch.nameSource !== void 0) state.nameSource = patch.nameSource;
|
|
20133
20668
|
if (patch.taskCount !== void 0) state.taskCount = patch.taskCount;
|
|
20134
|
-
|
|
20669
|
+
fs31.writeFileSync(file, JSON.stringify(state, null, 2), "utf8");
|
|
20135
20670
|
return true;
|
|
20136
20671
|
} catch {
|
|
20137
20672
|
return false;
|
|
@@ -20140,9 +20675,9 @@ function updateSessionMetaFile(stateDir2, sessionId, patch) {
|
|
|
20140
20675
|
|
|
20141
20676
|
// src/cli/debug.ts
|
|
20142
20677
|
init_cjs_shims();
|
|
20143
|
-
var
|
|
20678
|
+
var fs32 = __toESM(require("fs"), 1);
|
|
20144
20679
|
var os8 = __toESM(require("os"), 1);
|
|
20145
|
-
var
|
|
20680
|
+
var path41 = __toESM(require("path"), 1);
|
|
20146
20681
|
var LOG_NAME = "zqagent-debug.log";
|
|
20147
20682
|
var TRUTHY = /^(1|true|yes|on)$/i;
|
|
20148
20683
|
function bootRef() {
|
|
@@ -20153,9 +20688,9 @@ var logFile = null;
|
|
|
20153
20688
|
var startedAt = Date.now();
|
|
20154
20689
|
function resolveLogFile() {
|
|
20155
20690
|
const explicit = process.env.ZQAGENT_DEBUG_LOG;
|
|
20156
|
-
if (explicit) return
|
|
20691
|
+
if (explicit) return path41.resolve(explicit);
|
|
20157
20692
|
const dir = process.env.ZQAGENT_DEBUG_DIR;
|
|
20158
|
-
return
|
|
20693
|
+
return path41.join(dir ? path41.resolve(dir) : os8.tmpdir(), LOG_NAME);
|
|
20159
20694
|
}
|
|
20160
20695
|
function enableDebug(argv = process.argv) {
|
|
20161
20696
|
if (enabled) return true;
|
|
@@ -20171,8 +20706,8 @@ function enableDebug(argv = process.argv) {
|
|
|
20171
20706
|
enabled = true;
|
|
20172
20707
|
logFile = resolveLogFile();
|
|
20173
20708
|
try {
|
|
20174
|
-
|
|
20175
|
-
|
|
20709
|
+
fs32.mkdirSync(path41.dirname(logFile), { recursive: true });
|
|
20710
|
+
fs32.writeFileSync(logFile, "");
|
|
20176
20711
|
} catch {
|
|
20177
20712
|
logFile = null;
|
|
20178
20713
|
}
|
|
@@ -20189,7 +20724,7 @@ function dlog(stage, message = "") {
|
|
|
20189
20724
|
const line = `[+${String(Date.now() - startedAt).padStart(6)}ms] [${stage}] ${message}`;
|
|
20190
20725
|
if (logFile) {
|
|
20191
20726
|
try {
|
|
20192
|
-
|
|
20727
|
+
fs32.appendFileSync(logFile, line + "\n");
|
|
20193
20728
|
} catch {
|
|
20194
20729
|
}
|
|
20195
20730
|
}
|
|
@@ -20349,18 +20884,18 @@ if (enableDebug(process.argv)) {
|
|
|
20349
20884
|
logEnvironment();
|
|
20350
20885
|
}
|
|
20351
20886
|
var MODEL = process.env.OPENAI_MODEL ?? "gpt-4o";
|
|
20352
|
-
var WORKSPACE =
|
|
20887
|
+
var WORKSPACE = path42.resolve(process.env.WORKSPACE ?? ".");
|
|
20353
20888
|
var MAX_ITERATIONS = parseMaxIterations(process.env.MAX_ITERATIONS, 300);
|
|
20354
20889
|
var STATE_DIR = stateDir();
|
|
20355
20890
|
function listSessions() {
|
|
20356
20891
|
try {
|
|
20357
|
-
const files =
|
|
20892
|
+
const files = fs33.readdirSync(STATE_DIR);
|
|
20358
20893
|
const sessions = [];
|
|
20359
20894
|
for (const f of files) {
|
|
20360
20895
|
if (!f.endsWith("_state.json")) continue;
|
|
20361
20896
|
try {
|
|
20362
20897
|
const parsed = JSON.parse(
|
|
20363
|
-
|
|
20898
|
+
fs33.readFileSync(path42.join(STATE_DIR, f), "utf8")
|
|
20364
20899
|
);
|
|
20365
20900
|
if (parsed && typeof parsed.sessionId === "string") {
|
|
20366
20901
|
sessions.push(parsed);
|
|
@@ -20394,11 +20929,11 @@ function printLastAssistantMessage(messages) {
|
|
|
20394
20929
|
out += renderer.flush();
|
|
20395
20930
|
cliWrite(out + "\n");
|
|
20396
20931
|
}
|
|
20397
|
-
var AGENTS_FILE =
|
|
20932
|
+
var AGENTS_FILE = path42.join(WORKSPACE, ".agent", "agents.json");
|
|
20398
20933
|
function loadAgentsFromFile() {
|
|
20399
20934
|
try {
|
|
20400
|
-
if (!
|
|
20401
|
-
const raw =
|
|
20935
|
+
if (!fs33.existsSync(AGENTS_FILE)) return [];
|
|
20936
|
+
const raw = fs33.readFileSync(AGENTS_FILE, "utf8");
|
|
20402
20937
|
const parsed = JSON.parse(raw);
|
|
20403
20938
|
if (!Array.isArray(parsed)) return [];
|
|
20404
20939
|
return parsed.filter(
|
|
@@ -20410,8 +20945,8 @@ function loadAgentsFromFile() {
|
|
|
20410
20945
|
}
|
|
20411
20946
|
function saveAgentsToFile(defs) {
|
|
20412
20947
|
try {
|
|
20413
|
-
|
|
20414
|
-
|
|
20948
|
+
fs33.mkdirSync(path42.dirname(AGENTS_FILE), { recursive: true });
|
|
20949
|
+
fs33.writeFileSync(AGENTS_FILE, JSON.stringify(defs, null, 2) + "\n", "utf8");
|
|
20415
20950
|
} catch (err) {
|
|
20416
20951
|
cliErr(`\u26A0\uFE0F \u4FDD\u5B58 agents \u914D\u7F6E\u5931\u8D25: ${err}`);
|
|
20417
20952
|
}
|
|
@@ -20420,12 +20955,12 @@ var agentRegistry = new AgentRegistry([
|
|
|
20420
20955
|
...BUILTIN_AGENTS,
|
|
20421
20956
|
...loadAgentsFromFile()
|
|
20422
20957
|
]);
|
|
20423
|
-
var MCP_FILE =
|
|
20424
|
-
var COMMAND_TOOLS_FILE =
|
|
20958
|
+
var MCP_FILE = path42.join(WORKSPACE, ".agent", "mcp.json");
|
|
20959
|
+
var COMMAND_TOOLS_FILE = path42.join(WORKSPACE, ".agent", "tools.json");
|
|
20425
20960
|
function loadJsonArray(file, validate) {
|
|
20426
20961
|
try {
|
|
20427
|
-
if (!
|
|
20428
|
-
const parsed = JSON.parse(
|
|
20962
|
+
if (!fs33.existsSync(file)) return [];
|
|
20963
|
+
const parsed = JSON.parse(fs33.readFileSync(file, "utf8"));
|
|
20429
20964
|
if (!Array.isArray(parsed)) return [];
|
|
20430
20965
|
if (!validate) return parsed;
|
|
20431
20966
|
return parsed.filter((v) => validate(v));
|
|
@@ -20435,8 +20970,8 @@ function loadJsonArray(file, validate) {
|
|
|
20435
20970
|
}
|
|
20436
20971
|
function saveJsonFile(file, data) {
|
|
20437
20972
|
try {
|
|
20438
|
-
|
|
20439
|
-
|
|
20973
|
+
fs33.mkdirSync(path42.dirname(file), { recursive: true });
|
|
20974
|
+
fs33.writeFileSync(file, JSON.stringify(data, null, 2) + "\n", "utf8");
|
|
20440
20975
|
} catch (err) {
|
|
20441
20976
|
cliErr(`\u26A0\uFE0F \u4FDD\u5B58\u914D\u7F6E\u5931\u8D25: ${err}`);
|
|
20442
20977
|
}
|
|
@@ -20537,7 +21072,7 @@ function pruneEmptySessions(keepSessionId) {
|
|
|
20537
21072
|
if (!isEmptySession(s) || s.sessionId === keepSessionId) continue;
|
|
20538
21073
|
for (const suffix of ["_state.json", ".jsonl"]) {
|
|
20539
21074
|
try {
|
|
20540
|
-
|
|
21075
|
+
fs33.unlinkSync(path42.join(STATE_DIR, `${s.sessionId}${suffix}`));
|
|
20541
21076
|
} catch {
|
|
20542
21077
|
}
|
|
20543
21078
|
}
|
|
@@ -20727,6 +21262,7 @@ function buildEngine(sessionId, savedState) {
|
|
|
20727
21262
|
// 引擎内置表(lookupContextWindow 兜底,见 TurnEngine._contextWindow)
|
|
20728
21263
|
contextWindow: parseOptionalPositiveNumber(process.env.CONTEXT_WINDOW) ?? modelContextWindow(conn?.modelMeta, model),
|
|
20729
21264
|
thresholdPct: parseRatio(process.env.COMPACTION_THRESHOLD_PCT),
|
|
21265
|
+
softThresholdPct: parseRatio(process.env.COMPACTION_SOFT_THRESHOLD_PCT),
|
|
20730
21266
|
capTokens: parseOptionalPositiveNumber(process.env.COMPACTION_CAP_TOKENS) ?? null,
|
|
20731
21267
|
// 系统提示词按当前 agent 组装(agent prompt + 叙述规则 + 环境信息)
|
|
20732
21268
|
instructions: agentRegistry.buildSystemPrompt(
|
|
@@ -21069,7 +21605,7 @@ async function offerTerminalSetup(engine, canUseAgent) {
|
|
|
21069
21605
|
}
|
|
21070
21606
|
var KNOWN_SUBCOMMANDS = /* @__PURE__ */ new Set(["link", "serve", "update"]);
|
|
21071
21607
|
function cliVersion() {
|
|
21072
|
-
const env3 = "0.2.
|
|
21608
|
+
const env3 = "0.2.6"?.trim();
|
|
21073
21609
|
if (env3) return env3;
|
|
21074
21610
|
try {
|
|
21075
21611
|
const req2 = (0, import_module.createRequire)(importMetaUrl);
|
|
@@ -21273,8 +21809,8 @@ async function main() {
|
|
|
21273
21809
|
}
|
|
21274
21810
|
});
|
|
21275
21811
|
const savedState = resumeId ? FileLogHook.loadState(resumeId, STATE_DIR) : null;
|
|
21276
|
-
const metaStateFile =
|
|
21277
|
-
const stateForMeta = savedState ?? (
|
|
21812
|
+
const metaStateFile = path42.join(STATE_DIR, `${SESSION_ID}_state.json`);
|
|
21813
|
+
const stateForMeta = savedState ?? (fs33.existsSync(metaStateFile) ? FileLogHook.loadState(SESSION_ID, STATE_DIR) : null);
|
|
21278
21814
|
sessionMeta = {
|
|
21279
21815
|
sessionId: SESSION_ID,
|
|
21280
21816
|
name: stateForMeta?.name,
|