deepseeker-code 1.0.55 → 1.0.57
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/dist/cli.mjs +631 -206
- package/package.json +4 -3
package/dist/cli.mjs
CHANGED
|
@@ -225,6 +225,33 @@ ${cwd}
|
|
|
225
225
|
DeepSeeker-Code \u5C06\u5728\u6B64\u76EE\u5F55\u8BFB\u53D6\u3001\u7F16\u8F91\u548C\u6267\u884C\u6587\u4EF6\u3002`,
|
|
226
226
|
optTrust: "\u4FE1\u4EFB\u6B64\u76EE\u5F55",
|
|
227
227
|
optExit: "\u9000\u51FA",
|
|
228
|
+
trustEmpty: "\u5DF2\u4FE1\u4EFB\u76EE\u5F55\uFF1A\uFF08\u65E0\uFF09\u3002\u9996\u6B21\u8FDB\u5165\u67D0\u76EE\u5F55\u65F6\u4F1A\u8BE2\u95EE\u662F\u5426\u4FE1\u4EFB\u3002",
|
|
229
|
+
trustList: (list) => `\u5DF2\u4FE1\u4EFB\u76EE\u5F55\uFF08\u64A4\u9500\u7528 /trust <\u5E8F\u53F7 \u6216 \u8DEF\u5F84>\uFF09\uFF1A
|
|
230
|
+
${list}
|
|
231
|
+
|
|
232
|
+
\u64A4\u9500\u540E\u9700\u91CD\u542F CLI \u751F\u6548\uFF08\u9879\u76EE\u7EA7\u914D\u7F6E\u4EC5\u5728\u542F\u52A8\u65F6\u52A0\u8F7D\uFF09\u3002`,
|
|
233
|
+
trustRemoved: (target) => `\u5DF2\u64A4\u9500\u4FE1\u4EFB\uFF1A${target}
|
|
234
|
+
\uFF08\u91CD\u542F CLI \u540E\u751F\u6548\u2014\u2014\u9879\u76EE\u7EA7\u914D\u7F6E\u4EC5\u5728\u542F\u52A8\u65F6\u52A0\u8F7D\uFF09`,
|
|
235
|
+
trustNotFound: (target) => `\u672A\u627E\u5230\u8BE5\u4FE1\u4EFB\u76EE\u5F55\uFF1A${target}`,
|
|
236
|
+
archiveSummary: (s) => `\u{1F4DC} \u6700\u8FD1\u4E00\u6B21\u538B\u7F29\u7684\u5F52\u6863\u6458\u8981\uFF1A
|
|
237
|
+
${s}`,
|
|
238
|
+
archiveNone: "\u672C\u4F1A\u8BDD\u542F\u52A8\u4EE5\u6765\u5C1A\u672A\u53D1\u751F\u8FC7\u538B\u7F29\uFF08\u6458\u8981\u4EC5\u4FDD\u7559\u8FD0\u884C\u65F6\u6700\u8FD1\u4E00\u6B21\uFF09\u3002",
|
|
239
|
+
planModeSet: (on) => `\u8BA1\u5212\u6A21\u5F0F\uFF1A${on ? "\u5F00\uFF08\u4E0B\u6B21\u63D0\u95EE\u5148\u53EA\u8BFB\u8C03\u7814\u5E76\u4EA7\u51FA\u65B9\u6848\uFF0C\u5BA1\u6279\u540E\u5B9E\u73B0\uFF09" : "\u5173"}`,
|
|
240
|
+
budgetView: (budget, last) => `\u{1F4B0} \u9884\u7B97\uFF1A${budget != null ? `\xA5${budget}/run` : "\u672A\u8BBE\u7F6E\uFF08/budget 0.5 \u8BBE\u7F6E\u6BCF\u4E2A run \u7684\u82B1\u8D39\u4E0A\u9650\uFF09"}${last != null ? ` \xB7 \u4E0A\u4E2A run \u5DF2\u82B1 \xA5${last.toFixed(3)}` : " \xB7 \u5C1A\u65E0\u5B8C\u6210 run"}`,
|
|
241
|
+
budgetOff: "\u{1F4B0} \u9884\u7B97\u5DF2\u5173\u95ED\uFF08\u4E0D\u9650\u82B1\u8D39\uFF09\u3002",
|
|
242
|
+
budgetUsage: "\u7528\u6CD5\uFF1A/budget 0.5\uFF08\u5143/run\uFF09\xB7 /budget off \xB7 /budget \u67E5\u770B",
|
|
243
|
+
budgetSet: (n) => `\u{1F4B0} \u9884\u7B97\u5DF2\u8BBE\u7F6E\uFF1A\u6BCF run \xA5${n}\uFF08\u8D85\u9650\u5148\u63D0\u9192\u6536\u655B\uFF0C\u4ECD\u8D85 120% \u5C06\u622A\u65AD\u672C run\uFF09\u3002`,
|
|
244
|
+
autoModeSet: (on) => `\u81EA\u52A8\u6A21\u5F0F\uFF1A${on ? "\u5F00\uFF08\u5DE5\u4F5C\u533A\u5185\u6587\u4EF6\u7F16\u8F91\u7531\u5206\u7C7B\u5668\u81EA\u52A8\u653E\u884C\uFF0C\u9AD8\u5371\u8F6C\u4EBA\u5DE5\uFF09" : "\u5173"}`,
|
|
245
|
+
thinkingInvalid: (arg) => `\u65E0\u6548\u7B49\u7EA7\uFF1A${arg}\uFF08\u53EF\u9009\uFF1Aoff \u5173\u95ED / high \u5E38\u89C4 / max \u6DF1\u5EA6\uFF09`,
|
|
246
|
+
thinkingCurrent: (level) => `\u5F53\u524D\u601D\u8003\u7B49\u7EA7\uFF1A${level}\uFF08off \u5173\u95ED / high \u5E38\u89C4 / max \u6DF1\u5EA6\uFF09`,
|
|
247
|
+
thinkingSet: (lvl) => `\u601D\u8003\u7B49\u7EA7\uFF1A${lvl}${lvl === "off" ? "\uFF08\u5173\u95ED\uFF0C\u7B80\u5355\u4EFB\u52A1\u66F4\u5FEB\u66F4\u7701\uFF09" : lvl === "max" ? "\uFF08\u6DF1\u5EA6\uFF0C\u590D\u6742\u4EFB\u52A1\uFF09" : "\uFF08\u5E38\u89C4\uFF09"}`,
|
|
248
|
+
engineLoading: "\u23F3 \u5F15\u64CE\u52A0\u8F7D\u4E2D\uFF08MCP/skills/commands\uFF09\u2026",
|
|
249
|
+
unknownCmd: (name) => `\u672A\u77E5\u547D\u4EE4\uFF1A/${name || "(\u7A7A)"}\uFF08\u8F93\u5165 / \u67E5\u770B\u53EF\u7528\u547D\u4EE4\uFF09`,
|
|
250
|
+
bangUsage: "\u7528\u6CD5\uFF1A!<shell \u547D\u4EE4>\uFF08\u5982 !git status\uFF09\uFF1B\u8F93\u51FA\u4F1A\u5E26\u5165\u4E0B\u8F6E\u5BF9\u8BDD\u4E0A\u4E0B\u6587\u3002",
|
|
251
|
+
bangHead: (timedOut, ok, exitCode) => timedOut ? "\u23F1 \u8D85\u65F6\u4E2D\u6B62" : ok ? "\u2705 \u9000\u51FA\u7801 0" : exitCode != null ? `\u274C \u9000\u51FA\u7801 ${exitCode}` : "\u274C \u5DF2\u4E2D\u6B62",
|
|
252
|
+
bangNoOutput: "(\u65E0\u8F93\u51FA)",
|
|
253
|
+
visionDowngraded: (model) => `\u{1F5BC} \u6A21\u578B ${model} \u4E0D\u652F\u6301\u56FE\u7247\uFF0C\u5DF2\u81EA\u52A8\u964D\u7EA7\u4E3A\u6587\u672C\u5904\u7406\uFF08\u5DF2\u8BB0\u4F4F\uFF0C\u540E\u7EED\u6D88\u606F\u76F4\u63A5\u6309\u6587\u672C\u53D1\u9001\uFF09`,
|
|
254
|
+
planEnterSwitched: (reason) => `\u{1F4CB} \u6A21\u578B\u8BF7\u6C42\u8FDB\u5165\u8BA1\u5212\u6A21\u5F0F${reason ? `\uFF1A${reason}` : ""}\uFF0C\u5DF2\u5207\u6362\u2026`,
|
|
228
255
|
helpText: (model, thinking, locale2) => [
|
|
229
256
|
"/help \xB7 /status \xB7 /clear \xB7 /exit",
|
|
230
257
|
"/plan \u2014 \u5207\u6362\u8BA1\u5212\u6A21\u5F0F\uFF08\u53EA\u8BFB\u8C03\u7814 \u2192 \u65B9\u6848\u5BA1\u6279 \u2192 \u5B9E\u73B0\uFF09",
|
|
@@ -380,6 +407,33 @@ ${cwd}
|
|
|
380
407
|
DeepSeeker-Code will read, edit, and execute files here.`,
|
|
381
408
|
optTrust: "Yes, I trust this folder",
|
|
382
409
|
optExit: "No, exit",
|
|
410
|
+
trustEmpty: "Trusted dirs: (none). You'll be asked on first entry to a directory.",
|
|
411
|
+
trustList: (list) => `Trusted dirs (revoke with /trust <index or path>):
|
|
412
|
+
${list}
|
|
413
|
+
|
|
414
|
+
Revocation takes effect after a CLI restart (project config loads at startup only).`,
|
|
415
|
+
trustRemoved: (target) => `Trust revoked: ${target}
|
|
416
|
+
(takes effect after a CLI restart \u2014 project config loads at startup only)`,
|
|
417
|
+
trustNotFound: (target) => `No such trusted dir: ${target}`,
|
|
418
|
+
archiveSummary: (s) => `\u{1F4DC} Latest compaction summary:
|
|
419
|
+
${s}`,
|
|
420
|
+
archiveNone: "No compaction has happened since this session started (only the latest runtime summary is kept).",
|
|
421
|
+
planModeSet: (on) => `Plan mode: ${on ? "on (next question starts read-only research, plan review, then implementation)" : "off"}`,
|
|
422
|
+
budgetView: (budget, last) => `\u{1F4B0} Budget: ${budget != null ? `\xA5${budget}/run` : "not set (/budget 0.5 to cap per-run cost)"}${last != null ? ` \xB7 last run cost \xA5${last.toFixed(3)}` : " \xB7 no completed run yet"}`,
|
|
423
|
+
budgetOff: "\u{1F4B0} Budget disabled (no cap).",
|
|
424
|
+
budgetUsage: "Usage: /budget 0.5 (\xA5/run) \xB7 /budget off \xB7 /budget to view",
|
|
425
|
+
budgetSet: (n) => `\u{1F4B0} Budget set: \xA5${n} per run (soft nudge on breach, hard truncation at 120%).`,
|
|
426
|
+
autoModeSet: (on) => `Auto mode: ${on ? "on (in-workspace file edits auto-approved by classifier, risky ops to human)" : "off"}`,
|
|
427
|
+
thinkingInvalid: (arg) => `Invalid level: ${arg} (choose: off / high / max)`,
|
|
428
|
+
thinkingCurrent: (level) => `Current thinking level: ${level} (off / high / max)`,
|
|
429
|
+
thinkingSet: (lvl) => `Thinking level: ${lvl}${lvl === "off" ? " (off \u2014 faster and cheaper for simple tasks)" : lvl === "max" ? " (deep, for complex tasks)" : " (standard)"}`,
|
|
430
|
+
engineLoading: "\u23F3 Loading engine (MCP/skills/commands)\u2026",
|
|
431
|
+
unknownCmd: (name) => `Unknown command: /${name || "(empty)"} (type / to list commands)`,
|
|
432
|
+
bangUsage: "Usage: !<shell command> (e.g. !git status); output joins the next turn's context.",
|
|
433
|
+
bangHead: (timedOut, ok, exitCode) => timedOut ? "\u23F1 timed out" : ok ? "\u2705 exit code 0" : exitCode != null ? `\u274C exit code ${exitCode}` : "\u274C aborted",
|
|
434
|
+
bangNoOutput: "(no output)",
|
|
435
|
+
visionDowngraded: (model) => `\u{1F5BC} Model ${model} doesn't support images; downgraded to text this turn (remembered \u2014 future messages send as text)`,
|
|
436
|
+
planEnterSwitched: (reason) => `\u{1F4CB} Model requested plan mode${reason ? `: ${reason}` : ""}; switched\u2026`,
|
|
383
437
|
helpText: (model, thinking, locale2) => [
|
|
384
438
|
"/help \xB7 /status \xB7 /clear \xB7 /exit",
|
|
385
439
|
"/plan \u2014 Toggle plan mode (read-only research \u2192 review \u2192 implement)",
|
|
@@ -796,10 +850,33 @@ var init_trust = __esm({
|
|
|
796
850
|
|
|
797
851
|
// ../core/src/batch/ticket.ts
|
|
798
852
|
import fs4 from "fs/promises";
|
|
799
|
-
var generateBatchId, parseToolsValue, parsePositiveNumber, parseBatchTicket, readBatchTicket;
|
|
853
|
+
var TICKET_MSG, ticketMsg, generateBatchId, parseToolsValue, parsePositiveNumber, parseBatchTicket, readBatchTicket;
|
|
800
854
|
var init_ticket = __esm({
|
|
801
855
|
"../core/src/batch/ticket.ts"() {
|
|
802
856
|
"use strict";
|
|
857
|
+
TICKET_MSG = {
|
|
858
|
+
zh: {
|
|
859
|
+
noFrontmatter: "\u7F3A\u5C11 frontmatter\uFF08--- \u5305\u88F9\u7684\u5934\u90E8\u5757\uFF09\u3002\u5DE5\u5355\u683C\u5F0F\u89C1 batch add \u5E2E\u52A9\u3002",
|
|
860
|
+
noAccept: "frontmatter \u7F3A accept\uFF08\u9A8C\u6536\u547D\u4EE4\uFF09\u3002\u6302\u673A\u4EFB\u52A1\u5FC5\u987B\u5E26\u53EF\u6267\u884C\u9A8C\u6536\uFF0C\u7F3A\u9A8C\u6536\u62D2\u7EDD\u5165\u961F\u3002",
|
|
861
|
+
badBudget: (v) => `budget-yuan \u975E\u6CD5\uFF08"${v}"\uFF09\uFF1A\u987B\u4E3A\u6B63\u6570\uFF08\u5143\uFF09\u3002`,
|
|
862
|
+
badTimeout: (v) => `timeout-min \u975E\u6CD5\uFF08"${v}"\uFF09\uFF1A\u987B\u4E3A\u6B63\u6574\u6570\uFF08\u5206\u949F\uFF09\u3002`,
|
|
863
|
+
badTools: "tools \u4E3A\u7A7A\uFF1A\u8981\u4E48\u5220\u6389\u8BE5\u884C\uFF08\u7528\u7F3A\u7701\u7981\u7528\u6E05\u5355\uFF09\uFF0C\u8981\u4E48\u5217\u5DE5\u5177\u540D\uFF08\u9017\u53F7\u5206\u9694\uFF09\u3002",
|
|
864
|
+
emptyBody: "\u4EFB\u52A1\u6B63\u6587\u4E3A\u7A7A\uFF1Afrontmatter \u4E4B\u540E\u5E94\u5199\u4EFB\u52A1\u63CF\u8FF0\u3002",
|
|
865
|
+
untitled: "(\u672A\u547D\u540D\u4EFB\u52A1)",
|
|
866
|
+
readFail: (e) => `\u8BFB\u5DE5\u5355\u5931\u8D25\uFF1A${e}`
|
|
867
|
+
},
|
|
868
|
+
en: {
|
|
869
|
+
noFrontmatter: "Missing frontmatter (a --- delimited header block). See `batch add` help for the ticket format.",
|
|
870
|
+
noAccept: "Frontmatter is missing `accept` (acceptance command). Batch tasks must carry an executable acceptance check \u2014 rejected without one.",
|
|
871
|
+
badBudget: (v) => `Invalid budget-yuan ("${v}"): must be a positive number (yuan).`,
|
|
872
|
+
badTimeout: (v) => `Invalid timeout-min ("${v}"): must be a positive integer (minutes).`,
|
|
873
|
+
badTools: "Empty tools: either remove the line (use the default denylist) or list tool names (comma-separated).",
|
|
874
|
+
emptyBody: "Empty task body: write the task description after the frontmatter.",
|
|
875
|
+
untitled: "(untitled task)",
|
|
876
|
+
readFail: (e) => `Failed to read ticket: ${e}`
|
|
877
|
+
}
|
|
878
|
+
};
|
|
879
|
+
ticketMsg = (locale2, key) => (TICKET_MSG[locale2] ?? TICKET_MSG.zh)[key] ?? TICKET_MSG.zh[key] ?? key;
|
|
803
880
|
generateBatchId = (now = /* @__PURE__ */ new Date()) => {
|
|
804
881
|
const p = (n, w = 2) => String(n).padStart(w, "0");
|
|
805
882
|
const rand = Math.random().toString(36).slice(2, 6);
|
|
@@ -810,9 +887,9 @@ var init_ticket = __esm({
|
|
|
810
887
|
const n = Number(raw.trim());
|
|
811
888
|
return Number.isFinite(n) && n > 0 ? n : null;
|
|
812
889
|
};
|
|
813
|
-
parseBatchTicket = (source) => {
|
|
890
|
+
parseBatchTicket = (source, locale2 = "zh") => {
|
|
814
891
|
const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(source);
|
|
815
|
-
if (!m) return { ok: false, error:
|
|
892
|
+
if (!m) return { ok: false, error: ticketMsg(locale2, "noFrontmatter") };
|
|
816
893
|
const [, fmRaw, bodyRaw] = m;
|
|
817
894
|
const fm = {};
|
|
818
895
|
for (const line of fmRaw.split(/\r?\n/)) {
|
|
@@ -821,34 +898,35 @@ var init_ticket = __esm({
|
|
|
821
898
|
fm[kv[1].toLowerCase()] = kv[2].trim();
|
|
822
899
|
}
|
|
823
900
|
const accept = (fm["accept"] ?? "").trim();
|
|
824
|
-
if (!accept) return { ok: false, error:
|
|
901
|
+
if (!accept) return { ok: false, error: ticketMsg(locale2, "noAccept") };
|
|
825
902
|
let budgetYuan;
|
|
826
903
|
if (fm["budget-yuan"] !== void 0) {
|
|
827
904
|
const n = parsePositiveNumber(fm["budget-yuan"]);
|
|
828
|
-
if (n === null) return { ok: false, error:
|
|
905
|
+
if (n === null) return { ok: false, error: ticketMsg(locale2, "badBudget")(fm["budget-yuan"]) };
|
|
829
906
|
budgetYuan = n;
|
|
830
907
|
}
|
|
831
908
|
let timeoutMin;
|
|
832
909
|
if (fm["timeout-min"] !== void 0) {
|
|
833
910
|
const n = parsePositiveNumber(fm["timeout-min"]);
|
|
834
|
-
if (n === null) return { ok: false, error:
|
|
911
|
+
if (n === null) return { ok: false, error: ticketMsg(locale2, "badTimeout")(fm["timeout-min"]) };
|
|
835
912
|
timeoutMin = n;
|
|
836
913
|
}
|
|
837
914
|
const tools = fm["tools"] !== void 0 ? parseToolsValue(fm["tools"]) : void 0;
|
|
838
|
-
if (tools && tools.length === 0) return { ok: false, error:
|
|
915
|
+
if (tools && tools.length === 0) return { ok: false, error: ticketMsg(locale2, "badTools") };
|
|
916
|
+
const setup = (fm["setup"] ?? "").trim() || void 0;
|
|
839
917
|
const body = bodyRaw.trim();
|
|
840
|
-
if (!body) return { ok: false, error:
|
|
841
|
-
const title = (fm["title"] ?? "").trim() || body.split(/\r?\n/).find((l) => l.trim())?.slice(0, 40) || "
|
|
842
|
-
return { ok: true, ticket: { title, accept, budgetYuan, timeoutMin, tools: tools && tools.length > 0 ? tools : void 0, body } };
|
|
918
|
+
if (!body) return { ok: false, error: ticketMsg(locale2, "emptyBody") };
|
|
919
|
+
const title = (fm["title"] ?? "").trim() || body.split(/\r?\n/).find((l) => l.trim())?.slice(0, 40) || ticketMsg(locale2, "untitled");
|
|
920
|
+
return { ok: true, ticket: { title, accept, setup, budgetYuan, timeoutMin, tools: tools && tools.length > 0 ? tools : void 0, body } };
|
|
843
921
|
};
|
|
844
|
-
readBatchTicket = async (filePath) => {
|
|
922
|
+
readBatchTicket = async (filePath, locale2 = "zh") => {
|
|
845
923
|
let source;
|
|
846
924
|
try {
|
|
847
925
|
source = await fs4.readFile(filePath, "utf-8");
|
|
848
926
|
} catch (e) {
|
|
849
|
-
return { ok: false, error:
|
|
927
|
+
return { ok: false, error: ticketMsg(locale2, "readFail")(e?.message ?? e) };
|
|
850
928
|
}
|
|
851
|
-
return parseBatchTicket(source);
|
|
929
|
+
return parseBatchTicket(source, locale2);
|
|
852
930
|
};
|
|
853
931
|
}
|
|
854
932
|
});
|
|
@@ -856,11 +934,21 @@ var init_ticket = __esm({
|
|
|
856
934
|
// ../core/src/batch/queue.ts
|
|
857
935
|
import fs5 from "fs/promises";
|
|
858
936
|
import path6 from "path";
|
|
859
|
-
var batchQueueRoot, stateDir, lockPath, listState, snapshotQueue, reportPath, enqueueTicketFile, takeNextTicket, requeueStaleRunning, finishTicket, cleanDone, pidAlive, acquireRunLock, releaseRunLock;
|
|
937
|
+
var LOCK_MSG, batchQueueRoot, stateDir, lockPath, listState, snapshotQueue, reportPath, enqueueTicketFile, takeNextTicket, requeueStaleRunning, finishTicket, cleanDone, pidAlive, acquireRunLock, releaseRunLock;
|
|
860
938
|
var init_queue = __esm({
|
|
861
939
|
"../core/src/batch/queue.ts"() {
|
|
862
940
|
"use strict";
|
|
863
941
|
init_ticket();
|
|
942
|
+
LOCK_MSG = {
|
|
943
|
+
zh: {
|
|
944
|
+
createFail: (e) => `\u9501\u521B\u5EFA\u5931\u8D25\uFF1A${e}`,
|
|
945
|
+
held: (pid) => `\u5DF2\u6709 batch runner \u5728\u8FD0\u884C\uFF08pid ${pid}\uFF09\u3002\u6302\u673A\u6A21\u5F0F\u4E32\u884C\uFF0C\u52FF\u5E76\u53D1\u8DD1\u4E24\u4E2A runner\u3002`
|
|
946
|
+
},
|
|
947
|
+
en: {
|
|
948
|
+
createFail: (e) => `Failed to create the lock file: ${e}`,
|
|
949
|
+
held: (pid) => `Another batch runner is already running (pid ${pid}). Batch mode is serial \u2014 don't run two runners at once.`
|
|
950
|
+
}
|
|
951
|
+
};
|
|
864
952
|
batchQueueRoot = () => process.env.DEEPSEEKER_CODE_BATCH_DIR || path6.join(process.cwd(), ".deepseeker-code", "batch");
|
|
865
953
|
stateDir = (s) => path6.join(batchQueueRoot(), s);
|
|
866
954
|
lockPath = () => path6.join(batchQueueRoot(), ".lock");
|
|
@@ -877,8 +965,8 @@ var init_queue = __esm({
|
|
|
877
965
|
done: (await listState("done")).map((f) => f.replace(/\.md$/, ""))
|
|
878
966
|
});
|
|
879
967
|
reportPath = (id) => path6.join(stateDir("done"), `${id}.report.md`);
|
|
880
|
-
enqueueTicketFile = async (srcPath) => {
|
|
881
|
-
const parsed = await readBatchTicket(srcPath);
|
|
968
|
+
enqueueTicketFile = async (srcPath, locale2 = "zh") => {
|
|
969
|
+
const parsed = await readBatchTicket(srcPath, locale2);
|
|
882
970
|
if (!parsed.ok) return parsed;
|
|
883
971
|
const source = await fs5.readFile(srcPath, "utf-8");
|
|
884
972
|
const id = generateBatchId();
|
|
@@ -935,18 +1023,18 @@ var init_queue = __esm({
|
|
|
935
1023
|
return e?.code === "EPERM";
|
|
936
1024
|
}
|
|
937
1025
|
};
|
|
938
|
-
acquireRunLock = async () => {
|
|
1026
|
+
acquireRunLock = async (locale2 = "zh") => {
|
|
939
1027
|
await fs5.mkdir(batchQueueRoot(), { recursive: true });
|
|
940
1028
|
const payload = `${process.pid} ${(/* @__PURE__ */ new Date()).toISOString()}`;
|
|
941
1029
|
try {
|
|
942
1030
|
await fs5.writeFile(lockPath(), payload, { flag: "wx" });
|
|
943
1031
|
return { ok: true };
|
|
944
1032
|
} catch (e) {
|
|
945
|
-
if (e?.code !== "EEXIST") return { ok: false, error:
|
|
1033
|
+
if (e?.code !== "EEXIST") return { ok: false, error: LOCK_MSG[locale2].createFail(e?.message ?? e) };
|
|
946
1034
|
const raw = await fs5.readFile(lockPath(), "utf-8").catch(() => "");
|
|
947
1035
|
const ownerPid = parseInt(raw.split(" ")[0], 10);
|
|
948
1036
|
if (Number.isFinite(ownerPid) && pidAlive(ownerPid)) {
|
|
949
|
-
return { ok: false, error:
|
|
1037
|
+
return { ok: false, error: LOCK_MSG[locale2].held(ownerPid) };
|
|
950
1038
|
}
|
|
951
1039
|
await fs5.writeFile(lockPath(), payload).catch(() => {
|
|
952
1040
|
});
|
|
@@ -963,6 +1051,219 @@ var init_queue = __esm({
|
|
|
963
1051
|
}
|
|
964
1052
|
});
|
|
965
1053
|
|
|
1054
|
+
// src/batchStrings.ts
|
|
1055
|
+
var ZH, EN, DICT, batchT;
|
|
1056
|
+
var init_batchStrings = __esm({
|
|
1057
|
+
"src/batchStrings.ts"() {
|
|
1058
|
+
"use strict";
|
|
1059
|
+
ZH = {
|
|
1060
|
+
// —— batchAdmin(add / list / clean / help) ——
|
|
1061
|
+
usage: `deepseeker-code batch \u2014\u2014 \u6302\u673A\u6279\u5904\u7406\uFF08\u6210\u672C\u4FE1\u4EFB\u94FE\u7B2C\u56DB\u73AF\uFF09
|
|
1062
|
+
|
|
1063
|
+
\u7528\u6CD5\uFF1Adeepseeker-code batch <\u5B50\u547D\u4EE4>
|
|
1064
|
+
add <\u5DE5\u5355.md> [...] \u6295\u9012\u4EFB\u52A1\uFF08\u53EF\u4E00\u6B21\u591A\u4E2A\u6587\u4EF6\uFF09
|
|
1065
|
+
list \u67E5\u770B pending / running / done \u4E09\u6001\u961F\u5217
|
|
1066
|
+
run [--wait-window HH:MM-HH:MM] \u6267\u884C\u961F\u5217\uFF08\u4E32\u884C\uFF0C\u9010\u4EFB\u52A1\u51FA\u62A5\u544A\uFF1B--wait-window \u5230\u70B9\u518D\u5F00\u8DD1\uFF09
|
|
1067
|
+
clean \u6E05\u7A7A done/\uFF08\u5DF2\u8BFB\u8FC7\u7684\u62A5\u544A\u4E0E\u5DE5\u5355\u5B58\u6863\uFF09
|
|
1068
|
+
|
|
1069
|
+
\u5DE5\u5355\u683C\u5F0F\uFF08Markdown\uFF0Cfrontmatter \u7684 accept \u5FC5\u586B\u2014\u2014\u7F3A\u9A8C\u6536\u62D2\u7EDD\u5165\u961F\uFF09\uFF1A
|
|
1070
|
+
---
|
|
1071
|
+
title: \u4FEE\u590D\u65E5\u671F\u89E3\u6790 bug
|
|
1072
|
+
accept: npm test
|
|
1073
|
+
setup: pnpm install # \u53EF\u9009\uFF1Aagent \u524D\u5728 worktree \u5185\u5907\u73AF\u5883\uFF08\u5E72\u51C0\u68C0\u51FA\u65E0 node_modules\uFF0C\u9A8C\u6536\u4F9D\u8D56\u73AF\u5883\u65F6\u5148\u88C5\uFF09
|
|
1074
|
+
budget-yuan: 0.5 # \u53EF\u9009\uFF1A\u672C\u4EFB\u52A1\u82B1\u8D39\u4E0A\u9650\uFF08\u5143\uFF09
|
|
1075
|
+
timeout-min: 30 # \u53EF\u9009\uFF1Aagent \u9636\u6BB5\u8D85\u65F6\uFF08\u5206\u949F\uFF0C\u7F3A\u7701 30\uFF09
|
|
1076
|
+
tools: run_command # \u53EF\u9009\uFF1A\u663E\u5F0F\u89E3\u9501\u9AD8\u5371\u5DE5\u5177\uFF08\u7F3A\u7701\u7981 run_command/delete_path\uFF09
|
|
1077
|
+
---
|
|
1078
|
+
\u4EFB\u52A1\u63CF\u8FF0\u6B63\u6587\uFF08Markdown\uFF09\u2026
|
|
1079
|
+
|
|
1080
|
+
\u4EA7\u7269\uFF1A<\u9879\u76EE>/.deepseeker-code/batch/done/<id>.report.md\uFF08\u72B6\u6001/\u7ED3\u7B97\u5355/\u9A8C\u6536\u8F93\u51FA/diff \u6458\u8981\uFF09\uFF1B
|
|
1081
|
+
\u6539\u52A8\u6536\u5272\u5728\u72EC\u7ACB git worktree\uFF08\u4E34\u65F6\u5206\u652F\uFF09\u4E0A\uFF0C\u4FDD\u7559\u5F85\u4EBA\u5DE5 merge \u6216\u4E22\u5F03\u3002`,
|
|
1082
|
+
adminAddUsage: "\u7528\u6CD5\uFF1Adeepseeker-code batch add <\u5DE5\u5355.md> [...]\uFF08\u7F3A\u9A8C\u6536\u547D\u4EE4\u7684\u5DE5\u5355\u4F1A\u88AB\u62D2\u7EDD\uFF09\n\u8BE6\u60C5\uFF1Adeepseeker-code batch help",
|
|
1083
|
+
readFileFail: (e) => `\u8BFB\u6587\u4EF6\u5931\u8D25\uFF1A${e}`,
|
|
1084
|
+
enqueued: (id, title) => `\u{1F4E5} \u5DF2\u5165\u961F [${id}] ${title}`,
|
|
1085
|
+
addRejected: (name, err) => `\u{1F6AB} \u62D2\u7EDD ${name}\uFF1A${err}`,
|
|
1086
|
+
nextStepRun: "\n\u8DD1\u6279\uFF1Adeepseeker-code batch run",
|
|
1087
|
+
adminQueueEmpty: "\u961F\u5217\u7A7A\u3002\u6295\u9012\uFF1Adeepseeker-code batch add <\u5DE5\u5355.md>\uFF08\u683C\u5F0F\u89C1 batch help\uFF09",
|
|
1088
|
+
listRunningHead: "\u25B6 \u8FD0\u884C\u4E2D\uFF1A",
|
|
1089
|
+
listPendingHead: (n) => `\u23F3 \u5F85\u8DD1 ${n}\uFF1A`,
|
|
1090
|
+
listDoneHead: (n) => `\u2714 \u5DF2\u5B8C\u6210 ${n}\uFF1A`,
|
|
1091
|
+
cleaned: (n) => `\u{1F9F9} \u5DF2\u6E05\u7A7A done/\uFF08${n} \u4E2A\u4EFB\u52A1\u5B58\u6863\uFF09\u3002pending/running \u4E0D\u53D7\u5F71\u54CD\u3002`,
|
|
1092
|
+
reportMissing: "\uFF08\u62A5\u544A\u7F3A\u5931\uFF09",
|
|
1093
|
+
// —— batchRunner 控制台进度 ——
|
|
1094
|
+
ticketRejected: (id, err) => `\u{1F6AB} [${id}] \u5DE5\u5355\u88AB\u62D2\uFF1A${err}`,
|
|
1095
|
+
taskMeta: (budget, timeoutMin, accept) => ` \u9884\u7B97 ${budget !== void 0 ? `\xA5${budget}` : "\u4E0D\u9650"} \xB7 \u8D85\u65F6 ${timeoutMin}min \xB7 \u9A8C\u6536 \`${accept}\``,
|
|
1096
|
+
setupLine: (cmd) => `\u{1F6E0}\uFE0F setup\uFF1A\`${cmd}\`\uFF08worktree \u5185\u5907\u73AF\u5883\uFF09`,
|
|
1097
|
+
setupFail: (cmd, code) => `\u73AF\u5883\u51C6\u5907\u5931\u8D25\uFF08setup \`${cmd}\` exit ${code ?? "null"}\uFF09\u2014\u2014\u8DF3\u8FC7 agent \u9636\u6BB5\uFF0C\u4EFB\u52A1\u8BB0\u5931\u8D25`,
|
|
1098
|
+
roundLine: (ts2, round) => ` [${ts2}] \u8F6E ${round}`,
|
|
1099
|
+
wtCreateFail: (e) => `\u521B\u5EFA worktree \u5931\u8D25\uFF08\u9700\u8981\u4E3B\u5DE5\u4F5C\u533A\u662F git \u4ED3\u5E93\uFF09\uFF1A${e}`,
|
|
1100
|
+
agentErrorLine: (id, err) => `\u{1F4A5} [${id}] agent \u5F02\u5E38\uFF1A${err}`,
|
|
1101
|
+
timeoutLine: (id, min) => `\u23F1\uFE0F [${id}] \u8D85\u65F6\uFF08${min}min\uFF09\uFF0C\u622A\u65AD\u6536\u5C3E\uFF08\u9A8C\u6536\u4E0D\u8DD1\uFF09`,
|
|
1102
|
+
acceptLine: (passed, id, code) => `${passed ? "\u2705" : "\u274C"} [${id}] \u9A8C\u6536 exit ${code}`,
|
|
1103
|
+
acceptKilledSuffix: "\uFF08\u8D85\u65F6\u88AB\u6740\uFF09",
|
|
1104
|
+
timeoutAbort: (min) => `\u4EFB\u52A1\u8D85\u65F6\uFF08${min} \u5206\u949F\uFF09`,
|
|
1105
|
+
artifactLine: (p, branch) => ` \u4EA7\u7269\uFF1A${p}\uFF08\u5206\u652F ${branch}\uFF0C\u4FDD\u7559\u5F85\u4EBA\u5DE5\u5904\u7F6E\uFF09`,
|
|
1106
|
+
inWindowNow: (hhmm) => `\u23F0 \u5F53\u524D ${hhmm} \u5DF2\u5728\u7A97\u53E3\u5185\uFF0C\u7ACB\u5373\u5F00\u8DD1\u3002`,
|
|
1107
|
+
waitWindowWait: (h, m) => `\u23F0 --wait-window\uFF1A${h} \u5C0F\u65F6 ${m} \u5206\u540E\uFF08\u7A97\u53E3\u8D77\u70B9\uFF09\u5F00\u8DD1\u3002\u6302\u673A\u7B49\u5F85\u4E2D\uFF0CCtrl+C \u53EF\u53D6\u6D88\u3002`,
|
|
1108
|
+
waitWindowInvalid: (s) => `\u274C --wait-window \u683C\u5F0F\u975E\u6CD5\uFF1A"${s}"\uFF08\u5E94\u4E3A HH:MM-HH:MM\uFF0C\u5982 23:30-06:30\uFF09`,
|
|
1109
|
+
runnerQueueEmpty: "\u961F\u5217\u7A7A\uFF1Apending/ \u65E0\u4EFB\u52A1\u3002\u6295\u9012\uFF1Adeepseeker-code batch add <\u5DE5\u5355.md>",
|
|
1110
|
+
summaryDone: (total, passed, mins) => `\u{1F319} \u6302\u673A\u7ED3\u675F\uFF1A${total} \u4EFB\u52A1 \xB7 ${passed} \u8FC7 \xB7 ${total - passed} \u672A\u8FC7\uFF08\u8017\u65F6 ${mins}min\uFF09`,
|
|
1111
|
+
summaryCost: (sum, tasks) => `\u{1F4B0} \u603B\u82B1\u8D39\uFF1A\xA5${sum}\uFF08${tasks} \u4E2A\u4EFB\u52A1\u8BA1\u4EF7\uFF09`,
|
|
1112
|
+
summaryCostFree: "\u{1F4B0} \u603B\u82B1\u8D39\uFF1A\u5168\u90E8\u65E0\u4EF7\u6A21\u578B\uFF0C\u672A\u8BA1\u94B1",
|
|
1113
|
+
failedHead: "\u26A0\uFE0F \u672A\u8FC7\u6E05\u5355\uFF1A",
|
|
1114
|
+
artifactsDir: "\u62A5\u544A\u4E0E\u6539\u52A8\uFF1A.deepseeker-code/batch/done/\uFF08worktree \u5747\u4FDD\u7559\u5F85\u4EBA\u5DE5\u5904\u7F6E\uFF09",
|
|
1115
|
+
// —— 状态标签(控制台与报告共用) ——
|
|
1116
|
+
statusLabel: (s) => ({
|
|
1117
|
+
passed: "\u2705 \u901A\u8FC7\u9A8C\u6536",
|
|
1118
|
+
"accept-failed": "\u274C \u9A8C\u6536\u672A\u8FC7",
|
|
1119
|
+
timeout: "\u23F1\uFE0F \u8D85\u65F6\u622A\u65AD",
|
|
1120
|
+
error: "\u{1F4A5} agent \u5F02\u5E38",
|
|
1121
|
+
"setup-failed": "\u{1F6E0}\uFE0F \u73AF\u5883\u51C6\u5907\u5931\u8D25",
|
|
1122
|
+
rejected: "\u{1F6AB} \u5DE5\u5355\u88AB\u62D2"
|
|
1123
|
+
})[s],
|
|
1124
|
+
// —— 验收命令执行(输出嵌入报告) ——
|
|
1125
|
+
spawnFail: (e) => `\u542F\u52A8\u5931\u8D25\uFF1A${e}`,
|
|
1126
|
+
execFail: (e) => `\u6267\u884C\u5931\u8D25\uFF1A${e}`,
|
|
1127
|
+
tailOmitted: (n) => `\uFF08\u524D ${n} \u884C\u5DF2\u7701\u7565\uFF09`,
|
|
1128
|
+
noOutput: "\uFF08\u65E0\u8F93\u51FA\uFF09",
|
|
1129
|
+
// —— 结算单聚合与 receipt 行(报告内嵌) ——
|
|
1130
|
+
costFree: "\uFF08\u65E0\u4EF7\u6A21\u578B\uFF0C\u4E0D\u8BA1\u94B1\uFF09",
|
|
1131
|
+
costSummary: (c) => {
|
|
1132
|
+
const money = c.costYuan !== null ? `\xA5${c.costYuan.toFixed(4)}` : "\uFF08\u65E0\u4EF7\u6A21\u578B\uFF0C\u4E0D\u8BA1\u94B1\uFF09";
|
|
1133
|
+
const hit = c.promptTokens > 0 ? Math.round(c.cachedTokens / c.promptTokens * 100) : 0;
|
|
1134
|
+
const mins = Math.round(c.durationMs / 6e3) / 10;
|
|
1135
|
+
return `${c.rounds} \u8F6E \xB7 ${money} \xB7 \u7F13\u5B58\u547D\u4E2D ${hit}% \xB7 ${mins}min${c.partialPrice ? "\uFF08\u90E8\u5206\u8BB0\u5F55\u65E0\u4EF7\uFF0C\u94B1\u4E3A\u90E8\u5206\u548C\uFF09" : ""}${c.subRuns > 0 ? ` \xB7 \u5B50 run ${c.subRuns} \u4E2A\u5DF2\u8BA1\u5165` : ""}`;
|
|
1136
|
+
},
|
|
1137
|
+
noReceipt: "\uFF08\u65E0\u7ED3\u7B97\u5355\u2014\u2014run \u672A\u5230\u6536\u5C3E\u5373\u88AB\u622A\u65AD\uFF0C\u82B1\u8D39\u4EE5\u4E0A\u65B9 usageLog \u805A\u5408\u4E3A\u51C6\uFF09",
|
|
1138
|
+
receiptLine: (r) => `${r.rounds} \u8F6E \xB7 ${r.costYuan !== null ? `\xA5${r.costYuan.toFixed(4)}` : "\u65E0\u4EF7"} \xB7 \u7F13\u5B58\u547D\u4E2D ${Math.round(r.cacheHitRate * 100)}% \xB7 ${(r.durationMs / 1e3).toFixed(0)}s`,
|
|
1139
|
+
// —— 报告骨架 ——
|
|
1140
|
+
rejectedTitle: "# \u6302\u673A\u4EFB\u52A1\u88AB\u62D2",
|
|
1141
|
+
reportTitle: (title) => `# \u6302\u673A\u4EFB\u52A1\u62A5\u544A\uFF1A${title}`,
|
|
1142
|
+
statusEntry: (v) => `- \u72B6\u6001\uFF1A${v}`,
|
|
1143
|
+
budgetTruncNote: "\uFF08\u26A0\uFE0F \u9884\u7B97\u622A\u65AD\u540E\u6536\u5C3E\uFF09",
|
|
1144
|
+
costEntry: (v) => `- \u7ED3\u7B97\u5355\uFF1A${v}`,
|
|
1145
|
+
receiptEntry: (v) => `- \u672C\u8F6E receipt\uFF1A${v}`,
|
|
1146
|
+
errorEntry: (v) => `- \u5F02\u5E38\uFF1A${v}
|
|
1147
|
+
`,
|
|
1148
|
+
notCreated: "\uFF08\u672A\u521B\u5EFA\uFF09",
|
|
1149
|
+
taskH: "## \u4EFB\u52A1",
|
|
1150
|
+
finalH: "## \u6A21\u578B\u6536\u5C3E\u6C47\u62A5",
|
|
1151
|
+
noFinal: "\uFF08\u65E0\u8F93\u51FA\u2014\u2014run \u5728\u4EA7\u51FA\u6B63\u6587\u524D\u88AB\u622A\u65AD/\u5F02\u5E38\uFF09",
|
|
1152
|
+
acceptH: "## \u9A8C\u6536",
|
|
1153
|
+
acceptCmdLine: (cmd, code) => `\u547D\u4EE4\uFF1A\`${cmd}\` \u2192 exit ${code}`,
|
|
1154
|
+
acceptTimeoutSuffix: "\uFF08\u23F1\uFE0F \u9A8C\u6536\u8D85\u65F6\u88AB\u6740\uFF09",
|
|
1155
|
+
acceptTail: "\u8F93\u51FA\u5C3E\u90E8\uFF1A",
|
|
1156
|
+
noAccept: "\n\uFF08\u672A\u6267\u884C\u9A8C\u6536\u2014\u2014\u6539\u52A8\u4E0D\u5B8C\u6574\uFF0C\u8DD1\u4E86\u4E5F\u662F\u566A\u58F0\uFF09",
|
|
1157
|
+
deniedH: "## \u88AB\u62D2\u5DE5\u5177\u8C03\u7528\uFF08fail-closed \u8BB0\u5F55\uFF09",
|
|
1158
|
+
deniedNone: "\u65E0\u3002",
|
|
1159
|
+
diffH: "## Diff \u6458\u8981\uFF08worktree \u76F8\u5BF9\u57FA\u5EA7\uFF0C\u672A\u63D0\u4EA4\uFF0C\u5F85\u4EBA\u5DE5\u5904\u7F6E\uFF09",
|
|
1160
|
+
diffNote: (branch, p) => `\u6539\u52A8\u5728\u72EC\u7ACB worktree\uFF08\u5206\u652F \`${branch}\`\uFF0C\u8DEF\u5F84 ${p}\uFF09\u3002\u5904\u7F6E\uFF1A\u68C0\u67E5\u6EE1\u610F \u2192 \u5728 worktree \u5185 commit \u5E76\u5408\u56DE\u4E3B\u4ED3\uFF1B\u4E22\u5F03 \u2192 \u5220\u9664\u8BE5 worktree \u76EE\u5F55 + \`git worktree prune\` + \`git branch -D <\u5206\u652F>\`\u3002`,
|
|
1161
|
+
diffNone: "\uFF08\u65E0\uFF09"
|
|
1162
|
+
};
|
|
1163
|
+
EN = {
|
|
1164
|
+
usage: `deepseeker-code batch \u2014 unattended batch runs (cost trust chain)
|
|
1165
|
+
|
|
1166
|
+
Usage: deepseeker-code batch <subcommand>
|
|
1167
|
+
add <ticket.md> [...] Enqueue tasks (multiple files at once)
|
|
1168
|
+
list Show the pending / running / done queue
|
|
1169
|
+
run [--wait-window HH:MM-HH:MM] Run the queue (serial, one report per task; --wait-window waits for the window)
|
|
1170
|
+
clean Clear done/ (reports and ticket archives you've read)
|
|
1171
|
+
|
|
1172
|
+
Ticket format (Markdown; frontmatter \`accept\` is required \u2014 no acceptance, no enqueue):
|
|
1173
|
+
---
|
|
1174
|
+
title: Fix date parsing bug
|
|
1175
|
+
accept: npm test # required: acceptance command (exit 0 = pass)
|
|
1176
|
+
setup: pnpm install # optional: prep env inside the worktree before the agent (fresh checkout has no node_modules)
|
|
1177
|
+
budget-yuan: 0.5 # optional: per-task cost cap (yuan)
|
|
1178
|
+
timeout-min: 30 # optional: agent-phase timeout (minutes, default 30)
|
|
1179
|
+
tools: run_command # optional: unlock risky tools (run_command/delete_path denied by default)
|
|
1180
|
+
---
|
|
1181
|
+
|
|
1182
|
+
Task description body (Markdown)\u2026
|
|
1183
|
+
|
|
1184
|
+
Artifacts: <project>/.deepseeker-code/batch/done/<id>.report.md (status / receipt / acceptance output / diff summary);
|
|
1185
|
+
changes are harvested onto an isolated git worktree (temp branch), kept for manual merge or disposal.`,
|
|
1186
|
+
adminAddUsage: "Usage: deepseeker-code batch add <ticket.md> [...] (tickets without an acceptance command are rejected)\nDetails: deepseeker-code batch help",
|
|
1187
|
+
readFileFail: (e) => `Failed to read file: ${e}`,
|
|
1188
|
+
enqueued: (id, title) => `\u{1F4E5} Enqueued [${id}] ${title}`,
|
|
1189
|
+
addRejected: (name, err) => `\u{1F6AB} Rejected ${name}: ${err}`,
|
|
1190
|
+
nextStepRun: "\nRun the queue: deepseeker-code batch run",
|
|
1191
|
+
adminQueueEmpty: "Queue is empty. Enqueue: deepseeker-code batch add <ticket.md> (format: batch help)",
|
|
1192
|
+
listRunningHead: "\u25B6 Running:",
|
|
1193
|
+
listPendingHead: (n) => `\u23F3 Pending ${n}:`,
|
|
1194
|
+
listDoneHead: (n) => `\u2714 Done ${n}:`,
|
|
1195
|
+
cleaned: (n) => `\u{1F9F9} Cleared done/ (${n} task archives). pending/running untouched.`,
|
|
1196
|
+
reportMissing: "(report missing)",
|
|
1197
|
+
ticketRejected: (id, err) => `\u{1F6AB} [${id}] Ticket rejected: ${err}`,
|
|
1198
|
+
taskMeta: (budget, timeoutMin, accept) => ` Budget ${budget !== void 0 ? `\xA5${budget}` : "uncapped"} \xB7 timeout ${timeoutMin}min \xB7 accept \`${accept}\``,
|
|
1199
|
+
setupLine: (cmd) => `\u{1F6E0}\uFE0F setup: \`${cmd}\` (preparing the environment inside the worktree)`,
|
|
1200
|
+
setupFail: (cmd, code) => `Setup failed (\`${cmd}\` exit ${code ?? "null"}) \u2014 agent phase skipped, task marked failed`,
|
|
1201
|
+
roundLine: (ts2, round) => ` [${ts2}] round ${round}`,
|
|
1202
|
+
wtCreateFail: (e) => `Failed to create worktree (the main workspace must be a git repo): ${e}`,
|
|
1203
|
+
agentErrorLine: (id, err) => `\u{1F4A5} [${id}] agent error: ${err}`,
|
|
1204
|
+
timeoutLine: (id, min) => `\u23F1\uFE0F [${id}] Timed out (${min}min); wrapped up truncated (acceptance skipped)`,
|
|
1205
|
+
acceptLine: (passed, id, code) => `${passed ? "\u2705" : "\u274C"} [${id}] acceptance exit ${code}`,
|
|
1206
|
+
acceptKilledSuffix: " (killed on timeout)",
|
|
1207
|
+
timeoutAbort: (min) => `Task timed out (${min} minutes)`,
|
|
1208
|
+
artifactLine: (p, branch) => ` Artifact: ${p} (branch ${branch}, kept for manual handling)`,
|
|
1209
|
+
inWindowNow: (hhmm) => `\u23F0 It's ${hhmm}, already inside the window \u2014 starting now.`,
|
|
1210
|
+
waitWindowWait: (h, m) => `\u23F0 --wait-window: starting in ${h}h ${m}m (at the window start). Waiting \u2014 Ctrl+C to cancel.`,
|
|
1211
|
+
waitWindowInvalid: (s) => `\u274C Invalid --wait-window: "${s}" (expected HH:MM-HH:MM, e.g. 23:30-06:30)`,
|
|
1212
|
+
runnerQueueEmpty: "Queue empty: no tasks in pending/. Enqueue: deepseeker-code batch add <ticket.md>",
|
|
1213
|
+
summaryDone: (total, passed, mins) => `\u{1F319} Batch finished: ${total} tasks \xB7 ${passed} passed \xB7 ${total - passed} failed (${mins}min)`,
|
|
1214
|
+
summaryCost: (sum, tasks) => `\u{1F4B0} Total cost: \xA5${sum} (${tasks} tasks priced)`,
|
|
1215
|
+
summaryCostFree: "\u{1F4B0} Total cost: all records unpriced, no money counted",
|
|
1216
|
+
failedHead: "\u26A0\uFE0F Failed tasks:",
|
|
1217
|
+
artifactsDir: "Reports and changes: .deepseeker-code/batch/done/ (worktrees kept for manual handling)",
|
|
1218
|
+
statusLabel: (s) => ({
|
|
1219
|
+
passed: "\u2705 acceptance passed",
|
|
1220
|
+
"accept-failed": "\u274C acceptance failed",
|
|
1221
|
+
timeout: "\u23F1\uFE0F timed out",
|
|
1222
|
+
error: "\u{1F4A5} agent error",
|
|
1223
|
+
"setup-failed": "\u{1F6E0}\uFE0F setup failed",
|
|
1224
|
+
rejected: "\u{1F6AB} ticket rejected"
|
|
1225
|
+
})[s],
|
|
1226
|
+
spawnFail: (e) => `Spawn failed: ${e}`,
|
|
1227
|
+
execFail: (e) => `Execution failed: ${e}`,
|
|
1228
|
+
tailOmitted: (n) => `(first ${n} lines omitted)`,
|
|
1229
|
+
noOutput: "(no output)",
|
|
1230
|
+
costFree: "(unpriced model, no money counted)",
|
|
1231
|
+
costSummary: (c) => {
|
|
1232
|
+
const money = c.costYuan !== null ? `\xA5${c.costYuan.toFixed(4)}` : "(unpriced model, no money counted)";
|
|
1233
|
+
const hit = c.promptTokens > 0 ? Math.round(c.cachedTokens / c.promptTokens * 100) : 0;
|
|
1234
|
+
const mins = Math.round(c.durationMs / 6e3) / 10;
|
|
1235
|
+
return `${c.rounds} rounds \xB7 ${money} \xB7 cache hit ${hit}% \xB7 ${mins}min${c.partialPrice ? " (some records unpriced; money is a partial sum)" : ""}${c.subRuns > 0 ? ` \xB7 ${c.subRuns} sub-runs included` : ""}`;
|
|
1236
|
+
},
|
|
1237
|
+
noReceipt: "(no receipt \u2014 the run was truncated before finishing; cost per the usageLog aggregate above)",
|
|
1238
|
+
receiptLine: (r) => `${r.rounds} rounds \xB7 ${r.costYuan !== null ? `\xA5${r.costYuan.toFixed(4)}` : "unpriced"} \xB7 cache hit ${Math.round(r.cacheHitRate * 100)}% \xB7 ${(r.durationMs / 1e3).toFixed(0)}s`,
|
|
1239
|
+
rejectedTitle: "# Batch task rejected",
|
|
1240
|
+
reportTitle: (title) => `# Batch task report: ${title}`,
|
|
1241
|
+
statusEntry: (v) => `- Status: ${v}`,
|
|
1242
|
+
budgetTruncNote: " (\u26A0\uFE0F wrapped up after budget truncation)",
|
|
1243
|
+
costEntry: (v) => `- Receipt: ${v}`,
|
|
1244
|
+
receiptEntry: (v) => `- This run's receipt: ${v}`,
|
|
1245
|
+
errorEntry: (v) => `- Error: ${v}
|
|
1246
|
+
`,
|
|
1247
|
+
notCreated: "(not created)",
|
|
1248
|
+
taskH: "## Task",
|
|
1249
|
+
finalH: "## Model final report",
|
|
1250
|
+
noFinal: "(no output \u2014 the run was truncated/errored before producing any text)",
|
|
1251
|
+
acceptH: "## Acceptance",
|
|
1252
|
+
acceptCmdLine: (cmd, code) => `Command: \`${cmd}\` \u2192 exit ${code}`,
|
|
1253
|
+
acceptTimeoutSuffix: " (\u23F1\uFE0F acceptance timed out, killed)",
|
|
1254
|
+
acceptTail: "Output tail:",
|
|
1255
|
+
noAccept: "\n(Acceptance not run \u2014 changes incomplete, running it would be noise.)",
|
|
1256
|
+
deniedH: "## Denied tool calls (fail-closed log)",
|
|
1257
|
+
deniedNone: "None.",
|
|
1258
|
+
diffH: "## Diff summary (worktree vs base, uncommitted, awaiting manual handling)",
|
|
1259
|
+
diffNote: (branch, p) => `Changes live in an isolated worktree (branch \`${branch}\`, path ${p}). To keep: commit inside the worktree and merge back. To discard: delete the worktree directory + \`git worktree prune\` + \`git branch -D <branch>\`.`,
|
|
1260
|
+
diffNone: "(none)"
|
|
1261
|
+
};
|
|
1262
|
+
DICT = { zh: ZH, en: EN };
|
|
1263
|
+
batchT = (locale2) => DICT[locale2] ?? ZH;
|
|
1264
|
+
}
|
|
1265
|
+
});
|
|
1266
|
+
|
|
966
1267
|
// src/batchAdmin.ts
|
|
967
1268
|
var batchAdmin_exports = {};
|
|
968
1269
|
__export(batchAdmin_exports, {
|
|
@@ -971,11 +1272,14 @@ __export(batchAdmin_exports, {
|
|
|
971
1272
|
});
|
|
972
1273
|
import fs6 from "fs/promises";
|
|
973
1274
|
import path7 from "path";
|
|
974
|
-
var emit, parseBatchArgv,
|
|
1275
|
+
var emit, parseBatchArgv, handleBatchAdmin, describeDone;
|
|
975
1276
|
var init_batchAdmin = __esm({
|
|
976
1277
|
"src/batchAdmin.ts"() {
|
|
977
1278
|
"use strict";
|
|
978
1279
|
init_queue();
|
|
1280
|
+
init_batchStrings();
|
|
1281
|
+
init_strings();
|
|
1282
|
+
init_prefs();
|
|
979
1283
|
emit = (s = "") => {
|
|
980
1284
|
process.stdout.write(s + "\n");
|
|
981
1285
|
};
|
|
@@ -992,62 +1296,45 @@ var init_batchAdmin = __esm({
|
|
|
992
1296
|
if (sub === "clean") return { sub: "clean" };
|
|
993
1297
|
return { sub: "help" };
|
|
994
1298
|
};
|
|
995
|
-
USAGE = `deepseeker-code batch \u2014\u2014 \u6302\u673A\u6279\u5904\u7406\uFF08\u6210\u672C\u4FE1\u4EFB\u94FE\u7B2C\u56DB\u73AF\uFF09
|
|
996
|
-
|
|
997
|
-
\u7528\u6CD5\uFF1Adeepseeker-code batch <\u5B50\u547D\u4EE4>
|
|
998
|
-
add <\u5DE5\u5355.md> [...] \u6295\u9012\u4EFB\u52A1\uFF08\u53EF\u4E00\u6B21\u591A\u4E2A\u6587\u4EF6\uFF09
|
|
999
|
-
list \u67E5\u770B pending / running / done \u4E09\u6001\u961F\u5217
|
|
1000
|
-
run [--wait-window HH:MM-HH:MM] \u6267\u884C\u961F\u5217\uFF08\u4E32\u884C\uFF0C\u9010\u4EFB\u52A1\u51FA\u62A5\u544A\uFF1B--wait-window \u5230\u70B9\u518D\u5F00\u8DD1\uFF09
|
|
1001
|
-
clean \u6E05\u7A7A done/\uFF08\u5DF2\u8BFB\u8FC7\u7684\u62A5\u544A\u4E0E\u5DE5\u5355\u5B58\u6863\uFF09
|
|
1002
|
-
|
|
1003
|
-
\u5DE5\u5355\u683C\u5F0F\uFF08Markdown\uFF0Cfrontmatter \u7684 accept \u5FC5\u586B\u2014\u2014\u7F3A\u9A8C\u6536\u62D2\u7EDD\u5165\u961F\uFF09\uFF1A
|
|
1004
|
-
---
|
|
1005
|
-
title: \u4FEE\u590D\u65E5\u671F\u89E3\u6790 bug
|
|
1006
|
-
accept: npm test
|
|
1007
|
-
budget-yuan: 0.5 # \u53EF\u9009\uFF1A\u672C\u4EFB\u52A1\u82B1\u8D39\u4E0A\u9650\uFF08\u5143\uFF09
|
|
1008
|
-
timeout-min: 30 # \u53EF\u9009\uFF1Aagent \u9636\u6BB5\u8D85\u65F6\uFF08\u5206\u949F\uFF0C\u7F3A\u7701 30\uFF09
|
|
1009
|
-
tools: run_command # \u53EF\u9009\uFF1A\u663E\u5F0F\u89E3\u9501\u9AD8\u5371\u5DE5\u5177\uFF08\u7F3A\u7701\u7981 run_command/delete_path\uFF09
|
|
1010
|
-
---
|
|
1011
|
-
\u4EFB\u52A1\u63CF\u8FF0\u6B63\u6587\uFF08Markdown\uFF09\u2026
|
|
1012
|
-
|
|
1013
|
-
\u4EA7\u7269\uFF1A<\u9879\u76EE>/.deepseeker-code/batch/done/<id>.report.md\uFF08\u72B6\u6001/\u7ED3\u7B97\u5355/\u9A8C\u6536\u8F93\u51FA/diff \u6458\u8981\uFF09\uFF1B
|
|
1014
|
-
\u6539\u52A8\u6536\u5272\u5728\u72EC\u7ACB git worktree\uFF08\u4E34\u65F6\u5206\u652F\uFF09\u4E0A\uFF0C\u4FDD\u7559\u5F85\u4EBA\u5DE5 merge \u6216\u4E22\u5F03\u3002`;
|
|
1015
1299
|
handleBatchAdmin = async (b) => {
|
|
1300
|
+
const saved = await readLocale();
|
|
1301
|
+
if (saved) setLocale(saved);
|
|
1302
|
+
const T = batchT(getLocale());
|
|
1016
1303
|
if (b.sub === "help") {
|
|
1017
|
-
emit(
|
|
1304
|
+
emit(T.usage);
|
|
1018
1305
|
return;
|
|
1019
1306
|
}
|
|
1020
1307
|
if (b.sub === "add") {
|
|
1021
1308
|
if (b.files.length === 0) {
|
|
1022
|
-
emit(
|
|
1309
|
+
emit(T.adminAddUsage);
|
|
1023
1310
|
return;
|
|
1024
1311
|
}
|
|
1025
1312
|
for (const f of b.files) {
|
|
1026
1313
|
const abs = path7.resolve(f);
|
|
1027
|
-
const r = await enqueueTicketFile(abs).catch((e) => ({ ok: false, error:
|
|
1028
|
-
if (r.ok) emit(
|
|
1029
|
-
else emit(
|
|
1314
|
+
const r = await enqueueTicketFile(abs, getLocale()).catch((e) => ({ ok: false, error: T.readFileFail(e?.message ?? e) }));
|
|
1315
|
+
if (r.ok) emit(T.enqueued(r.id, r.title));
|
|
1316
|
+
else emit(T.addRejected(path7.basename(abs), r.error));
|
|
1030
1317
|
}
|
|
1031
|
-
emit(
|
|
1318
|
+
emit(T.nextStepRun);
|
|
1032
1319
|
return;
|
|
1033
1320
|
}
|
|
1034
1321
|
if (b.sub === "list") {
|
|
1035
1322
|
const q = await snapshotQueue();
|
|
1036
1323
|
if (q.pending.length + q.running.length + q.done.length === 0) {
|
|
1037
|
-
emit(
|
|
1324
|
+
emit(T.adminQueueEmpty);
|
|
1038
1325
|
return;
|
|
1039
1326
|
}
|
|
1040
|
-
if (q.running.length > 0) emit(
|
|
1327
|
+
if (q.running.length > 0) emit(T.listRunningHead);
|
|
1041
1328
|
for (const f of q.running) emit(` ${f.replace(/\.md$/, "")}`);
|
|
1042
|
-
if (q.pending.length > 0) emit(
|
|
1329
|
+
if (q.pending.length > 0) emit(T.listPendingHead(q.pending.length));
|
|
1043
1330
|
for (const f of q.pending) emit(` ${f.replace(/\.md$/, "")}`);
|
|
1044
|
-
if (q.done.length > 0) emit(
|
|
1331
|
+
if (q.done.length > 0) emit(T.listDoneHead(q.done.length));
|
|
1045
1332
|
for (const id of q.done) emit(` ${id} ${await describeDone(id)}`);
|
|
1046
1333
|
return;
|
|
1047
1334
|
}
|
|
1048
1335
|
if (b.sub === "clean") {
|
|
1049
1336
|
const n = await cleanDone();
|
|
1050
|
-
emit(
|
|
1337
|
+
emit(T.cleaned(n));
|
|
1051
1338
|
return;
|
|
1052
1339
|
}
|
|
1053
1340
|
};
|
|
@@ -1056,7 +1343,7 @@ var init_batchAdmin = __esm({
|
|
|
1056
1343
|
try {
|
|
1057
1344
|
text = await fs6.readFile(reportPath(id), "utf-8");
|
|
1058
1345
|
} catch {
|
|
1059
|
-
return
|
|
1346
|
+
return batchT(getLocale()).reportMissing;
|
|
1060
1347
|
}
|
|
1061
1348
|
const fm = (key) => {
|
|
1062
1349
|
const m = new RegExp(`^${key}:\\s*(.+)$`, "m").exec(text);
|
|
@@ -12537,13 +12824,29 @@ var init_usageLog = __esm({
|
|
|
12537
12824
|
});
|
|
12538
12825
|
|
|
12539
12826
|
// ../core/src/config/prices.ts
|
|
12540
|
-
var MODEL_PRICES, envPrice, ENV_OVERRIDE, priceFor, calcCostYuan;
|
|
12827
|
+
var MODEL_PRICES, PRICES_VERIFIED_AT, PRICES_STALE_DAYS, pricesAgeDays, isBeijingPeak, envPrice, ENV_OVERRIDE, priceFor, calcCostYuan;
|
|
12541
12828
|
var init_prices = __esm({
|
|
12542
12829
|
"../core/src/config/prices.ts"() {
|
|
12543
12830
|
"use strict";
|
|
12544
12831
|
MODEL_PRICES = {
|
|
12545
|
-
"deepseek-flash": {
|
|
12546
|
-
|
|
12832
|
+
"deepseek-flash": {
|
|
12833
|
+
idle: { input: 1, output: 4, cacheHit: 0.02 },
|
|
12834
|
+
peak: { input: 2, output: 8, cacheHit: 0.04 }
|
|
12835
|
+
},
|
|
12836
|
+
"deepseek-v4-pro": {
|
|
12837
|
+
idle: { input: 4.5, output: 13.5, cacheHit: 0.15 },
|
|
12838
|
+
peak: { input: 9, output: 27, cacheHit: 0.3 }
|
|
12839
|
+
}
|
|
12840
|
+
};
|
|
12841
|
+
PRICES_VERIFIED_AT = "2026-10-16";
|
|
12842
|
+
PRICES_STALE_DAYS = 30;
|
|
12843
|
+
pricesAgeDays = () => Math.max(0, Math.floor((Date.now() - Date.parse(`${PRICES_VERIFIED_AT}T00:00:00Z`)) / 864e5));
|
|
12844
|
+
isBeijingPeak = (ts2 = /* @__PURE__ */ new Date()) => {
|
|
12845
|
+
const bj = new Date(ts2.getTime() + 8 * 36e5);
|
|
12846
|
+
const day = bj.getUTCDay();
|
|
12847
|
+
if (day === 0 || day === 6) return false;
|
|
12848
|
+
const h = bj.getUTCHours();
|
|
12849
|
+
return h >= 9 && h < 12 || h >= 14 && h < 18;
|
|
12547
12850
|
};
|
|
12548
12851
|
envPrice = (name) => {
|
|
12549
12852
|
const raw = process.env[name];
|
|
@@ -12558,8 +12861,9 @@ var init_prices = __esm({
|
|
|
12558
12861
|
if (input === void 0 && output === void 0 && cacheHit === void 0) return null;
|
|
12559
12862
|
return { input, output, cacheHit };
|
|
12560
12863
|
})();
|
|
12561
|
-
priceFor = (model) => {
|
|
12562
|
-
const
|
|
12864
|
+
priceFor = (model, ts2) => {
|
|
12865
|
+
const tier = MODEL_PRICES[model];
|
|
12866
|
+
const base = tier ? isBeijingPeak(ts2 ?? /* @__PURE__ */ new Date()) ? tier.peak : tier.idle : void 0;
|
|
12563
12867
|
if (!ENV_OVERRIDE) return base ?? null;
|
|
12564
12868
|
const input = ENV_OVERRIDE.input ?? base?.input;
|
|
12565
12869
|
const output = ENV_OVERRIDE.output ?? base?.output;
|
|
@@ -12567,8 +12871,8 @@ var init_prices = __esm({
|
|
|
12567
12871
|
if (input === void 0 || output === void 0 || cacheHit === void 0) return null;
|
|
12568
12872
|
return { input, output, cacheHit };
|
|
12569
12873
|
};
|
|
12570
|
-
calcCostYuan = (model, u) => {
|
|
12571
|
-
const p = priceFor(model);
|
|
12874
|
+
calcCostYuan = (model, u, ts2) => {
|
|
12875
|
+
const p = priceFor(model, ts2);
|
|
12572
12876
|
if (!p) return null;
|
|
12573
12877
|
const cached2 = Math.max(0, u.cachedTokens ?? 0);
|
|
12574
12878
|
const miss = Math.max(0, (u.promptTokens ?? 0) - cached2);
|
|
@@ -15390,7 +15694,7 @@ var init_useChatState = __esm({
|
|
|
15390
15694
|
break;
|
|
15391
15695
|
}
|
|
15392
15696
|
case "vision.downgraded":
|
|
15393
|
-
pushInfo(
|
|
15697
|
+
pushInfo(S.visionDowngraded(String(obj.model ?? "")));
|
|
15394
15698
|
break;
|
|
15395
15699
|
default:
|
|
15396
15700
|
break;
|
|
@@ -15535,7 +15839,7 @@ ${finalPlan}`, false, res.autoExecute);
|
|
|
15535
15839
|
} else {
|
|
15536
15840
|
const enterReason = takeEnterPlanRequest();
|
|
15537
15841
|
if (enterReason != null) {
|
|
15538
|
-
pushInfo(
|
|
15842
|
+
pushInfo(S.planEnterSwitched(enterReason));
|
|
15539
15843
|
planModeRef.current = true;
|
|
15540
15844
|
const kept = await runPlanStage(sid, ENTER_PLAN_RESEARCH_PROMPT);
|
|
15541
15845
|
if (kept) planModeRef.current = false;
|
|
@@ -15549,7 +15853,7 @@ ${finalPlan}`, false, res.autoExecute);
|
|
|
15549
15853
|
const runBangCommand = useCallback(async (raw) => {
|
|
15550
15854
|
const cmd = raw.replace(/^!/, "").trim();
|
|
15551
15855
|
if (!cmd) {
|
|
15552
|
-
pushInfo(
|
|
15856
|
+
pushInfo(S.bangUsage);
|
|
15553
15857
|
return;
|
|
15554
15858
|
}
|
|
15555
15859
|
pushUser(raw);
|
|
@@ -15557,9 +15861,9 @@ ${finalPlan}`, false, res.autoExecute);
|
|
|
15557
15861
|
sessionIdRef.current = await getOrCreateSessionId(initialSessionId ?? void 0);
|
|
15558
15862
|
}
|
|
15559
15863
|
const r = await runBashDirect(cmd, getActiveWorkspaceRoot());
|
|
15560
|
-
const head = r.timedOut
|
|
15864
|
+
const head = S.bangHead(r.timedOut, r.ok, r.exitCode ?? null);
|
|
15561
15865
|
pushInfo(`${head} \xB7 ${Math.round(r.durationMs / 100) / 10}s
|
|
15562
|
-
${r.output.trim() ||
|
|
15866
|
+
${r.output.trim() || S.bangNoOutput}`);
|
|
15563
15867
|
await recordBashEntry(sessionIdRef.current, formatBashEntry(cmd, r));
|
|
15564
15868
|
}, [initialSessionId, pushUser, pushInfo]);
|
|
15565
15869
|
const abortCurrent = useCallback(() => {
|
|
@@ -16854,7 +17158,7 @@ var init_TopPanel = __esm({
|
|
|
16854
17158
|
|
|
16855
17159
|
// ../core/src/observability/inspect.ts
|
|
16856
17160
|
import fs48 from "fs";
|
|
16857
|
-
var CWD, fmt, readTrace,
|
|
17161
|
+
var OBS, obsT, CWD, fmt, readTrace, fmtK, inspectUsage, inspectContext, inspectPermissions, inspectMcp, inspectHooks, inspectDebug;
|
|
16858
17162
|
var init_inspect = __esm({
|
|
16859
17163
|
"../core/src/observability/inspect.ts"() {
|
|
16860
17164
|
"use strict";
|
|
@@ -16870,6 +17174,106 @@ var init_inspect = __esm({
|
|
|
16870
17174
|
init_truncate();
|
|
16871
17175
|
init_recall();
|
|
16872
17176
|
init_createModel();
|
|
17177
|
+
OBS = {
|
|
17178
|
+
zh: {
|
|
17179
|
+
usageNoData: "\u{1F4CA} Token \u7528\u91CF\uFF1A\u6682\u65E0\u6570\u636E\uFF08\u672C\u4F1A\u8BDD\u5C1A\u65E0 LLM \u54CD\u5E94\u843D\u76D8\uFF09\u3002",
|
|
17180
|
+
usageHead: (rounds) => `\u{1F4CA} Token \u7528\u91CF\uFF08\u672C\u4F1A\u8BDD\uFF0C${rounds} \u6B21 LLM \u54CD\u5E94\uFF09`,
|
|
17181
|
+
usageTokens: (prompt, completion, total) => ` \u8F93\u5165(prompt): ${prompt} | \u8F93\u51FA(completion): ${completion} | \u5408\u8BA1: ${total}`,
|
|
17182
|
+
usageCache: (hit, rate, miss) => ` \u7F13\u5B58\u547D\u4E2D: ${hit}\uFF08${rate}%\uFF09 | \u7F13\u5B58\u672A\u547D\u4E2D: ${miss}`,
|
|
17183
|
+
usageSplit: (main2, sub) => ` \u4E3B agent: ${main2} | \u5B50 agent(spawn/workflow): ${sub}`,
|
|
17184
|
+
usageSessionRuns: (runs, rounds, avg, aborted, pct) => ` \u258E\u672C\u4F1A\u8BDD ${runs} \u4E2A run\uFF1A${rounds} \u8F6E\uFF08\u5747 ${avg} \u8F6E/run\uFF09\xB7 \u4E2D\u6B62 ${aborted}/${runs}\uFF08${pct}%\uFF09`,
|
|
17185
|
+
usageNoTools: "\uFF08\u65E0\u5DE5\u5177\u8C03\u7528\uFF09",
|
|
17186
|
+
usageRunLine: (ts2, rounds, tok, stop, tools) => ` ${ts2} ${rounds}\u8F6E ${tok} tok ${stop} ${tools}`,
|
|
17187
|
+
stopLabel: { normal: "\u5B8C\u6210", aborted: "\u4E2D\u6B62", error: "\u9519\u8BEF", repeat: "\u7194\u65AD", limit: "\u8D85\u9650" },
|
|
17188
|
+
usageWeek: (runs, rounds, avg, abortPct, tokens, hitPct) => ` \u258E\u8FD1 7 \u5929\uFF08\u4F7F\u7528\u65E5\u5FD7 \xB7 \u5168\u9879\u76EE\uFF09\uFF1A${runs} runs \xB7 ${rounds} \u8F6E\uFF08\u5747 ${avg} \u8F6E/run\uFF09\xB7 \u4E2D\u6B62 ${abortPct}% \xB7 ${tokens} tok\uFF08\u7F13\u5B58\u547D\u4E2D ${hitPct}%\uFF09`,
|
|
17189
|
+
usageTopTools: (tools) => ` \u5E38\u7528\u5DE5\u5177: ${tools.join("\u3001") || "\uFF08\u65E0\uFF09"}`,
|
|
17190
|
+
usageWeekCost: (cost, saved, unpriced) => ` \u8FD1 7 \u5929\u82B1\u8D39 \xA5${cost}\uFF08\u7F13\u5B58\u547D\u4E2D\u5DF2\u7701 \xA5${saved}\uFF09${unpriced > 0 ? ` \xB7 ${unpriced} \u6761\u65E0\u4EF7\u8BB0\u5F55\u672A\u8BA1` : ""}`,
|
|
17191
|
+
usageTopSessions: (tops) => ` \u8D39\u7528 top \u4F1A\u8BDD: ${tops}`,
|
|
17192
|
+
usagePriceStale: (days, at) => ` \u26A0\uFE0F \u4EF7\u683C\u8868 ${at} \u6838\u5B9E\u540E\u5DF2 ${days} \u5929\u672A\u590D\u6838\u2014\u2014\u5B98\u7F51\u82E5\u5DF2\u8C03\u4EF7\uFF0C\u4E0A\u65B9\u82B1\u8D39\u4F1A\u5931\u771F\uFF08\u53EF\u8BBE DEEP_SEEK_PRICE_* \u4E34\u65F6\u6821\u51C6\uFF09\u3002`,
|
|
17193
|
+
usageTip: " \u63D0\u793A\uFF1A\u5E76\u884C workflow \u4F1A\u653E\u5927\u5B50 agent \u7528\u91CF\uFF1B\u7F13\u5B58\u547D\u4E2D\u7387\u8D8A\u9AD8\uFF0C\u8F93\u5165\u6210\u672C\u8D8A\u4F4E\u3002",
|
|
17194
|
+
ctxHead: "\u{1F9E0} \u4E0A\u4E0B\u6587\u6CBB\u7406",
|
|
17195
|
+
ctxWindow: (window, threshold, ratio, keep) => ` \u7A97\u53E3\u4E0A\u9650: ${window} | \u538B\u7F29\u9608\u503C: ${threshold}\uFF08${ratio}\xD7\uFF09 | \u4FDD\u7559\u6700\u8FD1: ${keep} \u5BF9\u8BDD\u5355\u5143`,
|
|
17196
|
+
ctxLastPrompt: (p, fillRate) => ` \u6700\u8FD1 prompt: ${p ?? "\uFF08\u5C1A\u65E0\uFF09"}${fillRate ? `\uFF08\u5360\u7A97\u53E3 ${fillRate}%\uFF09` : ""}`,
|
|
17197
|
+
ctxArchived: (n) => ` \u5DF2\u5F52\u6863(\u538B\u7F29)\u6D88\u606F\u6761\u6570: ${n}`,
|
|
17198
|
+
ctxEntities: (n) => ` \u672C\u4F1A\u8BDD\u5DF2\u5F52\u6863\u5B9E\u4F53: ${n} \u4E2A\uFF08\u6458\u8981\u69FD\u7D22\u5F15\uFF09`,
|
|
17199
|
+
ctxRecall: (n) => ` \u53EC\u56DE\u547D\u4E2D: ${n} \u6B21\uFF08recall \u5DE5\u5177\uFF0C\u672C\u6B21\u8FDB\u7A0B\u5185\u8BA1\u6570\uFF09`,
|
|
17200
|
+
ctxSidecar: (n) => ` \u4FA7\u8F66\u5B58\u6863: ${n} \u6761\uFF08\u8D85\u957F\u5DE5\u5177\u7ED3\u679C\u539F\u6587\uFF0Crecall with_full \u53D6\u56DE\uFF09`,
|
|
17201
|
+
ctxTip: (pct) => ` \u8D85\u8FC7\u9608\u503C\u5373\u89E6\u53D1\u6EDA\u52A8\u538B\u7F29\uFF1BfillRate \u63A5\u8FD1 ${pct}% \u65F6\u5373\u5C06\u538B\u7F29\u3002`,
|
|
17202
|
+
permEmpty: "\u{1F512} \u6743\u9650\u89C4\u5219\uFF1A\u65E0\uFF08\u5168\u90E8\u8D70\u9ED8\u8BA4 safetyLevel\uFF1ASAFE \u514D\u5BA1 / MUTATION\xB7DANGER \u5BA1\u6279\uFF09\u3002",
|
|
17203
|
+
permHead: "\u{1F512} \u6743\u9650\u89C4\u5219\uFF08\u4F18\u5148\u7EA7 deny > ask > allow\uFF1B\u672A\u5339\u914D\u8D70\u9ED8\u8BA4 safetyLevel\uFF09",
|
|
17204
|
+
permNone: "(\u65E0)",
|
|
17205
|
+
permGroup: (icon, label, n) => ` ${icon} ${label}\uFF08${n}\uFF09:`,
|
|
17206
|
+
mcpEmpty: "\u{1F50C} MCP\uFF1A\u65E0\u5DF2\u8FDE\u63A5 server\uFF08\u5728 ~/.deepseeker-code/mcp.json \u914D\u7F6E\uFF09\u3002",
|
|
17207
|
+
mcpHead: (n, tools) => `\u{1F50C} MCP server\uFF08${n} \u4E2A\uFF0C\u5171 ${tools} \u4E2A\u5DE5\u5177\uFF09`,
|
|
17208
|
+
mcpLine: (name, tools) => ` \u2022 ${name}\uFF08${tools}\uFF09`,
|
|
17209
|
+
mcpToolCount: (n) => `${n} \u4E2A\u5DE5\u5177`,
|
|
17210
|
+
mcpToolCountFail: "\u5DE5\u5177\u6570\u83B7\u53D6\u5931\u8D25",
|
|
17211
|
+
hooksEmpty: "\u{1FA9D} Hooks\uFF1A\u65E0\uFF08\u5728 ~/.deepseeker-code/settings.json \u7684 hooks \u6BB5\u914D\u7F6E\uFF09\u3002",
|
|
17212
|
+
hooksHead: (n) => `\u{1FA9D} Hooks\uFF08\u5171 ${n} \u6761\uFF0C\u6309\u4E8B\u4EF6\u5206\u7EC4\uFF09`,
|
|
17213
|
+
hooksGroup: (evt, n) => ` \u2022 ${evt}\uFF08${n}\uFF09:`,
|
|
17214
|
+
dbgHead: "\u{1F41E} Debug \u5FEB\u7167",
|
|
17215
|
+
dbgSessionNone: "(\u672A\u521D\u59CB\u5316)",
|
|
17216
|
+
dbgModels: (main2, aux) => ` \u4E3B\u6A21\u578B: ${main2} | \u8F85\u52A9\u6A21\u578B: ${aux}`,
|
|
17217
|
+
dbgAuxNone: "(\u672A\u914D\u7F6E)",
|
|
17218
|
+
dbgOn: "\u5F00",
|
|
17219
|
+
dbgOff: "\u5173",
|
|
17220
|
+
dbgParallel: (on, conc, steps) => ` \u5E76\u884C\u5DE5\u5177: ${on} | workflow \u5E76\u53D1\u4E0A\u9650: ${conc} | workflow \u6700\u5927\u6B65\u6570: ${steps}`,
|
|
17221
|
+
dbgUndo: (on, search) => ` undo: ${on} | \u641C\u7D22\u540E\u7AEF: ${search}`,
|
|
17222
|
+
dbgSearchAuto: "(\u81EA\u52A8)",
|
|
17223
|
+
dbgPlatform: (node, platform) => ` Node: ${node} | \u5E73\u53F0: ${platform}`
|
|
17224
|
+
},
|
|
17225
|
+
en: {
|
|
17226
|
+
usageNoData: "\u{1F4CA} Token usage: no data yet (no LLM responses logged for this session).",
|
|
17227
|
+
usageHead: (rounds) => `\u{1F4CA} Token usage (this session, ${rounds} LLM responses)`,
|
|
17228
|
+
usageTokens: (prompt, completion, total) => ` Input (prompt): ${prompt} | Output (completion): ${completion} | Total: ${total}`,
|
|
17229
|
+
usageCache: (hit, rate, miss) => ` Cache hit: ${hit} (${rate}%) | Cache miss: ${miss}`,
|
|
17230
|
+
usageSplit: (main2, sub) => ` Main agent: ${main2} | Sub agents (spawn/workflow): ${sub}`,
|
|
17231
|
+
usageSessionRuns: (runs, rounds, avg, aborted, pct) => ` \u258EThis session: ${runs} runs, ${rounds} rounds (avg ${avg}/run) \xB7 aborted ${aborted}/${runs} (${pct}%)`,
|
|
17232
|
+
usageNoTools: "(no tool calls)",
|
|
17233
|
+
usageRunLine: (ts2, rounds, tok, stop, tools) => ` ${ts2} ${rounds} rounds ${tok} tok ${stop} ${tools}`,
|
|
17234
|
+
stopLabel: { normal: "done", aborted: "aborted", error: "error", repeat: "fuse", limit: "limit" },
|
|
17235
|
+
usageWeek: (runs, rounds, avg, abortPct, tokens, hitPct) => ` \u258ELast 7 days (usage log \xB7 all projects): ${runs} runs \xB7 ${rounds} rounds (avg ${avg}/run) \xB7 aborted ${abortPct}% \xB7 ${tokens} tok (cache hit ${hitPct}%)`,
|
|
17236
|
+
usageTopTools: (tools) => ` Top tools: ${tools.join(", ") || "(none)"}`,
|
|
17237
|
+
usageWeekCost: (cost, saved, unpriced) => ` 7-day spend \xA5${cost} (cache hits saved \xA5${saved})${unpriced > 0 ? ` \xB7 ${unpriced} unpriced records excluded` : ""}`,
|
|
17238
|
+
usageTopSessions: (tops) => ` Costliest sessions: ${tops}`,
|
|
17239
|
+
usagePriceStale: (days, at) => ` \u26A0\uFE0F Price table verified on ${at}, ${days} days ago \u2014 if official pricing changed, costs above may drift (set DEEP_SEEK_PRICE_* to correct).`,
|
|
17240
|
+
usageTip: " Tip: parallel workflows multiply sub-agent usage; higher cache hit rate means lower input cost.",
|
|
17241
|
+
ctxHead: "\u{1F9E0} Context governance",
|
|
17242
|
+
ctxWindow: (window, threshold, ratio, keep) => ` Window cap: ${window} | Compact threshold: ${threshold} (${ratio}\xD7) | Keep recent: ${keep} dialogue units`,
|
|
17243
|
+
ctxLastPrompt: (p, fillRate) => ` Last prompt: ${p ?? "(none yet)"}${fillRate ? ` (${fillRate}% of window)` : ""}`,
|
|
17244
|
+
ctxArchived: (n) => ` Archived (compacted) messages: ${n}`,
|
|
17245
|
+
ctxEntities: (n) => ` Archived entities this session: ${n} (summary-slot index)`,
|
|
17246
|
+
ctxRecall: (n) => ` Recall hits: ${n} (recall tool, in-process count)`,
|
|
17247
|
+
ctxSidecar: (n) => ` Sidecar archives: ${n} (full tool outputs, retrievable via recall with_full)`,
|
|
17248
|
+
ctxTip: (pct) => ` Rolling compaction triggers past the threshold; fillRate near ${pct}% means compaction is imminent.`,
|
|
17249
|
+
permEmpty: "\u{1F512} Permission rules: none (everything uses default safetyLevel: SAFE auto-approve / MUTATION\xB7DANGER gated).",
|
|
17250
|
+
permHead: "\u{1F512} Permission rules (priority deny > ask > allow; unmatched uses default safetyLevel)",
|
|
17251
|
+
permNone: "(none)",
|
|
17252
|
+
permGroup: (icon, label, n) => ` ${icon} ${label} (${n}):`,
|
|
17253
|
+
mcpEmpty: "\u{1F50C} MCP: no connected servers (configure in ~/.deepseeker-code/mcp.json).",
|
|
17254
|
+
mcpHead: (n, tools) => `\u{1F50C} MCP servers (${n}, ${tools} tools total)`,
|
|
17255
|
+
mcpLine: (name, tools) => ` \u2022 ${name} (${tools})`,
|
|
17256
|
+
mcpToolCount: (n) => `${n} tools`,
|
|
17257
|
+
mcpToolCountFail: "failed to count tools",
|
|
17258
|
+
hooksEmpty: "\u{1FA9D} Hooks: none (configure under the hooks key in ~/.deepseeker-code/settings.json).",
|
|
17259
|
+
hooksHead: (n) => `\u{1FA9D} Hooks (${n} total, grouped by event)`,
|
|
17260
|
+
hooksGroup: (evt, n) => ` \u2022 ${evt} (${n}):`,
|
|
17261
|
+
dbgHead: "\u{1F41E} Debug snapshot",
|
|
17262
|
+
dbgSessionNone: "(not initialized)",
|
|
17263
|
+
dbgModels: (main2, aux) => ` Main model: ${main2} | Aux model: ${aux}`,
|
|
17264
|
+
dbgAuxNone: "(not configured)",
|
|
17265
|
+
dbgOn: "on",
|
|
17266
|
+
dbgOff: "off",
|
|
17267
|
+
dbgParallel: (on, conc, steps) => ` Parallel tools: ${on} | Workflow concurrency cap: ${conc} | Workflow max steps: ${steps}`,
|
|
17268
|
+
dbgUndo: (on, search) => ` undo: ${on} | Search backend: ${search}`,
|
|
17269
|
+
dbgSearchAuto: "(auto)",
|
|
17270
|
+
dbgPlatform: (node, platform) => ` Node: ${node} | Platform: ${platform}`
|
|
17271
|
+
}
|
|
17272
|
+
};
|
|
17273
|
+
obsT = (locale2) => {
|
|
17274
|
+
const dict = OBS[locale2] ?? OBS.zh;
|
|
17275
|
+
return (key) => dict[key] ?? OBS.zh[key] ?? key;
|
|
17276
|
+
};
|
|
16873
17277
|
CWD = process.cwd();
|
|
16874
17278
|
fmt = (n) => typeof n === "number" && Number.isFinite(n) ? n.toLocaleString("en-US") : "-";
|
|
16875
17279
|
readTrace = async (sessionId) => {
|
|
@@ -16890,13 +17294,13 @@ var init_inspect = __esm({
|
|
|
16890
17294
|
return [];
|
|
16891
17295
|
}
|
|
16892
17296
|
};
|
|
16893
|
-
STOP_LABEL = { normal: "\u5B8C\u6210", aborted: "\u4E2D\u6B62", error: "\u9519\u8BEF", repeat: "\u7194\u65AD", limit: "\u8D85\u9650" };
|
|
16894
17297
|
fmtK = (n) => n >= 1e4 ? `${(n / 1e3).toFixed(1)}k` : fmt(n);
|
|
16895
|
-
inspectUsage = async (sessionId) => {
|
|
17298
|
+
inspectUsage = async (sessionId, locale2 = "zh") => {
|
|
17299
|
+
const t = obsT(locale2);
|
|
16896
17300
|
const trace = await readTrace(sessionId);
|
|
16897
|
-
const responses = trace.filter((
|
|
17301
|
+
const responses = trace.filter((x) => x?.eventType === "llm.response" && x?.usage);
|
|
16898
17302
|
const sessionRuns = (await readUsageRecords()).filter((r) => r.sessionId === sessionId);
|
|
16899
|
-
if (responses.length === 0 && sessionRuns.length === 0) return
|
|
17303
|
+
if (responses.length === 0 && sessionRuns.length === 0) return t("usageNoData");
|
|
16900
17304
|
let prompt = 0, completion = 0, total = 0, cacheHit = 0, cacheMiss = 0;
|
|
16901
17305
|
let mainTotal = 0, subTotal = 0;
|
|
16902
17306
|
for (const r of responses) {
|
|
@@ -16912,20 +17316,21 @@ var init_inspect = __esm({
|
|
|
16912
17316
|
}
|
|
16913
17317
|
const cacheRate = prompt > 0 ? (cacheHit / prompt * 100).toFixed(1) : "0.0";
|
|
16914
17318
|
const rounds = responses.length;
|
|
17319
|
+
const stopLabel = t("stopLabel");
|
|
16915
17320
|
const lines = [
|
|
16916
|
-
|
|
16917
|
-
|
|
16918
|
-
|
|
16919
|
-
|
|
17321
|
+
t("usageHead")(rounds),
|
|
17322
|
+
t("usageTokens")(fmt(prompt), fmt(completion), fmt(total)),
|
|
17323
|
+
t("usageCache")(fmt(cacheHit), cacheRate, fmt(cacheMiss)),
|
|
17324
|
+
t("usageSplit")(fmt(mainTotal), fmt(subTotal))
|
|
16920
17325
|
];
|
|
16921
17326
|
if (sessionRuns.length > 0) {
|
|
16922
17327
|
const ss = summarizeUsage(sessionRuns);
|
|
16923
17328
|
const abortedPct = ss.mainRuns > 0 ? Math.round(ss.stopReasons.aborted / ss.mainRuns * 100) : 0;
|
|
16924
17329
|
const avgRounds = ss.mainRuns > 0 ? (ss.mainRounds / ss.mainRuns).toFixed(1) : "0";
|
|
16925
|
-
lines.push(
|
|
17330
|
+
lines.push(t("usageSessionRuns")(ss.mainRuns, ss.mainRounds, avgRounds, ss.stopReasons.aborted, abortedPct));
|
|
16926
17331
|
for (const r of sessionRuns.filter((x) => x.depth === 0).slice(-6)) {
|
|
16927
|
-
const tools = topTools(r.tools, 3).map(([n, c]) => `${n}\xD7${c}`).join(" ") || "
|
|
16928
|
-
lines.push(
|
|
17332
|
+
const tools = topTools(r.tools, 3).map(([n, c]) => `${n}\xD7${c}`).join(" ") || t("usageNoTools");
|
|
17333
|
+
lines.push(t("usageRunLine")(String(r.ts).slice(5, 16).replace("T", " "), r.rounds, fmtK(r.totalTokens ?? 0), stopLabel[r.stopReason] ?? r.stopReason, tools));
|
|
16929
17334
|
}
|
|
16930
17335
|
}
|
|
16931
17336
|
const weekRecords = await readUsageRecords(7);
|
|
@@ -16934,33 +17339,37 @@ var init_inspect = __esm({
|
|
|
16934
17339
|
const weekHit = week.promptTokens > 0 ? (week.cachedTokens / week.promptTokens * 100).toFixed(1) : "0.0";
|
|
16935
17340
|
const weekAbort = week.mainRuns > 0 ? Math.round(week.stopReasons.aborted / week.mainRuns * 100) : 0;
|
|
16936
17341
|
const weekAvg = week.mainRuns > 0 ? (week.mainRounds / week.mainRuns).toFixed(1) : "0";
|
|
16937
|
-
const tools = topTools(week.tools, 4).map(([n, c]) => `${n}\xD7${c}`)
|
|
17342
|
+
const tools = topTools(week.tools, 4).map(([n, c]) => `${n}\xD7${c}`);
|
|
16938
17343
|
lines.push(
|
|
16939
|
-
|
|
16940
|
-
|
|
17344
|
+
t("usageWeek")(week.mainRuns, week.mainRounds, weekAvg, weekAbort, fmtK(week.totalTokens), weekHit),
|
|
17345
|
+
t("usageTopTools")(tools)
|
|
16941
17346
|
);
|
|
16942
17347
|
const bySession = /* @__PURE__ */ new Map();
|
|
16943
17348
|
let weekCost = 0, weekSaved = 0, pricedRuns = 0;
|
|
16944
17349
|
for (const r of weekRecords) {
|
|
16945
|
-
const
|
|
17350
|
+
const at = Number.isNaN(Date.parse(String(r.ts))) ? void 0 : new Date(r.ts);
|
|
17351
|
+
const c = r.costYuan ?? calcCostYuan(r.model, r, at);
|
|
16946
17352
|
if (c == null) continue;
|
|
16947
17353
|
pricedRuns++;
|
|
16948
17354
|
weekCost += c;
|
|
16949
17355
|
bySession.set(r.sessionId, (bySession.get(r.sessionId) ?? 0) + c);
|
|
16950
|
-
const p = priceFor(r.model);
|
|
17356
|
+
const p = priceFor(r.model, at);
|
|
16951
17357
|
if (p) weekSaved += (r.cachedTokens ?? 0) * (p.input - p.cacheHit) / 1e6;
|
|
16952
17358
|
}
|
|
16953
17359
|
if (pricedRuns > 0) {
|
|
16954
17360
|
const tops = [...bySession.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3).map(([sid, c]) => `${sid.slice(0, 8)} \xA5${c.toFixed(3)}`).join(" \xB7 ");
|
|
16955
17361
|
const unpaid = week.runs - pricedRuns;
|
|
16956
|
-
lines.push(
|
|
16957
|
-
if (tops) lines.push(
|
|
17362
|
+
lines.push(t("usageWeekCost")(weekCost.toFixed(3), weekSaved.toFixed(3), unpaid));
|
|
17363
|
+
if (tops) lines.push(t("usageTopSessions")(tops));
|
|
16958
17364
|
}
|
|
16959
17365
|
}
|
|
16960
|
-
|
|
17366
|
+
const staleDays = pricesAgeDays();
|
|
17367
|
+
if (staleDays >= PRICES_STALE_DAYS) lines.push(t("usagePriceStale")(staleDays, PRICES_VERIFIED_AT));
|
|
17368
|
+
lines.push(t("usageTip"));
|
|
16961
17369
|
return lines.join("\n");
|
|
16962
17370
|
};
|
|
16963
|
-
inspectContext = async (sessionId) => {
|
|
17371
|
+
inspectContext = async (sessionId, locale2 = "zh") => {
|
|
17372
|
+
const t = obsT(locale2);
|
|
16964
17373
|
const trace = await readTrace(sessionId);
|
|
16965
17374
|
let lastPrompt;
|
|
16966
17375
|
for (let i = trace.length - 1; i >= 0; i--) {
|
|
@@ -16988,38 +17397,40 @@ var init_inspect = __esm({
|
|
|
16988
17397
|
const threshold = Math.round(window * ratio);
|
|
16989
17398
|
const fillRate = lastPrompt ? (lastPrompt / window * 100).toFixed(1) : null;
|
|
16990
17399
|
return [
|
|
16991
|
-
|
|
16992
|
-
|
|
16993
|
-
|
|
16994
|
-
|
|
16995
|
-
|
|
16996
|
-
|
|
16997
|
-
|
|
16998
|
-
|
|
17400
|
+
t("ctxHead"),
|
|
17401
|
+
t("ctxWindow")(fmt(window), fmt(threshold), ratio, appConfig.KEEP_RECENT_UNITS),
|
|
17402
|
+
t("ctxLastPrompt")(lastPrompt ? fmt(lastPrompt) : null, fillRate),
|
|
17403
|
+
t("ctxArchived")(archived),
|
|
17404
|
+
t("ctxEntities")(archivedEntities),
|
|
17405
|
+
t("ctxRecall")(getRecallHitCount(sessionId)),
|
|
17406
|
+
t("ctxSidecar")(sidecarCount),
|
|
17407
|
+
t("ctxTip")(Math.round(ratio * 100))
|
|
16999
17408
|
].join("\n");
|
|
17000
17409
|
};
|
|
17001
|
-
inspectPermissions = () => {
|
|
17410
|
+
inspectPermissions = (locale2 = "zh") => {
|
|
17411
|
+
const t = obsT(locale2);
|
|
17002
17412
|
const r = listPermissionRules();
|
|
17003
17413
|
const total = r.allow.length + r.deny.length + r.ask.length;
|
|
17004
|
-
if (total === 0) return
|
|
17414
|
+
if (total === 0) return t("permEmpty");
|
|
17005
17415
|
const render2 = (label, kind, icon) => {
|
|
17006
17416
|
const list = r[kind];
|
|
17007
|
-
if (list.length === 0) return ` ${icon} ${label}: (
|
|
17008
|
-
return `
|
|
17009
|
-
` + list.map((x) => ` ${x.toolName}${x.raw && x.raw !== x.toolName ? ` \u2190 ${x.raw}` : ""}`).join("\n");
|
|
17417
|
+
if (list.length === 0) return ` ${icon} ${label}: ${t("permNone")}`;
|
|
17418
|
+
return t("permGroup")(icon, label, list.length) + "\n" + list.map((x) => ` ${x.toolName}${x.raw && x.raw !== x.toolName ? ` \u2190 ${x.raw}` : ""}`).join("\n");
|
|
17010
17419
|
};
|
|
17011
|
-
return [
|
|
17420
|
+
return [t("permHead"), render2("Deny", "deny", "\u{1F6AB}"), render2("Ask", "ask", "\u2753"), render2("Allow", "allow", "\u2705")].join("\n");
|
|
17012
17421
|
};
|
|
17013
|
-
inspectMcp = async () => {
|
|
17422
|
+
inspectMcp = async (locale2 = "zh") => {
|
|
17423
|
+
const t = obsT(locale2);
|
|
17014
17424
|
const clients2 = await listMcpClients();
|
|
17015
|
-
if (clients2.length === 0) return
|
|
17016
|
-
const lines = clients2.map((c) =>
|
|
17425
|
+
if (clients2.length === 0) return t("mcpEmpty");
|
|
17426
|
+
const lines = clients2.map((c) => t("mcpLine")(c.serverName, c.toolCount >= 0 ? t("mcpToolCount")(c.toolCount) : t("mcpToolCountFail")));
|
|
17017
17427
|
const totalTools = clients2.reduce((s, c) => s + (c.toolCount > 0 ? c.toolCount : 0), 0);
|
|
17018
|
-
return [
|
|
17428
|
+
return [t("mcpHead")(clients2.length, totalTools), ...lines].join("\n");
|
|
17019
17429
|
};
|
|
17020
|
-
inspectHooks = () => {
|
|
17430
|
+
inspectHooks = (locale2 = "zh") => {
|
|
17431
|
+
const t = obsT(locale2);
|
|
17021
17432
|
const hooks = listHooks();
|
|
17022
|
-
if (hooks.length === 0) return
|
|
17433
|
+
if (hooks.length === 0) return t("hooksEmpty");
|
|
17023
17434
|
const byEvent = /* @__PURE__ */ new Map();
|
|
17024
17435
|
for (const h of hooks) {
|
|
17025
17436
|
const arr = byEvent.get(h.event) ?? [];
|
|
@@ -17027,21 +17438,21 @@ var init_inspect = __esm({
|
|
|
17027
17438
|
byEvent.set(h.event, arr);
|
|
17028
17439
|
}
|
|
17029
17440
|
const lines = [...byEvent.entries()].map(([evt, arr]) => {
|
|
17030
|
-
return
|
|
17031
|
-
` + arr.map((h) => ` matcher=${h.matcher} source=${h.source}${h.onError ? ` onError=${h.onError}` : ""}`).join("\n");
|
|
17441
|
+
return t("hooksGroup")(evt, arr.length) + "\n" + arr.map((h) => ` matcher=${h.matcher} source=${h.source}${h.onError ? ` onError=${h.onError}` : ""}`).join("\n");
|
|
17032
17442
|
});
|
|
17033
|
-
return [
|
|
17443
|
+
return [t("hooksHead")(hooks.length), ...lines].join("\n");
|
|
17034
17444
|
};
|
|
17035
|
-
inspectDebug = (sessionId) => {
|
|
17445
|
+
inspectDebug = (sessionId, locale2 = "zh") => {
|
|
17446
|
+
const t = obsT(locale2);
|
|
17036
17447
|
return [
|
|
17037
|
-
|
|
17038
|
-
` session: ${sessionId || "
|
|
17448
|
+
t("dbgHead"),
|
|
17449
|
+
` session: ${sessionId || t("dbgSessionNone")}`,
|
|
17039
17450
|
` cwd: ${CWD}`,
|
|
17040
|
-
|
|
17451
|
+
t("dbgModels")(MODEL_NAME, AUX_MODEL_NAME ?? t("dbgAuxNone")),
|
|
17041
17452
|
` dataDir: ${appConfig.dataDir}`,
|
|
17042
|
-
|
|
17043
|
-
|
|
17044
|
-
|
|
17453
|
+
t("dbgParallel")(appConfig.parallelSafeTools ? t("dbgOn") : t("dbgOff"), appConfig.workflowConcurrency, appConfig.workflowMaxSteps),
|
|
17454
|
+
t("dbgUndo")(appConfig.undoEnabled ? t("dbgOn") : t("dbgOff"), appConfig.searchProvider || t("dbgSearchAuto")),
|
|
17455
|
+
t("dbgPlatform")(process.version, process.platform)
|
|
17045
17456
|
].join("\n");
|
|
17046
17457
|
};
|
|
17047
17458
|
}
|
|
@@ -17340,54 +17751,49 @@ var init_App = __esm({
|
|
|
17340
17751
|
state.pushInfo(S.statusText(modelDisplay, state.getThinkingLevel(), state.getPlanMode(), getLocale(), CWD2));
|
|
17341
17752
|
return true;
|
|
17342
17753
|
case "/usage":
|
|
17343
|
-
state.pushInfo(await inspectUsage(state.sessionIdRef.current ?? ""));
|
|
17754
|
+
state.pushInfo(await inspectUsage(state.sessionIdRef.current ?? "", getLocale()));
|
|
17344
17755
|
return true;
|
|
17345
17756
|
case "/context":
|
|
17346
|
-
state.pushInfo(await inspectContext(state.sessionIdRef.current ?? ""));
|
|
17757
|
+
state.pushInfo(await inspectContext(state.sessionIdRef.current ?? "", getLocale()));
|
|
17347
17758
|
return true;
|
|
17348
17759
|
case "/permissions":
|
|
17349
|
-
state.pushInfo(inspectPermissions());
|
|
17760
|
+
state.pushInfo(inspectPermissions(getLocale()));
|
|
17350
17761
|
return true;
|
|
17351
17762
|
case "/mcp":
|
|
17352
|
-
state.pushInfo(await inspectMcp());
|
|
17763
|
+
state.pushInfo(await inspectMcp(getLocale()));
|
|
17353
17764
|
return true;
|
|
17354
17765
|
case "/hooks":
|
|
17355
|
-
state.pushInfo(inspectHooks());
|
|
17766
|
+
state.pushInfo(inspectHooks(getLocale()));
|
|
17356
17767
|
return true;
|
|
17357
17768
|
case "/trust": {
|
|
17358
17769
|
const trusted = await readTrustedDirs();
|
|
17359
17770
|
if (!arg) {
|
|
17360
17771
|
if (trusted.length === 0) {
|
|
17361
|
-
state.pushInfo(
|
|
17772
|
+
state.pushInfo(S.trustEmpty);
|
|
17362
17773
|
return true;
|
|
17363
17774
|
}
|
|
17364
17775
|
const list = trusted.map((d, i) => ` [${i}] ${d}`).join("\n");
|
|
17365
|
-
state.pushInfo(
|
|
17366
|
-
${list}
|
|
17367
|
-
|
|
17368
|
-
\u64A4\u9500\u540E\u9700\u91CD\u542F CLI \u751F\u6548\uFF08\u9879\u76EE\u7EA7\u914D\u7F6E\u4EC5\u5728\u542F\u52A8\u65F6\u52A0\u8F7D\uFF09\u3002`);
|
|
17776
|
+
state.pushInfo(S.trustList(list));
|
|
17369
17777
|
return true;
|
|
17370
17778
|
}
|
|
17371
17779
|
const idx = Number(arg);
|
|
17372
17780
|
const target = Number.isInteger(idx) && idx >= 0 && idx < trusted.length ? trusted[idx] : arg;
|
|
17373
17781
|
const removed = await untrustDir(target);
|
|
17374
|
-
state.pushInfo(removed ?
|
|
17375
|
-
\uFF08\u91CD\u542F CLI \u540E\u751F\u6548\u2014\u2014\u9879\u76EE\u7EA7\u914D\u7F6E\u4EC5\u5728\u542F\u52A8\u65F6\u52A0\u8F7D\uFF09` : `\u672A\u627E\u5230\u8BE5\u4FE1\u4EFB\u76EE\u5F55\uFF1A${target}`);
|
|
17782
|
+
state.pushInfo(removed ? S.trustRemoved(target) : S.trustNotFound(target));
|
|
17376
17783
|
return true;
|
|
17377
17784
|
}
|
|
17378
17785
|
case "/debug":
|
|
17379
|
-
state.pushInfo(inspectDebug(state.sessionIdRef.current ?? ""));
|
|
17786
|
+
state.pushInfo(inspectDebug(state.sessionIdRef.current ?? "", getLocale()));
|
|
17380
17787
|
return true;
|
|
17381
17788
|
case "/archive": {
|
|
17382
17789
|
const s = state.getArchivedSummary();
|
|
17383
|
-
state.pushInfo(s ?
|
|
17384
|
-
${s}` : "\u672C\u4F1A\u8BDD\u542F\u52A8\u4EE5\u6765\u5C1A\u672A\u53D1\u751F\u8FC7\u538B\u7F29\uFF08\u6458\u8981\u4EC5\u4FDD\u7559\u8FD0\u884C\u65F6\u6700\u8FD1\u4E00\u6B21\uFF09\u3002");
|
|
17790
|
+
state.pushInfo(s ? S.archiveSummary(s) : S.archiveNone);
|
|
17385
17791
|
return true;
|
|
17386
17792
|
}
|
|
17387
17793
|
case "/plan": {
|
|
17388
17794
|
const on = !state.getPlanMode();
|
|
17389
17795
|
state.setPlanMode(on);
|
|
17390
|
-
state.pushInfo(
|
|
17796
|
+
state.pushInfo(S.planModeSet(on));
|
|
17391
17797
|
return true;
|
|
17392
17798
|
}
|
|
17393
17799
|
case "/budget": {
|
|
@@ -17395,27 +17801,27 @@ ${s}` : "\u672C\u4F1A\u8BDD\u542F\u52A8\u4EE5\u6765\u5C1A\u672A\u53D1\u751F\u8FC
|
|
|
17395
17801
|
if (!v) {
|
|
17396
17802
|
const b = state.getBudgetYuan();
|
|
17397
17803
|
const last = state.getLastRunCostYuan();
|
|
17398
|
-
state.pushInfo(
|
|
17804
|
+
state.pushInfo(S.budgetView(b, last));
|
|
17399
17805
|
return true;
|
|
17400
17806
|
}
|
|
17401
17807
|
if (v === "off" || v === "0") {
|
|
17402
17808
|
state.setBudgetYuan(void 0);
|
|
17403
|
-
state.pushInfo(
|
|
17809
|
+
state.pushInfo(S.budgetOff);
|
|
17404
17810
|
return true;
|
|
17405
17811
|
}
|
|
17406
17812
|
const n = Number(v);
|
|
17407
17813
|
if (!Number.isFinite(n) || n <= 0) {
|
|
17408
|
-
state.pushInfo(
|
|
17814
|
+
state.pushInfo(S.budgetUsage);
|
|
17409
17815
|
return true;
|
|
17410
17816
|
}
|
|
17411
17817
|
state.setBudgetYuan(n);
|
|
17412
|
-
state.pushInfo(
|
|
17818
|
+
state.pushInfo(S.budgetSet(n));
|
|
17413
17819
|
return true;
|
|
17414
17820
|
}
|
|
17415
17821
|
case "/auto": {
|
|
17416
17822
|
const on = !state.getAutoMode();
|
|
17417
17823
|
state.setAutoMode(on);
|
|
17418
|
-
state.pushInfo(
|
|
17824
|
+
state.pushInfo(S.autoModeSet(on));
|
|
17419
17825
|
return true;
|
|
17420
17826
|
}
|
|
17421
17827
|
case "/model":
|
|
@@ -17435,15 +17841,15 @@ ${s}` : "\u672C\u4F1A\u8BDD\u542F\u52A8\u4EE5\u6765\u5C1A\u672A\u53D1\u751F\u8FC
|
|
|
17435
17841
|
case "/thinking": {
|
|
17436
17842
|
const lvl = arg.toLowerCase();
|
|
17437
17843
|
if (arg && lvl !== "off" && lvl !== "high" && lvl !== "max") {
|
|
17438
|
-
state.pushInfo(
|
|
17844
|
+
state.pushInfo(S.thinkingInvalid(arg));
|
|
17439
17845
|
return true;
|
|
17440
17846
|
}
|
|
17441
17847
|
if (!arg) {
|
|
17442
|
-
state.pushInfo(
|
|
17848
|
+
state.pushInfo(S.thinkingCurrent(state.getThinkingLevel()));
|
|
17443
17849
|
return true;
|
|
17444
17850
|
}
|
|
17445
17851
|
state.setThinkingLevel(lvl);
|
|
17446
|
-
state.pushInfo(
|
|
17852
|
+
state.pushInfo(S.thinkingSet(lvl));
|
|
17447
17853
|
return true;
|
|
17448
17854
|
}
|
|
17449
17855
|
case "/lang": {
|
|
@@ -17497,7 +17903,7 @@ ${listText}`);
|
|
|
17497
17903
|
};
|
|
17498
17904
|
const ensureEngine = async () => {
|
|
17499
17905
|
if (engineReadyFlag) return;
|
|
17500
|
-
state.pushInfo(
|
|
17906
|
+
state.pushInfo(S.engineLoading);
|
|
17501
17907
|
await engineReady;
|
|
17502
17908
|
};
|
|
17503
17909
|
const executeSlash = async (fullText) => {
|
|
@@ -17513,7 +17919,7 @@ ${listText}`);
|
|
|
17513
17919
|
await state.submit(text);
|
|
17514
17920
|
return;
|
|
17515
17921
|
}
|
|
17516
|
-
state.pushInfo(
|
|
17922
|
+
state.pushInfo(S.unknownCmd(name));
|
|
17517
17923
|
};
|
|
17518
17924
|
const onSubmit = async () => {
|
|
17519
17925
|
const v = inputRef.current.trim();
|
|
@@ -17793,7 +18199,7 @@ __export(batchRunner_exports, {
|
|
|
17793
18199
|
});
|
|
17794
18200
|
import fs49 from "fs";
|
|
17795
18201
|
import { spawn as spawn6 } from "child_process";
|
|
17796
|
-
var BATCH_EDIT_TOOLS, BATCH_DEFAULT_DENYLIST, ACCEPT_TIMEOUT_MIN, ACCEPT_TAIL_LINES, emit2, ts,
|
|
18202
|
+
var BATCH_EDIT_TOOLS, BATCH_DEFAULT_DENYLIST, ACCEPT_TIMEOUT_MIN, ACCEPT_TAIL_LINES, emit2, ts, runAcceptCommand, collectSessionCost, buildReport, runOneTask, parseWaitWindow, nowMinutes, sleep, waitUntilWindow, runBatchQueue;
|
|
17797
18203
|
var init_batchRunner = __esm({
|
|
17798
18204
|
"src/batchRunner.ts"() {
|
|
17799
18205
|
"use strict";
|
|
@@ -17807,6 +18213,8 @@ var init_batchRunner = __esm({
|
|
|
17807
18213
|
init_usageLog();
|
|
17808
18214
|
init_ticket();
|
|
17809
18215
|
init_queue();
|
|
18216
|
+
init_batchStrings();
|
|
18217
|
+
init_strings();
|
|
17810
18218
|
BATCH_EDIT_TOOLS = /* @__PURE__ */ new Set(["edit_file", "create_file", "write_file", "move_file", "notebook_edit"]);
|
|
17811
18219
|
BATCH_DEFAULT_DENYLIST = /* @__PURE__ */ new Set(["run_command", "delete_path"]);
|
|
17812
18220
|
ACCEPT_TIMEOUT_MIN = 10;
|
|
@@ -17815,14 +18223,8 @@ var init_batchRunner = __esm({
|
|
|
17815
18223
|
process.stdout.write(s + "\n");
|
|
17816
18224
|
};
|
|
17817
18225
|
ts = () => (/* @__PURE__ */ new Date()).toLocaleTimeString("zh-CN", { hour12: false });
|
|
17818
|
-
STATUS_LABEL = {
|
|
17819
|
-
passed: "\u2705 \u901A\u8FC7\u9A8C\u6536",
|
|
17820
|
-
"accept-failed": "\u274C \u9A8C\u6536\u672A\u8FC7",
|
|
17821
|
-
timeout: "\u23F1\uFE0F \u8D85\u65F6\u622A\u65AD",
|
|
17822
|
-
error: "\u{1F4A5} agent \u5F02\u5E38",
|
|
17823
|
-
rejected: "\u{1F6AB} \u5DE5\u5355\u88AB\u62D2"
|
|
17824
|
-
};
|
|
17825
18226
|
runAcceptCommand = async (cmd, cwd) => {
|
|
18227
|
+
const T = batchT(getLocale());
|
|
17826
18228
|
const isWin = process.platform === "win32";
|
|
17827
18229
|
return new Promise((resolve) => {
|
|
17828
18230
|
let child;
|
|
@@ -17835,7 +18237,7 @@ var init_batchRunner = __esm({
|
|
|
17835
18237
|
// 剔除 agent 自身凭证(同 run_command 红线)
|
|
17836
18238
|
});
|
|
17837
18239
|
} catch (e) {
|
|
17838
|
-
resolve({ code: null, output:
|
|
18240
|
+
resolve({ code: null, output: T.spawnFail(e?.message ?? e), timedOut: false });
|
|
17839
18241
|
return;
|
|
17840
18242
|
}
|
|
17841
18243
|
const chunks = [];
|
|
@@ -17851,15 +18253,15 @@ var init_batchRunner = __esm({
|
|
|
17851
18253
|
}, ACCEPT_TIMEOUT_MIN * 6e4);
|
|
17852
18254
|
child.on("error", (e) => {
|
|
17853
18255
|
clearTimeout(killer);
|
|
17854
|
-
resolve({ code: null, output:
|
|
18256
|
+
resolve({ code: null, output: T.execFail(e?.message ?? e), timedOut });
|
|
17855
18257
|
});
|
|
17856
18258
|
child.on("close", (code) => {
|
|
17857
18259
|
clearTimeout(killer);
|
|
17858
18260
|
const text = decodeProcessOutput(Buffer.concat(chunks)).trim();
|
|
17859
18261
|
const lines = text.split("\n");
|
|
17860
|
-
const tail = lines.length > ACCEPT_TAIL_LINES ?
|
|
18262
|
+
const tail = lines.length > ACCEPT_TAIL_LINES ? `${T.tailOmitted(lines.length - ACCEPT_TAIL_LINES)}
|
|
17861
18263
|
${lines.slice(-ACCEPT_TAIL_LINES).join("\n")}` : text;
|
|
17862
|
-
resolve({ code, output: tail ||
|
|
18264
|
+
resolve({ code, output: tail || T.noOutput, timedOut });
|
|
17863
18265
|
});
|
|
17864
18266
|
});
|
|
17865
18267
|
};
|
|
@@ -17880,19 +18282,10 @@ ${lines.slice(-ACCEPT_TAIL_LINES).join("\n")}` : text;
|
|
|
17880
18282
|
if (c.costYuan === null) c.partialPrice = false;
|
|
17881
18283
|
return c;
|
|
17882
18284
|
};
|
|
17883
|
-
fmtCost = (c) => {
|
|
17884
|
-
const money = c.costYuan !== null ? `\xA5${c.costYuan.toFixed(4)}` : "\uFF08\u65E0\u4EF7\u6A21\u578B\uFF0C\u4E0D\u8BA1\u94B1\uFF09";
|
|
17885
|
-
const hit = c.promptTokens > 0 ? Math.round(c.cachedTokens / c.promptTokens * 100) : 0;
|
|
17886
|
-
const mins = Math.round(c.durationMs / 6e3) / 10;
|
|
17887
|
-
return `${c.rounds} \u8F6E \xB7 ${money} \xB7 \u7F13\u5B58\u547D\u4E2D ${hit}% \xB7 ${mins}min${c.partialPrice ? "\uFF08\u90E8\u5206\u8BB0\u5F55\u65E0\u4EF7\uFF0C\u94B1\u4E3A\u90E8\u5206\u548C\uFF09" : ""}${c.subRuns > 0 ? ` \xB7 \u5B50 run ${c.subRuns} \u4E2A\u5DF2\u8BA1\u5165` : ""}`;
|
|
17888
|
-
};
|
|
17889
|
-
fmtReceiptLine = (receipt) => {
|
|
17890
|
-
if (!receipt) return "\uFF08\u65E0\u7ED3\u7B97\u5355\u2014\u2014run \u672A\u5230\u6536\u5C3E\u5373\u88AB\u622A\u65AD\uFF0C\u82B1\u8D39\u4EE5\u4E0A\u65B9 usageLog \u805A\u5408\u4E3A\u51C6\uFF09";
|
|
17891
|
-
return `${receipt.rounds} \u8F6E \xB7 ${receipt.costYuan !== null ? `\xA5${receipt.costYuan.toFixed(4)}` : "\u65E0\u4EF7"} \xB7 \u7F13\u5B58\u547D\u4E2D ${Math.round(receipt.cacheHitRate * 100)}% \xB7 ${(receipt.durationMs / 1e3).toFixed(0)}s`;
|
|
17892
|
-
};
|
|
17893
18285
|
buildReport = (args) => {
|
|
17894
18286
|
const { id, ticket, status, budgetTruncated, cost, receipt, finalText, accept, deniedTools, diff, wt } = args;
|
|
17895
|
-
const
|
|
18287
|
+
const T = batchT(getLocale());
|
|
18288
|
+
const budgetNote = budgetTruncated ? T.budgetTruncNote : "";
|
|
17896
18289
|
return `---
|
|
17897
18290
|
id: ${id}
|
|
17898
18291
|
title: ${ticket.title}
|
|
@@ -17901,43 +18294,42 @@ cost-yuan: ${cost.costYuan !== null ? cost.costYuan.toFixed(4) : "null"}
|
|
|
17901
18294
|
rounds: ${cost.rounds}
|
|
17902
18295
|
budget-truncated: ${budgetTruncated}
|
|
17903
18296
|
session: batch-${id}
|
|
17904
|
-
worktree: ${wt?.path ??
|
|
17905
|
-
branch: ${wt?.branch ??
|
|
18297
|
+
worktree: ${wt?.path ?? T.notCreated}
|
|
18298
|
+
branch: ${wt?.branch ?? T.notCreated}
|
|
17906
18299
|
---
|
|
17907
18300
|
|
|
17908
|
-
|
|
18301
|
+
${T.reportTitle(ticket.title)}
|
|
17909
18302
|
|
|
17910
|
-
|
|
17911
|
-
|
|
17912
|
-
|
|
17913
|
-
${args.errorMessage ?
|
|
17914
|
-
|
|
17915
|
-
## \u4EFB\u52A1
|
|
18303
|
+
${T.statusEntry(`${T.statusLabel(status)}${budgetNote}`)}
|
|
18304
|
+
${T.costEntry(T.costSummary(cost))}
|
|
18305
|
+
${T.receiptEntry(receipt ? T.receiptLine(receipt) : T.noReceipt)}
|
|
18306
|
+
${args.errorMessage ? T.errorEntry(args.errorMessage) : ""}
|
|
18307
|
+
${T.taskH}
|
|
17916
18308
|
|
|
17917
18309
|
${ticket.body}
|
|
17918
18310
|
|
|
17919
|
-
|
|
18311
|
+
${T.finalH}
|
|
17920
18312
|
|
|
17921
|
-
${finalText.trim() ||
|
|
18313
|
+
${finalText.trim() || T.noFinal}
|
|
17922
18314
|
|
|
17923
|
-
|
|
18315
|
+
${T.acceptH}
|
|
17924
18316
|
${accept ? `
|
|
17925
|
-
|
|
18317
|
+
${T.acceptCmdLine(accept.cmd, accept.code)}${accept.timedOut ? T.acceptTimeoutSuffix : ""}
|
|
17926
18318
|
|
|
17927
|
-
|
|
18319
|
+
${T.acceptTail}
|
|
17928
18320
|
|
|
17929
18321
|
\`\`\`
|
|
17930
18322
|
${accept.output}
|
|
17931
18323
|
\`\`\`
|
|
17932
|
-
` :
|
|
18324
|
+
` : T.noAccept}
|
|
17933
18325
|
|
|
17934
|
-
|
|
18326
|
+
${T.deniedH}
|
|
17935
18327
|
|
|
17936
|
-
${deniedTools.length === 0 ?
|
|
18328
|
+
${deniedTools.length === 0 ? T.deniedNone : deniedTools.map((d) => `- **${d.tool}** \u2014 ${d.detail}`).join("\n")}
|
|
17937
18329
|
|
|
17938
|
-
|
|
18330
|
+
${T.diffH}
|
|
17939
18331
|
|
|
17940
|
-
|
|
18332
|
+
${T.diffNote(wt?.branch ?? "?", wt?.path ?? "?")}
|
|
17941
18333
|
|
|
17942
18334
|
\`\`\`\`\`diff
|
|
17943
18335
|
${diff}
|
|
@@ -17945,8 +18337,9 @@ ${diff}
|
|
|
17945
18337
|
`;
|
|
17946
18338
|
};
|
|
17947
18339
|
runOneTask = async (task) => {
|
|
18340
|
+
const T = batchT(getLocale());
|
|
17948
18341
|
const source = await fs49.promises.readFile(task.path, "utf-8");
|
|
17949
|
-
const parsed = parseBatchTicket(source);
|
|
18342
|
+
const parsed = parseBatchTicket(source, getLocale());
|
|
17950
18343
|
if (!parsed.ok) {
|
|
17951
18344
|
const cost2 = { rounds: 0, mainRounds: 0, subRuns: 0, promptTokens: 0, completionTokens: 0, cachedTokens: 0, costYuan: 0, partialPrice: false, durationMs: 0 };
|
|
17952
18345
|
await finishTicket(task.id, `---
|
|
@@ -17955,17 +18348,17 @@ title: ${task.id}
|
|
|
17955
18348
|
status: rejected
|
|
17956
18349
|
---
|
|
17957
18350
|
|
|
17958
|
-
|
|
18351
|
+
${T.rejectedTitle}
|
|
17959
18352
|
|
|
17960
18353
|
${parsed.error}`);
|
|
17961
|
-
emit2(
|
|
18354
|
+
emit2(T.ticketRejected(task.id, parsed.error));
|
|
17962
18355
|
return { status: "rejected", cost: cost2, budgetTruncated: false };
|
|
17963
18356
|
}
|
|
17964
18357
|
const t = parsed.ticket;
|
|
17965
18358
|
const sessionId = `batch-${task.id}`;
|
|
17966
18359
|
const timeoutMin = t.timeoutMin ?? 30;
|
|
17967
18360
|
emit2(`\u25B6 [${task.id}] ${t.title}`);
|
|
17968
|
-
emit2(
|
|
18361
|
+
emit2(T.taskMeta(t.budgetYuan, timeoutMin, t.accept));
|
|
17969
18362
|
const unlocked = new Set(t.tools ?? []);
|
|
17970
18363
|
const denySchemas = new Set([...BATCH_DEFAULT_DENYLIST].filter((n) => !unlocked.has(n)));
|
|
17971
18364
|
const toolSchemas = agentTools.filter((x) => !denySchemas.has(x?.function?.name));
|
|
@@ -17975,7 +18368,7 @@ ${parsed.error}`);
|
|
|
17975
18368
|
try {
|
|
17976
18369
|
wt = await createWorktree(sessionId, task.id);
|
|
17977
18370
|
} catch (e) {
|
|
17978
|
-
const msg =
|
|
18371
|
+
const msg = T.wtCreateFail(e?.message ?? e);
|
|
17979
18372
|
const cost2 = await collectSessionCost(sessionId);
|
|
17980
18373
|
await finishTicket(task.id, buildReport({
|
|
17981
18374
|
id: task.id,
|
|
@@ -17987,7 +18380,7 @@ ${parsed.error}`);
|
|
|
17987
18380
|
finalText: "",
|
|
17988
18381
|
accept: null,
|
|
17989
18382
|
deniedTools: [],
|
|
17990
|
-
diff:
|
|
18383
|
+
diff: T.diffNone,
|
|
17991
18384
|
wt: null,
|
|
17992
18385
|
errorMessage: msg
|
|
17993
18386
|
}));
|
|
@@ -17995,8 +18388,38 @@ ${parsed.error}`);
|
|
|
17995
18388
|
return { status: "error", cost: cost2, budgetTruncated: false };
|
|
17996
18389
|
}
|
|
17997
18390
|
setSessionWorktree(sessionId, wt);
|
|
18391
|
+
if (t.setup) {
|
|
18392
|
+
emit2(T.setupLine(t.setup));
|
|
18393
|
+
const s = await runAcceptCommand(t.setup, wt.path);
|
|
18394
|
+
if (s.code !== 0 || s.timedOut) {
|
|
18395
|
+
const msg = `${T.setupFail(t.setup, s.code)}${s.timedOut ? T.acceptTimeoutSuffix : ""}
|
|
18396
|
+
|
|
18397
|
+
\`\`\`
|
|
18398
|
+
${s.output}
|
|
18399
|
+
\`\`\``;
|
|
18400
|
+
await killBackgroundTasksUnder(wt.path).catch(() => {
|
|
18401
|
+
});
|
|
18402
|
+
const cost2 = await collectSessionCost(sessionId);
|
|
18403
|
+
await finishTicket(task.id, buildReport({
|
|
18404
|
+
id: task.id,
|
|
18405
|
+
ticket: t,
|
|
18406
|
+
status: "setup-failed",
|
|
18407
|
+
budgetTruncated: false,
|
|
18408
|
+
cost: cost2,
|
|
18409
|
+
receipt: void 0,
|
|
18410
|
+
finalText: "",
|
|
18411
|
+
accept: null,
|
|
18412
|
+
deniedTools: [],
|
|
18413
|
+
diff: T.diffNone,
|
|
18414
|
+
wt,
|
|
18415
|
+
errorMessage: msg
|
|
18416
|
+
}));
|
|
18417
|
+
emit2(`\u{1F6E0}\uFE0F [${task.id}] ${T.setupFail(t.setup, s.code)}`);
|
|
18418
|
+
return { status: "setup-failed", cost: cost2, budgetTruncated: false };
|
|
18419
|
+
}
|
|
18420
|
+
}
|
|
17998
18421
|
const ac = new AbortController();
|
|
17999
|
-
const timer = setTimeout(() => ac.abort(new Error(
|
|
18422
|
+
const timer = setTimeout(() => ac.abort(new Error(T.timeoutAbort(timeoutMin))), timeoutMin * 6e4);
|
|
18000
18423
|
let receipt;
|
|
18001
18424
|
let finalText = "";
|
|
18002
18425
|
let agentError;
|
|
@@ -18009,7 +18432,7 @@ ${parsed.error}`);
|
|
|
18009
18432
|
if (evt?.type === "text.delta") finalText += evt.text;
|
|
18010
18433
|
else if (evt?.type === "text.reset") finalText = "";
|
|
18011
18434
|
else if (evt?.type === "final") finalText = evt.text || finalText;
|
|
18012
|
-
else if (evt?.type === "round.start") emit2(
|
|
18435
|
+
else if (evt?.type === "round.start") emit2(T.roundLine(ts(), evt.round));
|
|
18013
18436
|
},
|
|
18014
18437
|
ac.signal,
|
|
18015
18438
|
{
|
|
@@ -18037,15 +18460,15 @@ ${parsed.error}`);
|
|
|
18037
18460
|
let accept = null;
|
|
18038
18461
|
if (agentError) {
|
|
18039
18462
|
status = "error";
|
|
18040
|
-
emit2(
|
|
18463
|
+
emit2(T.agentErrorLine(task.id, agentError));
|
|
18041
18464
|
} else if (timedOut) {
|
|
18042
18465
|
status = "timeout";
|
|
18043
|
-
emit2(
|
|
18466
|
+
emit2(T.timeoutLine(task.id, timeoutMin));
|
|
18044
18467
|
} else {
|
|
18045
18468
|
const r = await runAcceptCommand(t.accept, wt.path);
|
|
18046
18469
|
accept = { cmd: t.accept, code: r.code, output: r.output, timedOut: r.timedOut };
|
|
18047
18470
|
status = r.code === 0 && !r.timedOut ? "passed" : "accept-failed";
|
|
18048
|
-
emit2(
|
|
18471
|
+
emit2(T.acceptLine(status === "passed", task.id, r.code) + (r.timedOut ? T.acceptKilledSuffix : ""));
|
|
18049
18472
|
}
|
|
18050
18473
|
await killBackgroundTasksUnder(wt.path).catch(() => {
|
|
18051
18474
|
});
|
|
@@ -18065,8 +18488,8 @@ ${parsed.error}`);
|
|
|
18065
18488
|
wt,
|
|
18066
18489
|
errorMessage: agentError
|
|
18067
18490
|
}));
|
|
18068
|
-
emit2(` ${
|
|
18069
|
-
emit2(
|
|
18491
|
+
emit2(` ${T.statusLabel(status)} \xB7 ${T.costSummary(cost)}`);
|
|
18492
|
+
emit2(T.artifactLine(wt.path, wt.branch));
|
|
18070
18493
|
return { status, cost, budgetTruncated };
|
|
18071
18494
|
};
|
|
18072
18495
|
parseWaitWindow = (s) => {
|
|
@@ -18084,14 +18507,15 @@ ${parsed.error}`);
|
|
|
18084
18507
|
};
|
|
18085
18508
|
sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
18086
18509
|
waitUntilWindow = async (w) => {
|
|
18510
|
+
const T = batchT(getLocale());
|
|
18087
18511
|
const now = nowMinutes();
|
|
18088
18512
|
let waitMin = 0;
|
|
18089
18513
|
if (now >= w.startMin && now < w.endMin) {
|
|
18090
|
-
emit2(
|
|
18514
|
+
emit2(T.inWindowNow(`${Math.floor(now / 60)}:${String(now % 60).padStart(2, "0")}`));
|
|
18091
18515
|
return;
|
|
18092
18516
|
}
|
|
18093
18517
|
waitMin = now < w.startMin ? w.startMin - now : 24 * 60 - now + w.startMin;
|
|
18094
|
-
emit2(
|
|
18518
|
+
emit2(T.waitWindowWait(Math.floor(waitMin / 60), waitMin % 60));
|
|
18095
18519
|
while (waitMin > 0) {
|
|
18096
18520
|
const chunkMin = Math.min(waitMin, 30);
|
|
18097
18521
|
await sleep(chunkMin * 6e4);
|
|
@@ -18099,14 +18523,15 @@ ${parsed.error}`);
|
|
|
18099
18523
|
}
|
|
18100
18524
|
};
|
|
18101
18525
|
runBatchQueue = async (opts) => {
|
|
18526
|
+
const T = batchT(getLocale());
|
|
18102
18527
|
const window = parseWaitWindow(opts?.waitWindow);
|
|
18103
18528
|
if (opts?.waitWindow && !window) {
|
|
18104
|
-
emit2(
|
|
18529
|
+
emit2(T.waitWindowInvalid(opts.waitWindow));
|
|
18105
18530
|
process.exitCode = 2;
|
|
18106
18531
|
return;
|
|
18107
18532
|
}
|
|
18108
18533
|
if (window) await waitUntilWindow(window);
|
|
18109
|
-
const lock = await acquireRunLock();
|
|
18534
|
+
const lock = await acquireRunLock(getLocale());
|
|
18110
18535
|
if (!lock.ok) {
|
|
18111
18536
|
emit2(`\u{1F6AB} ${lock.error}`);
|
|
18112
18537
|
process.exitCode = 1;
|
|
@@ -18125,7 +18550,7 @@ ${parsed.error}`);
|
|
|
18125
18550
|
total++;
|
|
18126
18551
|
const r = await runOneTask(task);
|
|
18127
18552
|
if (r.status === "passed") passed++;
|
|
18128
|
-
else failedIds.push(`[${task.id}] ${
|
|
18553
|
+
else failedIds.push(`[${task.id}] ${T.statusLabel(r.status)}`);
|
|
18129
18554
|
if (r.cost.costYuan !== null) {
|
|
18130
18555
|
costSum += r.cost.costYuan;
|
|
18131
18556
|
costTasks++;
|
|
@@ -18135,16 +18560,16 @@ ${parsed.error}`);
|
|
|
18135
18560
|
await releaseRunLock();
|
|
18136
18561
|
}
|
|
18137
18562
|
if (total === 0) {
|
|
18138
|
-
emit2(
|
|
18563
|
+
emit2(T.runnerQueueEmpty);
|
|
18139
18564
|
return;
|
|
18140
18565
|
}
|
|
18141
18566
|
emit2("");
|
|
18142
18567
|
emit2("\u2501".repeat(56));
|
|
18143
|
-
emit2(
|
|
18144
|
-
emit2(
|
|
18145
|
-
if (failedIds.length > 0) emit2(
|
|
18568
|
+
emit2(T.summaryDone(total, passed, `${Math.round((Date.now() - startedAt) / 6e3) / 10}`));
|
|
18569
|
+
emit2(costTasks > 0 ? T.summaryCost(costSum.toFixed(4), costTasks) : T.summaryCostFree);
|
|
18570
|
+
if (failedIds.length > 0) emit2(`${T.failedHead}
|
|
18146
18571
|
${failedIds.join("\n ")}`);
|
|
18147
|
-
emit2(
|
|
18572
|
+
emit2(T.artifactsDir);
|
|
18148
18573
|
};
|
|
18149
18574
|
}
|
|
18150
18575
|
});
|