reasonix 0.47.2 → 0.48.1
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 +14 -26
- package/README.zh-CN.md +5 -26
- package/dist/cli/{acp-GEOAKSTU.js → acp-QJGGHQLA.js} +52 -135
- package/dist/cli/acp-QJGGHQLA.js.map +1 -0
- package/dist/cli/{chat-YTPATMMG.js → chat-ZXF227MP.js} +25 -25
- package/dist/cli/{chunk-DN4B5S6Y.js → chunk-3FULTFRB.js} +2 -2
- package/dist/cli/chunk-43ROGEX2.js +5190 -0
- package/dist/cli/chunk-43ROGEX2.js.map +1 -0
- package/dist/cli/{chunk-DQ6K5ZQ7.js → chunk-4E2BHJU4.js} +4 -4
- package/dist/cli/chunk-4E2BHJU4.js.map +1 -0
- package/dist/cli/{chunk-T5A7EY6B.js → chunk-5AW6NIHU.js} +2 -2
- package/dist/cli/{chunk-DWPAKZTY.js → chunk-5U5LMMFF.js} +2 -2
- package/dist/cli/{chunk-TRSAHHCL.js → chunk-6FRNXWDZ.js} +321 -76
- package/dist/cli/chunk-6FRNXWDZ.js.map +1 -0
- package/dist/cli/{chunk-KYQVQ5X4.js → chunk-B5CZL2SE.js} +9 -4
- package/dist/cli/chunk-B5CZL2SE.js.map +1 -0
- package/dist/cli/{chunk-XMHP7BEE.js → chunk-DABAOQSV.js} +2273 -2517
- package/dist/cli/chunk-DABAOQSV.js.map +1 -0
- package/dist/cli/chunk-EO6RPTJG.js +831 -0
- package/dist/cli/chunk-EO6RPTJG.js.map +1 -0
- package/dist/cli/{chunk-BQ6HC66J.js → chunk-FD7SNDWW.js} +4 -14
- package/dist/cli/chunk-FD7SNDWW.js.map +1 -0
- package/dist/cli/chunk-FPME5QOO.js +17747 -0
- package/dist/cli/chunk-FPME5QOO.js.map +1 -0
- package/dist/cli/{chunk-6QC5RQLE.js → chunk-H2F4LDNH.js} +2 -2
- package/dist/cli/{chunk-QCFLPSPH.js → chunk-IKSYVBBZ.js} +2 -2
- package/dist/cli/{chunk-5QCB62C4.js → chunk-J2TQAWOM.js} +135 -18
- package/dist/cli/{chunk-5QCB62C4.js.map → chunk-J2TQAWOM.js.map} +1 -1
- package/dist/cli/{chunk-JBH5RM7X.js → chunk-JFBGSWQB.js} +395 -85
- package/dist/cli/chunk-JFBGSWQB.js.map +1 -0
- package/dist/cli/{chunk-CCJAP7G3.js → chunk-KH5JIJJD.js} +2 -2
- package/dist/cli/{chunk-TDHXB2ER.js → chunk-NQZ5U37J.js} +2 -2
- package/dist/cli/{chunk-CNG32VAB.js → chunk-O3AGYTG2.js} +2 -2
- package/dist/cli/{chunk-NRQ5UP5T.js → chunk-PIC5HJRD.js} +234 -40
- package/dist/cli/chunk-PIC5HJRD.js.map +1 -0
- package/dist/cli/{chunk-GH7DC2Y5.js → chunk-PJIQIYTV.js} +6 -3
- package/dist/cli/chunk-PJIQIYTV.js.map +1 -0
- package/dist/cli/{chunk-KVZZ5U75.js → chunk-R7U44O3Y.js} +2 -2
- package/dist/cli/{chunk-ZXSCAODE.js → chunk-RCLS63KE.js} +71 -3
- package/dist/cli/chunk-RCLS63KE.js.map +1 -0
- package/dist/cli/{chunk-FY4S7TJZ.js → chunk-SLAFMXAZ.js} +10 -2
- package/dist/cli/chunk-SLAFMXAZ.js.map +1 -0
- package/dist/cli/{chunk-TRWHTFG7.js → chunk-SWUMD2LX.js} +2 -2
- package/dist/cli/{chunk-2XY77LW7.js → chunk-TIJ4ZHD6.js} +56 -24
- package/dist/cli/chunk-TIJ4ZHD6.js.map +1 -0
- package/dist/cli/{chunk-4MFCAZ2W.js → chunk-WKOXKCF3.js} +3 -3
- package/dist/cli/{chunk-HUILPCYX.js → chunk-XMR2VCGT.js} +3 -3
- package/dist/cli/{code-Q4NRVEDG.js → code-OKA5YPOH.js} +31 -32
- package/dist/cli/code-OKA5YPOH.js.map +1 -0
- package/dist/cli/{commands-4CDI4GFM.js → commands-3U6PUVSS.js} +4 -4
- package/dist/cli/{commit-GW7LDQP5.js → commit-HFB7SRBU.js} +3 -3
- package/dist/cli/{desktop-EG6P5SF2.js → desktop-G7UMW3CJ.js} +503 -48
- package/dist/cli/desktop-G7UMW3CJ.js.map +1 -0
- package/dist/cli/{diff-VI2YX4FN.js → diff-PGXW4YZD.js} +8 -8
- package/dist/cli/{doctor-CQTTZP27.js → doctor-WWJFLVCB.js} +9 -9
- package/dist/cli/index.js +53 -41
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/{mcp-J2UCD4RZ.js → mcp-Y3VKIK3T.js} +2 -2
- package/dist/cli/{mcp-browse-GSX34JEK.js → mcp-browse-4IN2QIFR.js} +2 -2
- package/dist/cli/{mcp-inspect-RRFYF4ZV.js → mcp-inspect-BUXFXDHB.js} +2 -2
- package/dist/cli/{prompt-5TQPIVHV.js → prompt-US57R6BA.js} +5 -4
- package/dist/cli/{replay-MJCEMODU.js → replay-EQJMZRB3.js} +8 -8
- package/dist/cli/{run-P4D5VDYE.js → run-KVEI66TR.js} +14 -14
- package/dist/cli/{server-C25JNNZV.js → server-D6C4GHWN.js} +18 -15
- package/dist/cli/server-D6C4GHWN.js.map +1 -0
- package/dist/cli/{sessions-QIONZJQ6.js → sessions-TGVS2RQZ.js} +13 -13
- package/dist/cli/{setup-NLQ6G5G4.js → setup-WLKX6GGG.js} +5 -5
- package/dist/cli/{stats-DFZEXHP4.js → stats-TCD7Q6MB.js} +6 -6
- package/dist/cli/{version-GR3X3MPI.js → version-BCWWS2OU.js} +13 -13
- package/dist/grammars/tree-sitter-go.wasm +0 -0
- package/dist/grammars/tree-sitter-java.wasm +0 -0
- package/dist/grammars/tree-sitter-javascript.wasm +0 -0
- package/dist/grammars/tree-sitter-python.wasm +0 -0
- package/dist/grammars/tree-sitter-rust.wasm +0 -0
- package/dist/grammars/tree-sitter-tsx.wasm +0 -0
- package/dist/grammars/tree-sitter-typescript.wasm +0 -0
- package/dist/grammars/web-tree-sitter.wasm +0 -0
- package/dist/index.d.ts +46 -12
- package/dist/index.js +684 -129
- package/dist/index.js.map +1 -1
- package/package.json +16 -4
- package/dist/cli/acp-GEOAKSTU.js.map +0 -1
- package/dist/cli/chunk-2XY77LW7.js.map +0 -1
- package/dist/cli/chunk-6CRPCJAU.js +0 -3141
- package/dist/cli/chunk-6CRPCJAU.js.map +0 -1
- package/dist/cli/chunk-BQ6HC66J.js.map +0 -1
- package/dist/cli/chunk-DQ6K5ZQ7.js.map +0 -1
- package/dist/cli/chunk-FY4S7TJZ.js.map +0 -1
- package/dist/cli/chunk-GH7DC2Y5.js.map +0 -1
- package/dist/cli/chunk-JBH5RM7X.js.map +0 -1
- package/dist/cli/chunk-KYQVQ5X4.js.map +0 -1
- package/dist/cli/chunk-NRQ5UP5T.js.map +0 -1
- package/dist/cli/chunk-TRSAHHCL.js.map +0 -1
- package/dist/cli/chunk-XD6P7AFH.js +0 -375
- package/dist/cli/chunk-XD6P7AFH.js.map +0 -1
- package/dist/cli/chunk-XMHP7BEE.js.map +0 -1
- package/dist/cli/chunk-YFP3MYMY.js +0 -323
- package/dist/cli/chunk-YFP3MYMY.js.map +0 -1
- package/dist/cli/chunk-ZXSCAODE.js.map +0 -1
- package/dist/cli/code-Q4NRVEDG.js.map +0 -1
- package/dist/cli/desktop-EG6P5SF2.js.map +0 -1
- package/dist/cli/server-C25JNNZV.js.map +0 -1
- /package/dist/cli/{chat-YTPATMMG.js.map → chat-ZXF227MP.js.map} +0 -0
- /package/dist/cli/{chunk-DN4B5S6Y.js.map → chunk-3FULTFRB.js.map} +0 -0
- /package/dist/cli/{chunk-T5A7EY6B.js.map → chunk-5AW6NIHU.js.map} +0 -0
- /package/dist/cli/{chunk-DWPAKZTY.js.map → chunk-5U5LMMFF.js.map} +0 -0
- /package/dist/cli/{chunk-6QC5RQLE.js.map → chunk-H2F4LDNH.js.map} +0 -0
- /package/dist/cli/{chunk-QCFLPSPH.js.map → chunk-IKSYVBBZ.js.map} +0 -0
- /package/dist/cli/{chunk-CCJAP7G3.js.map → chunk-KH5JIJJD.js.map} +0 -0
- /package/dist/cli/{chunk-TDHXB2ER.js.map → chunk-NQZ5U37J.js.map} +0 -0
- /package/dist/cli/{chunk-CNG32VAB.js.map → chunk-O3AGYTG2.js.map} +0 -0
- /package/dist/cli/{chunk-KVZZ5U75.js.map → chunk-R7U44O3Y.js.map} +0 -0
- /package/dist/cli/{chunk-TRWHTFG7.js.map → chunk-SWUMD2LX.js.map} +0 -0
- /package/dist/cli/{chunk-4MFCAZ2W.js.map → chunk-WKOXKCF3.js.map} +0 -0
- /package/dist/cli/{chunk-HUILPCYX.js.map → chunk-XMR2VCGT.js.map} +0 -0
- /package/dist/cli/{commands-4CDI4GFM.js.map → commands-3U6PUVSS.js.map} +0 -0
- /package/dist/cli/{commit-GW7LDQP5.js.map → commit-HFB7SRBU.js.map} +0 -0
- /package/dist/cli/{diff-VI2YX4FN.js.map → diff-PGXW4YZD.js.map} +0 -0
- /package/dist/cli/{doctor-CQTTZP27.js.map → doctor-WWJFLVCB.js.map} +0 -0
- /package/dist/cli/{mcp-J2UCD4RZ.js.map → mcp-Y3VKIK3T.js.map} +0 -0
- /package/dist/cli/{mcp-browse-GSX34JEK.js.map → mcp-browse-4IN2QIFR.js.map} +0 -0
- /package/dist/cli/{mcp-inspect-RRFYF4ZV.js.map → mcp-inspect-BUXFXDHB.js.map} +0 -0
- /package/dist/cli/{prompt-5TQPIVHV.js.map → prompt-US57R6BA.js.map} +0 -0
- /package/dist/cli/{replay-MJCEMODU.js.map → replay-EQJMZRB3.js.map} +0 -0
- /package/dist/cli/{run-P4D5VDYE.js.map → run-KVEI66TR.js.map} +0 -0
- /package/dist/cli/{sessions-QIONZJQ6.js.map → sessions-TGVS2RQZ.js.map} +0 -0
- /package/dist/cli/{setup-NLQ6G5G4.js.map → setup-WLKX6GGG.js.map} +0 -0
- /package/dist/cli/{stats-DFZEXHP4.js.map → stats-TCD7Q6MB.js.map} +0 -0
- /package/dist/cli/{version-GR3X3MPI.js.map → version-BCWWS2OU.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { createParser } from "eventsource-parser";
|
|
|
5
5
|
import { chmodSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
6
6
|
import { homedir } from "os";
|
|
7
7
|
import { dirname, isAbsolute, join, resolve } from "path";
|
|
8
|
+
import { z } from "zod";
|
|
8
9
|
|
|
9
10
|
// src/cli/ui/theme/tokens.ts
|
|
10
11
|
function card(fg, tone) {
|
|
@@ -465,12 +466,11 @@ function memoryTypeDefaults(typeName, cfg = readConfig()) {
|
|
|
465
466
|
if (found.expires) out.expires = found.expires;
|
|
466
467
|
return out;
|
|
467
468
|
}
|
|
468
|
-
var DEFAULT_METASO_API_KEY = "mk-E384C1DD5E8501BB7EFE27C949AFDE5B";
|
|
469
469
|
function loadMetasoApiKey(path2 = defaultConfigPath()) {
|
|
470
|
-
if (process.env.METASO_API_KEY) return process.env.METASO_API_KEY;
|
|
470
|
+
if (process.env.METASO_API_KEY) return process.env.METASO_API_KEY.trim();
|
|
471
471
|
const cfg = readConfig(path2).metasoApiKey;
|
|
472
472
|
if (cfg && typeof cfg === "string" && cfg.trim()) return cfg.trim();
|
|
473
|
-
return
|
|
473
|
+
return void 0;
|
|
474
474
|
}
|
|
475
475
|
function loadTavilyApiKey(path2 = defaultConfigPath()) {
|
|
476
476
|
if (process.env.TAVILY_API_KEY) return process.env.TAVILY_API_KEY.trim();
|
|
@@ -478,14 +478,65 @@ function loadTavilyApiKey(path2 = defaultConfigPath()) {
|
|
|
478
478
|
if (cfg && typeof cfg === "string" && cfg.trim()) return cfg.trim();
|
|
479
479
|
return void 0;
|
|
480
480
|
}
|
|
481
|
+
function loadPerplexityApiKey(path2 = defaultConfigPath()) {
|
|
482
|
+
if (process.env.PERPLEXITY_API_KEY) return process.env.PERPLEXITY_API_KEY.trim();
|
|
483
|
+
const cfg = readConfig(path2).perplexityApiKey;
|
|
484
|
+
if (cfg && typeof cfg === "string" && cfg.trim()) return cfg.trim();
|
|
485
|
+
return void 0;
|
|
486
|
+
}
|
|
487
|
+
function loadExaApiKey(path2 = defaultConfigPath()) {
|
|
488
|
+
if (process.env.EXA_API_KEY) return process.env.EXA_API_KEY.trim();
|
|
489
|
+
const cfg = readConfig(path2).exaApiKey;
|
|
490
|
+
if (cfg && typeof cfg === "string" && cfg.trim()) return cfg.trim();
|
|
491
|
+
return void 0;
|
|
492
|
+
}
|
|
481
493
|
function defaultConfigPath() {
|
|
482
494
|
return join(homedir(), ".reasonix", "config.json");
|
|
483
495
|
}
|
|
496
|
+
var STRING_ARRAY_FIELDS = [
|
|
497
|
+
["mcp"],
|
|
498
|
+
["mcpDisabled"],
|
|
499
|
+
["recentWorkspaces"],
|
|
500
|
+
["skills", "paths"]
|
|
501
|
+
];
|
|
502
|
+
var stringArraySchema = z.array(z.string());
|
|
503
|
+
function sanitizeStringArrayField(cfg, segments, filePath) {
|
|
504
|
+
if (segments.length === 0) return;
|
|
505
|
+
let parent = cfg;
|
|
506
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
507
|
+
const seg = segments[i];
|
|
508
|
+
const next = parent[seg];
|
|
509
|
+
if (!next || typeof next !== "object" || Array.isArray(next)) return;
|
|
510
|
+
parent = next;
|
|
511
|
+
}
|
|
512
|
+
const leaf = segments[segments.length - 1];
|
|
513
|
+
const value = parent[leaf];
|
|
514
|
+
if (value === void 0) return;
|
|
515
|
+
const fieldName = segments.join(".");
|
|
516
|
+
if (!Array.isArray(value)) {
|
|
517
|
+
console.warn(`reasonix: config "${filePath}" field "${fieldName}" is not an array \u2014 ignoring`);
|
|
518
|
+
delete parent[leaf];
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
const parsed = stringArraySchema.safeParse(value);
|
|
522
|
+
if (parsed.success) return;
|
|
523
|
+
const filtered = value.filter((x) => typeof x === "string");
|
|
524
|
+
console.warn(
|
|
525
|
+
`reasonix: config "${filePath}" field "${fieldName}" had ${value.length - filtered.length} non-string item(s) \u2014 dropped`
|
|
526
|
+
);
|
|
527
|
+
parent[leaf] = filtered;
|
|
528
|
+
}
|
|
484
529
|
function readConfig(path2 = defaultConfigPath()) {
|
|
485
530
|
try {
|
|
486
|
-
const raw = readFileSync(path2, "utf8");
|
|
531
|
+
const raw = readFileSync(path2, "utf8").replace(/^\uFEFF/, "");
|
|
487
532
|
const parsed = JSON.parse(raw);
|
|
488
|
-
if (parsed && typeof parsed === "object"
|
|
533
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
534
|
+
const cfg = parsed;
|
|
535
|
+
for (const segments of STRING_ARRAY_FIELDS) {
|
|
536
|
+
sanitizeStringArrayField(cfg, segments, path2);
|
|
537
|
+
}
|
|
538
|
+
return cfg;
|
|
539
|
+
}
|
|
489
540
|
} catch {
|
|
490
541
|
}
|
|
491
542
|
return {};
|
|
@@ -580,6 +631,8 @@ function webSearchEngine(path2 = defaultConfigPath()) {
|
|
|
580
631
|
if (cfg === "searxng") return "searxng";
|
|
581
632
|
if (cfg === "metaso") return "metaso";
|
|
582
633
|
if (cfg === "tavily") return "tavily";
|
|
634
|
+
if (cfg === "perplexity") return "perplexity";
|
|
635
|
+
if (cfg === "exa") return "exa";
|
|
583
636
|
return "mojeek";
|
|
584
637
|
}
|
|
585
638
|
function webSearchEndpoint(path2 = defaultConfigPath()) {
|
|
@@ -615,6 +668,11 @@ function addProjectShellAllowed(rootDir, prefix, path2 = defaultConfigPath()) {
|
|
|
615
668
|
cfg.projects[key].shellAllowed = [...existing, trimmed];
|
|
616
669
|
writeConfig(cfg, path2);
|
|
617
670
|
}
|
|
671
|
+
function projectHooksTrusted(rootDir, path2 = defaultConfigPath()) {
|
|
672
|
+
const cfg = readConfig(path2);
|
|
673
|
+
const key = findProjectKey(cfg, rootDir);
|
|
674
|
+
return key !== void 0 && cfg.projects?.[key]?.hooksTrusted === true;
|
|
675
|
+
}
|
|
618
676
|
function loadProjectPathAllowed(rootDir, path2 = defaultConfigPath()) {
|
|
619
677
|
const cfg = readConfig(path2);
|
|
620
678
|
const key = findProjectKey(cfg, rootDir);
|
|
@@ -1286,6 +1344,8 @@ var EN = {
|
|
|
1286
1344
|
tipShownOnce: "shown once",
|
|
1287
1345
|
modelOverride: "override the default model",
|
|
1288
1346
|
noSession: "disable session persistence for this run",
|
|
1347
|
+
noMouseHint: "disable SGR mouse tracking; restores native drag-select and right-click",
|
|
1348
|
+
noProxyHint: "ignore HTTPS_PROXY / HTTP_PROXY for this run; go direct",
|
|
1289
1349
|
resumeHint: "force-resume the named session (even if idle)",
|
|
1290
1350
|
newHint: "force a fresh session (ignore --session / --continue)",
|
|
1291
1351
|
transcriptHint: "path to write the JSONL transcript",
|
|
@@ -1427,6 +1487,7 @@ var EN = {
|
|
|
1427
1487
|
},
|
|
1428
1488
|
stop: { description: "abort the current model turn (typed alternative to Esc)" },
|
|
1429
1489
|
feedback: { description: "open a GitHub issue with diagnostic info copied to clipboard" },
|
|
1490
|
+
about: { description: "project info \u2014 version, website, repo, license" },
|
|
1430
1491
|
keys: { description: "keyboard + mouse + copy/paste reference" },
|
|
1431
1492
|
plans: { description: "list this session's active + archived plans, newest first" },
|
|
1432
1493
|
replay: {
|
|
@@ -1502,8 +1563,8 @@ var EN = {
|
|
|
1502
1563
|
argsHint: "<question>"
|
|
1503
1564
|
},
|
|
1504
1565
|
"search-engine": {
|
|
1505
|
-
description: "switch web search backend \u2014 mojeek (default, no deps), searxng (self-hosted),
|
|
1506
|
-
argsHint: "<mojeek|searxng|metaso> [<
|
|
1566
|
+
description: "switch web search backend \u2014 mojeek (default, no deps), searxng (self-hosted), metaso (free 100/d), tavily (free 1000/mo), perplexity (AI-native), or exa (AI-native)",
|
|
1567
|
+
argsHint: "<mojeek|searxng|metaso|tavily|perplexity|exa> [<key>]"
|
|
1507
1568
|
}
|
|
1508
1569
|
},
|
|
1509
1570
|
wizard: {
|
|
@@ -1694,7 +1755,24 @@ var EN = {
|
|
|
1694
1755
|
continuingAfter: "\u25B8 continuing after {label}{counter}",
|
|
1695
1756
|
planStoppedAt: "\u25B8 plan stopped at {label}{counter}",
|
|
1696
1757
|
revisingAfter: "\u25B8 revising after {label} \u2014 {feedback}",
|
|
1697
|
-
historyScrollHint: " \u2191 reading history \xB7 End / PgDn returns to bottom \xB7 \u2193 advances one line"
|
|
1758
|
+
historyScrollHint: " \u2191 reading history \xB7 End / PgDn returns to bottom \xB7 \u2193 advances one line",
|
|
1759
|
+
editHistoryTitle: "Edit history (oldest first):",
|
|
1760
|
+
editHistoryNoCodeMode: "not in code mode",
|
|
1761
|
+
editHistoryNoEdits: "no edits recorded this session yet",
|
|
1762
|
+
editHistoryNoShowId: "usage: /show [id] [path] (omit id for newest; path from the per-file summary)",
|
|
1763
|
+
editHistoryIdNotFound: "no edit #{id} \u2014 run /history to see valid ids",
|
|
1764
|
+
editHistoryLookupFailed: "unexpected: history lookup failed",
|
|
1765
|
+
editHistoryBatchNoFile: `batch #{id} doesn't include "{path}" \u2014 files in this batch: {files}`,
|
|
1766
|
+
editHistoryNoEdits2: "no edits recorded this session \u2014 /history is empty",
|
|
1767
|
+
editHistoryStatusApplied: "applied",
|
|
1768
|
+
editHistoryStatusPartial: "PARTIAL",
|
|
1769
|
+
editHistoryStatusUndone: "UNDONE",
|
|
1770
|
+
editHistoryHelpShow: "/show <id> \u2192 per-file summary \xB7 /show <id> <path> \u2192 full diff of one file",
|
|
1771
|
+
editHistoryHelpUndo: "/undo \u2192 newest non-undone \xB7 /undo <id> [path] \u2192 target a specific batch or file",
|
|
1772
|
+
editHistoryAlreadyReverted: "(already reverted \u2014 /history shows the batch-level status)",
|
|
1773
|
+
editHistoryRevertFile: "/undo {id} {path} \u2192 revert just this file",
|
|
1774
|
+
mcpFailed: "MCP {name} failed",
|
|
1775
|
+
mcpWarn: "MCP {name} warn"
|
|
1698
1776
|
},
|
|
1699
1777
|
hooks: {
|
|
1700
1778
|
head: "hook {tag} `{cmd}` {decision}{truncTag}",
|
|
@@ -1717,9 +1795,9 @@ var EN = {
|
|
|
1717
1795
|
abortedAtIter: "aborted at iter {iter} \u2014 stopped without producing a summary (press \u2191 + Enter or /retry to resume)",
|
|
1718
1796
|
toolUploadStatus: "tool result uploaded \xB7 model thinking before next response\u2026",
|
|
1719
1797
|
preflightTruncateStatus: "preflight: context near full, truncating oldest history\u2026",
|
|
1720
|
-
preflightTruncated: "preflight: request ~{estimate}/{ctxMax} tokens ({pct}%) \u2014 truncated {beforeMessages} messages \u2192 {afterMessages}. Sending.",
|
|
1721
|
-
preflightTruncatedStillFull: "preflight: request still ~{estimate}/{ctxMax} tokens ({pct}%) after truncating {beforeMessages} messages \u2192 {afterMessages}. DeepSeek will likely 400. Run /clear or /new to start fresh.",
|
|
1722
|
-
preflightNoFold: "preflight: request ~{estimate}/{ctxMax} tokens ({pct}%) and nothing left to truncate \u2014 DeepSeek will likely 400. Run /clear or /new to start fresh.",
|
|
1798
|
+
preflightTruncated: "preflight: request ~{estimate}/{ctxMax} tokens ({pct}%) \xB7 body {bodyKB} KB \u2014 truncated {beforeMessages} messages \u2192 {afterMessages}. Sending.",
|
|
1799
|
+
preflightTruncatedStillFull: "preflight: request still ~{estimate}/{ctxMax} tokens ({pct}%) \xB7 body {bodyKB} KB after truncating {beforeMessages} messages \u2192 {afterMessages}. DeepSeek will likely 400. Run /clear or /new to start fresh.",
|
|
1800
|
+
preflightNoFold: "preflight: request ~{estimate}/{ctxMax} tokens ({pct}%) \xB7 body {bodyKB} KB and nothing left to truncate \u2014 DeepSeek will likely 400. Run /clear or /new to start fresh.",
|
|
1723
1801
|
flashEscalation: "\u21E7 flash requested escalation \u2014 retrying this turn on {model}{reasonSuffix}",
|
|
1724
1802
|
harvestStatus: "extracting plan state from reasoning\u2026",
|
|
1725
1803
|
repeatToolCallWarning: "Caught a repeated tool call \u2014 let the model see the issue and retry with a different approach.",
|
|
@@ -1795,6 +1873,10 @@ var EN = {
|
|
|
1795
1873
|
loopNoActiveHint: "no active loop. Start one with `/loop <interval> <prompt>` (e.g. /loop 30s npm test).\nCancels on: /loop stop \xB7 Esc \xB7 /clear /new \xB7 any user-typed prompt.",
|
|
1796
1874
|
loopStarted: '\u25B8 loop started \u2014 re-submitting "{prompt}" every {duration}. Type anything (or /loop stop) to cancel.',
|
|
1797
1875
|
keysNeedsTui: "/keys needs a TUI context (postKeys wired).",
|
|
1876
|
+
aboutHeader: "Reasonix v{version} \u2014 a cache-first DeepSeek coding agent",
|
|
1877
|
+
aboutWebsiteLabel: "Website",
|
|
1878
|
+
aboutRepoLabel: "GitHub ",
|
|
1879
|
+
aboutLicenseLabel: "License",
|
|
1798
1880
|
unknownCommand: "unknown command: /{cmd} \u2014 did you mean {list}?",
|
|
1799
1881
|
unknownCommandShort: "unknown command: /{cmd} (try /help)"
|
|
1800
1882
|
},
|
|
@@ -2002,6 +2084,12 @@ var EN = {
|
|
|
2002
2084
|
statusMcp: " mcp {servers} server(s), {tools} tool(s) in registry",
|
|
2003
2085
|
statusEdits: " edits {count} pending (/apply to commit, /discard to drop)",
|
|
2004
2086
|
statusPlan: " plan ON \u2014 writes gated (submit_plan + approval)",
|
|
2087
|
+
statusLifecycle: " lifecycle {mode}/{state} \xB7 {progress}{evidence}",
|
|
2088
|
+
lifecycleNoPlan: "no plan",
|
|
2089
|
+
lifecycleEvidencePending: "evidence pending",
|
|
2090
|
+
lifecycleRejected: "lifecycle: {tool} blocked in {state} \u2014 next: {next}",
|
|
2091
|
+
lifecycleEvidenceRejected: "lifecycle: step {stepId} needs evidence \u2014 next: {next}",
|
|
2092
|
+
lifecycleRepeatedRejected: "lifecycle: repeated {tool} rejection \u2014 do not retry identical args",
|
|
2005
2093
|
statusModeYolo: " mode YOLO \u2014 edits + shell auto-run with no prompt (/undo still rolls back \xB7 Shift+Tab to flip)",
|
|
2006
2094
|
statusModeAuto: " mode AUTO \u2014 edits apply immediately (u to undo within 5s \xB7 Shift+Tab to flip)",
|
|
2007
2095
|
statusModeReview: " mode review \u2014 edits queue for /apply or y (Shift+Tab to flip)",
|
|
@@ -2112,6 +2200,8 @@ var EN = {
|
|
|
2112
2200
|
usageSearxngUrl: " /search-engine searxng <url> use SearXNG at custom endpoint",
|
|
2113
2201
|
usageMetaso: " /search-engine metaso use Metaso API (100/d free, configure your own API key for more)",
|
|
2114
2202
|
usageTavily: " /search-engine tavily use Tavily API (LLM-friendly, free 1000/mo \u2014 set TAVILY_API_KEY or tavilyApiKey in config; get one at https://tavily.com)",
|
|
2203
|
+
usagePerplexity: " /search-engine perplexity use Perplexity AI (AI-native answer + citations \u2014 set PERPLEXITY_API_KEY or perplexityApiKey in config; get one at https://perplexity.ai/settings/api)",
|
|
2204
|
+
usageExa: " /search-engine exa use Exa API (AI-native answer + citations, free 1000/mo \u2014 set EXA_API_KEY or exaApiKey in config; sign up at https://exa.ai)",
|
|
2115
2205
|
alias: "Alias: /se",
|
|
2116
2206
|
searxngInfo: "SearXNG is a self-hosted metasearch engine (https://github.com/searxng/searxng).",
|
|
2117
2207
|
searxngInstall: "Install it with: docker run -d -p 8080:8080 searxng/searxng",
|
|
@@ -2119,7 +2209,11 @@ var EN = {
|
|
|
2119
2209
|
switchedSearxngNote: " Make sure SearXNG is running at {endpoint}.",
|
|
2120
2210
|
switchedMetasoNote: " There is a daily quota of 100 (configure your own API key for higher limits).",
|
|
2121
2211
|
switchedTavilyNote: " Set TAVILY_API_KEY or `tavilyApiKey` in config; free 1000/mo at https://tavily.com.",
|
|
2122
|
-
|
|
2212
|
+
switchedPerplexityNote: " Set PERPLEXITY_API_KEY or `perplexityApiKey` in config; get one at https://perplexity.ai/settings/api.",
|
|
2213
|
+
switchedExaNote: " Set EXA_API_KEY or `exaApiKey` in config; sign up at https://exa.ai.",
|
|
2214
|
+
keyNeeded: 'No API key configured for "{engine}".\n\n 1. Set the {envVar} environment variable\n 2. Or provide one inline: /search-engine {engine} <your-key>\n 3. Or add "{engine}ApiKey" to ~/.reasonix/config.json\n\nThen retry /search-engine {engine}.',
|
|
2215
|
+
keySaved: " API key saved to config.",
|
|
2216
|
+
confirmed: 'Web search engine set to "{engine}"{detail}. Next assistant turn will pick up the change.',
|
|
2123
2217
|
confirmedDetail: " ({endpoint})"
|
|
2124
2218
|
},
|
|
2125
2219
|
skill: {
|
|
@@ -2166,7 +2260,8 @@ var EN = {
|
|
|
2166
2260
|
evt: " evt",
|
|
2167
2261
|
editsLabel: "edits:",
|
|
2168
2262
|
mcpLoading: "MCP",
|
|
2169
|
-
ctx: "ctx"
|
|
2263
|
+
ctx: "ctx",
|
|
2264
|
+
shortcutsHint: "Ctrl+P shortcuts"
|
|
2170
2265
|
},
|
|
2171
2266
|
editMode: {
|
|
2172
2267
|
plan: "PLAN MODE",
|
|
@@ -2378,27 +2473,38 @@ var EN = {
|
|
|
2378
2473
|
probeFailed: "probe failed \u2014 {message}"
|
|
2379
2474
|
},
|
|
2380
2475
|
webErrors: {
|
|
2381
|
-
status: "web_search {status} \u2014 try: the search backend returned an error; rephrase the query, or switch engine with /search-engine mojeek|searxng",
|
|
2476
|
+
status: "web_search {status} \u2014 try: the search backend returned an error; rephrase the query, or switch engine with /search-engine mojeek|searxng|metaso|tavily|perplexity|exa",
|
|
2382
2477
|
rateLimit429: "web_search 429 \u2014 try: wait 10s before retrying, or rephrase the query; the search backend is rate-limiting this client",
|
|
2383
|
-
forbidden403: "web_search 403 \u2014 try: the search backend is blocking this client; switch engine with /search-engine mojeek|searxng, or wait and retry later",
|
|
2478
|
+
forbidden403: "web_search 403 \u2014 try: the search backend is blocking this client; switch engine with /search-engine mojeek|searxng|metaso|tavily|perplexity|exa, or wait and retry later",
|
|
2384
2479
|
serverError5xx: "web_search {status} \u2014 try: open the search URL in a browser; if it loads this is transient and a retry in 30s may help",
|
|
2385
|
-
mojeekBlocked: "web_search: Mojeek anti-bot page \u2014 rate-limited or blocked \u2014 try: wait 30s and retry, or switch engine with /search-engine searxng",
|
|
2386
|
-
mojeekNoResults: "web_search: 0 results but response doesn't look like a real empty page ({chars} chars, first 120: {preview}) \u2014 try: rephrase the query with simpler terms, or switch engine with /search-engine searxng",
|
|
2480
|
+
mojeekBlocked: "web_search: Mojeek anti-bot page \u2014 rate-limited or blocked \u2014 try: wait 30s and retry, or switch engine with /search-engine mojeek|searxng|metaso|tavily|perplexity|exa",
|
|
2481
|
+
mojeekNoResults: "web_search: 0 results but response doesn't look like a real empty page ({chars} chars, first 120: {preview}) \u2014 try: rephrase the query with simpler terms, or switch engine with /search-engine mojeek|searxng|metaso|tavily|perplexity|exa",
|
|
2387
2482
|
invalidEndpoint: 'web_search: invalid SearXNG endpoint "{endpoint}" \u2014 try: set a valid URL with /search-endpoint http://host:port',
|
|
2388
2483
|
endpointMustBeHttp: "web_search: SearXNG endpoint must be http(s), got {protocol} \u2014 try: set a valid URL with /search-endpoint http://host:port",
|
|
2389
|
-
cannotReach: "web_search: Cannot reach SearXNG server at {endpoint} \u2014 try: install and start SearXNG (https://github.com/searxng/searxng, e.g. `docker run -d -p 8080:8080 searxng/searxng`), or switch to
|
|
2390
|
-
searxngNoResults: "web_search: 0 results but SearXNG response doesn't look like an empty results page ({chars} chars) \u2014 try: rephrase the query with simpler terms, or switch engine with /search-engine mojeek",
|
|
2391
|
-
|
|
2484
|
+
cannotReach: "web_search: Cannot reach SearXNG server at {endpoint} \u2014 try: install and start SearXNG (https://github.com/searxng/searxng, e.g. `docker run -d -p 8080:8080 searxng/searxng`), or switch to another engine with /search-engine mojeek|searxng|metaso|tavily|perplexity|exa",
|
|
2485
|
+
searxngNoResults: "web_search: 0 results but SearXNG response doesn't look like an empty results page ({chars} chars) \u2014 try: rephrase the query with simpler terms, or switch engine with /search-engine mojeek|searxng|metaso|tavily|perplexity|exa",
|
|
2486
|
+
metasoMissingKey: "web_search: Metaso requires an API key \u2014 set METASO_API_KEY or configure one with /search-engine metaso <key>. Get one at https://metaso.cn/search-api/playground",
|
|
2487
|
+
metasoDailyLimit: "web_search: Metaso daily search limit reached \u2014 set METASO_API_KEY or get a key at https://metaso.cn/search-api/playground",
|
|
2392
2488
|
metasoUnauthorized: "web_search: Metaso API key rejected \u2014 check METASO_API_KEY or get one at https://metaso.cn/search-api/playground",
|
|
2393
2489
|
metasoRateLimit: "web_search: Metaso rate-limited \u2014 wait and retry, or get your own API key at https://metaso.cn/search-api/playground",
|
|
2394
|
-
metasoServerError: "web_search: Metaso server error ({status}) \u2014 try again later, or switch engine with /search-engine mojeek",
|
|
2490
|
+
metasoServerError: "web_search: Metaso server error ({status}) \u2014 try again later, or switch engine with /search-engine mojeek|searxng|metaso|tavily|perplexity|exa",
|
|
2395
2491
|
metasoParseError: "web_search: Metaso returned unparseable response (HTTP {status}) \u2014 try again later",
|
|
2396
2492
|
metasoApiError: "web_search: Metaso API error (code {code}: {message}) \u2014 try again later",
|
|
2397
2493
|
tavilyMissingKey: "web_search: Tavily backend requires an API key \u2014 set TAVILY_API_KEY env var or `tavilyApiKey` in ~/.reasonix/config.json; free 1000/mo signup at https://tavily.com",
|
|
2398
2494
|
tavilyUnauthorized: "web_search: Tavily API key rejected \u2014 check TAVILY_API_KEY or get one at https://tavily.com",
|
|
2399
|
-
tavilyRateLimit: "web_search: Tavily rate-limited or monthly quota exceeded \u2014 wait, switch engine with /search-engine mojeek, or upgrade your Tavily plan",
|
|
2400
|
-
tavilyServerError: "web_search: Tavily server error ({status}) \u2014 try again later, or switch engine with /search-engine mojeek",
|
|
2495
|
+
tavilyRateLimit: "web_search: Tavily rate-limited or monthly quota exceeded \u2014 wait, switch engine with /search-engine mojeek|searxng|metaso|tavily|perplexity|exa, or upgrade your Tavily plan",
|
|
2496
|
+
tavilyServerError: "web_search: Tavily server error ({status}) \u2014 try again later, or switch engine with /search-engine mojeek|searxng|metaso|tavily|perplexity|exa",
|
|
2401
2497
|
tavilyParseError: "web_search: Tavily returned unparseable response (HTTP {status}) \u2014 try again later",
|
|
2498
|
+
perplexityMissingKey: "web_search: Perplexity backend requires an API key \u2014 set PERPLEXITY_API_KEY env var or `perplexityApiKey` in ~/.reasonix/config.json; get one at https://perplexity.ai/settings/api",
|
|
2499
|
+
perplexityUnauthorized: "web_search: Perplexity API key rejected \u2014 check PERPLEXITY_API_KEY or get one at https://perplexity.ai/settings/api",
|
|
2500
|
+
perplexityRateLimit: "web_search: Perplexity rate-limited \u2014 wait and retry, or switch engine with /search-engine mojeek|searxng|metaso|tavily|perplexity|exa",
|
|
2501
|
+
perplexityServerError: "web_search: Perplexity server error ({status}) \u2014 try again later, or switch engine with /search-engine mojeek|searxng|metaso|tavily|perplexity|exa",
|
|
2502
|
+
perplexityParseError: "web_search: Perplexity returned unparseable response (HTTP {status}) \u2014 try again later",
|
|
2503
|
+
exaMissingKey: "web_search: Exa backend requires an API key \u2014 set EXA_API_KEY env var or `exaApiKey` in ~/.reasonix/config.json; free 1000/mo signup at https://exa.ai",
|
|
2504
|
+
exaUnauthorized: "web_search: Exa API key rejected \u2014 check EXA_API_KEY or get one at https://exa.ai",
|
|
2505
|
+
exaRateLimit: "web_search: Exa API rate-limited or monthly quota exceeded \u2014 wait or upgrade at https://exa.ai/pricing",
|
|
2506
|
+
exaServerError: "web_search: Exa server error ({status}) \u2014 try again later, or switch engine with /search-engine mojeek|searxng|metaso|tavily|perplexity|exa",
|
|
2507
|
+
exaParseError: "web_search: Exa returned unparseable response (HTTP {status}) \u2014 try again later",
|
|
2402
2508
|
fetchStatus: "web_fetch {status} for {url} \u2014 try: confirm the URL resolves in a browser; status suggests the host returned an error page",
|
|
2403
2509
|
fetchRateLimit429: "web_fetch 429 for {url} \u2014 try: wait 10s before retrying; the host is rate-limiting this client",
|
|
2404
2510
|
fetchForbidden403: "web_fetch 403 for {url} \u2014 try: the host is blocking this client; the page may require login or block bots \u2014 use web_search snippets instead",
|
|
@@ -2566,6 +2672,18 @@ var EN = {
|
|
|
2566
2672
|
serverCount: "{count} server{s}",
|
|
2567
2673
|
footer: "\u2191\u2193 pick \xB7 [r] reconnect \xB7 [d] disable \xB7 esc quit"
|
|
2568
2674
|
},
|
|
2675
|
+
mcpBrowse: {
|
|
2676
|
+
noResources: "No resources on any connected MCP server (or no servers connected). `/mcp` shows the current set.",
|
|
2677
|
+
readOne: "Read one: `/resource <uri>` \u2014 or use Tab in the picker.",
|
|
2678
|
+
noPrompts: "No prompts on any connected MCP server (or no servers connected). `/mcp` shows the current set.",
|
|
2679
|
+
fetchOne: "Fetch one: `/prompt <name>` \u2014 args are not supported yet; prompts with required args will surface an error from the server.",
|
|
2680
|
+
noServerForResource: 'no server exposes resource "{name}"',
|
|
2681
|
+
resourceHint: "`/resource` with no arg lists what's available.",
|
|
2682
|
+
readFailed: "readResource failed",
|
|
2683
|
+
noServerForPrompt: 'no server exposes prompt "{name}"',
|
|
2684
|
+
promptHint: "`/prompt` with no arg lists what's available.",
|
|
2685
|
+
fetchFailed: "getPrompt failed"
|
|
2686
|
+
},
|
|
2569
2687
|
mcpLifecycle: {
|
|
2570
2688
|
handshake: "handshake\u2026",
|
|
2571
2689
|
connected: "connected",
|
|
@@ -2577,7 +2695,9 @@ var EN = {
|
|
|
2577
2695
|
disabledDetail: "via /mcp disable {name}",
|
|
2578
2696
|
failedSetupHint: "\u2192 run `reasonix setup` to remove this entry, or fix the underlying issue (missing npm package, network, etc.).",
|
|
2579
2697
|
failedSetupConfigHint: "\u2192 run `reasonix setup` to remove broken entries from your saved config.",
|
|
2580
|
-
abortedHint: "MCP startup aborted \u2014 {count} server(s) skipped. Run /mcp to retry once you've fixed the underlying issue."
|
|
2698
|
+
abortedHint: "MCP startup aborted \u2014 {count} server(s) skipped. Run /mcp to retry once you've fixed the underlying issue.",
|
|
2699
|
+
toolsReady: "tools ready",
|
|
2700
|
+
warnLabel: "warn"
|
|
2581
2701
|
},
|
|
2582
2702
|
checkpointPicker: {
|
|
2583
2703
|
title: "restore a checkpoint \u2014 {workspace}",
|
|
@@ -2623,6 +2743,41 @@ var EN = {
|
|
|
2623
2743
|
noRecords: "no records",
|
|
2624
2744
|
untracked: "(untracked)",
|
|
2625
2745
|
churned: "(churned \xD7{count})"
|
|
2746
|
+
},
|
|
2747
|
+
builtinSkills: {
|
|
2748
|
+
explore: "Explore the codebase in an isolated subagent \u2014 wide-net read-only investigation that returns one distilled answer. Best for: 'find all places that\u2026', 'how does X work across the project', 'survey the code for Y'.",
|
|
2749
|
+
research: "Research a question by combining web search + code reading in an isolated subagent. Best for: 'is X feature supported by lib Y', 'what\u2019s the canonical way to do Z', 'compare our impl against the spec'.",
|
|
2750
|
+
review: "Review the pending changes (current branch diff by default) in an isolated subagent \u2014 flags correctness, security, missing tests, hidden behavior changes; reports verdict + per-issue file:line. Read-only; the parent decides what to act on.",
|
|
2751
|
+
securityReview: "Security-focused review of the current branch diff in an isolated subagent \u2014 flags injection/authz/secrets/deserialization/path-traversal/crypto issues, severity-tagged. Read-only. Use when shipping changes that touch auth, input parsing, file IO, or external requests.",
|
|
2752
|
+
test: "Run the project\u2019s test suite, diagnose failures, propose SEARCH/REPLACE fixes, re-run until green (or stop after 2 fix attempts on the same failure). Inlined \u2014 runs in the parent loop so you see the edit blocks and can /apply them. Detects npm/pnpm/yarn/pytest/go/cargo."
|
|
2753
|
+
},
|
|
2754
|
+
shortcutsHelp: {
|
|
2755
|
+
title: "Shortcuts",
|
|
2756
|
+
groupInput: "Input",
|
|
2757
|
+
groupNavigation: "Navigation",
|
|
2758
|
+
groupSession: "Session",
|
|
2759
|
+
groupSystem: "System",
|
|
2760
|
+
descEnter: "Send message",
|
|
2761
|
+
descShiftEnter: "New line",
|
|
2762
|
+
descCtrlU: "Clear input",
|
|
2763
|
+
descCtrlW: "Delete word",
|
|
2764
|
+
descCtrlP: "Toggle shortcut panel",
|
|
2765
|
+
descCtrlX: "Open in editor",
|
|
2766
|
+
descArrows: "Input history",
|
|
2767
|
+
descPgUpDown: "Scroll page",
|
|
2768
|
+
descCtrlL: "Clear screen",
|
|
2769
|
+
descCtrlB: "Toggle sidebar",
|
|
2770
|
+
descNewSession: "New session",
|
|
2771
|
+
descListSessions: "List sessions",
|
|
2772
|
+
descSwitchModel: "Switch model",
|
|
2773
|
+
descSwitchPreset: "Switch preset",
|
|
2774
|
+
descSwitchTheme: "Switch theme",
|
|
2775
|
+
descCtrlC: "Quit",
|
|
2776
|
+
descEsc: "Stop / Cancel",
|
|
2777
|
+
descCtrlR: "Toggle verbose",
|
|
2778
|
+
descCtrlO: "Expand stream",
|
|
2779
|
+
descHelp: "Show all commands",
|
|
2780
|
+
descShiftTab: "Switch edit mode"
|
|
2626
2781
|
}
|
|
2627
2782
|
};
|
|
2628
2783
|
|
|
@@ -2796,6 +2951,8 @@ var zhCN = {
|
|
|
2796
2951
|
tipShownOnce: "\u4EC5\u663E\u793A\u4E00\u6B21",
|
|
2797
2952
|
modelOverride: "\u8986\u76D6\u9ED8\u8BA4\u6A21\u578B",
|
|
2798
2953
|
noSession: "\u7981\u7528\u672C\u6B21\u8FD0\u884C\u7684\u4F1A\u8BDD\u6301\u4E45\u5316",
|
|
2954
|
+
noMouseHint: "\u5173\u95ED SGR \u9F20\u6807\u8DDF\u8E2A\uFF1B\u6062\u590D\u7EC8\u7AEF\u539F\u751F\u62D6\u9009\u548C\u53F3\u952E\u884C\u4E3A",
|
|
2955
|
+
noProxyHint: "\u672C\u6B21\u8FD0\u884C\u5FFD\u7565 HTTPS_PROXY / HTTP_PROXY\uFF0C\u76F4\u8FDE",
|
|
2799
2956
|
resumeHint: "\u5F3A\u5236\u6062\u590D\u6307\u5B9A\u4F1A\u8BDD\uFF08\u5373\u4F7F\u7A7A\u95F2\uFF09",
|
|
2800
2957
|
newHint: "\u5F3A\u5236\u521B\u5EFA\u65B0\u4F1A\u8BDD\uFF08\u5FFD\u7565 --session / --continue\uFF09",
|
|
2801
2958
|
transcriptHint: "JSONL \u8F6C\u5F55\u7A3F\u7684\u5199\u5165\u8DEF\u5F84",
|
|
@@ -2940,6 +3097,7 @@ var zhCN = {
|
|
|
2940
3097
|
},
|
|
2941
3098
|
stop: { description: "\u4E2D\u6B62\u5F53\u524D\u6A21\u578B\u56DE\u5408\uFF08\u6309 Esc \u7684\u66FF\u4EE3\u65B9\u5F0F\uFF09" },
|
|
2942
3099
|
feedback: { description: "\u6253\u5F00 GitHub Issue\uFF0C\u8BCA\u65AD\u4FE1\u606F\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F" },
|
|
3100
|
+
about: { description: "\u9879\u76EE\u4FE1\u606F \u2014 \u7248\u672C\u3001\u5B98\u7F51\u3001\u4ED3\u5E93\u3001\u534F\u8BAE" },
|
|
2943
3101
|
plans: { description: "\u5217\u51FA\u6B64\u4F1A\u8BDD\u7684\u6D3B\u8DC3 + \u5F52\u6863\u8BA1\u5212\uFF08\u6700\u65B0\u5728\u524D\uFF09" },
|
|
2944
3102
|
replay: {
|
|
2945
3103
|
description: "\u52A0\u8F7D\u5F52\u6863\u8BA1\u5212\u4E3A\u53EA\u8BFB\u7684\u65F6\u95F4\u65C5\u884C\u5FEB\u7167\uFF08\u9ED8\u8BA4\uFF1A\u6700\u65B0\uFF09",
|
|
@@ -3016,8 +3174,8 @@ var zhCN = {
|
|
|
3016
3174
|
argsHint: "<question>"
|
|
3017
3175
|
},
|
|
3018
3176
|
"search-engine": {
|
|
3019
|
-
description: "\u5207\u6362\u7F51\u7EDC\u641C\u7D22\u540E\u7AEF \u2014 mojeek\uFF08\u9ED8\u8BA4\uFF0C\u65E0\u4F9D\u8D56\uFF09\u3001searxng\uFF08\u81EA\u6258\u7BA1\uFF09\
|
|
3020
|
-
argsHint: "<mojeek|searxng|metaso> [<
|
|
3177
|
+
description: "\u5207\u6362\u7F51\u7EDC\u641C\u7D22\u540E\u7AEF \u2014 mojeek\uFF08\u9ED8\u8BA4\uFF0C\u65E0\u4F9D\u8D56\uFF09\u3001searxng\uFF08\u81EA\u6258\u7BA1\uFF09\u3001metaso\uFF08\u6BCF\u65E5 100 \u6B21\uFF09\u3001tavily\uFF08\u6BCF\u6708 1000 \u6B21\u514D\u8D39\uFF09\u3001perplexity\uFF08AI \u76F4\u63A5\u56DE\u7B54\uFF09\u6216 exa\uFF08AI \u76F4\u63A5\u56DE\u7B54\uFF09",
|
|
3178
|
+
argsHint: "<mojeek|searxng|metaso|tavily|perplexity|exa> [<key>]"
|
|
3021
3179
|
}
|
|
3022
3180
|
},
|
|
3023
3181
|
wizard: {
|
|
@@ -3208,7 +3366,24 @@ var zhCN = {
|
|
|
3208
3366
|
continuingAfter: "\u25B8 \u5728 {label}{counter} \u4E4B\u540E\u7EE7\u7EED",
|
|
3209
3367
|
planStoppedAt: "\u25B8 \u8BA1\u5212\u5728 {label}{counter} \u5904\u505C\u6B62",
|
|
3210
3368
|
revisingAfter: "\u25B8 \u5728 {label} \u4E4B\u540E\u4FEE\u8BA2 \u2014 {feedback}",
|
|
3211
|
-
historyScrollHint: " \u2191 \u6B63\u5728\u67E5\u770B\u5386\u53F2 \xB7 End / PgDn \u8FD4\u56DE\u5E95\u90E8 \xB7 \u2193 \u5411\u4E0B\u6EDA\u52A8\u4E00\u884C"
|
|
3369
|
+
historyScrollHint: " \u2191 \u6B63\u5728\u67E5\u770B\u5386\u53F2 \xB7 End / PgDn \u8FD4\u56DE\u5E95\u90E8 \xB7 \u2193 \u5411\u4E0B\u6EDA\u52A8\u4E00\u884C",
|
|
3370
|
+
editHistoryTitle: "\u7F16\u8F91\u5386\u53F2\uFF08\u4ECE\u65E7\u5230\u65B0\uFF09\uFF1A",
|
|
3371
|
+
editHistoryNoCodeMode: "\u4E0D\u5728\u4EE3\u7801\u6A21\u5F0F\u4E2D",
|
|
3372
|
+
editHistoryNoEdits: "\u6B64\u4F1A\u8BDD\u5C1A\u672A\u8BB0\u5F55\u4EFB\u4F55\u7F16\u8F91",
|
|
3373
|
+
editHistoryNoShowId: "\u7528\u6CD5\uFF1A/show [id] [path] \uFF08\u7701\u7565 id \u67E5\u770B\u6700\u65B0\uFF1Bpath \u6765\u81EA\u6587\u4EF6\u6458\u8981\uFF09",
|
|
3374
|
+
editHistoryIdNotFound: "\u672A\u627E\u5230\u7F16\u8F91 #{id} \u2014 \u8FD0\u884C /history \u67E5\u770B\u6709\u6548 ID",
|
|
3375
|
+
editHistoryLookupFailed: "\u610F\u5916\u9519\u8BEF\uFF1A\u5386\u53F2\u67E5\u627E\u5931\u8D25",
|
|
3376
|
+
editHistoryBatchNoFile: '\u6279\u6B21 #{id} \u4E0D\u5305\u542B "{path}" \u2014 \u6B64\u6279\u6B21\u4E2D\u7684\u6587\u4EF6\uFF1A{files}',
|
|
3377
|
+
editHistoryNoEdits2: "\u6B64\u4F1A\u8BDD\u5C1A\u672A\u8BB0\u5F55\u7F16\u8F91 \u2014 /history \u4E3A\u7A7A",
|
|
3378
|
+
editHistoryStatusApplied: "\u5DF2\u5E94\u7528",
|
|
3379
|
+
editHistoryStatusPartial: "\u90E8\u5206\u5E94\u7528",
|
|
3380
|
+
editHistoryStatusUndone: "\u5DF2\u64A4\u9500",
|
|
3381
|
+
editHistoryHelpShow: "/show <id> \u2192 \u6587\u4EF6\u6458\u8981 \xB7 /show <id> <path> \u2192 \u67D0\u4E2A\u6587\u4EF6\u7684\u5B8C\u6574 diff",
|
|
3382
|
+
editHistoryHelpUndo: "/undo \u2192 \u6700\u65B0\u7684\u672A\u64A4\u9500\u9879 \xB7 /undo <id> [path] \u2192 \u6307\u5B9A\u6279\u6B21\u6216\u6587\u4EF6",
|
|
3383
|
+
editHistoryAlreadyReverted: "\uFF08\u5DF2\u64A4\u9500 \u2014 /history \u663E\u793A\u6279\u6B21\u7EA7\u72B6\u6001\uFF09",
|
|
3384
|
+
editHistoryRevertFile: "/undo {id} {path} \u2192 \u4EC5\u8FD8\u539F\u6B64\u6587\u4EF6",
|
|
3385
|
+
mcpFailed: "MCP {name} \u5931\u8D25",
|
|
3386
|
+
mcpWarn: "MCP {name} \u8B66\u544A"
|
|
3212
3387
|
},
|
|
3213
3388
|
hooks: {
|
|
3214
3389
|
head: "\u94A9\u5B50 {tag} `{cmd}` {decision}{truncTag}",
|
|
@@ -3231,9 +3406,9 @@ var zhCN = {
|
|
|
3231
3406
|
abortedAtIter: "\u5728\u7B2C {iter} \u6B21\u5DE5\u5177\u8C03\u7528\u5904\u4E2D\u65AD \u2014 \u672A\u751F\u6210\u603B\u7ED3\u5373\u505C\u6B62\uFF08\u6309 \u2191 + Enter \u6216 /retry \u6062\u590D\uFF09",
|
|
3232
3407
|
toolUploadStatus: "\u5DE5\u5177\u7ED3\u679C\u5DF2\u4E0A\u4F20 \xB7 \u6A21\u578B\u5728\u751F\u6210\u4E0B\u4E00\u6761\u54CD\u5E94\u524D\u601D\u8003\u4E2D\u2026",
|
|
3233
3408
|
preflightTruncateStatus: "\u9884\u68C0\uFF1A\u4E0A\u4E0B\u6587\u63A5\u8FD1\u4E0A\u9650\uFF0C\u6B63\u5728\u88C1\u526A\u6700\u65E9\u5386\u53F2\u2026",
|
|
3234
|
-
preflightTruncated: "\u9884\u68C0\uFF1A\u8BF7\u6C42\u7EA6 {estimate}/{ctxMax} tokens\uFF08{pct}%\uFF09\u2014 \u5DF2\u88C1\u526A {beforeMessages} \u6761\u6D88\u606F \u2192 {afterMessages}\u3002\u53D1\u9001\u4E2D\u3002",
|
|
3235
|
-
preflightTruncatedStillFull: "\u9884\u68C0\uFF1A\u88C1\u526A {beforeMessages} \u6761\u6D88\u606F \u2192 {afterMessages} \u540E\uFF0C\u8BF7\u6C42\u4ECD\u7EA6 {estimate}/{ctxMax} tokens\uFF08{pct}%\uFF09\u2014 DeepSeek \u5927\u6982\u7387\u4F1A\u8FD4\u56DE 400\u3002\u8BF7\u8FD0\u884C /clear \u6216 /new \u91CD\u65B0\u5F00\u59CB\u3002",
|
|
3236
|
-
preflightNoFold: "\u9884\u68C0\uFF1A\u8BF7\u6C42\u7EA6 {estimate}/{ctxMax} tokens\uFF08{pct}%\uFF09\u4E14\u6CA1\u6709\u53EF\u88C1\u526A\u7684\u5185\u5BB9 \u2014 DeepSeek \u5927\u6982\u7387\u4F1A\u8FD4\u56DE 400\u3002\u8BF7\u8FD0\u884C /clear \u6216 /new \u91CD\u65B0\u5F00\u59CB\u3002",
|
|
3409
|
+
preflightTruncated: "\u9884\u68C0\uFF1A\u8BF7\u6C42\u7EA6 {estimate}/{ctxMax} tokens\uFF08{pct}%\uFF09\xB7 body {bodyKB} KB \u2014 \u5DF2\u88C1\u526A {beforeMessages} \u6761\u6D88\u606F \u2192 {afterMessages}\u3002\u53D1\u9001\u4E2D\u3002",
|
|
3410
|
+
preflightTruncatedStillFull: "\u9884\u68C0\uFF1A\u88C1\u526A {beforeMessages} \u6761\u6D88\u606F \u2192 {afterMessages} \u540E\uFF0C\u8BF7\u6C42\u4ECD\u7EA6 {estimate}/{ctxMax} tokens\uFF08{pct}%\uFF09\xB7 body {bodyKB} KB \u2014 DeepSeek \u5927\u6982\u7387\u4F1A\u8FD4\u56DE 400\u3002\u8BF7\u8FD0\u884C /clear \u6216 /new \u91CD\u65B0\u5F00\u59CB\u3002",
|
|
3411
|
+
preflightNoFold: "\u9884\u68C0\uFF1A\u8BF7\u6C42\u7EA6 {estimate}/{ctxMax} tokens\uFF08{pct}%\uFF09\xB7 body {bodyKB} KB \u4E14\u6CA1\u6709\u53EF\u88C1\u526A\u7684\u5185\u5BB9 \u2014 DeepSeek \u5927\u6982\u7387\u4F1A\u8FD4\u56DE 400\u3002\u8BF7\u8FD0\u884C /clear \u6216 /new \u91CD\u65B0\u5F00\u59CB\u3002",
|
|
3237
3412
|
flashEscalation: "\u21E7 flash \u8BF7\u6C42\u5347\u7EA7 \u2014 \u672C\u8F6E\u6539\u7528 {model}{reasonSuffix}",
|
|
3238
3413
|
harvestStatus: "\u6B63\u5728\u4ECE\u63A8\u7406\u8FC7\u7A0B\u63D0\u53D6\u8BA1\u5212\u72B6\u6001\u2026",
|
|
3239
3414
|
repeatToolCallWarning: "\u62E6\u622A\u5230\u91CD\u590D\u5DE5\u5177\u8C03\u7528 \u2014 \u8BA9\u6A21\u578B\u5BDF\u89C9\u95EE\u9898\u5E76\u6362\u79CD\u65B9\u5F0F\u91CD\u8BD5\u3002",
|
|
@@ -3309,6 +3484,10 @@ var zhCN = {
|
|
|
3309
3484
|
loopNoActiveHint: "\u6CA1\u6709\u6D3B\u52A8\u7684\u5FAA\u73AF\u3002\u4F7F\u7528 `/loop <interval> <prompt>` \u542F\u52A8\u4E00\u4E2A\uFF08\u4F8B\u5982 /loop 30s npm test\uFF09\u3002\n\u53D6\u6D88\u65B9\u5F0F\uFF1A/loop stop \xB7 Esc \xB7 /clear /new \xB7 \u4EFB\u4F55\u7528\u6237\u8F93\u5165\u7684\u63D0\u793A\u3002",
|
|
3310
3485
|
loopStarted: '\u25B8 \u5FAA\u73AF\u5DF2\u542F\u52A8 \u2014 \u6BCF {duration} \u91CD\u65B0\u63D0\u4EA4 "{prompt}"\u3002\u8F93\u5165\u4EFB\u4F55\u5185\u5BB9\uFF08\u6216 /loop stop\uFF09\u53D6\u6D88\u3002',
|
|
3311
3486
|
keysNeedsTui: "/keys \u9700\u8981 TUI \u4E0A\u4E0B\u6587\uFF08postKeys \u5DF2\u8FDE\u63A5\uFF09\u3002",
|
|
3487
|
+
aboutHeader: "Reasonix v{version} \u2014 \u7F13\u5B58\u4F18\u5148\u7684 DeepSeek \u7F16\u7801\u4EE3\u7406",
|
|
3488
|
+
aboutWebsiteLabel: "\u5B98\u7F51",
|
|
3489
|
+
aboutRepoLabel: "\u4ED3\u5E93",
|
|
3490
|
+
aboutLicenseLabel: "\u534F\u8BAE",
|
|
3312
3491
|
unknownCommand: "\u672A\u77E5\u547D\u4EE4\uFF1A/{cmd} \u2014 \u4F60\u662F\u4E0D\u662F\u60F3\u7528 {list}\uFF1F",
|
|
3313
3492
|
unknownCommandShort: "\u672A\u77E5\u547D\u4EE4\uFF1A/{cmd} \uFF08\u8BD5\u8BD5 /help\uFF09"
|
|
3314
3493
|
},
|
|
@@ -3516,6 +3695,12 @@ var zhCN = {
|
|
|
3516
3695
|
statusMcp: " MCP {servers} \u4E2A\u670D\u52A1\u5668\uFF0C\u6CE8\u518C\u8868\u4E2D {tools} \u4E2A\u5DE5\u5177",
|
|
3517
3696
|
statusEdits: " \u7F16\u8F91 {count} \u4E2A\u5F85\u5904\u7406\uFF08/apply \u63D0\u4EA4\uFF0C/discard \u4E22\u5F03\uFF09",
|
|
3518
3697
|
statusPlan: " \u8BA1\u5212 \u5F00\u542F \u2014 \u5199\u5165\u53D7\u9650\uFF08submit_plan + \u5BA1\u6279\uFF09",
|
|
3698
|
+
statusLifecycle: " \u751F\u547D\u5468\u671F {mode}/{state} \xB7 {progress}{evidence}",
|
|
3699
|
+
lifecycleNoPlan: "\u6682\u65E0\u8BA1\u5212",
|
|
3700
|
+
lifecycleEvidencePending: "\u7B49\u5F85 evidence",
|
|
3701
|
+
lifecycleRejected: "lifecycle\uFF1A{tool} \u5728 {state} \u72B6\u6001\u88AB\u62E6\u622A \u2014 \u4E0B\u4E00\u6B65\uFF1A{next}",
|
|
3702
|
+
lifecycleEvidenceRejected: "lifecycle\uFF1A\u6B65\u9AA4 {stepId} \u9700\u8981 evidence \u2014 \u4E0B\u4E00\u6B65\uFF1A{next}",
|
|
3703
|
+
lifecycleRepeatedRejected: "lifecycle\uFF1A{tool} \u88AB\u91CD\u590D\u62E6\u622A \u2014 \u4E0D\u8981\u7528\u76F8\u540C\u53C2\u6570\u53CD\u590D\u91CD\u8BD5",
|
|
3519
3704
|
statusModeYolo: " \u6A21\u5F0F YOLO \u2014 \u7F16\u8F91 + shell \u81EA\u52A8\u8FD0\u884C\uFF0C\u65E0\u63D0\u793A\uFF08/undo \u4ECD\u53EF\u56DE\u6EDA \xB7 Shift+Tab \u5207\u6362\uFF09",
|
|
3520
3705
|
statusModeAuto: " \u6A21\u5F0F AUTO \u2014 \u7F16\u8F91\u7ACB\u5373\u5E94\u7528\uFF085 \u79D2\u5185\u6309 u \u64A4\u6D88 \xB7 Shift+Tab \u5207\u6362\uFF09",
|
|
3521
3706
|
statusModeReview: " \u6A21\u5F0F review \u2014 \u7F16\u8F91\u6392\u961F\u7B49\u5F85 /apply \u6216 y\uFF08Shift+Tab \u5207\u6362\uFF09",
|
|
@@ -3626,6 +3811,8 @@ var zhCN = {
|
|
|
3626
3811
|
usageSearxngUrl: " /search-engine searxng <url> \u4F7F\u7528 SearXNG \u81EA\u5B9A\u4E49\u7AEF\u70B9",
|
|
3627
3812
|
usageMetaso: " /search-engine metaso \u4F7F\u7528 Metaso API\uFF08\u6BCF\u5929 100 \u6B21\u514D\u8D39\uFF0C\u914D\u7F6E\u4F60\u81EA\u5DF1\u7684 API \u5BC6\u94A5\u53EF\u63D0\u5347\u9650\u989D\uFF09",
|
|
3628
3813
|
usageTavily: " /search-engine tavily \u4F7F\u7528 Tavily API\uFF08LLM \u53CB\u597D\uFF0C\u6BCF\u6708 1000 \u6B21\u514D\u8D39 \u2014 \u8BBE\u7F6E TAVILY_API_KEY \u6216 config \u7684 tavilyApiKey\uFF1B\u6CE8\u518C https://tavily.com\uFF09",
|
|
3814
|
+
usagePerplexity: " /search-engine perplexity \u4F7F\u7528 Perplexity AI\uFF08AI \u76F4\u63A5\u56DE\u7B54 + \u5F15\u7528 \u2014 \u8BBE\u7F6E PERPLEXITY_API_KEY \u6216 config \u7684 perplexityApiKey\uFF1B\u5728 https://perplexity.ai/settings/api \u83B7\u53D6\u5BC6\u94A5\uFF09",
|
|
3815
|
+
usageExa: " /search-engine exa \u4F7F\u7528 Exa API\uFF08AI \u76F4\u63A5\u56DE\u7B54 + \u5F15\u7528\uFF0C\u6BCF\u6708 1000 \u6B21\u514D\u8D39 \u2014 \u8BBE\u7F6E EXA_API_KEY \u6216 config \u7684 exaApiKey\uFF1B\u6CE8\u518C https://exa.ai\uFF09",
|
|
3629
3816
|
alias: "\u522B\u540D\uFF1A/se",
|
|
3630
3817
|
searxngInfo: "SearXNG \u662F\u4E00\u4E2A\u81EA\u6258\u7BA1\u7684\u5143\u641C\u7D22\u5F15\u64CE\uFF08https://github.com/searxng/searxng\uFF09\u3002",
|
|
3631
3818
|
searxngInstall: "\u5B89\u88C5\u547D\u4EE4\uFF1A docker run -d -p 8080:8080 searxng/searxng",
|
|
@@ -3633,7 +3820,11 @@ var zhCN = {
|
|
|
3633
3820
|
switchedSearxngNote: " \u8BF7\u786E\u4FDD SearXNG \u5728 {endpoint} \u8FD0\u884C\u3002",
|
|
3634
3821
|
switchedMetasoNote: " \u6BCF\u65E5\u9650\u989D 100 \u6B21\uFF08\u914D\u7F6E\u4F60\u81EA\u5DF1\u7684 API \u5BC6\u94A5\u53EF\u63D0\u5347\u9650\u989D\uFF09\u3002",
|
|
3635
3822
|
switchedTavilyNote: " \u8BF7\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF TAVILY_API_KEY \u6216 config \u4E2D\u7684 `tavilyApiKey`\uFF1Bhttps://tavily.com \u6BCF\u6708 1000 \u6B21\u514D\u8D39\u3002",
|
|
3636
|
-
|
|
3823
|
+
switchedPerplexityNote: " \u8BF7\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF PERPLEXITY_API_KEY \u6216 config \u4E2D\u7684 `perplexityApiKey`\uFF1B\u5728 https://perplexity.ai/settings/api \u83B7\u53D6\u5BC6\u94A5\u3002",
|
|
3824
|
+
switchedExaNote: " \u8BF7\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF EXA_API_KEY \u6216 config \u4E2D\u7684 `exaApiKey`\uFF1B\u6CE8\u518C https://exa.ai\u3002",
|
|
3825
|
+
keyNeeded: '\u672A\u914D\u7F6E "{engine}" \u7684 API \u5BC6\u94A5\u3002\n\n 1. \u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF {envVar}\n 2. \u6216\u5185\u8054\u63D0\u4F9B\uFF1A/search-engine {engine} <your-key>\n 3. \u6216\u5728 ~/.reasonix/config.json \u4E2D\u6DFB\u52A0 "{engine}ApiKey"\n\n\u5B8C\u6210\u540E\u91CD\u65B0\u6267\u884C /search-engine {engine}\u3002',
|
|
3826
|
+
keySaved: " API \u5BC6\u94A5\u5DF2\u4FDD\u5B58\u5230\u914D\u7F6E\u3002",
|
|
3827
|
+
confirmed: '\u7F51\u9875\u641C\u7D22\u5F15\u64CE\u5DF2\u8BBE\u4E3A "{engine}"{detail}\u3002\u4E0B\u4E00\u8F6E\u6A21\u578B\u8C03\u7528\u5C06\u751F\u6548\u3002',
|
|
3637
3828
|
confirmedDetail: "\uFF08{endpoint}\uFF09"
|
|
3638
3829
|
},
|
|
3639
3830
|
skill: {
|
|
@@ -3680,7 +3871,8 @@ var zhCN = {
|
|
|
3680
3871
|
evt: " \u4E8B\u4EF6",
|
|
3681
3872
|
editsLabel: "\u7F16\u8F91:",
|
|
3682
3873
|
mcpLoading: "MCP",
|
|
3683
|
-
ctx: "\u4E0A\u4E0B\u6587"
|
|
3874
|
+
ctx: "\u4E0A\u4E0B\u6587",
|
|
3875
|
+
shortcutsHint: "Ctrl+P \u5FEB\u6377\u952E"
|
|
3684
3876
|
},
|
|
3685
3877
|
editMode: {
|
|
3686
3878
|
plan: "\u8BA1\u5212",
|
|
@@ -3892,27 +4084,38 @@ var zhCN = {
|
|
|
3892
4084
|
probeFailed: "\u63A2\u6D4B\u5931\u8D25 \u2014 {message}"
|
|
3893
4085
|
},
|
|
3894
4086
|
webErrors: {
|
|
3895
|
-
status: "web_search {status} \u2014 try: \u641C\u7D22\u540E\u7AEF\u8FD4\u56DE\u9519\u8BEF\uFF1B\u8BF7\u6539\u5199\u67E5\u8BE2\uFF0C\u6216\u4F7F\u7528 /search-engine mojeek|searxng \u5207\u6362\u5F15\u64CE",
|
|
4087
|
+
status: "web_search {status} \u2014 try: \u641C\u7D22\u540E\u7AEF\u8FD4\u56DE\u9519\u8BEF\uFF1B\u8BF7\u6539\u5199\u67E5\u8BE2\uFF0C\u6216\u4F7F\u7528 /search-engine mojeek|searxng|metaso|tavily|perplexity|exa \u5207\u6362\u5F15\u64CE",
|
|
3896
4088
|
rateLimit429: "web_search 429 \u2014 try: \u7B49\u5F85 10 \u79D2\u540E\u91CD\u8BD5\uFF0C\u6216\u6539\u5199\u67E5\u8BE2\uFF1B\u641C\u7D22\u540E\u7AEF\u6B63\u5728\u5BF9\u8BE5\u5BA2\u6237\u7AEF\u8FDB\u884C\u9650\u6D41",
|
|
3897
|
-
forbidden403: "web_search 403 \u2014 try: \u641C\u7D22\u540E\u7AEF\u62D2\u7EDD\u8BE5\u5BA2\u6237\u7AEF\u8BBF\u95EE\uFF1B\u4F7F\u7528 /search-engine mojeek|searxng \u5207\u6362\u5F15\u64CE\uFF0C\u6216\u7A0D\u540E\u91CD\u8BD5",
|
|
4089
|
+
forbidden403: "web_search 403 \u2014 try: \u641C\u7D22\u540E\u7AEF\u62D2\u7EDD\u8BE5\u5BA2\u6237\u7AEF\u8BBF\u95EE\uFF1B\u4F7F\u7528 /search-engine mojeek|searxng|metaso|tavily|perplexity|exa \u5207\u6362\u5F15\u64CE\uFF0C\u6216\u7A0D\u540E\u91CD\u8BD5",
|
|
3898
4090
|
serverError5xx: "web_search {status} \u2014 try: \u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00\u641C\u7D22 URL\uFF1B\u82E5\u80FD\u52A0\u8F7D\u5219\u5C5E\u4E34\u65F6\u6545\u969C\uFF0C\u7B49 30 \u79D2\u91CD\u8BD5\u5373\u53EF",
|
|
3899
|
-
mojeekBlocked: "web_search: Mojeek \u53CD\u722C\u9875\u9762 \u2014 \u9891\u7387\u9650\u5236\u6216\u88AB\u5C4F\u853D \u2014 try: \u7B49\u5F85 30 \u79D2\u540E\u91CD\u8BD5\uFF0C\u6216\u4F7F\u7528 /search-engine searxng \u5207\u6362\u5F15\u64CE",
|
|
3900
|
-
mojeekNoResults: "web_search: \u8FD4\u56DE 0 \u6761\u7ED3\u679C\u4F46\u54CD\u5E94\u770B\u8D77\u6765\u4E0D\u662F\u6B63\u5E38\u7A7A\u7ED3\u679C\u9875\uFF08{chars} \u5B57\u7B26\uFF0C\u524D 120 \u5B57\u7B26\uFF1A{preview}\uFF09\u2014 try: \u4F7F\u7528\u66F4\u7B80\u5355\u7684\u5173\u952E\u8BCD\u6539\u5199\u67E5\u8BE2\uFF0C\u6216\u4F7F\u7528 /search-engine searxng \u5207\u6362\u5F15\u64CE",
|
|
4091
|
+
mojeekBlocked: "web_search: Mojeek \u53CD\u722C\u9875\u9762 \u2014 \u9891\u7387\u9650\u5236\u6216\u88AB\u5C4F\u853D \u2014 try: \u7B49\u5F85 30 \u79D2\u540E\u91CD\u8BD5\uFF0C\u6216\u4F7F\u7528 /search-engine mojeek|searxng|metaso|tavily|perplexity|exa \u5207\u6362\u5F15\u64CE",
|
|
4092
|
+
mojeekNoResults: "web_search: \u8FD4\u56DE 0 \u6761\u7ED3\u679C\u4F46\u54CD\u5E94\u770B\u8D77\u6765\u4E0D\u662F\u6B63\u5E38\u7A7A\u7ED3\u679C\u9875\uFF08{chars} \u5B57\u7B26\uFF0C\u524D 120 \u5B57\u7B26\uFF1A{preview}\uFF09\u2014 try: \u4F7F\u7528\u66F4\u7B80\u5355\u7684\u5173\u952E\u8BCD\u6539\u5199\u67E5\u8BE2\uFF0C\u6216\u4F7F\u7528 /search-engine mojeek|searxng|metaso|tavily|perplexity|exa \u5207\u6362\u5F15\u64CE",
|
|
3901
4093
|
invalidEndpoint: 'web_search: \u65E0\u6548\u7684 SearXNG \u7AEF\u70B9 "{endpoint}" \u2014 try: \u4F7F\u7528 /search-endpoint http://host:port \u8BBE\u7F6E\u6709\u6548\u7684 URL',
|
|
3902
4094
|
endpointMustBeHttp: "web_search: SearXNG \u7AEF\u70B9\u5FC5\u987B\u662F http(s) \u534F\u8BAE\uFF0C\u5F53\u524D\u4E3A {protocol} \u2014 try: \u4F7F\u7528 /search-endpoint http://host:port \u8BBE\u7F6E\u6709\u6548\u7684 URL",
|
|
3903
|
-
cannotReach: "web_search: \u65E0\u6CD5\u8BBF\u95EE SearXNG \u670D\u52A1\u5668 {endpoint} \u2014 try: \u5B89\u88C5\u5E76\u542F\u52A8 SearXNG\uFF08https://github.com/searxng/searxng\uFF0C\u4F8B\u5982 `docker run -d -p 8080:8080 searxng/searxng`\uFF09\uFF0C\u6216\u4F7F\u7528 /search-engine mojeek \u5207\u6362\
|
|
3904
|
-
searxngNoResults: "web_search: \u8FD4\u56DE 0 \u6761\u7ED3\u679C\u4F46 SearXNG \u54CD\u5E94\u770B\u8D77\u6765\u4E0D\u662F\u6B63\u5E38\u7A7A\u7ED3\u679C\u9875\uFF08{chars} \u5B57\u7B26\uFF09\u2014 try: \u4F7F\u7528\u66F4\u7B80\u5355\u7684\u5173\u952E\u8BCD\u6539\u5199\u67E5\u8BE2\uFF0C\u6216\u4F7F\u7528 /search-engine mojeek \u5207\u6362\u5F15\u64CE",
|
|
3905
|
-
|
|
4095
|
+
cannotReach: "web_search: \u65E0\u6CD5\u8BBF\u95EE SearXNG \u670D\u52A1\u5668 {endpoint} \u2014 try: \u5B89\u88C5\u5E76\u542F\u52A8 SearXNG\uFF08https://github.com/searxng/searxng\uFF0C\u4F8B\u5982 `docker run -d -p 8080:8080 searxng/searxng`\uFF09\uFF0C\u6216\u4F7F\u7528 /search-engine mojeek|searxng|metaso|tavily|perplexity|exa \u5207\u6362\u5F15\u64CE",
|
|
4096
|
+
searxngNoResults: "web_search: \u8FD4\u56DE 0 \u6761\u7ED3\u679C\u4F46 SearXNG \u54CD\u5E94\u770B\u8D77\u6765\u4E0D\u662F\u6B63\u5E38\u7A7A\u7ED3\u679C\u9875\uFF08{chars} \u5B57\u7B26\uFF09\u2014 try: \u4F7F\u7528\u66F4\u7B80\u5355\u7684\u5173\u952E\u8BCD\u6539\u5199\u67E5\u8BE2\uFF0C\u6216\u4F7F\u7528 /search-engine mojeek|searxng|metaso|tavily|perplexity|exa \u5207\u6362\u5F15\u64CE",
|
|
4097
|
+
metasoMissingKey: "web_search: Metaso \u9700\u8981 API \u5BC6\u94A5 \u2014 \u8BBE\u7F6E METASO_API_KEY\uFF0C\u6216\u4F7F\u7528 /search-engine metaso <key> \u914D\u7F6E\uFF1B\u53EF\u5728 https://metaso.cn/search-api/playground \u83B7\u53D6\u5BC6\u94A5",
|
|
4098
|
+
metasoDailyLimit: "web_search: Metaso \u6BCF\u65E5\u641C\u7D22\u6B21\u6570\u5DF2\u8FBE\u4E0A\u9650 \u2014 \u8BBE\u7F6E METASO_API_KEY\uFF0C\u6216\u5728 https://metaso.cn/search-api/playground \u83B7\u53D6\u5BC6\u94A5",
|
|
3906
4099
|
metasoUnauthorized: "web_search: Metaso API \u5BC6\u94A5\u88AB\u62D2\u7EDD \u2014 \u68C0\u67E5 METASO_API_KEY\uFF0C\u6216\u5728 https://metaso.cn/search-api/playground \u83B7\u53D6\u5BC6\u94A5",
|
|
3907
4100
|
metasoRateLimit: "web_search: Metaso \u8BF7\u6C42\u9891\u7387\u9650\u5236 \u2014 \u7B49\u5F85\u540E\u91CD\u8BD5\uFF0C\u6216\u5728 https://metaso.cn/search-api/playground \u83B7\u53D6\u81EA\u5DF1\u7684\u5BC6\u94A5",
|
|
3908
|
-
metasoServerError: "web_search: Metaso \u670D\u52A1\u5668\u9519\u8BEF\uFF08{status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5\uFF0C\u6216\u4F7F\u7528 /search-engine mojeek \u5207\u6362\u5F15\u64CE",
|
|
4101
|
+
metasoServerError: "web_search: Metaso \u670D\u52A1\u5668\u9519\u8BEF\uFF08{status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5\uFF0C\u6216\u4F7F\u7528 /search-engine mojeek|searxng|metaso|tavily|perplexity|exa \u5207\u6362\u5F15\u64CE",
|
|
3909
4102
|
metasoParseError: "web_search: Metaso \u8FD4\u56DE\u65E0\u6CD5\u89E3\u6790\u7684\u54CD\u5E94\uFF08HTTP {status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5",
|
|
3910
4103
|
metasoApiError: "web_search: Metaso API \u9519\u8BEF\uFF08code {code}: {message}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5",
|
|
3911
4104
|
tavilyMissingKey: "web_search: Tavily \u540E\u7AEF\u9700\u8981 API \u5BC6\u94A5 \u2014 \u8BBE\u7F6E TAVILY_API_KEY \u73AF\u5883\u53D8\u91CF\uFF0C\u6216\u5728 ~/.reasonix/config.json \u4E2D\u914D\u7F6E `tavilyApiKey`\uFF1Bhttps://tavily.com \u6BCF\u6708 1000 \u6B21\u514D\u8D39",
|
|
3912
4105
|
tavilyUnauthorized: "web_search: Tavily API \u5BC6\u94A5\u88AB\u62D2\u7EDD \u2014 \u68C0\u67E5 TAVILY_API_KEY\uFF0C\u6216\u5728 https://tavily.com \u83B7\u53D6\u5BC6\u94A5",
|
|
3913
|
-
tavilyRateLimit: "web_search: Tavily \u8BF7\u6C42\u9891\u7387\u9650\u5236\u6216\u6708\u5EA6\u914D\u989D\u7528\u5C3D \u2014 \u7B49\u5F85\u3001\u7528 /search-engine mojeek \u5207\u6362\u5F15\u64CE\uFF0C\u6216\u5347\u7EA7 Tavily \u8BA1\u5212",
|
|
3914
|
-
tavilyServerError: "web_search: Tavily \u670D\u52A1\u5668\u9519\u8BEF\uFF08{status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5\uFF0C\u6216\u4F7F\u7528 /search-engine mojeek \u5207\u6362\u5F15\u64CE",
|
|
4106
|
+
tavilyRateLimit: "web_search: Tavily \u8BF7\u6C42\u9891\u7387\u9650\u5236\u6216\u6708\u5EA6\u914D\u989D\u7528\u5C3D \u2014 \u7B49\u5F85\u3001\u7528 /search-engine mojeek|searxng|metaso|tavily|perplexity|exa \u5207\u6362\u5F15\u64CE\uFF0C\u6216\u5347\u7EA7 Tavily \u8BA1\u5212",
|
|
4107
|
+
tavilyServerError: "web_search: Tavily \u670D\u52A1\u5668\u9519\u8BEF\uFF08{status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5\uFF0C\u6216\u4F7F\u7528 /search-engine mojeek|searxng|metaso|tavily|perplexity|exa \u5207\u6362\u5F15\u64CE",
|
|
3915
4108
|
tavilyParseError: "web_search: Tavily \u8FD4\u56DE\u65E0\u6CD5\u89E3\u6790\u7684\u54CD\u5E94\uFF08HTTP {status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5",
|
|
4109
|
+
perplexityMissingKey: "web_search: Perplexity \u540E\u7AEF\u9700\u8981 API \u5BC6\u94A5 \u2014 \u8BBE\u7F6E PERPLEXITY_API_KEY \u73AF\u5883\u53D8\u91CF\uFF0C\u6216\u5728 ~/.reasonix/config.json \u4E2D\u914D\u7F6E `perplexityApiKey`\uFF1B\u5728 https://perplexity.ai/settings/api \u83B7\u53D6\u5BC6\u94A5",
|
|
4110
|
+
perplexityUnauthorized: "web_search: Perplexity API \u5BC6\u94A5\u88AB\u62D2\u7EDD \u2014 \u68C0\u67E5 PERPLEXITY_API_KEY\uFF0C\u6216\u5728 https://perplexity.ai/settings/api \u83B7\u53D6\u5BC6\u94A5",
|
|
4111
|
+
perplexityRateLimit: "web_search: Perplexity \u8BF7\u6C42\u9891\u7387\u9650\u5236 \u2014 \u7B49\u5F85\u540E\u91CD\u8BD5\uFF0C\u6216\u4F7F\u7528 /search-engine mojeek|searxng|metaso|tavily|perplexity|exa \u5207\u6362\u5F15\u64CE",
|
|
4112
|
+
perplexityServerError: "web_search: Perplexity \u670D\u52A1\u5668\u9519\u8BEF\uFF08{status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5\uFF0C\u6216\u4F7F\u7528 /search-engine mojeek|searxng|metaso|tavily|perplexity|exa \u5207\u6362\u5F15\u64CE",
|
|
4113
|
+
perplexityParseError: "web_search: Perplexity \u8FD4\u56DE\u65E0\u6CD5\u89E3\u6790\u7684\u54CD\u5E94\uFF08HTTP {status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5",
|
|
4114
|
+
exaMissingKey: "web_search: Exa \u540E\u7AEF\u9700\u8981 API \u5BC6\u94A5 \u2014 \u8BBE\u7F6E EXA_API_KEY \u73AF\u5883\u53D8\u91CF\uFF0C\u6216\u5728 ~/.reasonix/config.json \u4E2D\u914D\u7F6E `exaApiKey`\uFF1Bhttps://exa.ai \u6BCF\u6708 1000 \u6B21\u514D\u8D39",
|
|
4115
|
+
exaUnauthorized: "web_search: Exa API \u5BC6\u94A5\u88AB\u62D2\u7EDD \u2014 \u68C0\u67E5 EXA_API_KEY\uFF0C\u6216\u5728 https://exa.ai \u83B7\u53D6\u5BC6\u94A5",
|
|
4116
|
+
exaRateLimit: "web_search: Exa \u8BF7\u6C42\u9891\u7387\u9650\u5236\u6216\u6708\u5EA6\u914D\u989D\u7528\u5C3D \u2014 \u7B49\u5F85\u5347\u7EA7\uFF0C\u6216\u5728 https://exa.ai/pricing \u67E5\u770B\u8BA1\u5212",
|
|
4117
|
+
exaServerError: "web_search: Exa \u670D\u52A1\u5668\u9519\u8BEF\uFF08{status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5\uFF0C\u6216\u4F7F\u7528 /search-engine mojeek|searxng|metaso|tavily|perplexity|exa \u5207\u6362\u5F15\u64CE",
|
|
4118
|
+
exaParseError: "web_search: Exa \u8FD4\u56DE\u65E0\u6CD5\u89E3\u6790\u7684\u54CD\u5E94\uFF08HTTP {status}\uFF09\u2014 \u7A0D\u540E\u91CD\u8BD5",
|
|
3916
4119
|
fetchStatus: "web_fetch {status} for {url} \u2014 try: \u5728\u6D4F\u89C8\u5668\u4E2D\u786E\u8BA4\u8BE5 URL \u80FD\u5426\u8BBF\u95EE\uFF1B\u8BE5\u72B6\u6001\u7801\u8868\u660E\u76EE\u6807\u4E3B\u673A\u8FD4\u56DE\u4E86\u9519\u8BEF\u9875\u9762",
|
|
3917
4120
|
fetchRateLimit429: "web_fetch 429 for {url} \u2014 try: \u7B49\u5F85 10 \u79D2\u540E\u91CD\u8BD5\uFF1B\u76EE\u6807\u4E3B\u673A\u6B63\u5728\u5BF9\u8BE5\u5BA2\u6237\u7AEF\u8FDB\u884C\u9650\u6D41",
|
|
3918
4121
|
fetchForbidden403: "web_fetch 403 for {url} \u2014 try: \u76EE\u6807\u4E3B\u673A\u62D2\u7EDD\u8BE5\u5BA2\u6237\u7AEF\u8BBF\u95EE\uFF1B\u8BE5\u9875\u9762\u53EF\u80FD\u9700\u8981\u767B\u5F55\u6216\u5C4F\u853D\u722C\u866B \u2014 \u6539\u7528 web_search \u6458\u8981",
|
|
@@ -4080,6 +4283,18 @@ var zhCN = {
|
|
|
4080
4283
|
serverCount: "{count} \u4E2A\u670D\u52A1\u5668",
|
|
4081
4284
|
footer: "\u2191\u2193 \u9009\u62E9 \xB7 [r] \u91CD\u8FDE \xB7 [d] \u7981\u7528 \xB7 Esc \u9000\u51FA"
|
|
4082
4285
|
},
|
|
4286
|
+
mcpBrowse: {
|
|
4287
|
+
noResources: "\u6CA1\u6709\u4EFB\u4F55\u5DF2\u8FDE\u63A5 MCP \u670D\u52A1\u5668\u4E0A\u7684\u8D44\u6E90\uFF08\u6216\u65E0\u670D\u52A1\u5668\u8FDE\u63A5\uFF09\u3002`/mcp` \u663E\u793A\u5F53\u524D\u5217\u8868\u3002",
|
|
4288
|
+
readOne: "\u8BFB\u53D6\uFF1A`/resource <uri>` \u2014 \u6216\u5728\u9009\u62E9\u5668\u4E2D\u4F7F\u7528 Tab \u952E\u3002",
|
|
4289
|
+
noPrompts: "\u6CA1\u6709\u4EFB\u4F55\u5DF2\u8FDE\u63A5 MCP \u670D\u52A1\u5668\u4E0A\u7684\u63D0\u793A\uFF08\u6216\u65E0\u670D\u52A1\u5668\u8FDE\u63A5\uFF09\u3002`/mcp` \u663E\u793A\u5F53\u524D\u5217\u8868\u3002",
|
|
4290
|
+
fetchOne: "\u83B7\u53D6\uFF1A`/prompt <name>` \u2014 \u6682\u4E0D\u652F\u6301\u53C2\u6570\uFF1B\u5E26\u5FC5\u9700\u53C2\u6570\u7684\u63D0\u793A\u5C06\u8FD4\u56DE\u670D\u52A1\u5668\u9519\u8BEF\u3002",
|
|
4291
|
+
noServerForResource: '\u6CA1\u6709\u670D\u52A1\u5668\u66B4\u9732\u8D44\u6E90 "{name}"',
|
|
4292
|
+
resourceHint: "`/resource` \u4E0D\u5E26\u53C2\u6570\u53EF\u67E5\u770B\u53EF\u7528\u5217\u8868\u3002",
|
|
4293
|
+
readFailed: "\u8BFB\u53D6\u8D44\u6E90\u5931\u8D25",
|
|
4294
|
+
noServerForPrompt: '\u6CA1\u6709\u670D\u52A1\u5668\u66B4\u9732 prompt "{name}"',
|
|
4295
|
+
promptHint: "`/prompt` \u4E0D\u5E26\u53C2\u6570\u53EF\u67E5\u770B\u53EF\u7528\u5217\u8868\u3002",
|
|
4296
|
+
fetchFailed: "\u83B7\u53D6 prompt \u5931\u8D25"
|
|
4297
|
+
},
|
|
4083
4298
|
mcpLifecycle: {
|
|
4084
4299
|
handshake: "\u63E1\u624B\u4E2D\u2026",
|
|
4085
4300
|
connected: "\u5DF2\u8FDE\u63A5",
|
|
@@ -4091,7 +4306,9 @@ var zhCN = {
|
|
|
4091
4306
|
disabledDetail: "\u901A\u8FC7 /mcp disable {name}",
|
|
4092
4307
|
failedSetupHint: "\u2192 \u8FD0\u884C `reasonix setup` \u79FB\u9664\u6B64\u6761\u76EE\uFF0C\u6216\u4FEE\u590D\u5E95\u5C42\u95EE\u9898\uFF08\u7F3A\u5C11 npm \u5305\u3001\u7F51\u7EDC\u7B49\uFF09\u3002",
|
|
4093
4308
|
failedSetupConfigHint: "\u2192 \u8FD0\u884C `reasonix setup` \u4ECE\u5DF2\u4FDD\u5B58\u914D\u7F6E\u4E2D\u79FB\u9664\u635F\u574F\u7684\u6761\u76EE\u3002",
|
|
4094
|
-
abortedHint: "\u5DF2\u4E2D\u65AD MCP \u542F\u52A8 \u2014 \u8DF3\u8FC7 {count} \u4E2A\u670D\u52A1\u5668\u3002\u95EE\u9898\u4FEE\u590D\u540E\u7528 /mcp \u91CD\u65B0\u8FDE\u63A5\u3002"
|
|
4309
|
+
abortedHint: "\u5DF2\u4E2D\u65AD MCP \u542F\u52A8 \u2014 \u8DF3\u8FC7 {count} \u4E2A\u670D\u52A1\u5668\u3002\u95EE\u9898\u4FEE\u590D\u540E\u7528 /mcp \u91CD\u65B0\u8FDE\u63A5\u3002",
|
|
4310
|
+
toolsReady: "\u5DE5\u5177\u5C31\u7EEA",
|
|
4311
|
+
warnLabel: "\u8B66\u544A"
|
|
4095
4312
|
},
|
|
4096
4313
|
checkpointPicker: {
|
|
4097
4314
|
title: "\u6062\u590D\u68C0\u67E5\u70B9 \u2014 {workspace}",
|
|
@@ -4137,6 +4354,41 @@ var zhCN = {
|
|
|
4137
4354
|
noRecords: "\u65E0\u8BB0\u5F55",
|
|
4138
4355
|
untracked: "\uFF08\u672A\u8FFD\u8E2A\uFF09",
|
|
4139
4356
|
churned: "\uFF08\u5DF2\u53D8\u66F4 \xD7{count}\uFF09"
|
|
4357
|
+
},
|
|
4358
|
+
builtinSkills: {
|
|
4359
|
+
explore: "\u5728\u9694\u79BB\u5B50 agent \u4E2D\u63A2\u7D22\u4EE3\u7801\u5E93 \u2014 \u53EA\u8BFB\u5BBD\u7F51\u8C03\u67E5\uFF0C\u8FD4\u56DE\u4E00\u4E2A\u7CBE\u70BC\u7ED3\u8BBA",
|
|
4360
|
+
research: "\u7ED3\u5408\u4EE3\u7801\u9605\u8BFB\u4E0E\u7F51\u7EDC\u641C\u7D22\u8FDB\u884C\u8C03\u7814 \u2014 \u5728\u9694\u79BB\u5B50 agent \u4E2D\u7EFC\u5408\u4FE1\u606F\u5E76\u8FD4\u56DE\u7ED3\u8BBA",
|
|
4361
|
+
review: "\u5BA1\u67E5\u5F53\u524D\u5206\u652F\u53D8\u66F4 \u2014 \u68C0\u67E5\u6B63\u786E\u6027\u3001\u5B89\u5168\u6027\u3001\u7F3A\u5931\u6D4B\u8BD5\u3001\u9690\u85CF\u884C\u4E3A\u53D8\u66F4",
|
|
4362
|
+
securityReview: "\u5B89\u5168\u4E13\u9879\u5BA1\u67E5 \u2014 \u6807\u8BB0\u6CE8\u5165/\u8BA4\u8BC1/\u5BC6\u94A5/\u53CD\u5E8F\u5217\u5316/\u8DEF\u5F84\u7A7F\u8D8A/\u52A0\u5BC6\u95EE\u9898",
|
|
4363
|
+
test: "\u8FD0\u884C\u6D4B\u8BD5\u5957\u4EF6\u5E76\u8BCA\u65AD\u5931\u8D25 \u2014 \u81EA\u52A8\u8BC6\u522B\u6D4B\u8BD5\u6846\u67B6\uFF0C\u4FEE\u590D\u540E\u91CD\u8DD1\u76F4\u81F3\u901A\u8FC7"
|
|
4364
|
+
},
|
|
4365
|
+
shortcutsHelp: {
|
|
4366
|
+
title: "\u5FEB\u6377\u952E",
|
|
4367
|
+
groupInput: "\u8F93\u5165",
|
|
4368
|
+
groupNavigation: "\u5BFC\u822A",
|
|
4369
|
+
groupSession: "\u4F1A\u8BDD",
|
|
4370
|
+
groupSystem: "\u7CFB\u7EDF",
|
|
4371
|
+
descEnter: "\u53D1\u9001\u6D88\u606F",
|
|
4372
|
+
descShiftEnter: "\u6362\u884C",
|
|
4373
|
+
descCtrlU: "\u6E05\u7A7A\u8F93\u5165",
|
|
4374
|
+
descCtrlW: "\u5220\u9664\u5355\u8BCD",
|
|
4375
|
+
descCtrlP: "\u6253\u5F00/\u5173\u95ED\u5FEB\u6377\u952E\u9762\u677F",
|
|
4376
|
+
descCtrlX: "\u5728\u7F16\u8F91\u5668\u4E2D\u6253\u5F00",
|
|
4377
|
+
descArrows: "\u6D4F\u89C8\u8F93\u5165\u5386\u53F2",
|
|
4378
|
+
descPgUpDown: "\u7FFB\u9875",
|
|
4379
|
+
descCtrlL: "\u6E05\u5C4F",
|
|
4380
|
+
descCtrlB: "\u5207\u6362\u4FA7\u8FB9\u680F",
|
|
4381
|
+
descNewSession: "\u65B0\u5EFA\u4F1A\u8BDD",
|
|
4382
|
+
descListSessions: "\u5217\u51FA\u4F1A\u8BDD",
|
|
4383
|
+
descSwitchModel: "\u5207\u6362\u6A21\u578B",
|
|
4384
|
+
descSwitchPreset: "\u5207\u6362\u9884\u8BBE",
|
|
4385
|
+
descSwitchTheme: "\u5207\u6362\u4E3B\u9898",
|
|
4386
|
+
descCtrlC: "\u9000\u51FA",
|
|
4387
|
+
descEsc: "\u505C\u6B62/\u53D6\u6D88",
|
|
4388
|
+
descCtrlR: "\u5207\u6362\u8BE6\u7EC6\u6A21\u5F0F",
|
|
4389
|
+
descCtrlO: "\u5C55\u5F00\u6D41\u5F0F\u8F93\u51FA",
|
|
4390
|
+
descHelp: "\u663E\u793A\u6240\u6709\u547D\u4EE4",
|
|
4391
|
+
descShiftTab: "\u5207\u6362\u7F16\u8F91\u6A21\u5F0F"
|
|
4140
4392
|
}
|
|
4141
4393
|
};
|
|
4142
4394
|
|
|
@@ -4212,7 +4464,7 @@ function readSettingsFile(path2) {
|
|
|
4212
4464
|
}
|
|
4213
4465
|
function loadHooks(opts = {}) {
|
|
4214
4466
|
const out = [];
|
|
4215
|
-
if (opts.projectRoot) {
|
|
4467
|
+
if (opts.projectRoot && (opts.trustProjectHooks === true || projectHooksTrusted(opts.projectRoot, opts.configPath))) {
|
|
4216
4468
|
const projPath = projectSettingsPath(opts.projectRoot);
|
|
4217
4469
|
const settings2 = readSettingsFile(projPath);
|
|
4218
4470
|
if (settings2) appendResolved(out, settings2, "project", projPath);
|
|
@@ -4826,8 +5078,8 @@ var ToolRegistry = class {
|
|
|
4826
5078
|
_resultAugmenter = null;
|
|
4827
5079
|
/** Per-tool fingerprint of the last call that failed schema validation. Cleared by any successful validation for that tool. */
|
|
4828
5080
|
_lastMalformed = /* @__PURE__ */ new Map();
|
|
4829
|
-
/** Per-tool fingerprint of the last host-side
|
|
4830
|
-
|
|
5081
|
+
/** Per-tool fingerprint of the last host-side gate rejection. */
|
|
5082
|
+
_lastGateRejection = /* @__PURE__ */ new Map();
|
|
4831
5083
|
constructor(opts = {}) {
|
|
4832
5084
|
this._autoFlatten = opts.autoFlatten !== false;
|
|
4833
5085
|
}
|
|
@@ -4914,20 +5166,21 @@ var ToolRegistry = class {
|
|
|
4914
5166
|
if (!tool) {
|
|
4915
5167
|
return JSON.stringify({ error: `unknown tool: ${name}` });
|
|
4916
5168
|
}
|
|
4917
|
-
const
|
|
5169
|
+
const rawFingerprint = rawFingerprintArgs(argumentsRaw);
|
|
4918
5170
|
let args;
|
|
4919
5171
|
try {
|
|
4920
5172
|
args = typeof argumentsRaw === "string" ? argumentsRaw.trim() ? JSON.parse(argumentsRaw) ?? {} : {} : argumentsRaw ?? {};
|
|
4921
5173
|
} catch (err) {
|
|
4922
5174
|
return this._noteMalformed(
|
|
4923
5175
|
name,
|
|
4924
|
-
|
|
5176
|
+
rawFingerprint,
|
|
4925
5177
|
`invalid tool arguments JSON: ${err.message}`
|
|
4926
5178
|
);
|
|
4927
5179
|
}
|
|
4928
5180
|
if (tool.flatSchema && args && typeof args === "object" && hasDotKey(args)) {
|
|
4929
5181
|
args = nestArguments(args);
|
|
4930
5182
|
}
|
|
5183
|
+
const fingerprint = fingerprintArgs(args);
|
|
4931
5184
|
const missing = tool.parameters ? missingRequiredParam(tool.parameters, args) : null;
|
|
4932
5185
|
if (missing) {
|
|
4933
5186
|
return this._noteMalformed(
|
|
@@ -4948,7 +5201,7 @@ var ToolRegistry = class {
|
|
|
4948
5201
|
try {
|
|
4949
5202
|
const short = await interceptor(name, args);
|
|
4950
5203
|
if (typeof short === "string") {
|
|
4951
|
-
const guarded = this.
|
|
5204
|
+
const guarded = this._noteGateRejection(name, fingerprint, short);
|
|
4952
5205
|
return this._augmentResult(name, args, guarded);
|
|
4953
5206
|
}
|
|
4954
5207
|
} catch (err) {
|
|
@@ -4957,7 +5210,6 @@ var ToolRegistry = class {
|
|
|
4957
5210
|
});
|
|
4958
5211
|
}
|
|
4959
5212
|
}
|
|
4960
|
-
this._lastInterceptorRejection.delete(name);
|
|
4961
5213
|
if (opts.signal?.aborted) {
|
|
4962
5214
|
return JSON.stringify({
|
|
4963
5215
|
error: `${name}: aborted before dispatch (user interrupt)`,
|
|
@@ -4995,6 +5247,7 @@ var ToolRegistry = class {
|
|
|
4995
5247
|
finalResult = JSON.stringify({ error: `${e.name}: ${e.message}` });
|
|
4996
5248
|
}
|
|
4997
5249
|
}
|
|
5250
|
+
finalResult = this._noteGateRejection(name, fingerprint, finalResult);
|
|
4998
5251
|
return this._augmentResult(name, args, finalResult);
|
|
4999
5252
|
}
|
|
5000
5253
|
_augmentResult(name, args, result) {
|
|
@@ -5018,18 +5271,18 @@ var ToolRegistry = class {
|
|
|
5018
5271
|
}
|
|
5019
5272
|
return JSON.stringify({ error: `${name}: ${detail}` });
|
|
5020
5273
|
}
|
|
5021
|
-
|
|
5022
|
-
const reason = rejectedReason(result);
|
|
5274
|
+
_noteGateRejection(name, fingerprint, result) {
|
|
5275
|
+
const reason = rejectedReason(name, result);
|
|
5023
5276
|
if (!reason) {
|
|
5024
|
-
this.
|
|
5277
|
+
this._lastGateRejection.delete(name);
|
|
5025
5278
|
return result;
|
|
5026
5279
|
}
|
|
5027
5280
|
const key = `${reason}:${fingerprint}`;
|
|
5028
|
-
const prev = this.
|
|
5029
|
-
this.
|
|
5281
|
+
const prev = this._lastGateRejection.get(name);
|
|
5282
|
+
this._lastGateRejection.set(name, key);
|
|
5030
5283
|
if (prev === key) {
|
|
5031
5284
|
return JSON.stringify({
|
|
5032
|
-
error: `${name}: same call was just rejected by ${reason} \u2014 do not retry identical args.
|
|
5285
|
+
error: `${name}: same call was just rejected by ${reason} \u2014 do not retry identical args. ${rejectionRecoveryHint(reason)}`,
|
|
5033
5286
|
rejectedReason: reason,
|
|
5034
5287
|
consecutiveInterceptorRejection: true
|
|
5035
5288
|
});
|
|
@@ -5037,16 +5290,44 @@ var ToolRegistry = class {
|
|
|
5037
5290
|
return result;
|
|
5038
5291
|
}
|
|
5039
5292
|
};
|
|
5040
|
-
function rejectedReason(result) {
|
|
5293
|
+
function rejectedReason(name, result) {
|
|
5294
|
+
const textReason = plainTextRejectedReason(name, result);
|
|
5295
|
+
if (textReason) return textReason;
|
|
5041
5296
|
try {
|
|
5042
5297
|
const parsed = JSON.parse(result);
|
|
5043
5298
|
if (!parsed || typeof parsed !== "object") return null;
|
|
5044
5299
|
const reason = parsed.rejectedReason;
|
|
5045
|
-
|
|
5300
|
+
if (typeof reason === "string" && reason) return reason;
|
|
5301
|
+
const error = parsed.error;
|
|
5302
|
+
if (typeof error === "string") return plainTextRejectedReason(name, error);
|
|
5303
|
+
return null;
|
|
5046
5304
|
} catch {
|
|
5047
5305
|
return null;
|
|
5048
5306
|
}
|
|
5049
5307
|
}
|
|
5308
|
+
function plainTextRejectedReason(name, result) {
|
|
5309
|
+
if ((name === "edit_file" || name === "write_file") && /rejected this edit/i.test(result)) {
|
|
5310
|
+
return "edit-gate";
|
|
5311
|
+
}
|
|
5312
|
+
if ((name === "run_command" || name === "run_background") && /\buser denied:/i.test(result)) {
|
|
5313
|
+
return "shell-gate";
|
|
5314
|
+
}
|
|
5315
|
+
return null;
|
|
5316
|
+
}
|
|
5317
|
+
function rejectionRecoveryHint(reason) {
|
|
5318
|
+
switch (reason) {
|
|
5319
|
+
case "edit-gate":
|
|
5320
|
+
return "Do not re-emit the same edit. Try a genuinely different edit or ask the user how to proceed.";
|
|
5321
|
+
case "shell-gate":
|
|
5322
|
+
return "Do not retry the same command. Use an allowlisted/read-only command, wait for approval, or ask the user how to proceed.";
|
|
5323
|
+
case "engineering-lifecycle":
|
|
5324
|
+
return "Switch to read-only exploration, submit or revise the plan, or choose a different tool call.";
|
|
5325
|
+
case "engineering-lifecycle-evidence":
|
|
5326
|
+
return "Submit completion evidence or revise/checkpoint the plan before marking the step complete.";
|
|
5327
|
+
default:
|
|
5328
|
+
return "Choose a different tool call or ask the user how to proceed.";
|
|
5329
|
+
}
|
|
5330
|
+
}
|
|
5050
5331
|
function isReadOnlyCall(tool, args) {
|
|
5051
5332
|
if (tool.readOnlyCheck) {
|
|
5052
5333
|
try {
|
|
@@ -5065,14 +5346,27 @@ function hasDotKey(obj) {
|
|
|
5065
5346
|
}
|
|
5066
5347
|
return false;
|
|
5067
5348
|
}
|
|
5068
|
-
function
|
|
5349
|
+
function rawFingerprintArgs(argumentsRaw) {
|
|
5069
5350
|
if (typeof argumentsRaw === "string") return argumentsRaw;
|
|
5351
|
+
return fingerprintArgs(argumentsRaw);
|
|
5352
|
+
}
|
|
5353
|
+
function fingerprintArgs(args) {
|
|
5070
5354
|
try {
|
|
5071
|
-
return JSON.stringify(
|
|
5355
|
+
return JSON.stringify(sortJson(args));
|
|
5072
5356
|
} catch {
|
|
5073
5357
|
return "";
|
|
5074
5358
|
}
|
|
5075
5359
|
}
|
|
5360
|
+
function sortJson(value) {
|
|
5361
|
+
if (Array.isArray(value)) return value.map(sortJson);
|
|
5362
|
+
if (!value || typeof value !== "object") return value;
|
|
5363
|
+
const out = {};
|
|
5364
|
+
for (const key of Object.keys(value).sort()) {
|
|
5365
|
+
const item = value[key];
|
|
5366
|
+
if (item !== void 0) out[key] = sortJson(item);
|
|
5367
|
+
}
|
|
5368
|
+
return out;
|
|
5369
|
+
}
|
|
5076
5370
|
function missingRequiredParam(schema, args) {
|
|
5077
5371
|
const required = schema.required;
|
|
5078
5372
|
if (!required || required.length === 0) return null;
|
|
@@ -5732,14 +6026,16 @@ function round(n, digits) {
|
|
|
5732
6026
|
}
|
|
5733
6027
|
|
|
5734
6028
|
// src/context-manager.ts
|
|
5735
|
-
var HISTORY_FOLD_THRESHOLD = 0.
|
|
6029
|
+
var HISTORY_FOLD_THRESHOLD = 0.75;
|
|
5736
6030
|
var HISTORY_FOLD_TAIL_FRACTION = 0.2;
|
|
5737
|
-
var HISTORY_FOLD_AGGRESSIVE_THRESHOLD = 0.
|
|
6031
|
+
var HISTORY_FOLD_AGGRESSIVE_THRESHOLD = 0.78;
|
|
5738
6032
|
var HISTORY_FOLD_AGGRESSIVE_TAIL_FRACTION = 0.1;
|
|
5739
6033
|
var HISTORY_FOLD_MIN_SAVINGS_FRACTION = 0.3;
|
|
5740
6034
|
var FORCE_SUMMARY_THRESHOLD = 0.8;
|
|
5741
6035
|
var PREFLIGHT_EMERGENCY_THRESHOLD = 0.95;
|
|
5742
6036
|
var PREFLIGHT_MECHANICAL_TARGET_FRACTION = 0.7;
|
|
6037
|
+
var MAX_BODY_BYTES = 7e5;
|
|
6038
|
+
var MAX_BODY_BYTES_TARGET = 5e5;
|
|
5743
6039
|
var HISTORY_FOLD_SUMMARY_TIMEOUT_MS = 15e3;
|
|
5744
6040
|
var HISTORY_FOLD_MARKER = "[CONVERSATION HISTORY SUMMARY \u2014 earlier turns folded for context efficiency]\n\n";
|
|
5745
6041
|
var SKILL_PIN_MEMO_HEADER = "[Active skill memos \u2014 preserved verbatim across the fold:]";
|
|
@@ -5764,6 +6060,20 @@ var ContextManager = class {
|
|
|
5764
6060
|
this.deps = deps;
|
|
5765
6061
|
}
|
|
5766
6062
|
deps;
|
|
6063
|
+
/** Real-time token count of the current log — used by Desktop to refresh the
|
|
6064
|
+
* context meter after /compact when no API usage event is available. */
|
|
6065
|
+
getLogTokens() {
|
|
6066
|
+
const entries = this.deps.log.toMessages();
|
|
6067
|
+
let total = 0;
|
|
6068
|
+
for (const e of entries) {
|
|
6069
|
+
const content = typeof e.content === "string" ? e.content : "";
|
|
6070
|
+
total += countTokensBounded(content);
|
|
6071
|
+
if (e.role === "assistant" && Array.isArray(e.tool_calls) && e.tool_calls.length > 0) {
|
|
6072
|
+
total += countTokensBounded(JSON.stringify(e.tool_calls));
|
|
6073
|
+
}
|
|
6074
|
+
}
|
|
6075
|
+
return total;
|
|
6076
|
+
}
|
|
5767
6077
|
/** Decision after a turn's response — fold, exit with summary, or carry on. */
|
|
5768
6078
|
decideAfterUsage(usage, model, alreadyFoldedThisTurn) {
|
|
5769
6079
|
const ctxMax = DEEPSEEK_CONTEXT_TOKENS[model] ?? DEFAULT_CONTEXT_TOKENS;
|
|
@@ -5792,14 +6102,25 @@ var ContextManager = class {
|
|
|
5792
6102
|
}
|
|
5793
6103
|
return { kind: "none", ...base };
|
|
5794
6104
|
}
|
|
5795
|
-
/** Local-side preflight before sending a request — catches oversized payloads early.
|
|
6105
|
+
/** Local-side preflight before sending a request — catches oversized payloads early.
|
|
6106
|
+
* Two independent signals trip mechanical truncate: token estimate above the context-window
|
|
6107
|
+
* fraction, OR JSON body bytes above the gateway limit (see `MAX_BODY_BYTES`). */
|
|
5796
6108
|
decidePreflight(messages, toolSpecs, model) {
|
|
5797
6109
|
const ctxMax = DEEPSEEK_CONTEXT_TOKENS[model] ?? DEFAULT_CONTEXT_TOKENS;
|
|
5798
6110
|
const estimate = estimateRequestTokens(messages, toolSpecs ?? null, true);
|
|
6111
|
+
const estimateBytes = Buffer.byteLength(JSON.stringify(messages), "utf8");
|
|
6112
|
+
const tokensOver = estimate / ctxMax > PREFLIGHT_EMERGENCY_THRESHOLD;
|
|
6113
|
+
const bytesOver = estimateBytes > MAX_BODY_BYTES;
|
|
6114
|
+
let trigger = "none";
|
|
6115
|
+
if (tokensOver && bytesOver) trigger = "both";
|
|
6116
|
+
else if (tokensOver) trigger = "tokens";
|
|
6117
|
+
else if (bytesOver) trigger = "bytes";
|
|
5799
6118
|
return {
|
|
5800
|
-
needsAction:
|
|
6119
|
+
needsAction: tokensOver || bytesOver,
|
|
5801
6120
|
estimateTokens: estimate,
|
|
5802
|
-
|
|
6121
|
+
estimateBytes,
|
|
6122
|
+
ctxMax,
|
|
6123
|
+
trigger
|
|
5803
6124
|
};
|
|
5804
6125
|
}
|
|
5805
6126
|
/** Replace older turns with one summary message; keep tail within keepRecentTokens budget. */
|
|
@@ -5852,10 +6173,13 @@ ${pinnedBodies.join("\n\n")}` : "";
|
|
|
5852
6173
|
summaryChars: summary.content.length
|
|
5853
6174
|
};
|
|
5854
6175
|
}
|
|
5855
|
-
/** Pure local emergency compaction for preflight: drop oldest log entries and keep a valid tail.
|
|
6176
|
+
/** Pure local emergency compaction for preflight: drop oldest log entries and keep a valid tail.
|
|
6177
|
+
* Bounded by tokens AND bytes — bytes matter because DeepSeek's gateway 400s on bodies past
|
|
6178
|
+
* `MAX_BODY_BYTES` even when the token budget is far from exhausted. */
|
|
5856
6179
|
mechanicalTruncate(model, opts) {
|
|
5857
6180
|
const ctxMax = DEEPSEEK_CONTEXT_TOKENS[model] ?? DEFAULT_CONTEXT_TOKENS;
|
|
5858
6181
|
const targetTokens = opts?.targetTokens ?? Math.floor(ctxMax * PREFLIGHT_MECHANICAL_TARGET_FRACTION);
|
|
6182
|
+
const targetBytes = opts?.targetBytes ?? MAX_BODY_BYTES_TARGET;
|
|
5859
6183
|
const all = this.deps.log.toMessages();
|
|
5860
6184
|
const noop = {
|
|
5861
6185
|
folded: false,
|
|
@@ -5865,6 +6189,7 @@ ${pinnedBodies.join("\n\n")}` : "";
|
|
|
5865
6189
|
};
|
|
5866
6190
|
if (all.length === 0) return noop;
|
|
5867
6191
|
const tokenCounts = all.map((m) => estimateConversationTokens([m], true));
|
|
6192
|
+
const byteCounts = all.map((m) => Buffer.byteLength(JSON.stringify(m), "utf8"));
|
|
5868
6193
|
let latestUserBoundary = -1;
|
|
5869
6194
|
for (let i = all.length - 1; i >= 0; i--) {
|
|
5870
6195
|
if (all[i].role === "user") {
|
|
@@ -5873,12 +6198,15 @@ ${pinnedBodies.join("\n\n")}` : "";
|
|
|
5873
6198
|
}
|
|
5874
6199
|
}
|
|
5875
6200
|
let cumTokens = 0;
|
|
6201
|
+
let cumBytes = 0;
|
|
5876
6202
|
let boundary = all.length;
|
|
5877
6203
|
let foundSafeBoundary = false;
|
|
5878
6204
|
for (let i = all.length - 1; i >= 0; i--) {
|
|
5879
|
-
const
|
|
5880
|
-
|
|
5881
|
-
|
|
6205
|
+
const nextTokens = cumTokens + tokenCounts[i];
|
|
6206
|
+
const nextBytes = cumBytes + byteCounts[i];
|
|
6207
|
+
if (nextTokens > targetTokens || nextBytes > targetBytes) break;
|
|
6208
|
+
cumTokens = nextTokens;
|
|
6209
|
+
cumBytes = nextBytes;
|
|
5882
6210
|
if (all[i].role === "user") {
|
|
5883
6211
|
boundary = i;
|
|
5884
6212
|
foundSafeBoundary = true;
|
|
@@ -6115,13 +6443,11 @@ async function* forceSummaryAfterIterLimit(ctx, opts) {
|
|
|
6115
6443
|
content: "The turn is being force-summarized (context guard or stuck-state). Summarize in plain prose what you learned from the tool results above. Do NOT emit any tool calls, function-call markup, DSML invocations, or SEARCH/REPLACE edit blocks \u2014 they will be silently discarded. Just plain text."
|
|
6116
6444
|
});
|
|
6117
6445
|
const summaryModel = "deepseek-v4-flash";
|
|
6118
|
-
const summaryEffort = "high";
|
|
6119
6446
|
const resp = await ctx.client.chat({
|
|
6120
6447
|
model: summaryModel,
|
|
6121
6448
|
messages,
|
|
6122
6449
|
signal: ctx.signal,
|
|
6123
|
-
thinking:
|
|
6124
|
-
reasoningEffort: summaryEffort
|
|
6450
|
+
thinking: "disabled"
|
|
6125
6451
|
});
|
|
6126
6452
|
const rawContent = resp.content?.trim() ?? "";
|
|
6127
6453
|
const cleaned = stripHallucinatedToolMarkup(rawContent);
|
|
@@ -6860,6 +7186,10 @@ var CacheFirstLoop = class {
|
|
|
6860
7186
|
async compactHistory(opts) {
|
|
6861
7187
|
return this.context.fold(this.model, opts);
|
|
6862
7188
|
}
|
|
7189
|
+
/** Real-time token count of the current log — forwarded to Desktop for meter refresh. */
|
|
7190
|
+
getCurrentLogTokens() {
|
|
7191
|
+
return this.context.getLogTokens();
|
|
7192
|
+
}
|
|
6863
7193
|
appendAndPersist(message) {
|
|
6864
7194
|
this.log.append(message);
|
|
6865
7195
|
if (this.sessionName) {
|
|
@@ -7175,21 +7505,24 @@ ${reason}`
|
|
|
7175
7505
|
const toolSpecs = this.prefix.tools();
|
|
7176
7506
|
for (let iter = 0; ; iter++) {
|
|
7177
7507
|
if (signal.aborted) {
|
|
7178
|
-
|
|
7179
|
-
|
|
7180
|
-
|
|
7181
|
-
|
|
7182
|
-
|
|
7183
|
-
|
|
7184
|
-
|
|
7185
|
-
|
|
7186
|
-
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
|
|
7190
|
-
|
|
7191
|
-
|
|
7192
|
-
|
|
7508
|
+
try {
|
|
7509
|
+
yield {
|
|
7510
|
+
turn: this._turn,
|
|
7511
|
+
role: "warning",
|
|
7512
|
+
content: t("loop.abortedAtIter", { iter })
|
|
7513
|
+
};
|
|
7514
|
+
const stoppedMsg = "[aborted by user (Esc) \u2014 no summary produced. Ask again or /retry when ready; prior tool output is still in the log.]";
|
|
7515
|
+
this.appendAndPersist(buildSyntheticAssistantMessage(stoppedMsg, this.model));
|
|
7516
|
+
yield {
|
|
7517
|
+
turn: this._turn,
|
|
7518
|
+
role: "assistant_final",
|
|
7519
|
+
content: stoppedMsg,
|
|
7520
|
+
forcedSummary: true
|
|
7521
|
+
};
|
|
7522
|
+
yield { turn: this._turn, role: "done", content: stoppedMsg };
|
|
7523
|
+
} finally {
|
|
7524
|
+
this._turnAbort = new AbortController();
|
|
7525
|
+
}
|
|
7193
7526
|
return;
|
|
7194
7527
|
}
|
|
7195
7528
|
if (iter > 0) {
|
|
@@ -7216,7 +7549,7 @@ ${reason}`
|
|
|
7216
7549
|
{
|
|
7217
7550
|
const decision2 = this.context.decidePreflight(messages, this.prefix.toolSpecs, this.model);
|
|
7218
7551
|
if (decision2.needsAction) {
|
|
7219
|
-
const { estimateTokens: estimate, ctxMax } = decision2;
|
|
7552
|
+
const { estimateTokens: estimate, estimateBytes, ctxMax } = decision2;
|
|
7220
7553
|
yield {
|
|
7221
7554
|
turn: this._turn,
|
|
7222
7555
|
role: "status",
|
|
@@ -7238,6 +7571,7 @@ ${reason}`
|
|
|
7238
7571
|
estimate: after.estimateTokens.toLocaleString(),
|
|
7239
7572
|
ctxMax: after.ctxMax.toLocaleString(),
|
|
7240
7573
|
pct: Math.round(after.estimateTokens / after.ctxMax * 100),
|
|
7574
|
+
bodyKB: Math.round(after.estimateBytes / 1024).toLocaleString(),
|
|
7241
7575
|
beforeMessages: result.beforeMessages,
|
|
7242
7576
|
afterMessages: result.afterMessages
|
|
7243
7577
|
}
|
|
@@ -7250,7 +7584,8 @@ ${reason}`
|
|
|
7250
7584
|
content: t("loop.preflightNoFold", {
|
|
7251
7585
|
estimate: estimate.toLocaleString(),
|
|
7252
7586
|
ctxMax: ctxMax.toLocaleString(),
|
|
7253
|
-
pct: Math.round(estimate / ctxMax * 100)
|
|
7587
|
+
pct: Math.round(estimate / ctxMax * 100),
|
|
7588
|
+
bodyKB: Math.round(estimateBytes / 1024).toLocaleString()
|
|
7254
7589
|
})
|
|
7255
7590
|
};
|
|
7256
7591
|
}
|
|
@@ -7365,8 +7700,11 @@ ${reason}`
|
|
|
7365
7700
|
}
|
|
7366
7701
|
} catch (err) {
|
|
7367
7702
|
if (signal.aborted) {
|
|
7368
|
-
|
|
7369
|
-
|
|
7703
|
+
try {
|
|
7704
|
+
yield { turn: this._turn, role: "done", content: "" };
|
|
7705
|
+
} finally {
|
|
7706
|
+
this._turnAbort = new AbortController();
|
|
7707
|
+
}
|
|
7370
7708
|
return;
|
|
7371
7709
|
}
|
|
7372
7710
|
const probe = is5xxError(err) ? await probeDeepSeekReachable(this.client) : void 0;
|
|
@@ -8465,8 +8803,13 @@ Tips:
|
|
|
8465
8803
|
- Add \`allowed-tools: read_file, search_content\` to scope a subagent's tools
|
|
8466
8804
|
`;
|
|
8467
8805
|
}
|
|
8806
|
+
function skillDescription(s) {
|
|
8807
|
+
if (s.scope !== "builtin") return s.description;
|
|
8808
|
+
const key = s.name === "security-review" ? "securityReview" : s.name;
|
|
8809
|
+
return t(`builtinSkills.${key}`);
|
|
8810
|
+
}
|
|
8468
8811
|
function skillIndexLine(s) {
|
|
8469
|
-
const safeDesc = s.
|
|
8812
|
+
const safeDesc = skillDescription(s).replace(/\n/g, " ").trim();
|
|
8470
8813
|
const tag = s.runAs === "subagent" ? " [\u{1F9EC} subagent]" : "";
|
|
8471
8814
|
const max = 130 - s.name.length - tag.length;
|
|
8472
8815
|
const clipped = safeDesc.length > max ? `${safeDesc.slice(0, Math.max(1, max - 1))}\u2026` : safeDesc;
|
|
@@ -9809,8 +10152,8 @@ async function searchContent(ctx, startAbs, args) {
|
|
|
9809
10152
|
for (let i = realStart; i <= winEnd; i++) {
|
|
9810
10153
|
const line = lines[i];
|
|
9811
10154
|
const display = line.length > 200 ? `${line.slice(0, 200)}\u2026` : line;
|
|
9812
|
-
const
|
|
9813
|
-
if (!pushLine(`${rel}:${i + 1}${
|
|
10155
|
+
const sep2 = hitSet.has(i) ? ":" : "-";
|
|
10156
|
+
if (!pushLine(`${rel}:${i + 1}${sep2} ${display}`)) return;
|
|
9814
10157
|
}
|
|
9815
10158
|
prevWindowEnd = winEnd;
|
|
9816
10159
|
}
|
|
@@ -9841,7 +10184,9 @@ var DEFAULT_OUTLINE_THRESHOLD_BYTES = 64 * 1024;
|
|
|
9841
10184
|
var DEFAULT_MAX_LIST_BYTES = 256 * 1024;
|
|
9842
10185
|
var HARD_MAX_FILE_BYTES = 32 * 1024 * 1024;
|
|
9843
10186
|
var OUTLINE_HEAD_LINES = 80;
|
|
9844
|
-
var SKIP_DIR_NAMES = new Set(
|
|
10187
|
+
var SKIP_DIR_NAMES = new Set(
|
|
10188
|
+
DEFAULT_INDEX_EXCLUDES.dirs.filter((d) => d !== ".reasonix")
|
|
10189
|
+
);
|
|
9845
10190
|
var BINARY_EXTENSIONS = new Set(DEFAULT_INDEX_EXCLUDES.exts);
|
|
9846
10191
|
function displayRel4(rootDir, full) {
|
|
9847
10192
|
return pathMod5.relative(rootDir, full).replaceAll("\\", "/");
|
|
@@ -10868,6 +11213,21 @@ function sanitizeEvidence(raw) {
|
|
|
10868
11213
|
}
|
|
10869
11214
|
return out.length > 0 ? out : void 0;
|
|
10870
11215
|
}
|
|
11216
|
+
function summarizeEvidence(evidence) {
|
|
11217
|
+
if (!evidence || evidence.length === 0) return void 0;
|
|
11218
|
+
const parts = evidence.map((item) => `${item.kind}: ${item.summary}`);
|
|
11219
|
+
return parts.join("; ");
|
|
11220
|
+
}
|
|
11221
|
+
function compactStepCompletion(update) {
|
|
11222
|
+
const compact = {
|
|
11223
|
+
kind: "step_completed",
|
|
11224
|
+
stepId: update.stepId,
|
|
11225
|
+
result: update.result
|
|
11226
|
+
};
|
|
11227
|
+
const evidenceSummary = summarizeEvidence(update.evidence);
|
|
11228
|
+
if (evidenceSummary) compact.evidenceSummary = evidenceSummary;
|
|
11229
|
+
return compact;
|
|
11230
|
+
}
|
|
10871
11231
|
function registerSubmitPlan(registry, opts) {
|
|
10872
11232
|
registry.register({
|
|
10873
11233
|
name: "submit_plan",
|
|
@@ -10981,9 +11341,9 @@ function registerMarkStepComplete(registry, opts) {
|
|
|
10981
11341
|
opts.onStepCompleted?.(update);
|
|
10982
11342
|
const verdict = await (ctx?.confirmationGate ?? pauseGate).ask({
|
|
10983
11343
|
kind: "plan_checkpoint",
|
|
10984
|
-
payload: { stepId, title, result, notes }
|
|
11344
|
+
payload: { stepId, title, result, notes, completion: update }
|
|
10985
11345
|
});
|
|
10986
|
-
if (verdict.type === "continue") return JSON.stringify(update);
|
|
11346
|
+
if (verdict.type === "continue") return JSON.stringify(compactStepCompletion(update));
|
|
10987
11347
|
if (verdict.type === "revise") {
|
|
10988
11348
|
if (verdict.feedback) return `revision requested: ${verdict.feedback}`;
|
|
10989
11349
|
throw new Error("user requested revision at checkpoint");
|
|
@@ -11310,12 +11670,40 @@ async function spawnSubagent(opts) {
|
|
|
11310
11670
|
let toolIter = 0;
|
|
11311
11671
|
let summarisingEmitted = false;
|
|
11312
11672
|
let forcedSummaryFired = false;
|
|
11673
|
+
let outputChars = 0;
|
|
11674
|
+
let reasoningChars = 0;
|
|
11675
|
+
let toolReadChars = 0;
|
|
11676
|
+
let lastStreamEmitAt = 0;
|
|
11677
|
+
let charsSinceLastEmit = 0;
|
|
11678
|
+
const STREAM_EMIT_INTERVAL_MS = 200;
|
|
11679
|
+
const STREAM_EMIT_CHARS = 400;
|
|
11680
|
+
const maybeEmitStreamProgress = (now, force) => {
|
|
11681
|
+
if (!sink?.current) return;
|
|
11682
|
+
if (!force && now - lastStreamEmitAt < STREAM_EMIT_INTERVAL_MS && charsSinceLastEmit < STREAM_EMIT_CHARS) {
|
|
11683
|
+
return;
|
|
11684
|
+
}
|
|
11685
|
+
lastStreamEmitAt = now;
|
|
11686
|
+
charsSinceLastEmit = 0;
|
|
11687
|
+
sink.current({
|
|
11688
|
+
kind: "stream-progress",
|
|
11689
|
+
runId,
|
|
11690
|
+
task: taskPreview,
|
|
11691
|
+
skillName,
|
|
11692
|
+
model,
|
|
11693
|
+
iter: toolIter,
|
|
11694
|
+
elapsedMs: now - startedAt,
|
|
11695
|
+
outputChars,
|
|
11696
|
+
reasoningChars,
|
|
11697
|
+
toolReadChars
|
|
11698
|
+
});
|
|
11699
|
+
};
|
|
11313
11700
|
try {
|
|
11314
11701
|
for await (const ev of childLoop.step(opts.task)) {
|
|
11315
11702
|
sink?.current?.({ kind: "inner", runId, task: taskPreview, skillName, model, inner: ev });
|
|
11316
11703
|
if (ev.role === "tool") {
|
|
11317
11704
|
toolIter++;
|
|
11318
11705
|
summarisingEmitted = false;
|
|
11706
|
+
toolReadChars += ev.content?.length ?? 0;
|
|
11319
11707
|
sink?.current?.({
|
|
11320
11708
|
kind: "progress",
|
|
11321
11709
|
runId,
|
|
@@ -11325,6 +11713,17 @@ async function spawnSubagent(opts) {
|
|
|
11325
11713
|
iter: toolIter,
|
|
11326
11714
|
elapsedMs: Date.now() - startedAt
|
|
11327
11715
|
});
|
|
11716
|
+
maybeEmitStreamProgress(Date.now(), true);
|
|
11717
|
+
}
|
|
11718
|
+
if (ev.role === "assistant_delta") {
|
|
11719
|
+
const dContent = ev.content?.length ?? 0;
|
|
11720
|
+
const dReason = ev.reasoningDelta?.length ?? 0;
|
|
11721
|
+
if (dContent > 0 || dReason > 0) {
|
|
11722
|
+
outputChars += dContent;
|
|
11723
|
+
reasoningChars += dReason;
|
|
11724
|
+
charsSinceLastEmit += dContent + dReason;
|
|
11725
|
+
maybeEmitStreamProgress(Date.now(), false);
|
|
11726
|
+
}
|
|
11328
11727
|
}
|
|
11329
11728
|
if (ev.role === "assistant_delta" && !summarisingEmitted && (ev.content ?? "").length > 0) {
|
|
11330
11729
|
summarisingEmitted = true;
|
|
@@ -13040,7 +13439,7 @@ function registerShellTools(registry, opts) {
|
|
|
13040
13439
|
properties: {
|
|
13041
13440
|
command: {
|
|
13042
13441
|
type: "string",
|
|
13043
|
-
description:
|
|
13442
|
+
description: "Full command line. Quoting + chain/redirect rules per the top-level description."
|
|
13044
13443
|
},
|
|
13045
13444
|
timeoutSec: {
|
|
13046
13445
|
type: "integer",
|
|
@@ -13287,6 +13686,8 @@ var USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (
|
|
|
13287
13686
|
var MOJEEK_ENDPOINT = "https://www.mojeek.com/search";
|
|
13288
13687
|
var METASO_ENDPOINT = "https://metaso.cn/api/v1";
|
|
13289
13688
|
var TAVILY_ENDPOINT = "https://api.tavily.com/search";
|
|
13689
|
+
var PERPLEXITY_ENDPOINT = "https://api.perplexity.ai/chat/completions";
|
|
13690
|
+
var EXA_ENDPOINT = "https://api.exa.ai/answer";
|
|
13290
13691
|
function searchStatusError(status) {
|
|
13291
13692
|
if (status === 429) return t("webErrors.rateLimit429");
|
|
13292
13693
|
if (status === 403) return t("webErrors.forbidden403");
|
|
@@ -13309,6 +13710,12 @@ async function webSearch(query, opts = {}) {
|
|
|
13309
13710
|
if (opts.engine === "tavily") {
|
|
13310
13711
|
return searchTavily(query, opts);
|
|
13311
13712
|
}
|
|
13713
|
+
if (opts.engine === "perplexity") {
|
|
13714
|
+
return searchPerplexity(query, opts);
|
|
13715
|
+
}
|
|
13716
|
+
if (opts.engine === "exa") {
|
|
13717
|
+
return searchExa(query, opts);
|
|
13718
|
+
}
|
|
13312
13719
|
return searchMojeek(query, opts);
|
|
13313
13720
|
}
|
|
13314
13721
|
async function searchMojeek(query, opts = {}) {
|
|
@@ -13384,6 +13791,7 @@ async function searchSearxng(query, opts = {}) {
|
|
|
13384
13791
|
async function searchMetaso(query, opts = {}) {
|
|
13385
13792
|
const topK = Math.max(1, Math.min(100, opts.topK ?? DEFAULT_TOPK));
|
|
13386
13793
|
const apiKey = loadMetasoApiKey();
|
|
13794
|
+
if (!apiKey) throw new Error(t("webErrors.metasoMissingKey"));
|
|
13387
13795
|
let resp;
|
|
13388
13796
|
try {
|
|
13389
13797
|
resp = await fetch(`${METASO_ENDPOINT}/search`, {
|
|
@@ -13492,6 +13900,121 @@ async function searchTavily(query, opts = {}) {
|
|
|
13492
13900
|
snippet: r.content ?? ""
|
|
13493
13901
|
}));
|
|
13494
13902
|
}
|
|
13903
|
+
async function searchPerplexity(query, opts = {}) {
|
|
13904
|
+
const topK = Math.max(1, Math.min(20, opts.topK ?? DEFAULT_TOPK));
|
|
13905
|
+
const apiKey = loadPerplexityApiKey();
|
|
13906
|
+
if (!apiKey) throw new Error(t("webErrors.perplexityMissingKey"));
|
|
13907
|
+
let resp;
|
|
13908
|
+
try {
|
|
13909
|
+
resp = await fetch(PERPLEXITY_ENDPOINT, {
|
|
13910
|
+
method: "POST",
|
|
13911
|
+
headers: {
|
|
13912
|
+
Authorization: `Bearer ${apiKey}`,
|
|
13913
|
+
"Content-Type": "application/json"
|
|
13914
|
+
},
|
|
13915
|
+
body: JSON.stringify({
|
|
13916
|
+
model: "sonar",
|
|
13917
|
+
messages: [{ role: "user", content: query }],
|
|
13918
|
+
max_tokens: 1024,
|
|
13919
|
+
return_related_questions: false
|
|
13920
|
+
}),
|
|
13921
|
+
signal: opts.signal
|
|
13922
|
+
});
|
|
13923
|
+
} catch (err) {
|
|
13924
|
+
if (err instanceof TypeError && err.message.includes("fetch")) {
|
|
13925
|
+
throw new Error(t("webErrors.cannotReach", { endpoint: PERPLEXITY_ENDPOINT }));
|
|
13926
|
+
}
|
|
13927
|
+
throw err;
|
|
13928
|
+
}
|
|
13929
|
+
if (!resp.ok) {
|
|
13930
|
+
if (resp.status === 401 || resp.status === 403) {
|
|
13931
|
+
throw new Error(t("webErrors.perplexityUnauthorized"));
|
|
13932
|
+
}
|
|
13933
|
+
if (resp.status === 429) throw new Error(t("webErrors.perplexityRateLimit"));
|
|
13934
|
+
throw new Error(t("webErrors.perplexityServerError", { status: resp.status }));
|
|
13935
|
+
}
|
|
13936
|
+
const raw = await resp.text();
|
|
13937
|
+
let data;
|
|
13938
|
+
try {
|
|
13939
|
+
data = JSON.parse(raw);
|
|
13940
|
+
} catch {
|
|
13941
|
+
throw new Error(t("webErrors.perplexityParseError", { status: resp.status }));
|
|
13942
|
+
}
|
|
13943
|
+
const answer = data.choices?.[0]?.message?.content ?? "";
|
|
13944
|
+
const citations = Array.isArray(data.citations) ? data.citations : [];
|
|
13945
|
+
const results = [];
|
|
13946
|
+
if (answer) {
|
|
13947
|
+
results.push({ title: answer, url: "", snippet: "", answer });
|
|
13948
|
+
}
|
|
13949
|
+
const count = Math.min(citations.length, topK);
|
|
13950
|
+
for (let i = 0; i < count; i++) {
|
|
13951
|
+
const c = citations[i];
|
|
13952
|
+
if (typeof c === "string") {
|
|
13953
|
+
results.push({ title: `Source ${i + 1}`, url: c, snippet: "" });
|
|
13954
|
+
} else if (c && typeof c === "object" && typeof c.url === "string") {
|
|
13955
|
+
const item = c;
|
|
13956
|
+
results.push({
|
|
13957
|
+
title: typeof item.title === "string" ? item.title : `Source ${i + 1}`,
|
|
13958
|
+
url: item.url,
|
|
13959
|
+
snippet: ""
|
|
13960
|
+
});
|
|
13961
|
+
}
|
|
13962
|
+
}
|
|
13963
|
+
return results;
|
|
13964
|
+
}
|
|
13965
|
+
async function searchExa(query, opts = {}) {
|
|
13966
|
+
const topK = Math.max(1, Math.min(20, opts.topK ?? DEFAULT_TOPK));
|
|
13967
|
+
const apiKey = loadExaApiKey();
|
|
13968
|
+
if (!apiKey) throw new Error(t("webErrors.exaMissingKey"));
|
|
13969
|
+
let resp;
|
|
13970
|
+
try {
|
|
13971
|
+
resp = await fetch(EXA_ENDPOINT, {
|
|
13972
|
+
method: "POST",
|
|
13973
|
+
headers: {
|
|
13974
|
+
"x-api-key": apiKey,
|
|
13975
|
+
"Content-Type": "application/json"
|
|
13976
|
+
},
|
|
13977
|
+
body: JSON.stringify({ query, text: true }),
|
|
13978
|
+
signal: opts.signal
|
|
13979
|
+
});
|
|
13980
|
+
} catch (err) {
|
|
13981
|
+
if (err instanceof TypeError && err.message.includes("fetch")) {
|
|
13982
|
+
throw new Error(t("webErrors.cannotReach", { endpoint: EXA_ENDPOINT }));
|
|
13983
|
+
}
|
|
13984
|
+
throw err;
|
|
13985
|
+
}
|
|
13986
|
+
if (!resp.ok) {
|
|
13987
|
+
if (resp.status === 401 || resp.status === 403) {
|
|
13988
|
+
throw new Error(t("webErrors.exaUnauthorized"));
|
|
13989
|
+
}
|
|
13990
|
+
if (resp.status === 429) throw new Error(t("webErrors.exaRateLimit"));
|
|
13991
|
+
throw new Error(t("webErrors.exaServerError", { status: resp.status }));
|
|
13992
|
+
}
|
|
13993
|
+
const raw = await resp.text();
|
|
13994
|
+
let data;
|
|
13995
|
+
try {
|
|
13996
|
+
data = JSON.parse(raw);
|
|
13997
|
+
} catch {
|
|
13998
|
+
throw new Error(t("webErrors.exaParseError", { status: resp.status }));
|
|
13999
|
+
}
|
|
14000
|
+
const answer = data.answer ?? "";
|
|
14001
|
+
const citations = data.citations ?? [];
|
|
14002
|
+
const results = [];
|
|
14003
|
+
if (answer) {
|
|
14004
|
+
results.push({ title: answer, url: "", snippet: "", answer });
|
|
14005
|
+
}
|
|
14006
|
+
const count = Math.min(citations.length, topK);
|
|
14007
|
+
for (let i = 0; i < count; i++) {
|
|
14008
|
+
const c = citations[i];
|
|
14009
|
+
if (!c.url) continue;
|
|
14010
|
+
results.push({
|
|
14011
|
+
title: c.title || `Source ${i + 1}`,
|
|
14012
|
+
url: c.url,
|
|
14013
|
+
snippet: c.text ?? ""
|
|
14014
|
+
});
|
|
14015
|
+
}
|
|
14016
|
+
return results;
|
|
14017
|
+
}
|
|
13495
14018
|
function parseSearxngHtmlResults(html) {
|
|
13496
14019
|
const root = parseHtml(html);
|
|
13497
14020
|
const results = [];
|
|
@@ -13710,7 +14233,7 @@ function registerWebTools(registry, opts = {}) {
|
|
|
13710
14233
|
const maxFetchChars = opts.maxFetchChars ?? DEFAULT_FETCH_MAX_CHARS;
|
|
13711
14234
|
registry.register({
|
|
13712
14235
|
name: "web_search",
|
|
13713
|
-
description: "Search the public web. Returns ranked results with title, url, and snippet. Call this when the answer's correctness depends on current state \u2014 anything that changes over time (events, prices, releases, status of a thing in the real world). Composing such answers from training memory invents stale numbers; search first, then ground the answer in the results. For evergreen / definitional questions you don't need this.
|
|
14236
|
+
description: "Search the public web. Returns ranked results with title, url, and snippet. Call this when the answer's correctness depends on current state \u2014 anything that changes over time (events, prices, releases, status of a thing in the real world). Composing such answers from training memory invents stale numbers; search first, then ground the answer in the results. For evergreen / definitional questions you don't need this.",
|
|
13714
14237
|
readOnly: true,
|
|
13715
14238
|
parallelSafe: true,
|
|
13716
14239
|
parameters: {
|
|
@@ -13719,7 +14242,7 @@ function registerWebTools(registry, opts = {}) {
|
|
|
13719
14242
|
query: { type: "string", description: "Natural-language search query." },
|
|
13720
14243
|
topK: {
|
|
13721
14244
|
type: "integer",
|
|
13722
|
-
description: `Number of results to return
|
|
14245
|
+
description: `Number of results to return. Default ${defaultTopK}.`
|
|
13723
14246
|
}
|
|
13724
14247
|
},
|
|
13725
14248
|
required: ["query"]
|
|
@@ -13763,14 +14286,30 @@ ${page.text}`;
|
|
|
13763
14286
|
return registry;
|
|
13764
14287
|
}
|
|
13765
14288
|
function formatSearchResults(query, results) {
|
|
13766
|
-
const lines = [`query: ${query}
|
|
13767
|
-
|
|
13768
|
-
|
|
14289
|
+
const lines = [`query: ${query}`];
|
|
14290
|
+
const hasAnswer = results.length > 0 && results[0]?.url === "" && results[0]?.answer;
|
|
14291
|
+
if (hasAnswer) {
|
|
14292
|
+
lines.push("\nanswer:");
|
|
14293
|
+
lines.push(` ${results[0].answer}`);
|
|
14294
|
+
const sources = results.slice(1);
|
|
13769
14295
|
lines.push(`
|
|
14296
|
+
sources (${sources.length}):`);
|
|
14297
|
+
sources.forEach((r, i) => {
|
|
14298
|
+
lines.push(`
|
|
13770
14299
|
${i + 1}. ${r.title}`);
|
|
13771
|
-
|
|
13772
|
-
|
|
13773
|
-
|
|
14300
|
+
lines.push(` ${r.url}`);
|
|
14301
|
+
if (r.snippet) lines.push(` ${r.snippet}`);
|
|
14302
|
+
});
|
|
14303
|
+
} else {
|
|
14304
|
+
lines.push(`
|
|
14305
|
+
results (${results.length}):`);
|
|
14306
|
+
results.forEach((r, i) => {
|
|
14307
|
+
lines.push(`
|
|
14308
|
+
${i + 1}. ${r.title}`);
|
|
14309
|
+
lines.push(` ${r.url}`);
|
|
14310
|
+
if (r.snippet) lines.push(` ${r.snippet}`);
|
|
14311
|
+
});
|
|
14312
|
+
}
|
|
13774
14313
|
return lines.join("\n");
|
|
13775
14314
|
}
|
|
13776
14315
|
|
|
@@ -15047,7 +15586,7 @@ import {
|
|
|
15047
15586
|
writeFileSync as writeFileSync6,
|
|
15048
15587
|
writeSync
|
|
15049
15588
|
} from "fs";
|
|
15050
|
-
import { dirname as dirname8, resolve as resolve12 } from "path";
|
|
15589
|
+
import { dirname as dirname8, isAbsolute as isAbsolute7, relative as relative8, resolve as resolve12 } from "path";
|
|
15051
15590
|
var BLOCK_RE = /^(\S[^\n]*)\n<{7} SEARCH\n([\s\S]*?)\n?={7}\n([\s\S]*?)\n?>{7} REPLACE/gm;
|
|
15052
15591
|
function parseEditBlocks(text) {
|
|
15053
15592
|
const out = [];
|
|
@@ -15064,10 +15603,30 @@ function parseEditBlocks(text) {
|
|
|
15064
15603
|
}
|
|
15065
15604
|
return out;
|
|
15066
15605
|
}
|
|
15606
|
+
function resolveEditPath(rootDir, rawPath) {
|
|
15607
|
+
const absRoot = resolve12(rootDir);
|
|
15608
|
+
if (/^[A-Za-z]:[\\/]/.test(rawPath) || looksLikeAbsoluteSystemPath2(rawPath)) {
|
|
15609
|
+
return resolve12(rawPath);
|
|
15610
|
+
}
|
|
15611
|
+
let rooted = rawPath;
|
|
15612
|
+
while (rooted.startsWith("/") || rooted.startsWith("\\")) {
|
|
15613
|
+
rooted = rooted.slice(1);
|
|
15614
|
+
}
|
|
15615
|
+
return resolve12(absRoot, rooted || ".");
|
|
15616
|
+
}
|
|
15617
|
+
function looksLikeAbsoluteSystemPath2(rawPath) {
|
|
15618
|
+
return /^\/(?:home|Users|etc|var|opt|tmp|usr|mnt|Library|Volumes|proc|sys|dev|run|srv|media|Applications|System|root|boot|private)(?:[/\\]|$)/.test(
|
|
15619
|
+
rawPath
|
|
15620
|
+
);
|
|
15621
|
+
}
|
|
15622
|
+
function pathIsUnder2(child, parent) {
|
|
15623
|
+
const rel = relative8(parent, child);
|
|
15624
|
+
return rel === "" || !rel.startsWith("..") && !isAbsolute7(rel);
|
|
15625
|
+
}
|
|
15067
15626
|
function applyEditBlock(block, rootDir) {
|
|
15068
15627
|
const absRoot = resolve12(rootDir);
|
|
15069
|
-
const absTarget =
|
|
15070
|
-
if (absTarget
|
|
15628
|
+
const absTarget = resolveEditPath(rootDir, block.path);
|
|
15629
|
+
if (!pathIsUnder2(absTarget, absRoot)) {
|
|
15071
15630
|
return {
|
|
15072
15631
|
path: block.path,
|
|
15073
15632
|
status: "path-escape",
|
|
@@ -15132,6 +15691,14 @@ function applyEditBlock(block, rootDir) {
|
|
|
15132
15691
|
message: "SEARCH text does not match the current file content exactly"
|
|
15133
15692
|
};
|
|
15134
15693
|
}
|
|
15694
|
+
const nextIdx = content.indexOf(adaptedSearch, idx + 1);
|
|
15695
|
+
if (nextIdx !== -1) {
|
|
15696
|
+
return {
|
|
15697
|
+
path: block.path,
|
|
15698
|
+
status: "not-found",
|
|
15699
|
+
message: "SEARCH text appears multiple times; include more context to disambiguate"
|
|
15700
|
+
};
|
|
15701
|
+
}
|
|
15135
15702
|
const replaced = `${content.slice(0, idx)}${adaptedReplace}${content.slice(idx + adaptedSearch.length)}`;
|
|
15136
15703
|
const outBuf = Buffer.from(replaced, "utf8");
|
|
15137
15704
|
ftruncateSync(fd, outBuf.length);
|
|
@@ -15153,13 +15720,12 @@ function applyEditBlocks(blocks, rootDir) {
|
|
|
15153
15720
|
return blocks.map((b) => applyEditBlock(b, rootDir));
|
|
15154
15721
|
}
|
|
15155
15722
|
function snapshotBeforeEdits(blocks, rootDir) {
|
|
15156
|
-
const absRoot = resolve12(rootDir);
|
|
15157
15723
|
const seen = /* @__PURE__ */ new Set();
|
|
15158
15724
|
const snapshots = [];
|
|
15159
15725
|
for (const b of blocks) {
|
|
15160
|
-
|
|
15161
|
-
seen.
|
|
15162
|
-
|
|
15726
|
+
const abs = resolveEditPath(rootDir, b.path);
|
|
15727
|
+
if (seen.has(abs)) continue;
|
|
15728
|
+
seen.add(abs);
|
|
15163
15729
|
if (!existsSync11(abs)) {
|
|
15164
15730
|
snapshots.push({ path: b.path, prevContent: null });
|
|
15165
15731
|
continue;
|
|
@@ -15175,8 +15741,8 @@ function snapshotBeforeEdits(blocks, rootDir) {
|
|
|
15175
15741
|
function restoreSnapshots(snapshots, rootDir) {
|
|
15176
15742
|
const absRoot = resolve12(rootDir);
|
|
15177
15743
|
return snapshots.map((snap) => {
|
|
15178
|
-
const abs =
|
|
15179
|
-
if (abs
|
|
15744
|
+
const abs = resolveEditPath(rootDir, snap.path);
|
|
15745
|
+
if (!pathIsUnder2(abs, absRoot)) {
|
|
15180
15746
|
return {
|
|
15181
15747
|
path: snap.path,
|
|
15182
15748
|
status: "path-escape",
|
|
@@ -15203,9 +15769,6 @@ function restoreSnapshots(snapshots, rootDir) {
|
|
|
15203
15769
|
}
|
|
15204
15770
|
});
|
|
15205
15771
|
}
|
|
15206
|
-
function sep2() {
|
|
15207
|
-
return process.platform === "win32" ? "\\" : "/";
|
|
15208
|
-
}
|
|
15209
15772
|
function lineEndingOf(text) {
|
|
15210
15773
|
return text.includes("\r\n") ? "\r\n" : "\n";
|
|
15211
15774
|
}
|
|
@@ -15333,18 +15896,8 @@ You have BOTH \`semantic_search\` (vector index) and \`search_content\` (literal
|
|
|
15333
15896
|
- **Exact-token queries** (a specific identifier, regex, or "find every call to foo") \u2192 call \`search_content\`.
|
|
15334
15897
|
|
|
15335
15898
|
If \`semantic_search\` returns nothing useful (low scores, off-topic), THEN fall back to \`search_content\`. Don't go the other way \u2014 grepping a paraphrased question wastes turns.`;
|
|
15336
|
-
var ENGINEERING_LIFECYCLE_CONTRACT = `
|
|
15337
|
-
|
|
15338
|
-
# Engineering lifecycle contract
|
|
15339
|
-
|
|
15340
|
-
Reasonix may enforce a prefix-stable Engineering Lifecycle for explicitly enabled high-risk engineering work. The runtime keeps lifecycle state outside the system prompt and tool list, so do not expect stage-specific prompt changes or new tools to appear. Treat any lifecycle block as a host constraint, not as a suggestion.
|
|
15341
|
-
|
|
15342
|
-
When high-risk mutations are bounced with \`rejectedReason: "engineering-lifecycle"\`, switch to read-only exploration, then call \`submit_plan\` with concrete steps before trying the mutation again. Add optional per-step \`targets\`, \`acceptance\`, and \`verification\` fields when they clarify scope or success criteria. For medium/high-risk steps, steps with verification criteria, or steps that changed code, \`mark_step_complete\` requires \`evidence\` entries such as verification output, diff summary, checkpoint id, or manual rationale.`;
|
|
15343
15899
|
function codeSystemPrompt(rootDir, opts = {}) {
|
|
15344
|
-
|
|
15345
|
-
if (opts.engineeringLifecycleMode === "strict") {
|
|
15346
|
-
codeBase = `${codeBase}${ENGINEERING_LIFECYCLE_CONTRACT}`;
|
|
15347
|
-
}
|
|
15900
|
+
const codeBase = codeSystemBase(opts.modelId ?? DEFAULT_CODE_MODEL);
|
|
15348
15901
|
const base = opts.hasSemanticSearch ? `${codeBase}${SEMANTIC_SEARCH_ROUTING}` : codeBase;
|
|
15349
15902
|
const withMemory = applyMemoryStack(base, rootDir);
|
|
15350
15903
|
const gitignorePath = join15(rootDir, ".gitignore");
|
|
@@ -15698,8 +16251,10 @@ export {
|
|
|
15698
16251
|
loadApiKey,
|
|
15699
16252
|
loadBaseUrl,
|
|
15700
16253
|
loadDotenv,
|
|
16254
|
+
loadExaApiKey,
|
|
15701
16255
|
loadHooks,
|
|
15702
16256
|
loadMetasoApiKey,
|
|
16257
|
+
loadPerplexityApiKey,
|
|
15703
16258
|
loadSessionMessages,
|
|
15704
16259
|
matchesTool,
|
|
15705
16260
|
memoryEnabled,
|