reasonix 0.30.4 → 0.31.0
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 +23 -0
- package/README.zh-CN.md +23 -0
- package/dashboard/app.css +149 -0
- package/dashboard/dist/app.js +691 -8
- package/dashboard/dist/app.js.map +1 -1
- package/dist/cli/{chunk-COFBA5FV.js → chunk-VWFJNLIK.js} +50 -8
- package/dist/cli/chunk-VWFJNLIK.js.map +1 -0
- package/dist/cli/index.js +2148 -1075
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/{prompt-VF7B6BWR.js → prompt-XHICFAYN.js} +2 -2
- package/dist/index.d.ts +22 -4
- package/dist/index.js +2279 -362
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/cli/chunk-COFBA5FV.js.map +0 -1
- /package/dist/cli/{prompt-VF7B6BWR.js.map → prompt-XHICFAYN.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -545,9 +545,1885 @@ var pauseGate = new PauseGate();
|
|
|
545
545
|
|
|
546
546
|
// src/hooks.ts
|
|
547
547
|
import { spawn } from "child_process";
|
|
548
|
-
import { existsSync, readFileSync } from "fs";
|
|
548
|
+
import { existsSync, readFileSync as readFileSync2 } from "fs";
|
|
549
|
+
import { homedir as homedir2 } from "os";
|
|
550
|
+
import { join as join2 } from "path";
|
|
551
|
+
|
|
552
|
+
// src/config.ts
|
|
553
|
+
import { chmodSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
549
554
|
import { homedir } from "os";
|
|
550
|
-
import { join } from "path";
|
|
555
|
+
import { dirname, join } from "path";
|
|
556
|
+
|
|
557
|
+
// src/index/config.ts
|
|
558
|
+
import picomatch from "picomatch";
|
|
559
|
+
var DEFAULT_INDEX_EXCLUDES = {
|
|
560
|
+
dirs: [
|
|
561
|
+
"node_modules",
|
|
562
|
+
".git",
|
|
563
|
+
".hg",
|
|
564
|
+
".svn",
|
|
565
|
+
"dist",
|
|
566
|
+
"build",
|
|
567
|
+
"out",
|
|
568
|
+
".next",
|
|
569
|
+
".nuxt",
|
|
570
|
+
"target",
|
|
571
|
+
".venv",
|
|
572
|
+
"venv",
|
|
573
|
+
"__pycache__",
|
|
574
|
+
".pytest_cache",
|
|
575
|
+
".mypy_cache",
|
|
576
|
+
".cache",
|
|
577
|
+
"coverage",
|
|
578
|
+
".turbo",
|
|
579
|
+
".vercel",
|
|
580
|
+
".reasonix"
|
|
581
|
+
],
|
|
582
|
+
files: [
|
|
583
|
+
"package-lock.json",
|
|
584
|
+
"yarn.lock",
|
|
585
|
+
"pnpm-lock.yaml",
|
|
586
|
+
"Cargo.lock",
|
|
587
|
+
"poetry.lock",
|
|
588
|
+
"Pipfile.lock",
|
|
589
|
+
"go.sum",
|
|
590
|
+
".DS_Store"
|
|
591
|
+
],
|
|
592
|
+
exts: [
|
|
593
|
+
".png",
|
|
594
|
+
".jpg",
|
|
595
|
+
".jpeg",
|
|
596
|
+
".gif",
|
|
597
|
+
".webp",
|
|
598
|
+
".bmp",
|
|
599
|
+
".ico",
|
|
600
|
+
".tiff",
|
|
601
|
+
".woff",
|
|
602
|
+
".woff2",
|
|
603
|
+
".ttf",
|
|
604
|
+
".otf",
|
|
605
|
+
".eot",
|
|
606
|
+
".zip",
|
|
607
|
+
".tar",
|
|
608
|
+
".gz",
|
|
609
|
+
".bz2",
|
|
610
|
+
".xz",
|
|
611
|
+
".rar",
|
|
612
|
+
".7z",
|
|
613
|
+
".exe",
|
|
614
|
+
".dll",
|
|
615
|
+
".so",
|
|
616
|
+
".dylib",
|
|
617
|
+
".bin",
|
|
618
|
+
".class",
|
|
619
|
+
".jar",
|
|
620
|
+
".war",
|
|
621
|
+
".wasm",
|
|
622
|
+
".o",
|
|
623
|
+
".obj",
|
|
624
|
+
".lib",
|
|
625
|
+
".a",
|
|
626
|
+
".pyc",
|
|
627
|
+
".pyo",
|
|
628
|
+
".mp3",
|
|
629
|
+
".mp4",
|
|
630
|
+
".wav",
|
|
631
|
+
".ogg",
|
|
632
|
+
".webm",
|
|
633
|
+
".mov",
|
|
634
|
+
".avi",
|
|
635
|
+
".pdf",
|
|
636
|
+
".sqlite",
|
|
637
|
+
".db"
|
|
638
|
+
]
|
|
639
|
+
};
|
|
640
|
+
var DEFAULT_MAX_FILE_BYTES = 256 * 1024;
|
|
641
|
+
|
|
642
|
+
// src/config.ts
|
|
643
|
+
function defaultConfigPath() {
|
|
644
|
+
return join(homedir(), ".reasonix", "config.json");
|
|
645
|
+
}
|
|
646
|
+
function readConfig(path2 = defaultConfigPath()) {
|
|
647
|
+
try {
|
|
648
|
+
const raw = readFileSync(path2, "utf8");
|
|
649
|
+
const parsed = JSON.parse(raw);
|
|
650
|
+
if (parsed && typeof parsed === "object") return parsed;
|
|
651
|
+
} catch {
|
|
652
|
+
}
|
|
653
|
+
return {};
|
|
654
|
+
}
|
|
655
|
+
function writeConfig(cfg, path2 = defaultConfigPath()) {
|
|
656
|
+
mkdirSync(dirname(path2), { recursive: true });
|
|
657
|
+
writeFileSync(path2, JSON.stringify(cfg, null, 2), "utf8");
|
|
658
|
+
try {
|
|
659
|
+
chmodSync(path2, 384);
|
|
660
|
+
} catch {
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
function loadLanguage(path2 = defaultConfigPath()) {
|
|
664
|
+
return readConfig(path2).lang;
|
|
665
|
+
}
|
|
666
|
+
function loadApiKey(path2 = defaultConfigPath()) {
|
|
667
|
+
if (process.env.DEEPSEEK_API_KEY) return process.env.DEEPSEEK_API_KEY;
|
|
668
|
+
return readConfig(path2).apiKey;
|
|
669
|
+
}
|
|
670
|
+
function webSearchEngine(path2 = defaultConfigPath()) {
|
|
671
|
+
const cfg = readConfig(path2).webSearchEngine;
|
|
672
|
+
if (cfg === "searxng") return "searxng";
|
|
673
|
+
return "mojeek";
|
|
674
|
+
}
|
|
675
|
+
function webSearchEndpoint(path2 = defaultConfigPath()) {
|
|
676
|
+
const cfg = readConfig(path2).webSearchEndpoint;
|
|
677
|
+
if (cfg && typeof cfg === "string") return cfg;
|
|
678
|
+
return "http://localhost:8080";
|
|
679
|
+
}
|
|
680
|
+
function saveApiKey(key, path2 = defaultConfigPath()) {
|
|
681
|
+
const cfg = readConfig(path2);
|
|
682
|
+
cfg.apiKey = key.trim();
|
|
683
|
+
writeConfig(cfg, path2);
|
|
684
|
+
}
|
|
685
|
+
function findProjectKey(cfg, rootDir) {
|
|
686
|
+
const projects = cfg.projects;
|
|
687
|
+
if (!projects) return void 0;
|
|
688
|
+
if (Object.hasOwn(projects, rootDir)) return rootDir;
|
|
689
|
+
if (process.platform !== "win32") return void 0;
|
|
690
|
+
const lower = rootDir.toLowerCase();
|
|
691
|
+
for (const k of Object.keys(projects)) {
|
|
692
|
+
if (k.toLowerCase() === lower) return k;
|
|
693
|
+
}
|
|
694
|
+
return void 0;
|
|
695
|
+
}
|
|
696
|
+
function addProjectShellAllowed(rootDir, prefix, path2 = defaultConfigPath()) {
|
|
697
|
+
const trimmed = prefix.trim();
|
|
698
|
+
if (!trimmed) return;
|
|
699
|
+
const cfg = readConfig(path2);
|
|
700
|
+
if (!cfg.projects) cfg.projects = {};
|
|
701
|
+
const key = findProjectKey(cfg, rootDir) ?? rootDir;
|
|
702
|
+
if (!cfg.projects[key]) cfg.projects[key] = {};
|
|
703
|
+
const existing = cfg.projects[key].shellAllowed ?? [];
|
|
704
|
+
if (existing.includes(trimmed)) return;
|
|
705
|
+
cfg.projects[key].shellAllowed = [...existing, trimmed];
|
|
706
|
+
writeConfig(cfg, path2);
|
|
707
|
+
}
|
|
708
|
+
function isPlausibleKey(key) {
|
|
709
|
+
const trimmed = key.trim();
|
|
710
|
+
return /^sk-[A-Za-z0-9_-]{16,}$/.test(trimmed);
|
|
711
|
+
}
|
|
712
|
+
function redactKey(key) {
|
|
713
|
+
if (!key) return "";
|
|
714
|
+
if (key.length <= 12) return "****";
|
|
715
|
+
return `${key.slice(0, 6)}\u2026${key.slice(-4)}`;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
// src/i18n/EN.ts
|
|
719
|
+
var EN = {
|
|
720
|
+
common: {
|
|
721
|
+
error: "Error",
|
|
722
|
+
warning: "Warning",
|
|
723
|
+
loading: "Loading...",
|
|
724
|
+
done: "Done",
|
|
725
|
+
cancel: "Cancel",
|
|
726
|
+
confirm: "Confirm",
|
|
727
|
+
back: "Back",
|
|
728
|
+
next: "Next"
|
|
729
|
+
},
|
|
730
|
+
cli: {
|
|
731
|
+
description: "DeepSeek-native agent framework \u2014 built for cache hits and cheap tokens.",
|
|
732
|
+
continue: "Resume the most recently used chat session without showing the picker.",
|
|
733
|
+
setup: "Interactive wizard \u2014 API key, preset, MCP servers. Re-run any time to reconfigure.",
|
|
734
|
+
code: "Code-editing chat \u2014 filesystem tools rooted at <dir> (default: cwd), coding system prompt, v4-flash baseline.",
|
|
735
|
+
chat: "Interactive Ink TUI with live cache/cost panel.",
|
|
736
|
+
run: "Run a single task non-interactively, streaming output.",
|
|
737
|
+
stats: "Show usage dashboard.",
|
|
738
|
+
doctor: "One-command health check.",
|
|
739
|
+
commit: "Draft a commit message from the staged diff.",
|
|
740
|
+
sessions: "List saved chat sessions, or inspect one by name.",
|
|
741
|
+
pruneSessions: "Delete saved sessions idle \u2265N days (default 90). Use --dry-run to preview.",
|
|
742
|
+
events: "Pretty-print the kernel event-log sidecar.",
|
|
743
|
+
replay: "Interactive Ink TUI to scrub through a transcript.",
|
|
744
|
+
diff: "Compare two transcripts in a split-pane Ink TUI.",
|
|
745
|
+
mcp: "Model Context Protocol helpers \u2014 discover servers, test your setup.",
|
|
746
|
+
version: "Print Reasonix version.",
|
|
747
|
+
update: "Check for a newer Reasonix and install it.",
|
|
748
|
+
index: "Build (or incrementally refresh) a local semantic search index."
|
|
749
|
+
},
|
|
750
|
+
ui: {
|
|
751
|
+
welcome: "Run `reasonix` any time to start chatting \u2014 your settings are remembered.",
|
|
752
|
+
taglineChat: "DeepSeek-native agent",
|
|
753
|
+
taglineCode: "DeepSeek-native coding agent",
|
|
754
|
+
taglineSub: "cache-first \xB7 flash-first",
|
|
755
|
+
startSessionHint: "type a message to start your session",
|
|
756
|
+
inputPlaceholder: "Ask anything... (type / for commands, @ for files)",
|
|
757
|
+
busy: "Thinking...",
|
|
758
|
+
thinking: "\u25B8 thinking...",
|
|
759
|
+
undo: "Undo",
|
|
760
|
+
undoHint: "press u within 5s to undo",
|
|
761
|
+
applied: "applied",
|
|
762
|
+
rejected: "rejected",
|
|
763
|
+
noDashboard: "Suppress the auto-launched embedded web dashboard.",
|
|
764
|
+
dashboardAutoStartFailed: "\u25B2 dashboard auto-start failed ({reason}) \u2014 try /dashboard, or pass --no-dashboard to silence",
|
|
765
|
+
systemAppendHint: "Append instructions to the code system prompt. Does NOT replace the default prompt \u2014 adds after it.",
|
|
766
|
+
systemAppendFileHint: "Append file contents to the code system prompt. Does NOT replace the default prompt. UTF-8, relative to cwd or absolute.",
|
|
767
|
+
resumedSession: '\u25B8 resumed session "{name}" with {count} prior messages \xB7 /forget to start over \xB7 /sessions to list',
|
|
768
|
+
newSession: '\u25B8 session "{name}" (new) \u2014 auto-saved as you chat \xB7 /forget to delete \xB7 /sessions to list',
|
|
769
|
+
ephemeralSession: "\u25B8 ephemeral chat (no session persistence) \u2014 drop --no-session to enable",
|
|
770
|
+
restoredEdits: "\u25B8 restored {count} pending edit block(s) from an interrupted prior run \u2014 /apply to commit or /discard to drop.",
|
|
771
|
+
resumedPlan: "Resumed plan \xB7 {when}{summary}",
|
|
772
|
+
tipEditBindings: "\u25B8 TIP: edit-gate keybindings\n y / n accept or drop pending edits\n Shift+Tab switch review \u2194 AUTO (persisted; AUTO applies instantly)\n u undo the last auto-applied batch (within the 5s banner)\n Current mode is shown in the bottom status bar. Run /keys anytime for the full list.\n (This tip shows once \u2014 suppressed after.)",
|
|
773
|
+
modelOverride: "override the default model",
|
|
774
|
+
noSession: "disable session persistence for this run",
|
|
775
|
+
resumeHint: "force-resume the named session (even if idle)",
|
|
776
|
+
newHint: "force a fresh session (ignore --session / --continue)",
|
|
777
|
+
transcriptHint: "path to write the JSONL transcript",
|
|
778
|
+
harvestHint: "opt into Pillar-2 plan-state extraction (costs +1 flash call per turn)",
|
|
779
|
+
budgetHint: "session USD cap \u2014 warns at 80%, refuses next turn at 100%",
|
|
780
|
+
modelIdHint: "DeepSeek model id (e.g. deepseek-v4-flash)",
|
|
781
|
+
systemPromptHint: "override the default system prompt",
|
|
782
|
+
presetHint: "model bundle \u2014 auto|flash|pro",
|
|
783
|
+
harvestOptInHint: "opt into Pillar-2 plan-state extraction",
|
|
784
|
+
branchHint: "run N parallel samples per turn (N>=2, manual only)",
|
|
785
|
+
sessionNameHint: "session name (default: 'default')",
|
|
786
|
+
ephemeralHint: "disable session persistence for this run",
|
|
787
|
+
mcpSpecHint: "MCP server spec (repeatable)",
|
|
788
|
+
mcpPrefixHint: "prefix MCP tool names with this string",
|
|
789
|
+
noConfigHint: "ignore ~/.reasonix/config.json for this run",
|
|
790
|
+
presetHintShort: "model bundle \u2014 auto|flash|pro",
|
|
791
|
+
harvestHintShort: "Pillar-2 plan-state extraction",
|
|
792
|
+
branchHintShort: "parallel samples per turn (N>=2)",
|
|
793
|
+
budgetHintShort: "session USD cap",
|
|
794
|
+
transcriptHintShort: "JSONL transcript path",
|
|
795
|
+
mcpSpecHintShort: "MCP server spec (repeatable)",
|
|
796
|
+
mcpPrefixHintShort: "MCP tool name prefix",
|
|
797
|
+
dryRunHint: "show what would be installed without actually installing",
|
|
798
|
+
rebuildHint: "rebuild the index from scratch",
|
|
799
|
+
embedModelHint: "embedding model name",
|
|
800
|
+
projectDirHint: "project root directory",
|
|
801
|
+
ollamaUrlHint: "Ollama server URL",
|
|
802
|
+
skipPromptsHint: "skip confirmation prompts",
|
|
803
|
+
verboseHint: "show full session metadata",
|
|
804
|
+
pruneDaysHint: "delete sessions idle this many days or more (default 90)",
|
|
805
|
+
pruneDryRunHint: "list what would be deleted without removing anything",
|
|
806
|
+
eventTypeHint: "filter by event type",
|
|
807
|
+
eventSinceHint: "start from this event id",
|
|
808
|
+
eventTailHint: "show only the last N events",
|
|
809
|
+
jsonHint: "output as JSON",
|
|
810
|
+
projectionHint: "show projected state at each event",
|
|
811
|
+
printHint: "print to stdout instead of TUI",
|
|
812
|
+
headHint: "show only the first N events",
|
|
813
|
+
tailHint: "show only the last N events",
|
|
814
|
+
mdReportHint: "write a markdown diff report to this path",
|
|
815
|
+
printHintTable: "print a table to stdout",
|
|
816
|
+
tuiHint: "open the interactive TUI",
|
|
817
|
+
labelAHint: "label for the left pane",
|
|
818
|
+
labelBHint: "label for the right pane",
|
|
819
|
+
mcpListDescription: "browse the MCP registry (official \u2192 smithery \u2192 local fallback)",
|
|
820
|
+
mcpInspectDescription: "inspect an MCP server spec (tools, resources, prompts)",
|
|
821
|
+
mcpSearchDescription: "search the MCP registry for servers matching a query",
|
|
822
|
+
mcpInstallDescription: "install an MCP server by name (writes its spec to your config)",
|
|
823
|
+
mcpBrowseDescription: "interactive marketplace browser \u2014 type to filter, enter to install",
|
|
824
|
+
mcpLocalHint: "show only the bundled offline catalog",
|
|
825
|
+
mcpRefreshHint: "bypass the 24h cache and refetch",
|
|
826
|
+
mcpLimitHint: "max entries to show",
|
|
827
|
+
mcpPagesHint: "eagerly load this many pages (default 1)",
|
|
828
|
+
mcpAllHint: "load every page (slow on first run)",
|
|
829
|
+
mcpMaxPagesHint: "cap how many pages to walk while searching (default 20)",
|
|
830
|
+
jsonHintCatalog: "output as JSON",
|
|
831
|
+
jsonHintReport: "output the inspection report as JSON",
|
|
832
|
+
modelOverrideFlash: "override the model (default: deepseek-v4-flash)",
|
|
833
|
+
skipConfirmHint: "skip the confirmation prompt"
|
|
834
|
+
},
|
|
835
|
+
slash: {
|
|
836
|
+
help: { description: "show the full command reference" },
|
|
837
|
+
status: { description: "current model, flags, context, session" },
|
|
838
|
+
preset: {
|
|
839
|
+
description: "model bundle \u2014 auto escalates flash \u2192 pro, flash/pro lock",
|
|
840
|
+
argsHint: "<auto|flash|pro>"
|
|
841
|
+
},
|
|
842
|
+
model: { description: "switch DeepSeek model id", argsHint: "<id>" },
|
|
843
|
+
models: { description: "list available models fetched from DeepSeek /models" },
|
|
844
|
+
language: {
|
|
845
|
+
description: "switch the runtime language",
|
|
846
|
+
argsHint: "<EN|zh-CN>",
|
|
847
|
+
success: "Language switched to English.",
|
|
848
|
+
unsupported: "Unsupported language code: {code}. Supported: {supported}."
|
|
849
|
+
},
|
|
850
|
+
harvest: { description: "toggle Pillar-2 plan-state extraction", argsHint: "[on|off]" },
|
|
851
|
+
branch: { description: "run N parallel samples per turn (N>=2)", argsHint: "<N|off>" },
|
|
852
|
+
effort: {
|
|
853
|
+
description: "reasoning_effort cap \u2014 max is default (agent-class), high is cheaper/faster",
|
|
854
|
+
argsHint: "<high|max>"
|
|
855
|
+
},
|
|
856
|
+
pro: {
|
|
857
|
+
description: "arm v4-pro for the NEXT turn only (one-shot \xB7 auto-disarms after turn)",
|
|
858
|
+
argsHint: "[off]"
|
|
859
|
+
},
|
|
860
|
+
budget: {
|
|
861
|
+
description: "session USD cap \u2014 warns at 80%, refuses next turn at 100%. Off by default. /budget alone shows status",
|
|
862
|
+
argsHint: "[usd|off]"
|
|
863
|
+
},
|
|
864
|
+
mcp: { description: "list MCP servers + tools attached to this session" },
|
|
865
|
+
resource: {
|
|
866
|
+
description: "browse + read MCP resources (no arg \u2192 list URIs; <uri> \u2192 fetch contents)",
|
|
867
|
+
argsHint: "[uri]"
|
|
868
|
+
},
|
|
869
|
+
prompt: {
|
|
870
|
+
description: "browse + fetch MCP prompts (no arg \u2192 list names; <name> \u2192 render prompt)",
|
|
871
|
+
argsHint: "[name]"
|
|
872
|
+
},
|
|
873
|
+
tool: { description: "dump full output of the Nth tool call (1=latest)", argsHint: "[N]" },
|
|
874
|
+
memory: {
|
|
875
|
+
description: "show / manage pinned memory (REASONIX.md + ~/.reasonix/memory)",
|
|
876
|
+
argsHint: "[list|show <name>|forget <name>|clear <scope> confirm]"
|
|
877
|
+
},
|
|
878
|
+
skill: {
|
|
879
|
+
description: "list / run user skills (<project>/.reasonix/skills + ~/.reasonix/skills)",
|
|
880
|
+
argsHint: "[list|show <name>|<name> [args]]"
|
|
881
|
+
},
|
|
882
|
+
hooks: {
|
|
883
|
+
description: "list active hooks (settings.json under .reasonix/) \xB7 reload re-reads from disk",
|
|
884
|
+
argsHint: "[reload]"
|
|
885
|
+
},
|
|
886
|
+
permissions: {
|
|
887
|
+
description: "show / edit shell allowlist (builtin read-only \xB7 per-project: ~/.reasonix/config.json)",
|
|
888
|
+
argsHint: "[list|add <prefix>|remove <prefix|N>|clear confirm]"
|
|
889
|
+
},
|
|
890
|
+
dashboard: {
|
|
891
|
+
description: "launch the embedded web dashboard (127.0.0.1, token-gated)",
|
|
892
|
+
argsHint: "[stop]"
|
|
893
|
+
},
|
|
894
|
+
update: { description: "show current vs latest version + the shell command to upgrade" },
|
|
895
|
+
stats: {
|
|
896
|
+
description: "cross-session cost dashboard (today / week / month / all-time \xB7 cache hit \xB7 vs Claude)"
|
|
897
|
+
},
|
|
898
|
+
cost: {
|
|
899
|
+
description: "bare \u2192 last turn's spend (Usage card); with text \u2192 estimate cost of sending it next (worst-case + likely-cache)",
|
|
900
|
+
argsHint: "[text]"
|
|
901
|
+
},
|
|
902
|
+
doctor: { description: "health check (api / config / api-reach / index / hooks / project)" },
|
|
903
|
+
think: { description: "dump the last turn's full R1 reasoning (reasoner only)" },
|
|
904
|
+
context: { description: "show context-window breakdown (system / tools / log / input)" },
|
|
905
|
+
retry: { description: "truncate & resend your last message (fresh sample)" },
|
|
906
|
+
compact: {
|
|
907
|
+
description: "shrink oversized tool results AND tool-call args (edit_file search/replace) in the log; cap in tokens, default 4000",
|
|
908
|
+
argsHint: "[tokens]"
|
|
909
|
+
},
|
|
910
|
+
keys: { description: "show all keyboard shortcuts and prompt prefixes" },
|
|
911
|
+
plans: { description: "list this session's active + archived plans, newest first" },
|
|
912
|
+
replay: {
|
|
913
|
+
description: "load an archived plan as a read-only Time Travel snapshot (default: newest)",
|
|
914
|
+
argsHint: "[N]"
|
|
915
|
+
},
|
|
916
|
+
sessions: { description: "list saved sessions (current marked with \u25B8)" },
|
|
917
|
+
rename: { description: "rename the current session on disk", argsHint: "<new-name>" },
|
|
918
|
+
resume: {
|
|
919
|
+
description: "show the launch command to resume a saved session",
|
|
920
|
+
argsHint: "<name>"
|
|
921
|
+
},
|
|
922
|
+
forget: { description: "delete the current session from disk" },
|
|
923
|
+
setup: { description: "reminds you to exit and run `reasonix setup`" },
|
|
924
|
+
semantic: {
|
|
925
|
+
description: "show semantic_search status \u2014 built? Ollama installed? how to enable"
|
|
926
|
+
},
|
|
927
|
+
clear: { description: "clear visible scrollback only (log/context kept)" },
|
|
928
|
+
new: { description: "start a fresh conversation (clear context + scrollback)" },
|
|
929
|
+
loop: {
|
|
930
|
+
description: "auto-resubmit <prompt> every <interval> until you type something / Esc / /loop stop",
|
|
931
|
+
argsHint: "<5s..6h> <prompt> \xB7 stop \xB7 (no args = status)"
|
|
932
|
+
},
|
|
933
|
+
exit: { description: "quit the TUI" },
|
|
934
|
+
init: {
|
|
935
|
+
description: "scan the project and synthesize a baseline REASONIX.md (model writes; review with /apply). `force` overwrites an existing file.",
|
|
936
|
+
argsHint: "[force]"
|
|
937
|
+
},
|
|
938
|
+
apply: {
|
|
939
|
+
description: "commit pending edit blocks to disk (no arg \u2192 all; `1`, `1,3`, or `1-4` \u2192 that subset, rest stay pending)",
|
|
940
|
+
argsHint: "[N|N,M|N-M]"
|
|
941
|
+
},
|
|
942
|
+
discard: {
|
|
943
|
+
description: "drop pending edit blocks without writing (no arg \u2192 all; indices \u2192 that subset)",
|
|
944
|
+
argsHint: "[N|N,M|N-M]"
|
|
945
|
+
},
|
|
946
|
+
walk: {
|
|
947
|
+
description: "step through pending edits one block at a time (git-add-p style: y/n per block, a apply rest, A flip AUTO)"
|
|
948
|
+
},
|
|
949
|
+
undo: { description: "roll back the last applied edit batch" },
|
|
950
|
+
history: { description: "list every edit batch this session (ids for /show, undone markers)" },
|
|
951
|
+
show: {
|
|
952
|
+
description: "dump a stored edit diff (omit id for newest non-undone)",
|
|
953
|
+
argsHint: "[id]"
|
|
954
|
+
},
|
|
955
|
+
commit: { description: "git add -A && git commit -m ...", argsHint: '"msg"' },
|
|
956
|
+
checkpoint: {
|
|
957
|
+
description: "snapshot every file the session has touched (Cursor-style internal store, not git). /checkpoint alone lists.",
|
|
958
|
+
argsHint: "[name|list|forget <id>]"
|
|
959
|
+
},
|
|
960
|
+
restore: {
|
|
961
|
+
description: "roll back files to a named checkpoint (see /checkpoint list)",
|
|
962
|
+
argsHint: "<name|id>"
|
|
963
|
+
},
|
|
964
|
+
plan: {
|
|
965
|
+
description: "toggle read-only plan mode (writes bounced until submit_plan + approval)",
|
|
966
|
+
argsHint: "[on|off]"
|
|
967
|
+
},
|
|
968
|
+
"apply-plan": {
|
|
969
|
+
description: "force-approve a pending / in-text plan (fallback if picker was missed)"
|
|
970
|
+
},
|
|
971
|
+
mode: {
|
|
972
|
+
description: "edit-gate: review (queue) \xB7 auto (apply+undo) \xB7 yolo (apply+auto-shell). Shift+Tab cycles.",
|
|
973
|
+
argsHint: "[review|auto|yolo]"
|
|
974
|
+
},
|
|
975
|
+
jobs: { description: "list background jobs started by run_background" },
|
|
976
|
+
kill: {
|
|
977
|
+
description: "stop a background job by id (SIGTERM \u2192 SIGKILL after grace)",
|
|
978
|
+
argsHint: "<id>"
|
|
979
|
+
},
|
|
980
|
+
logs: {
|
|
981
|
+
description: "tail a background job's output (default last 80 lines)",
|
|
982
|
+
argsHint: "<id> [lines]"
|
|
983
|
+
}
|
|
984
|
+
},
|
|
985
|
+
wizard: {
|
|
986
|
+
languageTitle: "Choose your language",
|
|
987
|
+
languageSubtitle: "Detected from your system locale. Switch later via /language.",
|
|
988
|
+
welcomeTitle: "Welcome to Reasonix.",
|
|
989
|
+
apiKeyPrompt: "Paste your DeepSeek API key to get started.",
|
|
990
|
+
apiKeyGetOne: "Get one at: https://platform.deepseek.com/api_keys",
|
|
991
|
+
apiKeySavedLocally: "Saved locally to {path}",
|
|
992
|
+
apiKeyInputLabel: "key \u203A ",
|
|
993
|
+
apiKeyInvalid: "Doesn't look like a DeepSeek key. They start with 'sk-' and are 30+ chars.",
|
|
994
|
+
apiKeyPreview: "preview: {redacted}",
|
|
995
|
+
presetTitle: "Pick a preset",
|
|
996
|
+
mcpTitle: "Which MCP servers should Reasonix wire up for you?",
|
|
997
|
+
mcpUserArgsHint: "(you'll provide {arg})",
|
|
998
|
+
mcpFooterMulti: "[\u2191\u2193] navigate \xB7 [Space] toggle \xB7 [Enter] confirm \xB7 [Esc] cancel \xB7 empty = skip",
|
|
999
|
+
mcpArgsTitle: "Configure {name}",
|
|
1000
|
+
mcpArgsDirMissing: "Directory {path} doesn't exist.",
|
|
1001
|
+
mcpArgsDirCreateHint: "[Y/Enter] create it (mkdir -p) \xB7 [N/Esc] enter a different path",
|
|
1002
|
+
mcpArgsDirCreateFailed: "Couldn't create {path}: {message}",
|
|
1003
|
+
mcpArgsRequiredParam: "Required parameter: ",
|
|
1004
|
+
mcpArgsEmpty: "{name} needs a value \u2014 got an empty string.",
|
|
1005
|
+
mcpArgsNotADir: "{path} exists but is not a directory.",
|
|
1006
|
+
reviewTitle: "Ready to save",
|
|
1007
|
+
reviewLabelApiKey: "API key",
|
|
1008
|
+
reviewLabelLanguage: "Language",
|
|
1009
|
+
reviewLabelPreset: "Preset",
|
|
1010
|
+
reviewLabelMcp: "MCP",
|
|
1011
|
+
reviewMcpNone: "(none)",
|
|
1012
|
+
reviewMcpServers: "{count} server(s)",
|
|
1013
|
+
reviewSavesTo: "Saves to {path}",
|
|
1014
|
+
reviewSaveError: "Could not save config: {message}",
|
|
1015
|
+
reviewFooter: "[Enter] save \xB7 [Esc] cancel",
|
|
1016
|
+
savedTitle: "\u25B8 Saved.",
|
|
1017
|
+
savedFooter: "[Enter] to exit",
|
|
1018
|
+
selectFooter: "[\u2191\u2193] navigate \xB7 [Enter] confirm \xB7 [Esc] cancel",
|
|
1019
|
+
stepCounter: "Step {step}/{total} \xB7 "
|
|
1020
|
+
},
|
|
1021
|
+
app: {
|
|
1022
|
+
walkCancelledRemaining: "\u25B8 walk cancelled \u2014 {count} block(s) still pending.",
|
|
1023
|
+
walkCancelled: "\u25B8 walk cancelled.",
|
|
1024
|
+
editModeYolo: "\u25B8 edit mode: YOLO \u2014 edits AND shell commands auto-run. /undo still rolls back edits. Use carefully.",
|
|
1025
|
+
editModeAuto: "\u25B8 edit mode: AUTO \u2014 edits apply immediately; press u within 5s to undo (space pauses the timer). Shell commands still ask.",
|
|
1026
|
+
editModeReview: "\u25B8 edit mode: review \u2014 edits queue for /apply (or y) / /discard (or n)",
|
|
1027
|
+
rejectedEdit: "\u25B8 rejected edit to {path}{context}",
|
|
1028
|
+
autoApprovingRest: "\u25B8 auto-approving remaining edits for this turn",
|
|
1029
|
+
flippedAutoSession: "\u25B8 flipped to AUTO mode for the rest of the session (persisted)",
|
|
1030
|
+
flippedAutoWalk: "\u25B8 flipped to AUTO mode \u2014 future edits will apply immediately. Walk exited.",
|
|
1031
|
+
dashboardStopped: "\u25B8 dashboard stopped.",
|
|
1032
|
+
notedMemory: "\u25B8 noted ({scope}) \u2014 {verb} {path}",
|
|
1033
|
+
notedScopeProject: "project",
|
|
1034
|
+
notedScopeGlobal: "global",
|
|
1035
|
+
notedVerbCreated: "created",
|
|
1036
|
+
notedVerbAppended: "appended to",
|
|
1037
|
+
memoryWriteFailed: "# memory write failed",
|
|
1038
|
+
commandFailed: "! command failed",
|
|
1039
|
+
restoreCodeOnly: "\u25B8 /restore is code-mode only",
|
|
1040
|
+
hookUserPromptSubmit: "UserPromptSubmit hook",
|
|
1041
|
+
hookStop: "Stop hook",
|
|
1042
|
+
atMentions: "\u25B8 @mentions: {parts}",
|
|
1043
|
+
atUrl: "\u25B8 @url: {parts}",
|
|
1044
|
+
atUrlFailed: "@url expansion failed",
|
|
1045
|
+
denied: "\u25B8 denied: {cmd}{context}",
|
|
1046
|
+
alwaysAllowed: '\u25B8 always allowed "{prefix}" for {dir}',
|
|
1047
|
+
runningCommand: "\u25B8 running: {cmd}",
|
|
1048
|
+
startingBackground: "\u25B8 starting (background): {cmd}",
|
|
1049
|
+
checkpointSaved: "\u26C1 checkpoint saved \xB7 {id} \xB7 {count} file{s} \xB7 /restore {id} to roll back this step",
|
|
1050
|
+
continuingAfter: "\u25B8 continuing after {label}{counter}",
|
|
1051
|
+
planStoppedAt: "\u25B8 plan stopped at {label}{counter}",
|
|
1052
|
+
revisingAfter: "\u25B8 revising after {label} \u2014 {feedback}"
|
|
1053
|
+
},
|
|
1054
|
+
hooks: {
|
|
1055
|
+
head: "hook {tag} `{cmd}` {decision}{truncTag}",
|
|
1056
|
+
headWithDetail: "hook {tag} `{cmd}` {decision}{truncTag}: {detail}",
|
|
1057
|
+
truncated: " (output truncated at 256KB)",
|
|
1058
|
+
decisionBlock: "block",
|
|
1059
|
+
decisionWarn: "warn",
|
|
1060
|
+
decisionTimeout: "timeout",
|
|
1061
|
+
decisionError: "error"
|
|
1062
|
+
},
|
|
1063
|
+
summary: {
|
|
1064
|
+
status: "summarizing what was gathered\u2026",
|
|
1065
|
+
hallucinatedFallback: "(model emitted fake tool-call markup instead of a prose summary \u2014 try /retry with a narrower question, or /think to inspect R1's reasoning)",
|
|
1066
|
+
failedAfterReason: "{label} and the fallback summary call failed: {message}. Run /clear and retry with a narrower question, or raise --max-tool-iters."
|
|
1067
|
+
},
|
|
1068
|
+
loop: {
|
|
1069
|
+
budgetExhausted: "session budget exhausted \u2014 spent ${spent} \u2265 cap ${cap}. Bump the cap with /budget <usd>, clear it with /budget off, or end the session.",
|
|
1070
|
+
budget80Pct: "\u25B2 budget 80% used \u2014 ${spent} of ${cap}. Next turn or two likely trips the cap.",
|
|
1071
|
+
proArmed: "\u21E7 /pro armed \u2014 this turn runs on deepseek-v4-pro (one-shot \xB7 disarms after turn)",
|
|
1072
|
+
abortedAtIter: "aborted at iter {iter}/{cap} \u2014 stopped without producing a summary (press \u2191 + Enter or /retry to resume)",
|
|
1073
|
+
toolUploadStatus: "tool result uploaded \xB7 model thinking before next response\u2026",
|
|
1074
|
+
toolBudgetWarning: "{iter}/{cap} tool calls used \u2014 approaching budget. Press Esc to force a summary now.",
|
|
1075
|
+
preflightFoldStatus: "preflight: context near full, attempting fold\u2026",
|
|
1076
|
+
preflightFolded: "preflight: request ~{estimate}/{ctxMax} tokens ({pct}%) \u2014 folded {beforeMessages} messages \u2192 {afterMessages} (summary {summaryChars} chars). Sending.",
|
|
1077
|
+
preflightNoFold: "preflight: request ~{estimate}/{ctxMax} tokens ({pct}%) and nothing left to fold \u2014 DeepSeek will likely 400. Run /clear or /new to start fresh.",
|
|
1078
|
+
flashEscalation: "\u21E7 flash requested escalation \u2014 retrying this turn on {model}{reasonSuffix}",
|
|
1079
|
+
harvestStatus: "extracting plan state from reasoning\u2026",
|
|
1080
|
+
autoEscalation: "\u21E7 auto-escalating to {model} for the rest of this turn \u2014 flash hit {breakdown}. Next turn falls back to {fallback} unless /pro is armed.",
|
|
1081
|
+
repeatToolCallWarning: "Caught a repeated tool call \u2014 let the model see the issue and retry with a different approach.",
|
|
1082
|
+
stormStuck: "Stopped a stuck retry loop \u2014 the model kept calling the same tool with identical args after a self-correction nudge. Try /retry, rephrase, or rule out the underlying blocker.",
|
|
1083
|
+
stormSuppressed: "Suppressed {count} repeated tool call(s) \u2014 same name + args fired 3+ times.",
|
|
1084
|
+
compactingHistoryStatus: "compacting history{aggressiveTag}\u2026",
|
|
1085
|
+
aggressiveTag: " (aggressive)",
|
|
1086
|
+
foldedHistory: "context {before}/{ctxMax} ({pct}%) \u2014 folded {beforeMessages} messages \u2192 {afterMessages} (summary {summaryChars} chars). Continuing.",
|
|
1087
|
+
aggressivelyFoldedHistory: "context {before}/{ctxMax} ({pct}%) \u2014 aggressively folded {beforeMessages} messages \u2192 {afterMessages} (summary {summaryChars} chars). Continuing.",
|
|
1088
|
+
forcingSummary: "context {before}/{ctxMax} ({pct}%) \u2014 forcing summary from what was gathered. Run /compact, /clear, or /new to reset."
|
|
1089
|
+
},
|
|
1090
|
+
errors: {
|
|
1091
|
+
contextOverflow: "Context overflow (DeepSeek 400): session history is {requested}, past the model's prompt limit (V4: 1M tokens; legacy chat/reasoner: 131k). Usually a single tool result grew too big. Reasonix caps new tool results at 8k tokens and auto-heals oversized history on session load \u2014 a restart often clears it. If it still overflows, run /forget (delete the session) or /clear (drop the displayed history) to start fresh.",
|
|
1092
|
+
contextOverflowTooMany: "too many tokens",
|
|
1093
|
+
auth401: "Authentication failed (DeepSeek 401): {inner}. Your API key is rejected. Fix with `reasonix setup` or `export DEEPSEEK_API_KEY=sk-...`. Get one at https://platform.deepseek.com/api_keys.",
|
|
1094
|
+
balance402: "Out of balance (DeepSeek 402): {inner}. Top up at https://platform.deepseek.com/top_up \u2014 the panel header shows your balance once it's non-zero.",
|
|
1095
|
+
badparam422: "Invalid parameter (DeepSeek 422): {inner}",
|
|
1096
|
+
badrequest400: "Bad request (DeepSeek 400): {inner}",
|
|
1097
|
+
deepseek5xxHead: "DeepSeek service unavailable ({status}) \u2014 this is a DeepSeek-side problem, not Reasonix. Already retried 4\xD7 with backoff.",
|
|
1098
|
+
deepseek5xxReachable: " DeepSeek's main API answered our health check, but /chat/completions is failing \u2014 partial outage on their side.",
|
|
1099
|
+
deepseek5xxUnreachable: " DeepSeek API is unreachable from your network \u2014 could be a wider DS outage or a local network issue.",
|
|
1100
|
+
deepseek5xxActionNetwork: " Try: (1) check your network, (2) wait 30s and retry, (3) status page: https://status.deepseek.com.",
|
|
1101
|
+
deepseek5xxActionRetry: " Try: (1) wait 30s and retry, (2) /preset to switch model, (3) status page: https://status.deepseek.com.",
|
|
1102
|
+
innerNoMessage: "(no message)",
|
|
1103
|
+
reasonAborted: "[aborted by user (Esc) \u2014 summarizing what I found so far]",
|
|
1104
|
+
reasonContextGuard: "[context budget running low \u2014 summarizing before the next call would overflow]",
|
|
1105
|
+
reasonStuck: "[stuck on a repeated tool call \u2014 explaining what was tried and what's blocking progress]",
|
|
1106
|
+
reasonBudget: "[tool-call budget ({iterCap}) reached \u2014 forcing summary from what I found]",
|
|
1107
|
+
labelAborted: "aborted by user",
|
|
1108
|
+
labelContextGuard: "context-guard triggered (prompt > 80% of window)",
|
|
1109
|
+
labelStuck: "stuck (repeated tool call suppressed by storm-breaker)",
|
|
1110
|
+
labelBudget: "tool-call budget ({iterCap}) reached"
|
|
1111
|
+
},
|
|
1112
|
+
handlers: {
|
|
1113
|
+
basic: {
|
|
1114
|
+
clearInfo: "\u25B8 terminal cleared (viewport + scrollback). Context (message log) is intact \u2014 next turn still sees everything. Use /new to start fresh, or /forget to delete the session entirely.",
|
|
1115
|
+
newInfo: "\u25B8 new conversation \u2014 dropped {count} message(s) from context. Same session, fresh slate.",
|
|
1116
|
+
helpTitle: "Commands:",
|
|
1117
|
+
helpHelp: " /help this message",
|
|
1118
|
+
helpKeys: " /keys keyboard shortcuts + prompt prefixes (!, @, /)",
|
|
1119
|
+
helpStatus: " /status show current settings",
|
|
1120
|
+
helpPreset: " /preset <auto|flash|pro> model bundle \u2014 see below",
|
|
1121
|
+
helpModel: " /model <id> deepseek-v4-flash or deepseek-v4-pro",
|
|
1122
|
+
helpPro: " /pro [off] arm v4-pro for NEXT turn only (one-shot, auto-disarms)",
|
|
1123
|
+
helpHarvest: " /harvest [on|off] Pillar 2: structured plan-state extraction (OPT-IN \u2014 costs extra)",
|
|
1124
|
+
helpBranch: " /branch <N|off> run N parallel samples (N>=2) \u2014 MANUAL ONLY, N\xD7 cost",
|
|
1125
|
+
helpEffort: " /effort <high|max> reasoning_effort cap (max=full thinking, high=cheaper/faster)",
|
|
1126
|
+
helpMcp: " /mcp list MCP servers + tools attached to this session",
|
|
1127
|
+
helpResource: " /resource [uri] browse + read MCP resources (no arg \u2192 list URIs; <uri> \u2192 fetch)",
|
|
1128
|
+
helpPrompt: " /prompt [name] browse + fetch MCP prompts (no arg \u2192 list names; <name> \u2192 render)",
|
|
1129
|
+
helpCompact: " /compact fold older turns into a summary (cache-safe; auto-fires at 50% ctx)",
|
|
1130
|
+
helpThink: " /think dump the most recent turn's full R1 reasoning (reasoner only)",
|
|
1131
|
+
helpTool: " /tool [N] list tool calls (or dump full output of #N, 1=most recent)",
|
|
1132
|
+
helpCost: " /cost [text] bare \u2192 last turn's spend; with text \u2192 estimate cost of sending it next",
|
|
1133
|
+
helpMemory: " /memory [sub] show pinned memory (REASONIX.md + ~/.reasonix/memory).",
|
|
1134
|
+
helpMemorySub: " subs: list | show <name> | forget <name> | clear <scope> confirm",
|
|
1135
|
+
helpSkill: " /skill [sub] list / run user skills (project/.reasonix/skills + ~/.reasonix/skills).",
|
|
1136
|
+
helpSkillSub: " subs: list | show <name> | <name> [args] (injects skill body as user turn)",
|
|
1137
|
+
helpRetry: " /retry truncate & resend your last message (fresh sample from the model)",
|
|
1138
|
+
helpApply: " /apply [N|1,3|1-4] (code mode) commit pending edit blocks (no arg \u2192 all; index \u2192 subset)",
|
|
1139
|
+
helpDiscard: " /discard [N|1,3|1-4] (code mode) drop pending edits (no arg \u2192 all; index \u2192 subset)",
|
|
1140
|
+
helpWalk: " /walk (code mode) step through pending edits one block at a time (y/n per block, a apply rest, A flip AUTO)",
|
|
1141
|
+
helpUndo: " /undo (code mode) roll back the latest non-undone edit batch",
|
|
1142
|
+
helpHistory: " /history (code mode) list every edit batch this session",
|
|
1143
|
+
helpShow: " /show [id] (code mode) dump a stored edit diff (newest when id omitted)",
|
|
1144
|
+
helpCommit: ' /commit "msg" (code mode) git add -A && git commit -m "msg"',
|
|
1145
|
+
helpPlan: " /plan [on|off] (code mode) toggle read-only plan mode; writes gated behind submit_plan + your approval",
|
|
1146
|
+
helpApplyPlan: " /apply-plan (code mode) force-approve pending/in-text plan (fallback)",
|
|
1147
|
+
helpMode: " /mode [review|auto|yolo] (code mode) review = queue \xB7 auto = apply+undo banner \xB7 yolo = apply+auto-shell. Shift+Tab cycles all three.",
|
|
1148
|
+
helpJobs: " /jobs (code mode) list background processes (run_background) \u2014 running and exited",
|
|
1149
|
+
helpKill: " /kill <id> (code mode) stop a background job by id (SIGTERM \u2192 SIGKILL)",
|
|
1150
|
+
helpLogs: " /logs <id> [lines] (code mode) tail a background job's output (default 80 lines)",
|
|
1151
|
+
helpSessions: " /sessions list saved sessions (current is marked with \u25B8)",
|
|
1152
|
+
helpForget: " /forget delete the current session from disk",
|
|
1153
|
+
helpNew: " /new start fresh: drop all context + clear scrollback",
|
|
1154
|
+
helpClear: " /clear clear displayed scrollback only (context kept \u2014 model still sees it)",
|
|
1155
|
+
helpLoop: " /loop <interval> <prompt> auto-resubmit <prompt> every <interval> (5s..6h). /loop stop \xB7 type anything to cancel.",
|
|
1156
|
+
helpExit: " /exit quit (aliases: /quit, /q)",
|
|
1157
|
+
helpShellTitle: "Shell shortcut:",
|
|
1158
|
+
helpShell: " !<cmd> run <cmd> in the sandbox root; output goes into",
|
|
1159
|
+
helpShellDetail: " the conversation so the model sees it next turn.",
|
|
1160
|
+
helpShellConsent: " No allowlist gate \u2014 user-typed = explicit consent.",
|
|
1161
|
+
helpShellExample: " Example: !git status !ls src/ !npm test",
|
|
1162
|
+
helpMemoryTitle: "Quick memory:",
|
|
1163
|
+
helpMemoryPin: " #<note> append <note> to <project>/REASONIX.md (committable).",
|
|
1164
|
+
helpMemoryPinEx: " Example: #findByEmail must be case-insensitive",
|
|
1165
|
+
helpMemoryGlobal: " #g <note> append <note> to ~/.reasonix/REASONIX.md (global, never committed).",
|
|
1166
|
+
helpMemoryGlobalEx: " Example: #g always run pnpm not npm",
|
|
1167
|
+
helpMemoryPinBoth: " Both pin into every future session's prefix. Faster than /memory.",
|
|
1168
|
+
helpMemoryEscape: " Use `\\#text` to send a literal `#text` to the model.",
|
|
1169
|
+
helpFileTitle: "File references (code mode):",
|
|
1170
|
+
helpFile: " @path/to/file inline file content under [Referenced files] on send.",
|
|
1171
|
+
helpFilePicker: " Type `@` to open the picker (\u2191\u2193 navigate, Tab/Enter pick).",
|
|
1172
|
+
helpUrlTitle: "URL references:",
|
|
1173
|
+
helpUrl: " @https://example.com fetch the URL, strip HTML, inline under [Referenced URLs].",
|
|
1174
|
+
helpUrlCache: " Same URL twice in one session fetches once (in-mem cache).",
|
|
1175
|
+
helpUrlPunct: " Trailing sentence punctuation (./,/)) is stripped automatically.",
|
|
1176
|
+
helpPresetsTitle: "Presets (branch + harvest are NEVER auto-enabled \u2014 opt-in only):",
|
|
1177
|
+
helpPresetAuto: " auto v4-flash \u2192 v4-pro on hard turns \u2190 default \xB7 cheap when easy, smart when hard",
|
|
1178
|
+
helpPresetFlash: " flash v4-flash always cheapest \xB7 predictable per-turn cost",
|
|
1179
|
+
helpPresetPro: " pro v4-pro always ~3\xD7 flash (5/31) \xB7 hard multi-turn work",
|
|
1180
|
+
helpSessionsTitle: "Sessions (auto-enabled by default, named 'default'):",
|
|
1181
|
+
helpSessionCustom: " reasonix chat --session <name> use a different named session",
|
|
1182
|
+
helpSessionNone: " reasonix chat --no-session disable persistence for this run",
|
|
1183
|
+
helpLimitationTitle: "Known limitation:",
|
|
1184
|
+
helpLimitation1: " Resizing the terminal mid-session may stack ghost header frames in",
|
|
1185
|
+
helpLimitation2: " scrollback (Ink library's live-region clear doesn't account for line",
|
|
1186
|
+
helpLimitation3: " re-wrapping at the new width). Scroll-up history is unaffected; the",
|
|
1187
|
+
helpLimitation4: " artifact is purely visual and clears the next time you /clear.",
|
|
1188
|
+
keysTitle: "Keyboard & prompt shortcuts:",
|
|
1189
|
+
keysEnter: " Enter submit the current prompt",
|
|
1190
|
+
keysNewline: " Shift+Enter / Ctrl+J insert a newline (multi-line prompt)",
|
|
1191
|
+
keysContinue: " \\<Enter> bash-style line continuation",
|
|
1192
|
+
keysArrow: " \u2190 \u2192 \u2191 \u2193 move cursor / recall history at buffer boundary",
|
|
1193
|
+
keysPage: " PageUp / PageDown jump to top / bottom of the WHOLE buffer (handy after a big paste)",
|
|
1194
|
+
keysHomeEnd: " Ctrl+A / Ctrl+E jump to start / end of the CURRENT line",
|
|
1195
|
+
keysClearLine: " Ctrl+U clear the entire input buffer",
|
|
1196
|
+
keysDeleteWord: " Ctrl+W delete the word before the cursor",
|
|
1197
|
+
keysBackspace: " Backspace delete left; Delete delete under cursor",
|
|
1198
|
+
keysEsc: " Esc abort the in-flight turn",
|
|
1199
|
+
keysEditYn: " y / n accept / reject pending edits (code mode)",
|
|
1200
|
+
keysEditTab: " Shift+Tab cycle edit gate: review \u2194 AUTO (code mode, persists to config)",
|
|
1201
|
+
keysEditUndo: " u undo the latest non-undone edit batch (session-wide, not just banner)",
|
|
1202
|
+
keysPromptTitle: "Prompt prefixes:",
|
|
1203
|
+
keysSlash: " /<name> slash command; Tab/Enter picks from the suggestion list",
|
|
1204
|
+
keysAtFile: " @<path> inline a file under [Referenced files] (code mode).",
|
|
1205
|
+
keysAtFilePicker: " Trailing `@\u2026` opens a file picker; \u2191/\u2193 navigate, Tab/Enter pick.",
|
|
1206
|
+
keysAtUrl: " @https://... fetch the URL, strip HTML, inline under [Referenced URLs].",
|
|
1207
|
+
keysAtUrlCache: " Cached per session \u2014 same URL twice fetches once.",
|
|
1208
|
+
keysBang: " !<cmd> run <cmd> as shell in the sandbox root; output goes into context",
|
|
1209
|
+
keysBangDetail: " so the model sees it next turn. No allowlist gate.",
|
|
1210
|
+
keysHash: " #<note> append <note> to <project>/REASONIX.md (committable, team-shared).",
|
|
1211
|
+
keysHashGlobal: " #g <note> append <note> to ~/.reasonix/REASONIX.md (global, never committed).",
|
|
1212
|
+
keysHashBoth: " Both pin into the immutable prefix every future session.",
|
|
1213
|
+
keysHashEscape: " Use `\\#literal` if you actually want a `#` heading sent to the model.",
|
|
1214
|
+
keysPickersTitle: "Pickers (slash + @-mention):",
|
|
1215
|
+
keysPickerNav: " \u2191 / \u2193 navigate the suggestion list",
|
|
1216
|
+
keysPickerTab: " Tab insert the highlighted item without submitting",
|
|
1217
|
+
keysPickerEnter: " Enter insert and (slash) run it, (@) keep editing",
|
|
1218
|
+
keysMcpTitle: "MCP exploration:",
|
|
1219
|
+
keysMcpServers: " /mcp servers + tool/resource/prompt counts",
|
|
1220
|
+
keysMcpResource: " /resource [uri] browse & read resources exposed by your MCP servers",
|
|
1221
|
+
keysMcpPrompt: " /prompt [name] browse & fetch prompts exposed by your MCP servers",
|
|
1222
|
+
keysUseful: "Useful slashes: /help \xB7 /context \xB7 /stats \xB7 /compact \xB7 /new \xB7 /exit",
|
|
1223
|
+
retryNone: "nothing to retry \u2014 no prior user message in this session's log.",
|
|
1224
|
+
retryInfo: '\u25B8 retrying: "{preview}"',
|
|
1225
|
+
loopTuiOnly: "/loop is only available in the interactive TUI (not in run/replay).",
|
|
1226
|
+
loopStopped: "\u25B8 loop stopped.",
|
|
1227
|
+
loopNoActive: "no active loop to stop.",
|
|
1228
|
+
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.",
|
|
1229
|
+
loopStarted: '\u25B8 loop started \u2014 re-submitting "{prompt}" every {duration}. Type anything (or /loop stop) to cancel.'
|
|
1230
|
+
},
|
|
1231
|
+
admin: {
|
|
1232
|
+
doctorNeedsTui: "/doctor needs a TUI context (postDoctor wired).",
|
|
1233
|
+
doctorRunning: "\u2695 Doctor \u2014 running health checks\u2026",
|
|
1234
|
+
hooksReloadUnavailable: "/hooks reload is not available in this context (no reload callback wired).",
|
|
1235
|
+
hooksReloaded: "\u25B8 reloaded hooks \xB7 {count} active",
|
|
1236
|
+
hooksUsage: "usage: /hooks list active hooks\n /hooks reload re-read settings.json files",
|
|
1237
|
+
hooksNone: "no hooks configured.",
|
|
1238
|
+
hooksDropHint: "drop a settings.json with a `hooks` key into either of:",
|
|
1239
|
+
hooksProject: " \xB7 {path} (project)",
|
|
1240
|
+
hooksProjectFallback: " \xB7 <project>/.reasonix/settings.json (project)",
|
|
1241
|
+
hooksGlobal: " \xB7 {path} (global)",
|
|
1242
|
+
hooksEvents: "events: PreToolUse, PostToolUse, UserPromptSubmit, Stop",
|
|
1243
|
+
hooksExitCodes: "exit 0 = pass \xB7 exit 2 = block (Pre*) \xB7 other = warn",
|
|
1244
|
+
hooksLoaded: "\u25B8 {count} hook(s) loaded",
|
|
1245
|
+
hooksSources: "sources: project={project} \xB7 global={global}",
|
|
1246
|
+
updateCurrent: "current: reasonix {version}",
|
|
1247
|
+
updateLatestPending: "latest: (not yet resolved \u2014 background check in flight or offline)",
|
|
1248
|
+
updateRetryHint: "triggered a fresh registry fetch \u2014 retry `/update` in a few seconds,",
|
|
1249
|
+
updateRetryHint2: "or run `reasonix update` in another terminal to force it synchronously.",
|
|
1250
|
+
updateLatest: "latest: reasonix {version}",
|
|
1251
|
+
updateUpToDate: "you're on the latest. nothing to do.",
|
|
1252
|
+
updateNpxHint: "you're running via npx \u2014 the next `npx reasonix ...` launch will auto-fetch.",
|
|
1253
|
+
updateNpxForce: "to force a refresh sooner: `npm cache clean --force`.",
|
|
1254
|
+
updateUpgradeHint: "to upgrade, exit this session and run:",
|
|
1255
|
+
updateUpgradeCmd1: " reasonix update (interactive, dry-run supported via --dry-run)",
|
|
1256
|
+
updateUpgradeCmd2: " npm install -g reasonix@latest (direct)",
|
|
1257
|
+
updateInSessionDisabled: "in-session install is deliberately disabled \u2014 the npm spawn would",
|
|
1258
|
+
updateInSessionDisabled2: "corrupt this TUI's rendering and Windows can lock the running binary.",
|
|
1259
|
+
statsNoData: "no usage data yet.",
|
|
1260
|
+
statsEveryTurn: "every turn you run here appends one record \u2014 this session's turns",
|
|
1261
|
+
statsWillAppear: "will show up in the dashboard once you send a message."
|
|
1262
|
+
},
|
|
1263
|
+
edits: {
|
|
1264
|
+
undoCodeOnly: "/undo is only available inside `reasonix code` \u2014 chat mode doesn't apply edits.",
|
|
1265
|
+
historyCodeOnly: "/history is only available inside `reasonix code`.",
|
|
1266
|
+
showCodeOnly: "/show is only available inside `reasonix code`.",
|
|
1267
|
+
applyCodeOnly: "/apply is only available inside `reasonix code` (nothing to apply here).",
|
|
1268
|
+
discardCodeOnly: "/discard is only available inside `reasonix code`.",
|
|
1269
|
+
planCodeOnly: "/plan is only available inside `reasonix code` \u2014 chat mode doesn't gate tool writes.",
|
|
1270
|
+
planOn: "\u25B8 plan mode ON \u2014 write tools are gated; the model MUST call `submit_plan` before anything executes. (The model can also call submit_plan on its own for big tasks even when plan mode is off \u2014 this toggle is the stronger, explicit constraint.) Type /plan off to leave.",
|
|
1271
|
+
planOff: "\u25B8 plan mode OFF \u2014 write tools are live again. Model can still propose plans autonomously for large tasks.",
|
|
1272
|
+
applyPlanCodeOnly: "/apply-plan is only available inside `reasonix code`.",
|
|
1273
|
+
applyPlanInfo: "\u25B8 plan approved \u2014 implementing",
|
|
1274
|
+
applyPlanResubmit: "The plan above has been approved. Implement it now. You are out of plan mode \u2014 use edit_file / write_file / run_command as needed. Stick to the plan unless you discover a concrete reason to deviate; if you do, tell me and wait for a response before making that deviation.",
|
|
1275
|
+
modeCodeOnly: "/mode is only available inside `reasonix code`.",
|
|
1276
|
+
modeUsage: "usage: /mode <review|auto|yolo> (Shift+Tab also cycles)",
|
|
1277
|
+
modeYolo: "\u25B8 edit mode: YOLO \u2014 edits AND shell commands auto-run with no prompt. /undo still rolls back edits. Use carefully.",
|
|
1278
|
+
modeAuto: "\u25B8 edit mode: AUTO \u2014 edits apply immediately; press u within 5s to undo, or /undo later. Shell commands still ask.",
|
|
1279
|
+
modeReview: "\u25B8 edit mode: review \u2014 edits queue for /apply (or y) / /discard (or n)",
|
|
1280
|
+
commitCodeOnly: "/commit is only available inside `reasonix code` (needs a rooted git repo).",
|
|
1281
|
+
commitUsage: 'usage: /commit "your commit message" \u2014 runs `git add -A && git commit -m "\u2026"` in {root}',
|
|
1282
|
+
walkCodeOnly: "/walk is only available inside `reasonix code`.",
|
|
1283
|
+
checkpointCodeOnly: "/checkpoint is only available inside `reasonix code` \u2014 chat mode doesn't apply edits.",
|
|
1284
|
+
checkpointNone: "no checkpoints yet \u2014 `/checkpoint <name>` snapshots every file the session has touched. Restore later with `/restore <name>`.",
|
|
1285
|
+
checkpointHeader: "\u25C8 checkpoints \xB7 {count} stored",
|
|
1286
|
+
checkpointRestoreHint: " /restore <name|id> \xB7 /checkpoint forget <id> \xB7 /checkpoint <name> to add",
|
|
1287
|
+
checkpointForgetUsage: "usage: /checkpoint forget <id|name>",
|
|
1288
|
+
checkpointNoMatch: '\u25B8 no checkpoint matching "{name}" \u2014 see /checkpoint list',
|
|
1289
|
+
checkpointDeleted: "\u25B8 deleted checkpoint {id} ({name})",
|
|
1290
|
+
checkpointDeleteFailed: "\u25B8 failed to delete {id} (already gone?)",
|
|
1291
|
+
checkpointSaveUsage: "usage: /checkpoint <name> (or /checkpoint list to see existing)",
|
|
1292
|
+
checkpointSavedEmpty: `\u25B8 checkpoint "{name}" saved ({id}) \u2014 but no files have been touched yet, so it's an empty baseline. Edits made after this point will be revertable.`,
|
|
1293
|
+
checkpointSaved: '\u25B8 checkpoint "{name}" saved ({id}) \u2014 {files} file{s}, {size} KB. Restore: /restore {name}',
|
|
1294
|
+
restoreCodeOnly: "/restore is only available inside `reasonix code`.",
|
|
1295
|
+
restoreUsage: "usage: /restore <name|id> (see /checkpoint list for ids)",
|
|
1296
|
+
restoreNoMatch: '\u25B8 no checkpoint matching "{target}" \u2014 try /checkpoint list',
|
|
1297
|
+
restoreInfo: '\u25B8 restored "{name}" ({id}) from {when}',
|
|
1298
|
+
restoreWrote: " \xB7 wrote back {count} file{s}",
|
|
1299
|
+
restoreRemoved: " \xB7 removed {count} file{s} (didn't exist at checkpoint time)",
|
|
1300
|
+
restoreSkipped: " \u2717 {count} file{s} skipped:"
|
|
1301
|
+
},
|
|
1302
|
+
model: {
|
|
1303
|
+
modelHint: "try deepseek-v4-flash or deepseek-v4-pro \u2014 run /models to fetch the live list",
|
|
1304
|
+
modelUsage: "usage: /model <id> ({hint})",
|
|
1305
|
+
modelNotInCatalog: "model \u2192 {id} (\u26A0 not in the fetched catalog: {list}. If this is wrong the next call will 400 \u2014 run /models to refresh.)",
|
|
1306
|
+
modelSet: "model \u2192 {id}",
|
|
1307
|
+
modelsFetching: "fetching /models from DeepSeek\u2026 run /models again in a moment. If it stays empty, your API key may lack permission or the network is blocked.",
|
|
1308
|
+
modelsEmpty: "DeepSeek /models returned an empty list. Try /models again, or check your account status at api-docs.deepseek.com.",
|
|
1309
|
+
modelsHeader: "Available models (DeepSeek /models \xB7 {count} total):",
|
|
1310
|
+
modelsCurrent: "\u25B8 {id} (current)",
|
|
1311
|
+
modelsSwitch: "Switch with: /model <id>",
|
|
1312
|
+
harvestOn: "harvest \u2192 on (Pillar-2 plan-state extraction \xB7 +1 cheap flash call per turn \xB7 opt-in only; no preset turns it on)",
|
|
1313
|
+
harvestOff: "harvest \u2192 off",
|
|
1314
|
+
presetAuto: "preset \u2192 auto (v4-flash \u2192 v4-pro on hard turns \xB7 default)",
|
|
1315
|
+
presetFlash: "preset \u2192 flash (v4-flash always \xB7 cheapest \xB7 /pro still bumps one turn)",
|
|
1316
|
+
presetPro: "preset \u2192 pro (v4-pro always \xB7 ~3\xD7 flash \xB7 for hard multi-turn work)",
|
|
1317
|
+
presetUsage: "usage: /preset <auto|flash|pro>",
|
|
1318
|
+
branchOff: "branch \u2192 off",
|
|
1319
|
+
branchUsage: "usage: /branch <N> (N>=2, or 'off')",
|
|
1320
|
+
branchCapped: "branch budget capped at 8 to prevent runaway cost",
|
|
1321
|
+
branchSet: "branch \u2192 {n} (runs {n} parallel samples per turn \xB7 {n}\xD7 per-turn cost \xB7 streaming disabled \xB7 manual only, no preset enables branching)",
|
|
1322
|
+
effortStatus: "reasoning_effort \u2192 {effort} (use /effort high for cheaper/faster, /effort max for the agent-class default \xB7 persisted across relaunches)",
|
|
1323
|
+
effortUsage: "usage: /effort <high|max>",
|
|
1324
|
+
effortSet: "reasoning_effort \u2192 {effort} (persisted)",
|
|
1325
|
+
proNothingArmed: "nothing armed \u2014 /pro with no args will arm pro for your next turn",
|
|
1326
|
+
proDisarmed: "\u25B8 /pro disarmed \u2014 next turn falls back to the current preset",
|
|
1327
|
+
proUsage: "usage: /pro arm pro for the next turn (one-shot, auto-disarms after)\n /pro off cancel armed state before the next turn",
|
|
1328
|
+
proArmed: "\u25B8 /pro armed \u2014 your NEXT message runs on {model} regardless of preset. Auto-disarms after one turn. Use /preset max for a persistent switch.",
|
|
1329
|
+
budgetNoCap: "no session budget set \u2014 Reasonix will keep going until you stop it. Set one with: /budget <usd> (e.g. /budget 5)",
|
|
1330
|
+
budgetStatus: "budget: ${spent} of ${cap} ({pct}%) \xB7 /budget off to clear, /budget <usd> to change",
|
|
1331
|
+
budgetOff: "budget \u2192 off (no cap)",
|
|
1332
|
+
budgetUsage: 'usage: /budget <usd> (got "{arg}" \u2014 must be a positive number, e.g. /budget 5 or /budget 12.50)',
|
|
1333
|
+
budgetExhausted: "\u25B2 budget \u2192 ${cap} but already spent ${spent}. Next turn will be refused \u2014 bump the cap higher to keep going, or end the session.",
|
|
1334
|
+
budgetSet: "budget \u2192 ${cap} (so far: ${spent} \xB7 warns at 80%, refuses next turn at 100% \xB7 /budget off to clear)"
|
|
1335
|
+
},
|
|
1336
|
+
sessions: {
|
|
1337
|
+
forgetNoSession: "not in a session \u2014 nothing to forget",
|
|
1338
|
+
forgetInfo: '\u25B8 deleted session "{name}" \u2014 current screen still shows the conversation, but next launch starts fresh',
|
|
1339
|
+
forgetFailed: 'could not delete session "{name}" (already gone?)',
|
|
1340
|
+
renameUsage: "usage: /rename <new-name>",
|
|
1341
|
+
renameNoSession: "not in a session \u2014 nothing to rename",
|
|
1342
|
+
renameFailed: 'could not rename \u2014 "{name}" already exists or sanitises to the same id as the current session',
|
|
1343
|
+
renameInfo: '\u25B8 renamed session \u2192 "{name}". Restart the TUI to pick it up under its new name.',
|
|
1344
|
+
resumeUsage: "usage: /resume <session-name> \u2014 list with /sessions",
|
|
1345
|
+
resumeNotFound: 'no session named "{name}" \u2014 list with /sessions',
|
|
1346
|
+
resumeInfo: '\u25B8 to resume "{name}", quit and run: reasonix chat --session {name}\n (mid-session swap requires a restart so the message log can rewind cleanly)'
|
|
1347
|
+
},
|
|
1348
|
+
permissions: {
|
|
1349
|
+
mutateCodeOnly: "/permissions add / remove / clear are only available inside `reasonix code` \u2014 they edit the project-scoped allowlist (`~/.reasonix/config.json` projects[<root>].shellAllowed).",
|
|
1350
|
+
addUsage: 'usage: /permissions add <prefix> (multi-token OK: /permissions add "git push origin")',
|
|
1351
|
+
addAlready: "\u25B8 already allowed: {prefix}",
|
|
1352
|
+
addBuiltin: "\u25B8 `{prefix}` is already in the builtin allowlist \u2014 no per-project entry needed. (Builtin entries are always on.)",
|
|
1353
|
+
addInfo: "\u25B8 added: {prefix}\n \u2192 next `{prefix}` invocation runs without prompting in this project.",
|
|
1354
|
+
removeUsage: "usage: /permissions remove <prefix-or-index> (e.g. /permissions remove 3, or /permissions remove npm)",
|
|
1355
|
+
removeEmpty: "\u25B8 no project allowlist entries to remove.",
|
|
1356
|
+
removeIndexOob: "\u25B8 index out of range: {idx} (project list has {count} entries)",
|
|
1357
|
+
removeNothing: "\u25B8 nothing to remove.",
|
|
1358
|
+
removeBuiltin: "\u25B8 `{prefix}` is in the builtin allowlist (read-only). Builtin entries can't be removed at runtime \u2014 they're baked into the binary.",
|
|
1359
|
+
removeInfo: "\u25B8 removed: {prefix}",
|
|
1360
|
+
removeNotFound: "\u25B8 no such project entry: {prefix} (try /permissions list to see what's stored)",
|
|
1361
|
+
clearAlready: "\u25B8 project allowlist is already empty.",
|
|
1362
|
+
clearConfirm: "about to drop {count} project allowlist entr{plural} for {root}. Re-run with the word 'confirm' to proceed: /permissions clear confirm",
|
|
1363
|
+
clearedNone: "\u25B8 project allowlist was already empty \u2014 nothing changed.",
|
|
1364
|
+
cleared: "\u25B8 cleared {count} project allowlist entr{plural}.",
|
|
1365
|
+
usage: 'usage: /permissions [list] show current state\n /permissions add <prefix> persist (e.g. "npm run build")\n /permissions remove <prefix-or-N> drop one entry\n /permissions clear confirm wipe every project entry',
|
|
1366
|
+
modeYolo: "\u25B8 edit mode: YOLO \u2014 every shell command auto-runs, allowlist is bypassed. /mode review to re-enable prompts.",
|
|
1367
|
+
modeAuto: "\u25B8 edit mode: auto \u2014 edits auto-apply, shell still gated by allowlist (or ShellConfirm prompt for non-allowlisted).",
|
|
1368
|
+
modeReview: "\u25B8 edit mode: review \u2014 both edits and non-allowlisted shell commands ask before running.",
|
|
1369
|
+
projectHeader: "Project allowlist ({count}) \u2014 {root}",
|
|
1370
|
+
projectNone1: ' (none \u2014 pick "always allow" on a ShellConfirm prompt to add one,',
|
|
1371
|
+
projectNone2: " or `/permissions add <prefix>` directly.)",
|
|
1372
|
+
projectNoRoot: "Project allowlist \u2014 (no project root; chat mode shows builtin entries only)",
|
|
1373
|
+
builtinHeader: "Builtin allowlist ({count}) \u2014 read-only, baked in",
|
|
1374
|
+
subcommands: "Subcommands: /permissions add <prefix> \xB7 /permissions remove <prefix-or-N> \xB7 /permissions clear confirm"
|
|
1375
|
+
},
|
|
1376
|
+
dashboard: {
|
|
1377
|
+
notAvailable: "/dashboard is not available in this context (no startDashboard callback wired).",
|
|
1378
|
+
stopNoCallback: "/dashboard stop: no stop callback wired.",
|
|
1379
|
+
notRunning: "\u25B8 dashboard is not running.",
|
|
1380
|
+
stopping: "\u25B8 dashboard stopping\u2026",
|
|
1381
|
+
alreadyRunning: "\u25B8 dashboard is already running:",
|
|
1382
|
+
alreadyRunningHint: "Open it in any browser. Type `/dashboard stop` to tear it down.",
|
|
1383
|
+
ready: "\u25B8 dashboard ready:",
|
|
1384
|
+
readyHint: "127.0.0.1 only \xB7 token-gated. Type `/dashboard stop` to shut down.",
|
|
1385
|
+
failed: "\u25B8 dashboard failed to start: {reason}",
|
|
1386
|
+
starting: "\u25B8 starting dashboard server\u2026"
|
|
1387
|
+
},
|
|
1388
|
+
observability: {
|
|
1389
|
+
thinkEmpty: "no reasoning cached. `/think` shows the full thinking-mode thought for the most recent turn \u2014 only thinking-mode models (deepseek-v4-flash / -v4-pro / -reasoner) produce it, and only once the turn completes.",
|
|
1390
|
+
thinkInfo: "\u21B3 full thinking ({count} chars):",
|
|
1391
|
+
toolEmpty: "no tool calls yet in this session. `/tool` lists them once the model has actually used a tool; `/tool N` dumps the full (untruncated) output of the Nth-most-recent.",
|
|
1392
|
+
toolUsage: "usage: /tool [N] (no arg \u2192 list; N=1 \u2192 most recent result in full, N=2 \u2192 previous, \u2026)",
|
|
1393
|
+
toolOob: "only {count} tool call(s) in history \u2014 asked for #{n}. Try /tool with no arg to see the list.",
|
|
1394
|
+
toolNotFound: "could not read tool call #{n}",
|
|
1395
|
+
toolInfo: "\u21B3 tool<{name}> #{n} ({chars} chars):",
|
|
1396
|
+
contextInfo: "context: ~{total} of {max} ({pct}%) \xB7 system {sys} \xB7 tools {tools} \xB7 log {log}",
|
|
1397
|
+
compactStarting: "\u25B8 folding older turns into a summary\u2026",
|
|
1398
|
+
compactNoop: "\u25B8 nothing to fold \u2014 log already small or recent turns alone exceed the budget.",
|
|
1399
|
+
compactDone: "\u25B8 folded {before} messages \u2192 {after} (summary {chars} chars). Continuing.",
|
|
1400
|
+
compactFailed: "\u25B8 fold failed: {reason}",
|
|
1401
|
+
costNoTurn: "no turn yet \u2014 `/cost` shows the most recent turn's token + spend breakdown.",
|
|
1402
|
+
costNeedsTui: "/cost needs a TUI context (postUsage wired).",
|
|
1403
|
+
costNoPricing: '\u25B8 /cost: no pricing table for model "{model}". Add one to telemetry/stats.ts.',
|
|
1404
|
+
costEstimate: "\u25B8 /cost estimate \xB7 {model} \xB7 {prompt} prompt tokens (sys {sys} + tools {tools} + log {log} + msg {msg})",
|
|
1405
|
+
costWorstCase: " worst case (full miss): {input} input + ~{output} output ({avg} avg) \u2248 {total}",
|
|
1406
|
+
costLikely: " likely ({pct}% session cache hit): {input} input + ~{output} output \u2248 {total}",
|
|
1407
|
+
costLikelyCold: " likely: matches worst case until cache fills (no completed turns yet)",
|
|
1408
|
+
statusModel: " model {model}",
|
|
1409
|
+
statusFlags: " flags harvest={harvest} \xB7 branch={branch} \xB7 stream={stream} \xB7 effort={effort}",
|
|
1410
|
+
statusCtx: " ctx {bar} {used}/{max} ({pct}%)",
|
|
1411
|
+
statusCtxNone: " ctx no turns yet",
|
|
1412
|
+
statusCost: " cost ${cost} \xB7 cache {bar} {pct}% \xB7 turns {turns}",
|
|
1413
|
+
statusCostCold: " cost ${cost} \xB7 turns {turns} (cache warming up)",
|
|
1414
|
+
statusBudget: " budget ${spent} / ${cap} ({pct}%){tag}",
|
|
1415
|
+
statusSession: ' session "{name}" \xB7 {count} messages in log (resumed {resumed})',
|
|
1416
|
+
statusSessionEphemeral: " session (ephemeral \u2014 no persistence)",
|
|
1417
|
+
statusWorkspace: " workspace {path} \xB7 pinned at launch (relaunch with --dir <path> to switch)",
|
|
1418
|
+
statusMcp: " mcp {servers} server(s), {tools} tool(s) in registry",
|
|
1419
|
+
statusEdits: " edits {count} pending (/apply to commit, /discard to drop)",
|
|
1420
|
+
statusPlan: " plan ON \u2014 writes gated (submit_plan + approval)",
|
|
1421
|
+
statusModeYolo: " mode YOLO \u2014 edits + shell auto-run with no prompt (/undo still rolls back \xB7 Shift+Tab to flip)",
|
|
1422
|
+
statusModeAuto: " mode AUTO \u2014 edits apply immediately (u to undo within 5s \xB7 Shift+Tab to flip)",
|
|
1423
|
+
statusModeReview: " mode review \u2014 edits queue for /apply or y (Shift+Tab to flip)",
|
|
1424
|
+
statusDash: " dash {url} (open in browser \xB7 /dashboard stop)"
|
|
1425
|
+
},
|
|
1426
|
+
plans: {
|
|
1427
|
+
noSession: "no session attached \u2014 `/plans` is per-session. Run `reasonix code` in a project to get a session.",
|
|
1428
|
+
activePlan: "\u25B8 active plan{label} \u2014 {done}/{total} step{s} done \xB7 last touched {when}",
|
|
1429
|
+
activeNone: "\u25B8 active plan: (none)",
|
|
1430
|
+
noArchives: "no archived plans yet for this session \u2014 they auto-archive when every step is done",
|
|
1431
|
+
archivedHeader: "Archived ({count}):",
|
|
1432
|
+
replayNoSession: "no session attached \u2014 `/replay` is per-session. Run `reasonix code` in a project to get a session.",
|
|
1433
|
+
replayNoArchives: "no archived plans yet for this session \u2014 `/replay` lights up once a plan completes (auto-archives when every step is done).",
|
|
1434
|
+
replayInvalidIndex: "invalid index \u2014 `/replay` takes 1..{max} (newest = 1). Use `/plans` to see the list.",
|
|
1435
|
+
archivedRow: " \u2713 {when} {total} step{s} \xB7 {completion} {label}",
|
|
1436
|
+
completionComplete: "complete",
|
|
1437
|
+
stopAborted: "\u25B8 plan stopped \u2014 model aborted; type a follow-up to continue or start a new task."
|
|
1438
|
+
},
|
|
1439
|
+
jobs: {
|
|
1440
|
+
codeOnly: "/jobs is only available inside `reasonix code`.",
|
|
1441
|
+
killCodeOnly: "/kill is only available inside `reasonix code`.",
|
|
1442
|
+
logsCodeOnly: "/logs is only available inside `reasonix code`.",
|
|
1443
|
+
empty: "\u25C8 jobs \xB7 0 running \xB7 0 total\n (run_background spawns one \u2014 dev servers, watchers, long-running scripts)",
|
|
1444
|
+
header: "\u25C8 jobs \xB7 {running} running \xB7 {total} total",
|
|
1445
|
+
footer: " /logs <id> tail \xB7 /kill <id> SIGTERM \u2192 SIGKILL",
|
|
1446
|
+
killUsage: "usage: /kill <id> (see /jobs for ids)",
|
|
1447
|
+
killNotFound: "job {id}: not found",
|
|
1448
|
+
killAlreadyExited: "job {id} already exited ({code})",
|
|
1449
|
+
killStopping: "\u25B8 stopping job {id} (tree kill: SIGTERM \u2192 SIGKILL after 2s grace; Windows: taskkill /T /F)",
|
|
1450
|
+
killStatus: "\u25B8 job {id} {status}",
|
|
1451
|
+
killStillAlive: "still alive after SIGKILL (!) \u2014 report this as a bug",
|
|
1452
|
+
logsUsage: "usage: /logs <id> [lines] (default last 80 lines)",
|
|
1453
|
+
logsNotFound: "job {id}: not found",
|
|
1454
|
+
logsStatus: "[job {id} \xB7 {status}]\n$ {command}",
|
|
1455
|
+
logsRunning: "running \xB7 pid {pid}",
|
|
1456
|
+
logsExited: "exited {code}",
|
|
1457
|
+
logsFailed: "failed ({reason})",
|
|
1458
|
+
logsStopped: "stopped"
|
|
1459
|
+
},
|
|
1460
|
+
memory: {
|
|
1461
|
+
disabled: "memory is disabled (REASONIX_MEMORY=off in env). Unset the var to re-enable \u2014 no REASONIX.md or ~/.reasonix/memory content will be pinned in the meantime.",
|
|
1462
|
+
noRoot: "no working directory on this session \u2014 `/memory` needs a root to resolve REASONIX.md from. (Running in a test harness?)",
|
|
1463
|
+
listEmpty: "no user memories yet. The model can call `remember` to save one, or you can create files by hand in ~/.reasonix/memory/global/ or the per-project subdir.",
|
|
1464
|
+
listHeader: "User memories ({count}):",
|
|
1465
|
+
listFooter: "View body: /memory show <name> Delete: /memory forget <name>",
|
|
1466
|
+
showUsage: "usage: /memory show <name> or /memory show <scope>/<name>",
|
|
1467
|
+
showNotFound: "no memory found: {target}",
|
|
1468
|
+
showFailed: "show failed: {reason}",
|
|
1469
|
+
forgetUsage: "usage: /memory forget <name> or /memory forget <scope>/<name>",
|
|
1470
|
+
forgetNotFound: "no memory found: {target}",
|
|
1471
|
+
forgetInfo: "\u25B8 forgot {scope}/{name}. Next /new or launch won't see it.",
|
|
1472
|
+
forgetFailed: "could not forget {scope}/{name} (already gone?)",
|
|
1473
|
+
forgetError: "forget failed: {reason}",
|
|
1474
|
+
clearUsage: "usage: /memory clear <global|project> confirm",
|
|
1475
|
+
clearConfirm: "about to delete every memory in scope={scope}. Re-run with the word 'confirm' to proceed: /memory clear {scope} confirm",
|
|
1476
|
+
cleared: "\u25B8 cleared scope={scope} \u2014 deleted {count} memory file(s).",
|
|
1477
|
+
noMemory: "no memory pinned in {root}.",
|
|
1478
|
+
layers: "Three layers are available:",
|
|
1479
|
+
layerProject: " 1. {file} \u2014 committable team memory (in the repo).",
|
|
1480
|
+
layerGlobal: " 2. ~/.reasonix/memory/global/ \u2014 your cross-project private memory.",
|
|
1481
|
+
layerProjectHash: " 3. ~/.reasonix/memory/<project-hash>/ \u2014 this project's private memory.",
|
|
1482
|
+
askModel: "Ask the model to `remember` something, or hand-edit files directly.",
|
|
1483
|
+
changesNote: "Changes take effect on next /new or launch \u2014 the system prompt is hashed once per session to keep the prefix cache warm.",
|
|
1484
|
+
subcommands: "Subcommands: /memory list | /memory show <name> | /memory forget <name> | /memory clear <scope> confirm",
|
|
1485
|
+
changesNoteShort: "Changes take effect on next /new or launch. Subcommands: /memory list | show | forget | clear"
|
|
1486
|
+
},
|
|
1487
|
+
mcp: {
|
|
1488
|
+
noServers: 'no MCP servers attached. Run `reasonix setup` to pick some, or launch with --mcp "<spec>". `reasonix mcp list` shows the catalog.',
|
|
1489
|
+
toolsLabel: " tools {count}",
|
|
1490
|
+
resourcesHint: "`/resource` to browse+read",
|
|
1491
|
+
promptsHint: "`/prompt` to browse+fetch",
|
|
1492
|
+
awarenessOnly: "Chat mode consumes tools today; resources+prompts are surfaced here for awareness.",
|
|
1493
|
+
catalogHint: "Full catalog: `reasonix mcp list` \xB7 deeper diagnosis: `reasonix mcp inspect <spec>`.",
|
|
1494
|
+
fallbackServers: "MCP servers ({count}):",
|
|
1495
|
+
fallbackTools: "Tools in registry ({count}):",
|
|
1496
|
+
fallbackChange: "To change this set, exit and run `reasonix setup`.",
|
|
1497
|
+
usageDisableEnable: "usage: /mcp {action} <name> \xB7 pick a name shown in /mcp (anonymous servers can't be named-toggled).",
|
|
1498
|
+
usageReconnect: "usage: /mcp reconnect <name> \xB7 pick a name shown in /mcp.",
|
|
1499
|
+
unknownServer: 'unknown MCP server "{name}". Known: {list}.',
|
|
1500
|
+
noneList: "(none)",
|
|
1501
|
+
reconnectNoTui: "/mcp reconnect requires the interactive TUI (postInfo not wired)."
|
|
1502
|
+
},
|
|
1503
|
+
init: {
|
|
1504
|
+
codeOnly: "/init only works in code mode (it needs filesystem tools).\nRun `reasonix code [path]` to start a session rooted at the\nproject you want to initialize, then run /init.",
|
|
1505
|
+
exists: "\u25B8 REASONIX.md already exists at {path}",
|
|
1506
|
+
existsForce: " /init force regenerate from scratch (overwrites)",
|
|
1507
|
+
existsEdit: " Or edit it by hand \u2014 it's just markdown. The current file is",
|
|
1508
|
+
existsPinned: " pinned into the system prompt every launch as-is.",
|
|
1509
|
+
info: "\u25B8 /init \u2014 model will scan the project and synthesize REASONIX.md.\n The result lands as a pending edit; review with /apply or /walk."
|
|
1510
|
+
},
|
|
1511
|
+
semantic: {
|
|
1512
|
+
codeOnly: "/semantic is only available inside `reasonix code` (needs a project root).",
|
|
1513
|
+
checking: "\u25B8 checking semantic_search status\u2026"
|
|
1514
|
+
},
|
|
1515
|
+
webSearchEngine: {
|
|
1516
|
+
currentEngine: "Current web search engine: {engine}",
|
|
1517
|
+
endpoint: "SearXNG endpoint: {url}",
|
|
1518
|
+
usageHeader: "Usage:",
|
|
1519
|
+
usageMojeek: " /search-engine mojeek use Mojeek (default, no external deps)",
|
|
1520
|
+
usageSearxng: " /search-engine searxng use SearXNG at default endpoint",
|
|
1521
|
+
usageSearxngUrl: " /search-engine searxng <url> use SearXNG at custom endpoint",
|
|
1522
|
+
alias: "Alias: /se",
|
|
1523
|
+
searxngInfo: "SearXNG is a self-hosted metasearch engine (https://github.com/searxng/searxng).",
|
|
1524
|
+
searxngInstall: "Install it with: docker run -d -p 8080:8080 searxng/searxng",
|
|
1525
|
+
switched: 'Switched web search engine to "{engine}".{note}',
|
|
1526
|
+
switchedSearxngNote: " Make sure SearXNG is running at {endpoint}.",
|
|
1527
|
+
confirmed: '\u2713 Web search engine set to "{engine}"{detail}. Next assistant turn will pick up the change.',
|
|
1528
|
+
confirmedDetail: " ({endpoint})"
|
|
1529
|
+
},
|
|
1530
|
+
skill: {
|
|
1531
|
+
listEmpty: "no skills found. Reasonix reads skills from:",
|
|
1532
|
+
listProjectScope: " \xB7 <project>/.reasonix/skills/<name>/SKILL.md (or <name>.md) \u2014 project scope",
|
|
1533
|
+
listGlobalScope: " \xB7 ~/.reasonix/skills/<name>/SKILL.md (or <name>.md) \u2014 global scope",
|
|
1534
|
+
listProjectOnly: " (project scope is only active in `reasonix code`)",
|
|
1535
|
+
listFrontmatter: "Each file's frontmatter needs at least `name` and `description`.",
|
|
1536
|
+
listInvoke: "Invoke a skill with `/skill <name> [args]` or by asking the model to call `run_skill`.",
|
|
1537
|
+
listHeader: "User skills ({count}):",
|
|
1538
|
+
listFooter: "View: /skill show <name> Run: /skill <name> [args] New: /skill new <name>",
|
|
1539
|
+
listEmptyNewHint: "Scaffold one with: /skill new <name> (project scope) \u2014 there's no remote registry yet; you author skills directly.",
|
|
1540
|
+
showUsage: "usage: /skill show <name>",
|
|
1541
|
+
showNotFound: "no skill found: {name}",
|
|
1542
|
+
runNotFound: "no skill found: {name} (try /skill list)",
|
|
1543
|
+
runInfo: "\u25B8 running skill: {name}{args}",
|
|
1544
|
+
newUsage: "usage: /skill new <name> [--global]",
|
|
1545
|
+
newCreated: "\u25B8 created skill: {name}\n {path}\n edit it, then `/skill {name}` to invoke",
|
|
1546
|
+
newError: "\u25B2 /skill new failed: {reason}"
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
};
|
|
1550
|
+
|
|
1551
|
+
// src/i18n/zh-CN.ts
|
|
1552
|
+
var zhCN = {
|
|
1553
|
+
common: {
|
|
1554
|
+
error: "\u9519\u8BEF",
|
|
1555
|
+
warning: "\u8B66\u544A",
|
|
1556
|
+
loading: "\u52A0\u8F7D\u4E2D...",
|
|
1557
|
+
done: "\u5B8C\u6210",
|
|
1558
|
+
cancel: "\u53D6\u6D88",
|
|
1559
|
+
confirm: "\u786E\u8BA4",
|
|
1560
|
+
back: "\u8FD4\u56DE",
|
|
1561
|
+
next: "\u4E0B\u4E00\u6B65"
|
|
1562
|
+
},
|
|
1563
|
+
cli: {
|
|
1564
|
+
description: "DeepSeek \u539F\u751F\u667A\u80FD\u4F53\u6846\u67B6 \u2014 \u4E13\u4E3A\u7F13\u5B58\u547D\u4E2D\u548C\u4F4E\u6210\u672C\u4EE4\u724C\u6784\u5EFA\u3002",
|
|
1565
|
+
continue: "\u6062\u590D\u6700\u8FD1\u4F7F\u7528\u7684\u804A\u5929\u4F1A\u8BDD\uFF0C\u4E0D\u663E\u793A\u9009\u62E9\u5668\u3002",
|
|
1566
|
+
setup: "\u4EA4\u4E92\u5F0F\u5411\u5BFC \u2014 API \u5BC6\u94A5\u3001\u9884\u8BBE\u3001MCP \u670D\u52A1\u5668\u3002\u968F\u65F6\u91CD\u65B0\u8FD0\u884C\u4EE5\u91CD\u65B0\u914D\u7F6E\u3002",
|
|
1567
|
+
code: "\u4EE3\u7801\u7F16\u8F91\u804A\u5929 \u2014 \u4EE5 <dir>\uFF08\u9ED8\u8BA4\uFF1Acwd\uFF09\u4E3A\u6839\u7684\u6587\u4EF6\u7CFB\u7EDF\u5DE5\u5177\uFF0C\u7F16\u7801\u7CFB\u7EDF\u63D0\u793A\u8BCD\uFF0Cv4-flash \u57FA\u7EBF\u3002",
|
|
1568
|
+
chat: "\u5177\u6709\u5B9E\u65F6\u7F13\u5B58/\u6210\u672C\u9762\u677F\u7684\u4EA4\u4E92\u5F0F Ink TUI\u3002",
|
|
1569
|
+
run: "\u4EE5\u975E\u4EA4\u4E92\u65B9\u5F0F\u8FD0\u884C\u5355\u4E2A\u4EFB\u52A1\uFF0C\u6D41\u5F0F\u8F93\u51FA\u3002",
|
|
1570
|
+
stats: "\u663E\u793A\u4F7F\u7528\u60C5\u51B5\u4EEA\u8868\u677F\u3002",
|
|
1571
|
+
doctor: "\u4E00\u952E\u5065\u5EB7\u68C0\u67E5\u3002",
|
|
1572
|
+
commit: "\u4ECE\u6682\u5B58\u7684\u5DEE\u5F02\u4E2D\u8D77\u8349\u63D0\u4EA4\u6D88\u606F\u3002",
|
|
1573
|
+
sessions: "\u5217\u51FA\u4FDD\u5B58\u7684\u804A\u5929\u4F1A\u8BDD\uFF0C\u6216\u6309\u540D\u79F0\u68C0\u67E5\u3002",
|
|
1574
|
+
pruneSessions: "\u5220\u9664\u7A7A\u95F2 \u2265N \u5929\u7684\u5DF2\u4FDD\u5B58\u4F1A\u8BDD\uFF08\u9ED8\u8BA4 90\uFF09\u3002\u4F7F\u7528 --dry-run \u9884\u89C8\u3002",
|
|
1575
|
+
events: "\u7F8E\u5316\u6253\u5370\u5185\u6838\u4E8B\u4EF6\u65E5\u5FD7\u4FA7\u8FB9\u6587\u4EF6\u3002",
|
|
1576
|
+
replay: "\u4EA4\u4E92\u5F0F Ink TUI\uFF0C\u7528\u4E8E\u6D4F\u89C8\u8F6C\u5F55\u7A3F\u3002",
|
|
1577
|
+
diff: "\u5728\u5206\u680F Ink TUI \u4E2D\u6BD4\u8F83\u4E24\u4E2A\u8F6C\u5F55\u7A3F\u3002",
|
|
1578
|
+
mcp: "\u6A21\u578B\u4E0A\u4E0B\u6587\u534F\u8BAE (MCP) \u52A9\u624B \u2014 \u53D1\u73B0\u670D\u52A1\u5668\uFF0C\u6D4B\u8BD5\u60A8\u7684\u8BBE\u7F6E\u3002",
|
|
1579
|
+
version: "\u6253\u5370 Reasonix \u7248\u672C\u3002",
|
|
1580
|
+
update: "\u68C0\u67E5\u8F83\u65B0\u7248\u672C\u7684 Reasonix \u5E76\u5B89\u88C5\u3002",
|
|
1581
|
+
index: "\u6784\u5EFA\uFF08\u6216\u589E\u91CF\u5237\u65B0\uFF09\u672C\u5730\u8BED\u4E49\u641C\u7D22\u7D22\u5F15\u3002"
|
|
1582
|
+
},
|
|
1583
|
+
ui: {
|
|
1584
|
+
welcome: "\u968F\u65F6\u8FD0\u884C `reasonix` \u5F00\u59CB\u804A\u5929 \u2014 \u60A8\u7684\u8BBE\u7F6E\u5C06\u88AB\u8BB0\u4F4F\u3002",
|
|
1585
|
+
taglineChat: "DeepSeek \u539F\u751F\u667A\u80FD\u4F53",
|
|
1586
|
+
taglineCode: "DeepSeek \u539F\u751F\u4EE3\u7801\u667A\u80FD\u4F53",
|
|
1587
|
+
taglineSub: "\u7F13\u5B58\u4F18\u5148 \xB7 Flash \u4F18\u5148",
|
|
1588
|
+
startSessionHint: "\u8F93\u5165\u6D88\u606F\u4EE5\u5F00\u59CB\u60A8\u7684\u4F1A\u8BDD",
|
|
1589
|
+
inputPlaceholder: "\u8F93\u5165\u4EFB\u4F55\u5185\u5BB9... (\u8F93\u5165 / \u4F7F\u7528\u547D\u4EE4, @ \u5F15\u7528\u6587\u4EF6)",
|
|
1590
|
+
busy: "\u601D\u8003\u4E2D...",
|
|
1591
|
+
thinking: "\u25B8 \u601D\u8003\u4E2D...",
|
|
1592
|
+
undo: "\u64A4\u6D88",
|
|
1593
|
+
undoHint: "\u5728 5 \u79D2\u5185\u6309 u \u64A4\u6D88",
|
|
1594
|
+
applied: "\u5DF2\u5E94\u7528",
|
|
1595
|
+
rejected: "\u5DF2\u62D2\u7EDD",
|
|
1596
|
+
noDashboard: "\u7981\u6B62\u81EA\u52A8\u542F\u52A8\u5D4C\u5165\u5F0F Web \u4EEA\u8868\u677F\u3002",
|
|
1597
|
+
dashboardAutoStartFailed: "\u25B2 \u4EEA\u8868\u677F\u81EA\u52A8\u542F\u52A8\u5931\u8D25 ({reason}) \u2014 \u5C1D\u8BD5 /dashboard\uFF0C\u6216\u4F20\u9012 --no-dashboard \u4EE5\u9759\u9ED8",
|
|
1598
|
+
systemAppendHint: "\u8FFD\u52A0\u6307\u4EE4\u5230\u4EE3\u7801\u7CFB\u7EDF\u63D0\u793A\u8BCD\u3002\u4E0D\u66FF\u6362\u9ED8\u8BA4\u63D0\u793A\u8BCD \u2014 \u5728\u5176\u540E\u6DFB\u52A0\u3002",
|
|
1599
|
+
systemAppendFileHint: "\u8FFD\u52A0\u6587\u4EF6\u5185\u5BB9\u5230\u4EE3\u7801\u7CFB\u7EDF\u63D0\u793A\u8BCD\u3002\u4E0D\u66FF\u6362\u9ED8\u8BA4\u63D0\u793A\u8BCD\u3002UTF-8\uFF0C\u76F8\u5BF9\u4E8E cwd \u6216\u7EDD\u5BF9\u8DEF\u5F84\u3002",
|
|
1600
|
+
resumedSession: '\u25B8 \u5DF2\u6062\u590D\u4F1A\u8BDD "{name}"\uFF0C\u5305\u542B {count} \u6761\u5386\u53F2\u6D88\u606F \xB7 /forget \u91CD\u65B0\u5F00\u59CB \xB7 /sessions \u5217\u51FA',
|
|
1601
|
+
newSession: '\u25B8 \u4F1A\u8BDD "{name}" (\u65B0) \u2014 \u968F\u804A\u968F\u5B58 \xB7 /forget \u5220\u9664 \xB7 /sessions \u5217\u51FA',
|
|
1602
|
+
ephemeralSession: "\u25B8 \u4E34\u65F6\u804A\u5929 (\u4E0D\u4FDD\u5B58\u4F1A\u8BDD) \u2014 \u53BB\u6389 --no-session \u4EE5\u542F\u7528\u4FDD\u5B58",
|
|
1603
|
+
restoredEdits: "\u25B8 \u4ECE\u4E2D\u65AD\u7684\u8FD0\u884C\u4E2D\u6062\u590D\u4E86 {count} \u4E2A\u5F85\u5904\u7406\u7684\u7F16\u8F91\u5757 \u2014 /apply \u63D0\u4EA4\u6216 /discard \u653E\u5F03\u3002",
|
|
1604
|
+
resumedPlan: "\u5DF2\u6062\u590D\u8BA1\u5212 \xB7 {when}{summary}",
|
|
1605
|
+
tipEditBindings: "\u25B8 \u63D0\u793A\uFF1A\u7F16\u8F91\u95E8\u63A7\u5FEB\u6377\u952E\n y / n \u63A5\u53D7\u6216\u653E\u5F03\u5F85\u5904\u7406\u7684\u7F16\u8F91\n Shift+Tab \u5207\u6362 \u9884\u89C8 \u2194 \u81EA\u52A8 (\u6301\u4E45\u5316\uFF1B\u81EA\u52A8\u6A21\u5F0F\u7ACB\u5373\u5E94\u7528)\n u \u64A4\u6D88\u4E0A\u6B21\u81EA\u52A8\u5E94\u7528\u7684\u6279\u5904\u7406 (\u5728 5 \u79D2\u6A2A\u5E45\u5185)\n \u5F53\u524D\u6A21\u5F0F\u663E\u793A\u5728\u5E95\u90E8\u72B6\u6001\u680F\u3002\u968F\u65F6\u8FD0\u884C /keys \u67E5\u770B\u5B8C\u6574\u5217\u8868\u3002\n (\u6B64\u63D0\u793A\u4EC5\u663E\u793A\u4E00\u6B21 \u2014 \u4E4B\u540E\u5C06\u9690\u85CF\u3002)",
|
|
1606
|
+
modelOverride: "\u8986\u76D6\u9ED8\u8BA4\u6A21\u578B",
|
|
1607
|
+
noSession: "\u7981\u7528\u672C\u6B21\u8FD0\u884C\u7684\u4F1A\u8BDD\u6301\u4E45\u5316",
|
|
1608
|
+
resumeHint: "\u5F3A\u5236\u6062\u590D\u6307\u5B9A\u4F1A\u8BDD\uFF08\u5373\u4F7F\u7A7A\u95F2\uFF09",
|
|
1609
|
+
newHint: "\u5F3A\u5236\u521B\u5EFA\u65B0\u4F1A\u8BDD\uFF08\u5FFD\u7565 --session / --continue\uFF09",
|
|
1610
|
+
transcriptHint: "JSONL \u8F6C\u5F55\u7A3F\u7684\u5199\u5165\u8DEF\u5F84",
|
|
1611
|
+
harvestHint: "\u542F\u7528 Pillar-2 \u8BA1\u5212\u72B6\u6001\u63D0\u53D6\uFF08\u6BCF\u8F6E\u989D\u5916\u6D88\u8017 1 \u6B21 flash \u8C03\u7528\uFF09",
|
|
1612
|
+
budgetHint: "\u4F1A\u8BDD\u7F8E\u5143\u4E0A\u9650 \u2014 80% \u65F6\u8B66\u544A\uFF0C100% \u65F6\u62D2\u7EDD\u4E0B\u4E00\u8F6E",
|
|
1613
|
+
modelIdHint: "DeepSeek \u6A21\u578B ID\uFF08\u4F8B\u5982 deepseek-v4-flash\uFF09",
|
|
1614
|
+
systemPromptHint: "\u8986\u76D6\u9ED8\u8BA4\u7CFB\u7EDF\u63D0\u793A\u8BCD",
|
|
1615
|
+
presetHint: "\u6A21\u578B\u7EC4\u5408 \u2014 auto|flash|pro",
|
|
1616
|
+
harvestOptInHint: "\u542F\u7528 Pillar-2 \u8BA1\u5212\u72B6\u6001\u63D0\u53D6",
|
|
1617
|
+
branchHint: "\u6BCF\u8F6E\u8FD0\u884C N \u4E2A\u5E76\u884C\u91C7\u6837\uFF08N>=2\uFF0C\u4EC5\u624B\u52A8\uFF09",
|
|
1618
|
+
sessionNameHint: "\u4F1A\u8BDD\u540D\u79F0\uFF08\u9ED8\u8BA4\uFF1A'default'\uFF09",
|
|
1619
|
+
ephemeralHint: "\u7981\u7528\u672C\u6B21\u8FD0\u884C\u7684\u4F1A\u8BDD\u6301\u4E45\u5316",
|
|
1620
|
+
mcpSpecHint: "MCP \u670D\u52A1\u5668\u89C4\u683C\uFF08\u53EF\u91CD\u590D\uFF09",
|
|
1621
|
+
mcpPrefixHint: "\u7528\u6B64\u5B57\u7B26\u4E32\u4E3A MCP \u5DE5\u5177\u540D\u6DFB\u52A0\u524D\u7F00",
|
|
1622
|
+
noConfigHint: "\u672C\u6B21\u8FD0\u884C\u5FFD\u7565 ~/.reasonix/config.json",
|
|
1623
|
+
presetHintShort: "\u6A21\u578B\u7EC4\u5408 \u2014 auto|flash|pro",
|
|
1624
|
+
harvestHintShort: "Pillar-2 \u8BA1\u5212\u72B6\u6001\u63D0\u53D6",
|
|
1625
|
+
branchHintShort: "\u6BCF\u8F6E\u5E76\u884C\u91C7\u6837\u6570\uFF08N>=2\uFF09",
|
|
1626
|
+
budgetHintShort: "\u4F1A\u8BDD\u7F8E\u5143\u4E0A\u9650",
|
|
1627
|
+
transcriptHintShort: "JSONL \u8F6C\u5F55\u7A3F\u8DEF\u5F84",
|
|
1628
|
+
mcpSpecHintShort: "MCP \u670D\u52A1\u5668\u89C4\u683C\uFF08\u53EF\u91CD\u590D\uFF09",
|
|
1629
|
+
mcpPrefixHintShort: "MCP \u5DE5\u5177\u540D\u524D\u7F00",
|
|
1630
|
+
dryRunHint: "\u663E\u793A\u5C06\u8981\u5B89\u88C5\u7684\u5185\u5BB9\u4F46\u4E0D\u5B9E\u9645\u5B89\u88C5",
|
|
1631
|
+
rebuildHint: "\u4ECE\u5934\u91CD\u5EFA\u7D22\u5F15",
|
|
1632
|
+
embedModelHint: "\u5D4C\u5165\u6A21\u578B\u540D\u79F0",
|
|
1633
|
+
projectDirHint: "\u9879\u76EE\u6839\u76EE\u5F55",
|
|
1634
|
+
ollamaUrlHint: "Ollama \u670D\u52A1\u5668 URL",
|
|
1635
|
+
skipPromptsHint: "\u8DF3\u8FC7\u786E\u8BA4\u63D0\u793A",
|
|
1636
|
+
verboseHint: "\u663E\u793A\u5B8C\u6574\u7684\u4F1A\u8BDD\u5143\u6570\u636E",
|
|
1637
|
+
pruneDaysHint: "\u5220\u9664\u7A7A\u95F2\u6B64\u5929\u6570\u6216\u66F4\u591A\u7684\u4F1A\u8BDD\uFF08\u9ED8\u8BA4 90\uFF09",
|
|
1638
|
+
pruneDryRunHint: "\u5217\u51FA\u5C06\u8981\u5220\u9664\u7684\u5185\u5BB9\u4F46\u4E0D\u5B9E\u9645\u5220\u9664",
|
|
1639
|
+
eventTypeHint: "\u6309\u4E8B\u4EF6\u7C7B\u578B\u8FC7\u6EE4",
|
|
1640
|
+
eventSinceHint: "\u4ECE\u6B64\u4E8B\u4EF6 ID \u5F00\u59CB",
|
|
1641
|
+
eventTailHint: "\u4EC5\u663E\u793A\u6700\u540E N \u4E2A\u4E8B\u4EF6",
|
|
1642
|
+
jsonHint: "\u4EE5 JSON \u683C\u5F0F\u8F93\u51FA",
|
|
1643
|
+
projectionHint: "\u663E\u793A\u6BCF\u4E2A\u4E8B\u4EF6\u7684\u6295\u5F71\u72B6\u6001",
|
|
1644
|
+
printHint: "\u6253\u5370\u5230\u6807\u51C6\u8F93\u51FA\u800C\u975E TUI",
|
|
1645
|
+
headHint: "\u4EC5\u663E\u793A\u524D N \u4E2A\u4E8B\u4EF6",
|
|
1646
|
+
tailHint: "\u4EC5\u663E\u793A\u6700\u540E N \u4E2A\u4E8B\u4EF6",
|
|
1647
|
+
mdReportHint: "\u5C06 markdown \u5DEE\u5F02\u62A5\u544A\u5199\u5165\u6B64\u8DEF\u5F84",
|
|
1648
|
+
printHintTable: "\u6253\u5370\u8868\u683C\u5230\u6807\u51C6\u8F93\u51FA",
|
|
1649
|
+
tuiHint: "\u6253\u5F00\u4EA4\u4E92\u5F0F TUI",
|
|
1650
|
+
labelAHint: "\u5DE6\u4FA7\u9762\u677F\u7684\u6807\u7B7E",
|
|
1651
|
+
labelBHint: "\u53F3\u4FA7\u9762\u677F\u7684\u6807\u7B7E",
|
|
1652
|
+
mcpListDescription: "\u6D4F\u89C8 MCP \u6CE8\u518C\u8868\uFF08\u5B98\u65B9 \u2192 smithery \u2192 \u672C\u5730 fallback\uFF09",
|
|
1653
|
+
mcpInspectDescription: "\u68C0\u67E5 MCP \u670D\u52A1\u5668\u89C4\u683C\uFF08\u5DE5\u5177\u3001\u8D44\u6E90\u3001\u63D0\u793A\uFF09",
|
|
1654
|
+
mcpSearchDescription: "\u5728 MCP \u6CE8\u518C\u8868\u4E2D\u641C\u7D22\u5339\u914D\u7684\u670D\u52A1\u5668",
|
|
1655
|
+
mcpInstallDescription: "\u6309\u540D\u79F0\u5B89\u88C5 MCP \u670D\u52A1\u5668\uFF08\u5C06\u5176\u89C4\u683C\u5199\u5165\u914D\u7F6E\uFF09",
|
|
1656
|
+
mcpBrowseDescription: "\u4EA4\u4E92\u5F0F\u5E02\u573A\u6D4F\u89C8\u5668 \u2014 \u8F93\u5165\u8FC7\u6EE4\u3001\u56DE\u8F66\u5B89\u88C5",
|
|
1657
|
+
mcpLocalHint: "\u53EA\u663E\u793A\u5185\u7F6E\u7684\u79BB\u7EBF\u76EE\u5F55",
|
|
1658
|
+
mcpRefreshHint: "\u5FFD\u7565 24 \u5C0F\u65F6\u7F13\u5B58\uFF0C\u5F3A\u5236\u5237\u65B0",
|
|
1659
|
+
mcpLimitHint: "\u6700\u591A\u663E\u793A\u591A\u5C11\u6761",
|
|
1660
|
+
mcpPagesHint: "\u4E00\u6B21\u6027\u9884\u52A0\u8F7D\u591A\u5C11\u9875\uFF08\u9ED8\u8BA4 1\uFF09",
|
|
1661
|
+
mcpAllHint: "\u52A0\u8F7D\u5168\u90E8\u9875\uFF08\u9996\u6B21\u8F83\u6162\uFF09",
|
|
1662
|
+
mcpMaxPagesHint: "\u641C\u7D22\u65F6\u6700\u591A\u8D70\u591A\u5C11\u9875\uFF08\u9ED8\u8BA4 20\uFF09",
|
|
1663
|
+
jsonHintCatalog: "\u4EE5 JSON \u683C\u5F0F\u8F93\u51FA",
|
|
1664
|
+
jsonHintReport: "\u4EE5 JSON \u683C\u5F0F\u8F93\u51FA\u68C0\u67E5\u62A5\u544A",
|
|
1665
|
+
modelOverrideFlash: "\u8986\u76D6\u6A21\u578B\uFF08\u9ED8\u8BA4\uFF1Adeepseek-v4-flash\uFF09",
|
|
1666
|
+
skipConfirmHint: "\u8DF3\u8FC7\u786E\u8BA4\u63D0\u793A"
|
|
1667
|
+
},
|
|
1668
|
+
slash: {
|
|
1669
|
+
help: { description: "\u663E\u793A\u5B8C\u6574\u547D\u4EE4\u53C2\u8003" },
|
|
1670
|
+
status: { description: "\u5F53\u524D\u6A21\u578B\u3001\u6807\u5FD7\u3001\u4E0A\u4E0B\u6587\u3001\u4F1A\u8BDD" },
|
|
1671
|
+
preset: {
|
|
1672
|
+
description: "\u6A21\u578B\u7EC4\u5408 \u2014 \u81EA\u52A8\u5728 flash \u2192 pro \u4E4B\u95F4\u5207\u6362\uFF0C\u6216\u9501\u5B9A flash/pro",
|
|
1673
|
+
argsHint: "<auto|flash|pro>"
|
|
1674
|
+
},
|
|
1675
|
+
model: { description: "\u5207\u6362 DeepSeek \u6A21\u578B ID", argsHint: "<id>" },
|
|
1676
|
+
models: { description: "\u5217\u51FA\u4ECE DeepSeek /models \u83B7\u53D6\u7684\u53EF\u7528\u6A21\u578B" },
|
|
1677
|
+
language: {
|
|
1678
|
+
description: "\u5207\u6362\u8FD0\u884C\u65F6\u8BED\u8A00",
|
|
1679
|
+
argsHint: "<en|zh-CN>",
|
|
1680
|
+
success: "\u8BED\u8A00\u5DF2\u5207\u6362\u4E3A\u7B80\u4F53\u4E2D\u6587\u3002",
|
|
1681
|
+
unsupported: "\u4E0D\u652F\u6301\u7684\u8BED\u8A00\u4EE3\u7801\uFF1A{code}\u3002\u652F\u6301\u7684\u8BED\u8A00\uFF1A{supported}\u3002"
|
|
1682
|
+
},
|
|
1683
|
+
harvest: { description: "\u5207\u6362 Pillar-2 \u8BA1\u5212\u72B6\u6001\u63D0\u53D6", argsHint: "[on|off]" },
|
|
1684
|
+
branch: { description: "\u6BCF\u8F6E\u8FD0\u884C N \u4E2A\u5E76\u884C\u91C7\u6837\uFF08N>=2\uFF09", argsHint: "<N|off>" },
|
|
1685
|
+
effort: {
|
|
1686
|
+
description: "reasoning_effort \u4E0A\u9650 \u2014 max \u4E3A\u9ED8\u8BA4\uFF08\u667A\u80FD\u4F53\u7EA7\uFF09\uFF0Chigh \u66F4\u4FBF\u5B9C/\u66F4\u5FEB",
|
|
1687
|
+
argsHint: "<high|max>"
|
|
1688
|
+
},
|
|
1689
|
+
pro: {
|
|
1690
|
+
description: "\u4EC5\u4E3A\u4E0B\u4E00\u8F6E\u542F\u7528 v4-pro\uFF08\u4E00\u6B21\u6027 \xB7 \u81EA\u52A8\u89E3\u9664\uFF09",
|
|
1691
|
+
argsHint: "[off]"
|
|
1692
|
+
},
|
|
1693
|
+
budget: {
|
|
1694
|
+
description: "\u4F1A\u8BDD\u7F8E\u5143\u4E0A\u9650 \u2014 80% \u65F6\u8B66\u544A\uFF0C100% \u65F6\u62D2\u7EDD\u4E0B\u4E00\u8F6E\u3002\u9ED8\u8BA4\u5173\u95ED\u3002\u5355\u72EC /budget \u663E\u793A\u72B6\u6001",
|
|
1695
|
+
argsHint: "[usd|off]"
|
|
1696
|
+
},
|
|
1697
|
+
mcp: { description: "\u5217\u51FA\u9644\u52A0\u5230\u6B64\u4F1A\u8BDD\u7684 MCP \u670D\u52A1\u5668 + \u5DE5\u5177" },
|
|
1698
|
+
resource: {
|
|
1699
|
+
description: "\u6D4F\u89C8 + \u8BFB\u53D6 MCP \u8D44\u6E90\uFF08\u65E0\u53C2\u6570 \u2192 \u5217\u51FA URI\uFF1B<uri> \u2192 \u83B7\u53D6\u5185\u5BB9\uFF09",
|
|
1700
|
+
argsHint: "[uri]"
|
|
1701
|
+
},
|
|
1702
|
+
prompt: {
|
|
1703
|
+
description: "\u6D4F\u89C8 + \u83B7\u53D6 MCP \u63D0\u793A\uFF08\u65E0\u53C2\u6570 \u2192 \u5217\u51FA\u540D\u79F0\uFF1B<name> \u2192 \u6E32\u67D3\u63D0\u793A\uFF09",
|
|
1704
|
+
argsHint: "[name]"
|
|
1705
|
+
},
|
|
1706
|
+
tool: { description: "\u8F6C\u50A8\u7B2C N \u4E2A\u5DE5\u5177\u8C03\u7528\u7684\u5B8C\u6574\u8F93\u51FA\uFF081=\u6700\u8FD1\uFF09", argsHint: "[N]" },
|
|
1707
|
+
memory: {
|
|
1708
|
+
description: "\u663E\u793A / \u7BA1\u7406\u56FA\u5B9A\u8BB0\u5FC6\uFF08REASONIX.md + ~/.reasonix/memory\uFF09",
|
|
1709
|
+
argsHint: "[list|show <name>|forget <name>|clear <scope> confirm]"
|
|
1710
|
+
},
|
|
1711
|
+
skill: {
|
|
1712
|
+
description: "\u5217\u51FA / \u8FD0\u884C\u7528\u6237\u6280\u80FD\uFF08<project>/.reasonix/skills + ~/.reasonix/skills\uFF09",
|
|
1713
|
+
argsHint: "[list|show <name>|<name> [args]]"
|
|
1714
|
+
},
|
|
1715
|
+
hooks: {
|
|
1716
|
+
description: "\u5217\u51FA\u6D3B\u8DC3\u7684 hooks\uFF08.reasonix/ \u4E0B\u7684 settings.json\uFF09\xB7 reload \u4ECE\u78C1\u76D8\u91CD\u65B0\u8BFB\u53D6",
|
|
1717
|
+
argsHint: "[reload]"
|
|
1718
|
+
},
|
|
1719
|
+
permissions: {
|
|
1720
|
+
description: "\u663E\u793A / \u7F16\u8F91 shell \u5141\u8BB8\u5217\u8868\uFF08\u5185\u7F6E\u53EA\u8BFB \xB7 \u9879\u76EE\u7EA7\uFF1A~/.reasonix/config.json\uFF09",
|
|
1721
|
+
argsHint: "[list|add <prefix>|remove <prefix|N>|clear confirm]"
|
|
1722
|
+
},
|
|
1723
|
+
dashboard: {
|
|
1724
|
+
description: "\u542F\u52A8\u5D4C\u5165\u5F0F Web \u4EEA\u8868\u677F\uFF08127.0.0.1\uFF0Ctoken \u4FDD\u62A4\uFF09",
|
|
1725
|
+
argsHint: "[stop]"
|
|
1726
|
+
},
|
|
1727
|
+
update: { description: "\u663E\u793A\u5F53\u524D\u7248\u672C\u4E0E\u6700\u65B0\u7248\u672C\u53CA\u5347\u7EA7\u547D\u4EE4" },
|
|
1728
|
+
stats: {
|
|
1729
|
+
description: "\u8DE8\u4F1A\u8BDD\u6210\u672C\u4EEA\u8868\u677F\uFF08\u4ECA\u65E5 / \u672C\u5468 / \u672C\u6708 / \u5168\u90E8 \xB7 \u7F13\u5B58\u547D\u4E2D \xB7 \u4E0E Claude \u5BF9\u6BD4\uFF09"
|
|
1730
|
+
},
|
|
1731
|
+
cost: {
|
|
1732
|
+
description: "\u7A7A \u2192 \u4E0A\u4E00\u8F6E\u82B1\u8D39\uFF08\u4F7F\u7528\u5361\u7247\uFF09\uFF1B\u5E26\u6587\u672C \u2192 \u4F30\u7B97\u53D1\u9001\u6210\u672C\uFF08\u6700\u574F\u60C5\u51B5 + \u53EF\u80FD\u7F13\u5B58\u547D\u4E2D\uFF09",
|
|
1733
|
+
argsHint: "[text]"
|
|
1734
|
+
},
|
|
1735
|
+
doctor: {
|
|
1736
|
+
description: "\u5065\u5EB7\u68C0\u67E5\uFF08api / config / api-reach / index / hooks / project\uFF09"
|
|
1737
|
+
},
|
|
1738
|
+
think: { description: "\u8F6C\u50A8\u6700\u8FD1\u4E00\u8F6E\u7684\u5B8C\u6574 R1 \u63A8\u7406\uFF08\u4EC5\u63A8\u7406\u6A21\u578B\uFF09" },
|
|
1739
|
+
context: { description: "\u663E\u793A\u4E0A\u4E0B\u6587\u7A97\u53E3\u5206\u89E3\uFF08\u7CFB\u7EDF / \u5DE5\u5177 / \u65E5\u5FD7 / \u8F93\u5165\uFF09" },
|
|
1740
|
+
retry: { description: "\u622A\u65AD\u5E76\u91CD\u53D1\u60A8\u7684\u6700\u540E\u4E00\u6761\u6D88\u606F\uFF08\u91CD\u65B0\u91C7\u6837\uFF09" },
|
|
1741
|
+
compact: {
|
|
1742
|
+
description: "\u7F29\u5C0F\u65E5\u5FD7\u4E2D\u8FC7\u5927\u7684\u5DE5\u5177\u7ED3\u679C\u548C\u5DE5\u5177\u8C03\u7528\u53C2\u6570\uFF1B\u4E0A\u9650\u4E3A tokens\uFF0C\u9ED8\u8BA4 4000",
|
|
1743
|
+
argsHint: "[tokens]"
|
|
1744
|
+
},
|
|
1745
|
+
keys: { description: "\u663E\u793A\u6240\u6709\u952E\u76D8\u5FEB\u6377\u952E\u548C\u63D0\u793A\u524D\u7F00" },
|
|
1746
|
+
plans: { description: "\u5217\u51FA\u6B64\u4F1A\u8BDD\u7684\u6D3B\u8DC3 + \u5F52\u6863\u8BA1\u5212\uFF08\u6700\u65B0\u5728\u524D\uFF09" },
|
|
1747
|
+
replay: {
|
|
1748
|
+
description: "\u52A0\u8F7D\u5F52\u6863\u8BA1\u5212\u4E3A\u53EA\u8BFB\u7684\u65F6\u95F4\u65C5\u884C\u5FEB\u7167\uFF08\u9ED8\u8BA4\uFF1A\u6700\u65B0\uFF09",
|
|
1749
|
+
argsHint: "[N]"
|
|
1750
|
+
},
|
|
1751
|
+
sessions: { description: "\u5217\u51FA\u5DF2\u4FDD\u5B58\u7684\u4F1A\u8BDD\uFF08\u5F53\u524D\u6807\u8BB0\u4E3A \u25B8\uFF09" },
|
|
1752
|
+
rename: { description: "\u91CD\u547D\u540D\u78C1\u76D8\u4E0A\u7684\u5F53\u524D\u4F1A\u8BDD", argsHint: "<new-name>" },
|
|
1753
|
+
resume: {
|
|
1754
|
+
description: "\u663E\u793A\u6062\u590D\u5DF2\u4FDD\u5B58\u4F1A\u8BDD\u7684\u542F\u52A8\u547D\u4EE4",
|
|
1755
|
+
argsHint: "<name>"
|
|
1756
|
+
},
|
|
1757
|
+
forget: { description: "\u4ECE\u78C1\u76D8\u5220\u9664\u5F53\u524D\u4F1A\u8BDD" },
|
|
1758
|
+
setup: { description: "\u63D0\u9192\u60A8\u9000\u51FA\u5E76\u8FD0\u884C `reasonix setup`" },
|
|
1759
|
+
semantic: {
|
|
1760
|
+
description: "\u663E\u793A semantic_search \u72B6\u6001 \u2014 \u5DF2\u6784\u5EFA\uFF1FOllama \u5DF2\u5B89\u88C5\uFF1F\u5982\u4F55\u542F\u7528"
|
|
1761
|
+
},
|
|
1762
|
+
clear: { description: "\u4EC5\u6E05\u9664\u53EF\u89C1\u7684\u6EDA\u52A8\u56DE\u653E\uFF08\u65E5\u5FD7/\u4E0A\u4E0B\u6587\u4FDD\u7559\uFF09" },
|
|
1763
|
+
new: { description: "\u5F00\u59CB\u5168\u65B0\u5BF9\u8BDD\uFF08\u6E05\u9664\u4E0A\u4E0B\u6587 + \u6EDA\u52A8\u56DE\u653E\uFF09" },
|
|
1764
|
+
loop: {
|
|
1765
|
+
description: "\u6BCF <interval> \u81EA\u52A8\u91CD\u65B0\u63D0\u4EA4 <prompt>\uFF0C\u76F4\u5230\u60A8\u8F93\u5165 / Esc / /loop stop",
|
|
1766
|
+
argsHint: "<5s..6h> <prompt> \xB7 stop \xB7 \uFF08\u65E0\u53C2\u6570 = \u72B6\u6001\uFF09"
|
|
1767
|
+
},
|
|
1768
|
+
exit: { description: "\u9000\u51FA TUI" },
|
|
1769
|
+
init: {
|
|
1770
|
+
description: "\u626B\u63CF\u9879\u76EE\u5E76\u5408\u6210\u57FA\u7EBF REASONIX.md\uFF08\u6A21\u578B\u5199\u5165\uFF1B\u4F7F\u7528 /apply \u5BA1\u67E5\uFF09\u3002`force` \u8986\u76D6\u5DF2\u6709\u6587\u4EF6\u3002",
|
|
1771
|
+
argsHint: "[force]"
|
|
1772
|
+
},
|
|
1773
|
+
apply: {
|
|
1774
|
+
description: "\u5C06\u5F85\u5904\u7406\u7684\u7F16\u8F91\u5757\u63D0\u4EA4\u5230\u78C1\u76D8\uFF08\u65E0\u53C2\u6570 \u2192 \u5168\u90E8\uFF1B`1`\u3001`1,3` \u6216 `1-4` \u2192 \u8BE5\u5B50\u96C6\uFF0C\u5176\u4F59\u4FDD\u6301\u5F85\u5904\u7406\uFF09",
|
|
1775
|
+
argsHint: "[N|N,M|N-M]"
|
|
1776
|
+
},
|
|
1777
|
+
discard: {
|
|
1778
|
+
description: "\u4E22\u5F03\u5F85\u5904\u7406\u7684\u7F16\u8F91\u5757\u800C\u4E0D\u5199\u5165\uFF08\u65E0\u53C2\u6570 \u2192 \u5168\u90E8\uFF1B\u7D22\u5F15 \u2192 \u8BE5\u5B50\u96C6\uFF09",
|
|
1779
|
+
argsHint: "[N|N,M|N-M]"
|
|
1780
|
+
},
|
|
1781
|
+
walk: {
|
|
1782
|
+
description: "\u9010\u5757\u9010\u6B65\u5904\u7406\u5F85\u5904\u7406\u7684\u7F16\u8F91\uFF08git-add-p \u98CE\u683C\uFF1A\u6BCF\u5757 y/n\uFF0Ca \u5E94\u7528\u5269\u4F59\uFF0CA \u5207\u6362 AUTO\uFF09"
|
|
1783
|
+
},
|
|
1784
|
+
undo: { description: "\u56DE\u6EDA\u6700\u540E\u5E94\u7528\u7684\u7F16\u8F91\u6279\u5904\u7406" },
|
|
1785
|
+
history: {
|
|
1786
|
+
description: "\u5217\u51FA\u6B64\u4F1A\u8BDD\u7684\u6BCF\u4E2A\u7F16\u8F91\u6279\u5904\u7406\uFF08\u7528\u4E8E /show \u7684 ID\uFF0C\u64A4\u6D88\u6807\u8BB0\uFF09"
|
|
1787
|
+
},
|
|
1788
|
+
show: {
|
|
1789
|
+
description: "\u8F6C\u50A8\u5B58\u50A8\u7684\u7F16\u8F91\u5DEE\u5F02\uFF08\u7701\u7565 id \u65F6\u4E3A\u6700\u65B0\u672A\u64A4\u6D88\u7684\uFF09",
|
|
1790
|
+
argsHint: "[id]"
|
|
1791
|
+
},
|
|
1792
|
+
commit: { description: "git add -A && git commit -m ...", argsHint: '"msg"' },
|
|
1793
|
+
checkpoint: {
|
|
1794
|
+
description: "\u5FEB\u7167\u4F1A\u8BDD\u6D89\u53CA\u7684\u6BCF\u4E2A\u6587\u4EF6\uFF08Cursor \u98CE\u683C\u5185\u90E8\u5B58\u50A8\uFF0C\u975E git\uFF09\u3002\u5355\u72EC /checkpoint \u5217\u51FA\u3002",
|
|
1795
|
+
argsHint: "[name|list|forget <id>]"
|
|
1796
|
+
},
|
|
1797
|
+
restore: {
|
|
1798
|
+
description: "\u5C06\u6587\u4EF6\u56DE\u6EDA\u5230\u547D\u540D\u7684\u68C0\u67E5\u70B9\uFF08\u89C1 /checkpoint list\uFF09",
|
|
1799
|
+
argsHint: "<name|id>"
|
|
1800
|
+
},
|
|
1801
|
+
plan: {
|
|
1802
|
+
description: "\u5207\u6362\u53EA\u8BFB\u8BA1\u5212\u6A21\u5F0F\uFF08\u5199\u5165\u88AB\u5F39\u56DE\u76F4\u5230 submit_plan + \u5BA1\u6279\uFF09",
|
|
1803
|
+
argsHint: "[on|off]"
|
|
1804
|
+
},
|
|
1805
|
+
"apply-plan": {
|
|
1806
|
+
description: "\u5F3A\u5236\u6279\u51C6\u5F85\u5904\u7406 / \u6587\u672C\u4E2D\u7684\u8BA1\u5212\uFF08\u5982\u679C\u9519\u8FC7\u4E86\u9009\u62E9\u5668\u65F6\u7684\u56DE\u9000\uFF09"
|
|
1807
|
+
},
|
|
1808
|
+
mode: {
|
|
1809
|
+
description: "\u7F16\u8F91\u95E8\u63A7\uFF1Areview\uFF08\u6392\u961F\uFF09\xB7 auto\uFF08\u5E94\u7528+\u64A4\u6D88\uFF09\xB7 yolo\uFF08\u5E94\u7528+\u81EA\u52A8 shell\uFF09\u3002Shift+Tab \u5FAA\u73AF\u3002",
|
|
1810
|
+
argsHint: "[review|auto|yolo]"
|
|
1811
|
+
},
|
|
1812
|
+
jobs: { description: "\u5217\u51FA run_background \u542F\u52A8\u7684\u540E\u53F0\u4F5C\u4E1A" },
|
|
1813
|
+
kill: {
|
|
1814
|
+
description: "\u6309 ID \u505C\u6B62\u540E\u53F0\u4F5C\u4E1A\uFF08SIGTERM \u2192 \u5BBD\u9650\u671F\u540E SIGKILL\uFF09",
|
|
1815
|
+
argsHint: "<id>"
|
|
1816
|
+
},
|
|
1817
|
+
logs: {
|
|
1818
|
+
description: "\u8DDF\u8E2A\u540E\u53F0\u4F5C\u4E1A\u7684\u8F93\u51FA\uFF08\u9ED8\u8BA4\u6700\u540E 80 \u884C\uFF09",
|
|
1819
|
+
argsHint: "<id> [lines]"
|
|
1820
|
+
}
|
|
1821
|
+
},
|
|
1822
|
+
wizard: {
|
|
1823
|
+
languageTitle: "\u9009\u62E9\u8BED\u8A00",
|
|
1824
|
+
languageSubtitle: "\u5DF2\u6839\u636E\u7CFB\u7EDF\u8BED\u8A00\u81EA\u52A8\u9009\u4E2D\u3002\u4E4B\u540E\u53EF\u7528 /language \u5207\u6362\u3002",
|
|
1825
|
+
welcomeTitle: "\u6B22\u8FCE\u4F7F\u7528 Reasonix\u3002",
|
|
1826
|
+
apiKeyPrompt: "\u7C98\u8D34\u4F60\u7684 DeepSeek API key \u5F00\u59CB\u4F7F\u7528\u3002",
|
|
1827
|
+
apiKeyGetOne: "\u5728\u6B64\u83B7\u53D6\uFF1Ahttps://platform.deepseek.com/api_keys",
|
|
1828
|
+
apiKeySavedLocally: "\u4FDD\u5B58\u5728\u672C\u5730\uFF1A{path}",
|
|
1829
|
+
apiKeyInputLabel: "key \u203A ",
|
|
1830
|
+
apiKeyInvalid: "\u8FD9\u770B\u8D77\u6765\u4E0D\u50CF DeepSeek \u7684 key\u3002\u5B83\u4EEC\u4EE5 'sk-' \u5F00\u5934\uFF0C30 \u5B57\u7B26\u4EE5\u4E0A\u3002",
|
|
1831
|
+
apiKeyPreview: "\u9884\u89C8\uFF1A{redacted}",
|
|
1832
|
+
presetTitle: "\u9009\u62E9\u9884\u8BBE",
|
|
1833
|
+
mcpTitle: "Reasonix \u8981\u4E3A\u4F60\u63A5\u5165\u54EA\u4E9B MCP \u670D\u52A1\u5668\uFF1F",
|
|
1834
|
+
mcpUserArgsHint: "\uFF08\u9700\u8981\u4F60\u63D0\u4F9B {arg}\uFF09",
|
|
1835
|
+
mcpFooterMulti: "[\u2191\u2193] \u79FB\u52A8 \xB7 [\u7A7A\u683C] \u9009\u62E9 \xB7 [Enter] \u786E\u8BA4 \xB7 [Esc] \u53D6\u6D88 \xB7 \u5168\u4E0D\u9009 = \u8DF3\u8FC7",
|
|
1836
|
+
mcpArgsTitle: "\u914D\u7F6E {name}",
|
|
1837
|
+
mcpArgsDirMissing: "\u76EE\u5F55 {path} \u4E0D\u5B58\u5728\u3002",
|
|
1838
|
+
mcpArgsDirCreateHint: "[Y/Enter] \u521B\u5EFA\uFF08mkdir -p\uFF09\xB7 [N/Esc] \u8F93\u5165\u5176\u4ED6\u8DEF\u5F84",
|
|
1839
|
+
mcpArgsDirCreateFailed: "\u65E0\u6CD5\u521B\u5EFA {path}\uFF1A{message}",
|
|
1840
|
+
mcpArgsRequiredParam: "\u5FC5\u586B\u53C2\u6570\uFF1A",
|
|
1841
|
+
mcpArgsEmpty: "{name} \u9700\u8981\u4E00\u4E2A\u503C \u2014 \u4E0D\u80FD\u4E3A\u7A7A\u3002",
|
|
1842
|
+
mcpArgsNotADir: "{path} \u5B58\u5728\u4F46\u4E0D\u662F\u76EE\u5F55\u3002",
|
|
1843
|
+
reviewTitle: "\u786E\u8BA4\u4FDD\u5B58",
|
|
1844
|
+
reviewLabelApiKey: "API key",
|
|
1845
|
+
reviewLabelLanguage: "\u8BED\u8A00",
|
|
1846
|
+
reviewLabelPreset: "\u9884\u8BBE",
|
|
1847
|
+
reviewLabelMcp: "MCP",
|
|
1848
|
+
reviewMcpNone: "\uFF08\u65E0\uFF09",
|
|
1849
|
+
reviewMcpServers: "{count} \u4E2A\u670D\u52A1\u5668",
|
|
1850
|
+
reviewSavesTo: "\u4FDD\u5B58\u5230 {path}",
|
|
1851
|
+
reviewSaveError: "\u4FDD\u5B58\u914D\u7F6E\u5931\u8D25\uFF1A{message}",
|
|
1852
|
+
reviewFooter: "[Enter] \u4FDD\u5B58 \xB7 [Esc] \u53D6\u6D88",
|
|
1853
|
+
savedTitle: "\u25B8 \u5DF2\u4FDD\u5B58\u3002",
|
|
1854
|
+
savedFooter: "[Enter] \u9000\u51FA",
|
|
1855
|
+
selectFooter: "[\u2191\u2193] \u79FB\u52A8 \xB7 [Enter] \u786E\u8BA4 \xB7 [Esc] \u53D6\u6D88",
|
|
1856
|
+
stepCounter: "\u6B65\u9AA4 {step}/{total} \xB7 "
|
|
1857
|
+
},
|
|
1858
|
+
app: {
|
|
1859
|
+
walkCancelledRemaining: "\u25B8 \u6D4F\u89C8\u5DF2\u53D6\u6D88 \u2014 \u8FD8\u6709 {count} \u4E2A\u5F85\u5904\u7406\u7F16\u8F91\u5757\u3002",
|
|
1860
|
+
walkCancelled: "\u25B8 \u6D4F\u89C8\u5DF2\u53D6\u6D88\u3002",
|
|
1861
|
+
editModeYolo: "\u25B8 \u7F16\u8F91\u6A21\u5F0F\uFF1AYOLO \u2014 \u7F16\u8F91\u548C shell \u547D\u4EE4\u90FD\u81EA\u52A8\u6267\u884C\u3002/undo \u4ECD\u53EF\u64A4\u9500\u7F16\u8F91\u3002\u8BF7\u8C28\u614E\u4F7F\u7528\u3002",
|
|
1862
|
+
editModeAuto: "\u25B8 \u7F16\u8F91\u6A21\u5F0F\uFF1AAUTO \u2014 \u7F16\u8F91\u7ACB\u5373\u5E94\u7528\uFF1B5 \u79D2\u5185\u6309 u \u64A4\u9500\uFF08\u7A7A\u683C\u6682\u505C\u8BA1\u65F6\uFF09\u3002shell \u547D\u4EE4\u4ECD\u4F1A\u8BE2\u95EE\u3002",
|
|
1863
|
+
editModeReview: "\u25B8 \u7F16\u8F91\u6A21\u5F0F\uFF1Areview \u2014 \u7F16\u8F91\u5165\u961F\u5F85 /apply\uFF08\u6216 y\uFF09/ /discard\uFF08\u6216 n\uFF09",
|
|
1864
|
+
rejectedEdit: "\u25B8 \u62D2\u7EDD\u4E86\u5BF9 {path} \u7684\u7F16\u8F91{context}",
|
|
1865
|
+
autoApprovingRest: "\u25B8 \u672C\u8F6E\u5269\u4F59\u7F16\u8F91\u81EA\u52A8\u6279\u51C6",
|
|
1866
|
+
flippedAutoSession: "\u25B8 \u5DF2\u5207\u6362\u5230 AUTO \u6A21\u5F0F\uFF08\u672C\u4F1A\u8BDD\u5269\u4F59\u751F\u6548\uFF0C\u5DF2\u6301\u4E45\u5316\uFF09",
|
|
1867
|
+
flippedAutoWalk: "\u25B8 \u5DF2\u5207\u6362\u5230 AUTO \u6A21\u5F0F \u2014 \u540E\u7EED\u7F16\u8F91\u7ACB\u5373\u5E94\u7528\u3002\u6D4F\u89C8\u6A21\u5F0F\u9000\u51FA\u3002",
|
|
1868
|
+
dashboardStopped: "\u25B8 \u4EEA\u8868\u677F\u5DF2\u505C\u6B62\u3002",
|
|
1869
|
+
notedMemory: "\u25B8 \u5DF2\u8BB0\u5F55\uFF08{scope}\uFF09\u2014 {verb} {path}",
|
|
1870
|
+
notedScopeProject: "\u9879\u76EE",
|
|
1871
|
+
notedScopeGlobal: "\u5168\u5C40",
|
|
1872
|
+
notedVerbCreated: "\u521B\u5EFA",
|
|
1873
|
+
notedVerbAppended: "\u8FFD\u52A0\u5230",
|
|
1874
|
+
memoryWriteFailed: "# \u8BB0\u5FC6\u5199\u5165\u5931\u8D25",
|
|
1875
|
+
commandFailed: "! \u547D\u4EE4\u5931\u8D25",
|
|
1876
|
+
restoreCodeOnly: "\u25B8 /restore \u4EC5\u5728\u4EE3\u7801\u6A21\u5F0F\u53EF\u7528",
|
|
1877
|
+
hookUserPromptSubmit: "UserPromptSubmit \u94A9\u5B50",
|
|
1878
|
+
hookStop: "Stop \u94A9\u5B50",
|
|
1879
|
+
atMentions: "\u25B8 @mentions\uFF1A{parts}",
|
|
1880
|
+
atUrl: "\u25B8 @url\uFF1A{parts}",
|
|
1881
|
+
atUrlFailed: "@url \u5C55\u5F00\u5931\u8D25",
|
|
1882
|
+
denied: "\u25B8 \u5DF2\u62D2\u7EDD\uFF1A{cmd}{context}",
|
|
1883
|
+
alwaysAllowed: '\u25B8 \u5DF2\u5BF9 {dir} \u6C38\u4E45\u5141\u8BB8 "{prefix}"',
|
|
1884
|
+
runningCommand: "\u25B8 \u6B63\u5728\u6267\u884C\uFF1A{cmd}",
|
|
1885
|
+
startingBackground: "\u25B8 \u540E\u53F0\u542F\u52A8\uFF1A{cmd}",
|
|
1886
|
+
checkpointSaved: "\u26C1 \u5DF2\u4FDD\u5B58\u68C0\u67E5\u70B9 \xB7 {id} \xB7 {count} \u4E2A\u6587\u4EF6 \xB7 /restore {id} \u53EF\u56DE\u6EDA\u6B64\u6B65",
|
|
1887
|
+
continuingAfter: "\u25B8 \u5728 {label}{counter} \u4E4B\u540E\u7EE7\u7EED",
|
|
1888
|
+
planStoppedAt: "\u25B8 \u8BA1\u5212\u5728 {label}{counter} \u5904\u505C\u6B62",
|
|
1889
|
+
revisingAfter: "\u25B8 \u5728 {label} \u4E4B\u540E\u4FEE\u8BA2 \u2014 {feedback}"
|
|
1890
|
+
},
|
|
1891
|
+
hooks: {
|
|
1892
|
+
head: "\u94A9\u5B50 {tag} `{cmd}` {decision}{truncTag}",
|
|
1893
|
+
headWithDetail: "\u94A9\u5B50 {tag} `{cmd}` {decision}{truncTag}\uFF1A{detail}",
|
|
1894
|
+
truncated: "\uFF08\u8F93\u51FA\u5728 256KB \u5904\u622A\u65AD\uFF09",
|
|
1895
|
+
decisionBlock: "\u62E6\u622A",
|
|
1896
|
+
decisionWarn: "\u544A\u8B66",
|
|
1897
|
+
decisionTimeout: "\u8D85\u65F6",
|
|
1898
|
+
decisionError: "\u9519\u8BEF"
|
|
1899
|
+
},
|
|
1900
|
+
summary: {
|
|
1901
|
+
status: "\u6B63\u5728\u603B\u7ED3\u5DF2\u6536\u96C6\u7684\u5185\u5BB9\u2026",
|
|
1902
|
+
hallucinatedFallback: "\uFF08\u6A21\u578B\u751F\u6210\u4E86\u4F2A\u9020\u7684\u5DE5\u5177\u8C03\u7528\u6807\u8BB0\u800C\u975E\u7EAF\u6587\u672C\u603B\u7ED3 \u2014 \u8BD5\u8BD5 /retry \u6362\u4E2A\u66F4\u7A84\u7684\u95EE\u9898\uFF0C\u6216 /think \u67E5\u770B R1 \u7684\u63A8\u7406\uFF09",
|
|
1903
|
+
failedAfterReason: "{label}\uFF0C\u4E14\u56DE\u9000\u7684\u603B\u7ED3\u8C03\u7528\u4E5F\u5931\u8D25\uFF1A{message}\u3002\u8BF7\u8FD0\u884C /clear \u540E\u7528\u66F4\u7A84\u7684\u95EE\u9898\u91CD\u8BD5\uFF0C\u6216\u63D0\u9AD8 --max-tool-iters\u3002"
|
|
1904
|
+
},
|
|
1905
|
+
loop: {
|
|
1906
|
+
budgetExhausted: "\u4F1A\u8BDD\u9884\u7B97\u5DF2\u7528\u5B8C \u2014 \u5DF2\u82B1\u8D39 ${spent} \u2265 \u4E0A\u9650 ${cap}\u3002\u7528 /budget <usd> \u63D0\u9AD8\u4E0A\u9650\uFF0C/budget off \u6E05\u9664\u4E0A\u9650\uFF0C\u6216\u7ED3\u675F\u4F1A\u8BDD\u3002",
|
|
1907
|
+
budget80Pct: "\u25B2 \u9884\u7B97\u5DF2\u7528 80% \u2014 ${spent} / ${cap}\u3002\u4E0B\u4E00\u4E24\u8F6E\u53EF\u80FD\u5C31\u89E6\u9876\u3002",
|
|
1908
|
+
proArmed: "\u21E7 /pro \u5DF2\u88C5\u5907 \u2014 \u672C\u8F6E\u4F7F\u7528 deepseek-v4-pro\uFF08\u4E00\u6B21\u6027 \xB7 \u672C\u8F6E\u540E\u81EA\u52A8\u89E3\u9664\uFF09",
|
|
1909
|
+
abortedAtIter: "\u5728\u7B2C {iter}/{cap} \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",
|
|
1910
|
+
toolUploadStatus: "\u5DE5\u5177\u7ED3\u679C\u5DF2\u4E0A\u4F20 \xB7 \u6A21\u578B\u5728\u751F\u6210\u4E0B\u4E00\u6761\u54CD\u5E94\u524D\u601D\u8003\u4E2D\u2026",
|
|
1911
|
+
toolBudgetWarning: "\u5DF2\u7528 {iter}/{cap} \u6B21\u5DE5\u5177\u8C03\u7528 \u2014 \u63A5\u8FD1\u4E0A\u9650\u3002\u6309 Esc \u7ACB\u5373\u5F3A\u5236\u603B\u7ED3\u3002",
|
|
1912
|
+
preflightFoldStatus: "\u9884\u68C0\uFF1A\u4E0A\u4E0B\u6587\u63A5\u8FD1\u4E0A\u9650\uFF0C\u5C1D\u8BD5\u6298\u53E0\u2026",
|
|
1913
|
+
preflightFolded: "\u9884\u68C0\uFF1A\u8BF7\u6C42\u7EA6 {estimate}/{ctxMax} tokens\uFF08{pct}%\uFF09\u2014 \u5DF2\u6298\u53E0 {beforeMessages} \u6761\u6D88\u606F \u2192 {afterMessages}\uFF08\u603B\u7ED3 {summaryChars} \u5B57\uFF09\u3002\u53D1\u9001\u4E2D\u3002",
|
|
1914
|
+
preflightNoFold: "\u9884\u68C0\uFF1A\u8BF7\u6C42\u7EA6 {estimate}/{ctxMax} tokens\uFF08{pct}%\uFF09\u4E14\u6CA1\u6709\u53EF\u6298\u53E0\u7684\u5185\u5BB9 \u2014 DeepSeek \u5927\u6982\u7387\u4F1A\u8FD4\u56DE 400\u3002\u8BF7\u8FD0\u884C /clear \u6216 /new \u91CD\u65B0\u5F00\u59CB\u3002",
|
|
1915
|
+
flashEscalation: "\u21E7 flash \u8BF7\u6C42\u5347\u7EA7 \u2014 \u672C\u8F6E\u6539\u7528 {model}{reasonSuffix}",
|
|
1916
|
+
harvestStatus: "\u6B63\u5728\u4ECE\u63A8\u7406\u8FC7\u7A0B\u63D0\u53D6\u8BA1\u5212\u72B6\u6001\u2026",
|
|
1917
|
+
autoEscalation: "\u21E7 \u672C\u8F6E\u5269\u4F59\u8C03\u7528\u81EA\u52A8\u5347\u7EA7\u5230 {model} \u2014 flash \u547D\u4E2D {breakdown}\u3002\u4E0B\u4E00\u8F6E\u56DE\u9000\u5230 {fallback}\uFF0C\u9664\u975E\u5DF2\u88C5\u5907 /pro\u3002",
|
|
1918
|
+
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",
|
|
1919
|
+
stormStuck: "\u5DF2\u505C\u6B62\u5361\u6B7B\u7684\u91CD\u8BD5\u5FAA\u73AF \u2014 \u6A21\u578B\u5728\u81EA\u7EA0\u63D0\u793A\u540E\u4ECD\u4EE5\u76F8\u540C\u53C2\u6570\u91CD\u590D\u8C03\u7528\u540C\u4E00\u5DE5\u5177\u3002\u8BF7\u5C1D\u8BD5 /retry\u3001\u6362\u79CD\u8BF4\u6CD5\uFF0C\u6216\u6392\u67E5\u5E95\u5C42\u963B\u585E\u3002",
|
|
1920
|
+
stormSuppressed: "\u5DF2\u6291\u5236 {count} \u6B21\u91CD\u590D\u5DE5\u5177\u8C03\u7528 \u2014 \u540C\u4E00\u540D\u79F0 + \u53C2\u6570\u89E6\u53D1 3 \u6B21\u4EE5\u4E0A\u3002",
|
|
1921
|
+
compactingHistoryStatus: "\u6B63\u5728\u538B\u7F29\u5386\u53F2{aggressiveTag}\u2026",
|
|
1922
|
+
aggressiveTag: "\uFF08\u6FC0\u8FDB\uFF09",
|
|
1923
|
+
foldedHistory: "\u4E0A\u4E0B\u6587 {before}/{ctxMax}\uFF08{pct}%\uFF09\u2014 \u5DF2\u6298\u53E0 {beforeMessages} \u6761\u6D88\u606F \u2192 {afterMessages}\uFF08\u603B\u7ED3 {summaryChars} \u5B57\uFF09\u3002\u7EE7\u7EED\u3002",
|
|
1924
|
+
aggressivelyFoldedHistory: "\u4E0A\u4E0B\u6587 {before}/{ctxMax}\uFF08{pct}%\uFF09\u2014 \u5DF2\u6FC0\u8FDB\u6298\u53E0 {beforeMessages} \u6761\u6D88\u606F \u2192 {afterMessages}\uFF08\u603B\u7ED3 {summaryChars} \u5B57\uFF09\u3002\u7EE7\u7EED\u3002",
|
|
1925
|
+
forcingSummary: "\u4E0A\u4E0B\u6587 {before}/{ctxMax}\uFF08{pct}%\uFF09\u2014 \u57FA\u4E8E\u5DF2\u6536\u96C6\u5230\u7684\u5185\u5BB9\u5F3A\u5236\u603B\u7ED3\u3002\u8BF7\u8FD0\u884C /compact\u3001/clear \u6216 /new \u91CD\u7F6E\u3002"
|
|
1926
|
+
},
|
|
1927
|
+
errors: {
|
|
1928
|
+
contextOverflow: "\u4E0A\u4E0B\u6587\u6EA2\u51FA\uFF08DeepSeek 400\uFF09\uFF1A\u4F1A\u8BDD\u5386\u53F2\u5DF2\u8FBE {requested}\uFF0C\u8D85\u51FA\u6A21\u578B prompt \u4E0A\u9650\uFF08V4\uFF1A1M tokens\uFF1B\u65E7\u7248 chat/reasoner\uFF1A131k\uFF09\u3002\u901A\u5E38\u662F\u5355\u4E2A\u5DE5\u5177\u7ED3\u679C\u592A\u5927\u3002Reasonix \u9ED8\u8BA4\u5C06\u65B0\u5DE5\u5177\u7ED3\u679C\u9650\u5236\u5728 8k tokens\uFF0C\u5E76\u5728\u4F1A\u8BDD\u52A0\u8F7D\u65F6\u81EA\u52A8\u4FEE\u590D\u8D85\u5927\u5386\u53F2 \u2014 \u91CD\u542F\u5E38\u80FD\u6E05\u6389\u3002\u5982\u679C\u4ECD\u7136\u6EA2\u51FA\uFF0C\u8FD0\u884C /forget\uFF08\u5220\u9664\u4F1A\u8BDD\uFF09\u6216 /clear\uFF08\u4E22\u5F03\u663E\u793A\u4E2D\u7684\u5386\u53F2\uFF09\u4ECE\u5934\u5F00\u59CB\u3002",
|
|
1929
|
+
contextOverflowTooMany: "tokens \u6570\u91CF\u8FC7\u591A",
|
|
1930
|
+
auth401: "\u8BA4\u8BC1\u5931\u8D25\uFF08DeepSeek 401\uFF09\uFF1A{inner}\u3002\u4F60\u7684 API key \u88AB\u62D2\u7EDD\u3002\u8FD0\u884C `reasonix setup` \u6216 `export DEEPSEEK_API_KEY=sk-...` \u4FEE\u590D\u3002\u5728 https://platform.deepseek.com/api_keys \u83B7\u53D6 key\u3002",
|
|
1931
|
+
balance402: "\u4F59\u989D\u4E0D\u8DB3\uFF08DeepSeek 402\uFF09\uFF1A{inner}\u3002\u5728 https://platform.deepseek.com/top_up \u5145\u503C \u2014 \u4F59\u989D\u975E\u96F6\u65F6\u9762\u677F\u9876\u680F\u4F1A\u663E\u793A\u3002",
|
|
1932
|
+
badparam422: "\u53C2\u6570\u9519\u8BEF\uFF08DeepSeek 422\uFF09\uFF1A{inner}",
|
|
1933
|
+
badrequest400: "\u8BF7\u6C42\u9519\u8BEF\uFF08DeepSeek 400\uFF09\uFF1A{inner}",
|
|
1934
|
+
deepseek5xxHead: "DeepSeek \u670D\u52A1\u4E0D\u53EF\u7528\uFF08{status}\uFF09 \u2014 \u8FD9\u662F DeepSeek \u670D\u52A1\u7AEF\u95EE\u9898\uFF0C\u4E0D\u662F Reasonix \u6545\u969C\u3002\u5DF2\u6309\u6307\u6570\u9000\u907F\u91CD\u8BD5 4 \u6B21\u3002",
|
|
1935
|
+
deepseek5xxReachable: " DeepSeek \u4E3B API \u5065\u5EB7\u68C0\u67E5\u901A\u8FC7\uFF0C\u4F46 /chat/completions \u5728\u6302 \u2014 \u4ED6\u4EEC\u90A3\u8FB9\u90E8\u5206\u670D\u52A1\u5F02\u5E38\u3002",
|
|
1936
|
+
deepseek5xxUnreachable: " \u65E0\u6CD5\u4ECE\u4F60\u7684\u7F51\u7EDC\u8BBF\u95EE DeepSeek API \u2014 \u53EF\u80FD\u662F DS \u6574\u4F53\u6545\u969C\uFF0C\u4E5F\u53EF\u80FD\u662F\u672C\u5730\u7F51\u7EDC\u95EE\u9898\u3002",
|
|
1937
|
+
deepseek5xxActionNetwork: " \u5EFA\u8BAE\uFF1A(1) \u68C0\u67E5\u7F51\u7EDC\uFF0C(2) \u7B49 30 \u79D2\u540E\u91CD\u8BD5\uFF0C(3) \u67E5\u770B\u72B6\u6001\u9875 https://status.deepseek.com\u3002",
|
|
1938
|
+
deepseek5xxActionRetry: " \u5EFA\u8BAE\uFF1A(1) \u7B49 30 \u79D2\u540E\u91CD\u8BD5\uFF0C(2) \u7528 /preset \u5207\u6362\u6A21\u578B\uFF0C(3) \u67E5\u770B\u72B6\u6001\u9875 https://status.deepseek.com\u3002",
|
|
1939
|
+
innerNoMessage: "\uFF08\u65E0\u9519\u8BEF\u4FE1\u606F\uFF09",
|
|
1940
|
+
reasonAborted: "[\u7528\u6237\u5DF2\u4E2D\u65AD\uFF08Esc\uFF09 \u2014 \u6B63\u5728\u603B\u7ED3\u5230\u76EE\u524D\u4E3A\u6B62\u7684\u53D1\u73B0]",
|
|
1941
|
+
reasonContextGuard: "[\u4E0A\u4E0B\u6587\u989D\u5EA6\u5373\u5C06\u8017\u5C3D \u2014 \u5728\u4E0B\u4E00\u6B21\u8C03\u7528\u6EA2\u51FA\u4E4B\u524D\u5148\u603B\u7ED3]",
|
|
1942
|
+
reasonStuck: "[\u5361\u5728\u91CD\u590D\u7684\u5DE5\u5177\u8C03\u7528\u4E0A \u2014 \u8BF4\u660E\u5DF2\u5C1D\u8BD5\u7684\u65B9\u6CD5\u4EE5\u53CA\u963B\u585E\u70B9]",
|
|
1943
|
+
reasonBudget: "[\u5DE5\u5177\u8C03\u7528\u914D\u989D\uFF08{iterCap}\uFF09\u5DF2\u7528\u5C3D \u2014 \u57FA\u4E8E\u5DF2\u53D1\u73B0\u7684\u5185\u5BB9\u5F3A\u5236\u603B\u7ED3]",
|
|
1944
|
+
labelAborted: "\u7528\u6237\u4E2D\u65AD",
|
|
1945
|
+
labelContextGuard: "\u89E6\u53D1\u4E0A\u4E0B\u6587\u4FDD\u62A4\uFF08prompt > 80% \u7A97\u53E3\uFF09",
|
|
1946
|
+
labelStuck: "\u5361\u6B7B\uFF08\u91CD\u590D\u5DE5\u5177\u8C03\u7528\u88AB\u53CD\u98CE\u66B4\u673A\u5236\u6291\u5236\uFF09",
|
|
1947
|
+
labelBudget: "\u5DE5\u5177\u8C03\u7528\u914D\u989D\uFF08{iterCap}\uFF09\u5DF2\u7528\u5C3D"
|
|
1948
|
+
},
|
|
1949
|
+
handlers: {
|
|
1950
|
+
basic: {
|
|
1951
|
+
clearInfo: "\u25B8 \u7EC8\u7AEF\u5DF2\u6E05\u9664\uFF08\u89C6\u53E3 + \u6EDA\u52A8\u56DE\u653E\uFF09\u3002\u4E0A\u4E0B\u6587\uFF08\u6D88\u606F\u65E5\u5FD7\uFF09\u5B8C\u597D\u65E0\u635F \u2014 \u4E0B\u4E00\u8F6E\u4ECD\u80FD\u770B\u5230\u6240\u6709\u5185\u5BB9\u3002\u4F7F\u7528 /new \u5168\u65B0\u5F00\u59CB\uFF0C\u6216 /forget \u5220\u9664\u6574\u4E2A\u4F1A\u8BDD\u3002",
|
|
1952
|
+
newInfo: "\u25B8 \u65B0\u5BF9\u8BDD \u2014 \u5DF2\u4ECE\u4E0A\u4E0B\u6587\u4E2D\u4E22\u5F03 {count} \u6761\u6D88\u606F\u3002\u540C\u4E00\u4F1A\u8BDD\uFF0C\u5168\u65B0\u5F00\u59CB\u3002",
|
|
1953
|
+
helpTitle: "\u547D\u4EE4\uFF1A",
|
|
1954
|
+
helpHelp: " /help \u663E\u793A\u6B64\u6D88\u606F",
|
|
1955
|
+
helpKeys: " /keys \u952E\u76D8\u5FEB\u6377\u952E + \u63D0\u793A\u524D\u7F00 (!, @, /)",
|
|
1956
|
+
helpStatus: " /status \u663E\u793A\u5F53\u524D\u8BBE\u7F6E",
|
|
1957
|
+
helpPreset: " /preset <auto|flash|pro> \u6A21\u578B\u7EC4\u5408 \u2014 \u89C1\u4E0B\u6587",
|
|
1958
|
+
helpModel: " /model <id> deepseek-v4-flash \u6216 deepseek-v4-pro",
|
|
1959
|
+
helpPro: " /pro [off] \u4E3A\u4E0B\u4E00\u8F6E\u542F\u7528 v4-pro\uFF08\u4E00\u6B21\u6027\uFF0C\u81EA\u52A8\u89E3\u9664\uFF09",
|
|
1960
|
+
helpHarvest: " /harvest [on|off] Pillar 2\uFF1A\u7ED3\u6784\u5316\u8BA1\u5212\u72B6\u6001\u63D0\u53D6\uFF08\u53EF\u9009 \u2014 \u989D\u5916\u6536\u8D39\uFF09",
|
|
1961
|
+
helpBranch: " /branch <N|off> \u8FD0\u884C N \u4E2A\u5E76\u884C\u91C7\u6837\uFF08N>=2\uFF09\u2014 \u4EC5\u624B\u52A8\uFF0CN \u500D\u6210\u672C",
|
|
1962
|
+
helpEffort: " /effort <high|max> reasoning_effort \u4E0A\u9650\uFF08max=\u5B8C\u6574\u601D\u8003\uFF0Chigh=\u66F4\u4FBF\u5B9C/\u66F4\u5FEB\uFF09",
|
|
1963
|
+
helpMcp: " /mcp \u5217\u51FA\u9644\u52A0\u5230\u6B64\u4F1A\u8BDD\u7684 MCP \u670D\u52A1\u5668 + \u5DE5\u5177",
|
|
1964
|
+
helpResource: " /resource [uri] \u6D4F\u89C8 + \u8BFB\u53D6 MCP \u8D44\u6E90\uFF08\u65E0\u53C2\u6570 \u2192 \u5217\u51FA URI\uFF1B<uri> \u2192 \u83B7\u53D6\uFF09",
|
|
1965
|
+
helpPrompt: " /prompt [name] \u6D4F\u89C8 + \u83B7\u53D6 MCP \u63D0\u793A\uFF08\u65E0\u53C2\u6570 \u2192 \u5217\u51FA\u540D\u79F0\uFF1B<name> \u2192 \u6E32\u67D3\uFF09",
|
|
1966
|
+
helpCompact: " /compact \u6298\u53E0\u65E7\u8F6E\u6B21\u4E3A\u6458\u8981\uFF08cache-safe\uFF0C50% \u81EA\u52A8\u89E6\u53D1\uFF09",
|
|
1967
|
+
helpThink: " /think \u8F6C\u50A8\u6700\u8FD1\u4E00\u8F6E\u7684\u5B8C\u6574 R1 \u63A8\u7406\uFF08\u4EC5\u63A8\u7406\u6A21\u578B\uFF09",
|
|
1968
|
+
helpTool: " /tool [N] \u5217\u51FA\u5DE5\u5177\u8C03\u7528\uFF08\u6216\u8F6C\u50A8\u7B2C N \u4E2A\u7684\u5B8C\u6574\u8F93\u51FA\uFF0C1=\u6700\u8FD1\uFF09",
|
|
1969
|
+
helpCost: " /cost [text] \u7A7A \u2192 \u4E0A\u4E00\u8F6E\u82B1\u8D39\uFF1B\u5E26\u6587\u672C \u2192 \u4F30\u7B97\u53D1\u9001\u6210\u672C",
|
|
1970
|
+
helpMemory: " /memory [sub] \u663E\u793A\u56FA\u5B9A\u8BB0\u5FC6\uFF08REASONIX.md + ~/.reasonix/memory\uFF09\u3002",
|
|
1971
|
+
helpMemorySub: " \u5B50\u547D\u4EE4\uFF1Alist | show <name> | forget <name> | clear <scope> confirm",
|
|
1972
|
+
helpSkill: " /skill [sub] \u5217\u51FA / \u8FD0\u884C\u7528\u6237\u6280\u80FD\uFF08project/.reasonix/skills + ~/.reasonix/skills\uFF09\u3002",
|
|
1973
|
+
helpSkillSub: " \u5B50\u547D\u4EE4\uFF1Alist | show <name> | <name> [args]\uFF08\u5C06\u6280\u80FD\u4F53\u6CE8\u5165\u4E3A\u7528\u6237\u8F6E\u6B21\uFF09",
|
|
1974
|
+
helpRetry: " /retry \u622A\u65AD\u5E76\u91CD\u53D1\u60A8\u7684\u6700\u540E\u4E00\u6761\u6D88\u606F\uFF08\u6A21\u578B\u91CD\u65B0\u91C7\u6837\uFF09",
|
|
1975
|
+
helpApply: " /apply [N|1,3|1-4] \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09\u63D0\u4EA4\u5F85\u5904\u7406\u7684\u7F16\u8F91\u5757\uFF08\u65E0\u53C2\u6570 \u2192 \u5168\u90E8\uFF1B\u7D22\u5F15 \u2192 \u5B50\u96C6\uFF09",
|
|
1976
|
+
helpDiscard: " /discard [N|1,3|1-4] \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09\u4E22\u5F03\u5F85\u5904\u7406\u7684\u7F16\u8F91\uFF08\u65E0\u53C2\u6570 \u2192 \u5168\u90E8\uFF1B\u7D22\u5F15 \u2192 \u5B50\u96C6\uFF09",
|
|
1977
|
+
helpWalk: " /walk \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09\u9010\u5757\u9010\u6B65\u5904\u7406\u5F85\u5904\u7406\u7684\u7F16\u8F91\uFF08\u6BCF\u5757 y/n\uFF0Ca \u5E94\u7528\u5269\u4F59\uFF0CA \u5207\u6362 AUTO\uFF09",
|
|
1978
|
+
helpUndo: " /undo \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09\u56DE\u6EDA\u6700\u8FD1\u672A\u64A4\u6D88\u7684\u7F16\u8F91\u6279\u5904\u7406",
|
|
1979
|
+
helpHistory: " /history \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09\u5217\u51FA\u6B64\u4F1A\u8BDD\u7684\u6BCF\u4E2A\u7F16\u8F91\u6279\u5904\u7406",
|
|
1980
|
+
helpShow: " /show [id] \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09\u8F6C\u50A8\u5B58\u50A8\u7684\u7F16\u8F91\u5DEE\u5F02\uFF08\u7701\u7565 id \u65F6\u4E3A\u6700\u65B0\uFF09",
|
|
1981
|
+
helpCommit: ' /commit "msg" \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09git add -A && git commit -m "msg"',
|
|
1982
|
+
helpPlan: " /plan [on|off] \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09\u5207\u6362\u53EA\u8BFB\u8BA1\u5212\u6A21\u5F0F\uFF1B\u5199\u5165\u9700\u7ECF submit_plan + \u5BA1\u6279",
|
|
1983
|
+
helpApplyPlan: " /apply-plan \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09\u5F3A\u5236\u6279\u51C6\u5F85\u5904\u7406/\u6587\u672C\u4E2D\u7684\u8BA1\u5212\uFF08\u56DE\u9000\uFF09",
|
|
1984
|
+
helpMode: " /mode [review|auto|yolo] \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09review = \u6392\u961F \xB7 auto = \u5E94\u7528+\u64A4\u6D88\u6A2A\u5E45 \xB7 yolo = \u5E94\u7528+\u81EA\u52A8 shell\u3002Shift+Tab \u5FAA\u73AF\u5207\u6362\u3002",
|
|
1985
|
+
helpJobs: " /jobs \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09\u5217\u51FA\u540E\u53F0\u8FDB\u7A0B\uFF08run_background\uFF09\u2014 \u8FD0\u884C\u4E2D\u548C\u5DF2\u9000\u51FA",
|
|
1986
|
+
helpKill: " /kill <id> \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09\u6309 ID \u505C\u6B62\u540E\u53F0\u4F5C\u4E1A\uFF08SIGTERM \u2192 SIGKILL\uFF09",
|
|
1987
|
+
helpLogs: " /logs <id> [lines] \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09\u8DDF\u8E2A\u540E\u53F0\u4F5C\u4E1A\u8F93\u51FA\uFF08\u9ED8\u8BA4\u6700\u540E 80 \u884C\uFF09",
|
|
1988
|
+
helpSessions: " /sessions \u5217\u51FA\u5DF2\u4FDD\u5B58\u7684\u4F1A\u8BDD\uFF08\u5F53\u524D\u6807\u8BB0\u4E3A \u25B8\uFF09",
|
|
1989
|
+
helpForget: " /forget \u4ECE\u78C1\u76D8\u5220\u9664\u5F53\u524D\u4F1A\u8BDD",
|
|
1990
|
+
helpNew: " /new \u5168\u65B0\u5F00\u59CB\uFF1A\u4E22\u5F03\u6240\u6709\u4E0A\u4E0B\u6587 + \u6E05\u9664\u6EDA\u52A8\u56DE\u653E",
|
|
1991
|
+
helpClear: " /clear \u4EC5\u6E05\u9664\u663E\u793A\u7684\u6EDA\u52A8\u56DE\u653E\uFF08\u4E0A\u4E0B\u6587\u4FDD\u7559 \u2014 \u6A21\u578B\u4ECD\u80FD\u770B\u5230\uFF09",
|
|
1992
|
+
helpLoop: " /loop <interval> <prompt> \u6BCF <interval> \u81EA\u52A8\u91CD\u65B0\u63D0\u4EA4 <prompt>\uFF085\u79D2..6\u5C0F\u65F6\uFF09\u3002/loop stop \xB7 \u8F93\u5165\u4EFB\u4F55\u5185\u5BB9\u53D6\u6D88\u3002",
|
|
1993
|
+
helpExit: " /exit \u9000\u51FA\uFF08\u522B\u540D\uFF1A/quit, /q\uFF09",
|
|
1994
|
+
helpShellTitle: "Shell \u5FEB\u6377\u65B9\u5F0F\uFF1A",
|
|
1995
|
+
helpShell: " !<cmd> \u5728\u6C99\u7BB1\u6839\u76EE\u5F55\u8FD0\u884C <cmd>\uFF1B\u8F93\u51FA\u8FDB\u5165\u5BF9\u8BDD",
|
|
1996
|
+
helpShellDetail: " \u4EE5\u4FBF\u6A21\u578B\u5728\u4E0B\u4E00\u8F6E\u770B\u5230\u3002\u65E0\u5141\u8BB8\u5217\u8868\u9650\u5236\u3002",
|
|
1997
|
+
helpShellConsent: " \u7528\u6237\u8F93\u5165 = \u660E\u786E\u540C\u610F\u3002",
|
|
1998
|
+
helpShellExample: " \u793A\u4F8B\uFF1A!git status !ls src/ !npm test",
|
|
1999
|
+
helpMemoryTitle: "\u5FEB\u901F\u8BB0\u5FC6\uFF1A",
|
|
2000
|
+
helpMemoryPin: " #<note> \u5C06 <note> \u8FFD\u52A0\u5230 <project>/REASONIX.md\uFF08\u53EF\u63D0\u4EA4\uFF09\u3002",
|
|
2001
|
+
helpMemoryPinEx: " \u793A\u4F8B\uFF1A#findByEmail \u5FC5\u987B\u533A\u5206\u5927\u5C0F\u5199",
|
|
2002
|
+
helpMemoryGlobal: " #g <note> \u5C06 <note> \u8FFD\u52A0\u5230 ~/.reasonix/REASONIX.md\uFF08\u5168\u5C40\uFF0C\u4E0D\u63D0\u4EA4\uFF09\u3002",
|
|
2003
|
+
helpMemoryGlobalEx: " \u793A\u4F8B\uFF1A#g \u59CB\u7EC8\u4F7F\u7528 pnpm \u800C\u975E npm",
|
|
2004
|
+
helpMemoryPinBoth: " \u4E24\u8005\u90FD\u56FA\u5B9A\u5230\u6BCF\u4E2A\u672A\u6765\u4F1A\u8BDD\u7684\u524D\u7F00\u4E2D\u3002\u6BD4 /memory \u66F4\u5FEB\u3002",
|
|
2005
|
+
helpMemoryEscape: " \u4F7F\u7528 `\\#text` \u53D1\u9001\u5B57\u9762\u91CF `#text` \u7ED9\u6A21\u578B\u3002",
|
|
2006
|
+
helpFileTitle: "\u6587\u4EF6\u5F15\u7528\uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09\uFF1A",
|
|
2007
|
+
helpFile: " @path/to/file \u53D1\u9001\u65F6\u5C06\u6587\u4EF6\u5185\u5BB9\u5185\u8054\u5230 [Referenced files] \u4E0B\u3002",
|
|
2008
|
+
helpFilePicker: " \u8F93\u5165 `@` \u6253\u5F00\u9009\u62E9\u5668\uFF08\u2191\u2193 \u5BFC\u822A\uFF0CTab/Enter \u9009\u62E9\uFF09\u3002",
|
|
2009
|
+
helpUrlTitle: "URL \u5F15\u7528\uFF1A",
|
|
2010
|
+
helpUrl: " @https://example.com \u83B7\u53D6 URL\uFF0C\u5265\u79BB HTML\uFF0C\u5185\u8054\u5230 [Referenced URLs] \u4E0B\u3002",
|
|
2011
|
+
helpUrlCache: " \u540C\u4E00\u4F1A\u8BDD\u4E2D\u76F8\u540C URL \u53EA\u83B7\u53D6\u4E00\u6B21\uFF08\u5185\u5B58\u7F13\u5B58\uFF09\u3002",
|
|
2012
|
+
helpUrlPunct: " \u81EA\u52A8\u5265\u79BB\u5C3E\u90E8\u6807\u70B9\u7B26\u53F7\uFF08./,/\uFF09\uFF09\u3002",
|
|
2013
|
+
helpPresetsTitle: "\u9884\u8BBE\uFF08branch + harvest \u6C38\u8FDC\u4E0D\u4F1A\u81EA\u52A8\u542F\u7528 \u2014 \u4EC5\u624B\u52A8\u9009\u62E9\uFF09\uFF1A",
|
|
2014
|
+
helpPresetAuto: " auto v4-flash \u2192 v4-pro \u5728\u56F0\u96BE\u8F6E\u6B21\u5207\u6362 \u2190 \u9ED8\u8BA4 \xB7 \u7B80\u5355\u65F6\u4FBF\u5B9C\uFF0C\u56F0\u96BE\u65F6\u667A\u80FD",
|
|
2015
|
+
helpPresetFlash: " flash \u59CB\u7EC8\u4F7F\u7528 v4-flash \u6700\u4FBF\u5B9C \xB7 \u6BCF\u8F6E\u6210\u672C\u53EF\u9884\u6D4B",
|
|
2016
|
+
helpPresetPro: " pro \u59CB\u7EC8\u4F7F\u7528 v4-pro \u7EA6 3 \u500D flash \xB7 \u7528\u4E8E\u56F0\u96BE\u7684\u591A\u8F6E\u5DE5\u4F5C",
|
|
2017
|
+
helpSessionsTitle: "\u4F1A\u8BDD\uFF08\u9ED8\u8BA4\u81EA\u52A8\u542F\u7528\uFF0C\u547D\u540D\u4E3A 'default'\uFF09\uFF1A",
|
|
2018
|
+
helpSessionCustom: " reasonix chat --session <name> \u4F7F\u7528\u4E0D\u540C\u7684\u547D\u540D\u4F1A\u8BDD",
|
|
2019
|
+
helpSessionNone: " reasonix chat --no-session \u7981\u7528\u672C\u6B21\u8FD0\u884C\u7684\u6301\u4E45\u5316",
|
|
2020
|
+
helpLimitationTitle: "\u5DF2\u77E5\u9650\u5236\uFF1A",
|
|
2021
|
+
helpLimitation1: " \u5728\u4F1A\u8BDD\u4E2D\u9014\u8C03\u6574\u7EC8\u7AEF\u5927\u5C0F\u53EF\u80FD\u4F1A\u5728\u6EDA\u52A8\u56DE\u653E\u4E2D\u5806\u53E0\u5E7D\u7075\u6807\u9898\u5E27",
|
|
2022
|
+
helpLimitation2: " \uFF08Ink \u5E93\u7684\u6D3B\u52A8\u533A\u57DF\u6E05\u9664\u672A\u8003\u8651\u65B0\u5BBD\u5EA6\u4E0B\u7684\u884C\u91CD\u6392\uFF09\u3002",
|
|
2023
|
+
helpLimitation3: " \u6EDA\u52A8\u5386\u53F2\u4E0D\u53D7\u5F71\u54CD\uFF1B\u8BE5\u7455\u75B5\u7EAF\u5C5E\u89C6\u89C9\u95EE\u9898\uFF0C",
|
|
2024
|
+
helpLimitation4: " \u4E0B\u6B21 /clear \u65F6\u6E05\u9664\u3002",
|
|
2025
|
+
keysTitle: "\u952E\u76D8\u548C\u63D0\u793A\u5FEB\u6377\u952E\uFF1A",
|
|
2026
|
+
keysEnter: " Enter \u63D0\u4EA4\u5F53\u524D\u63D0\u793A",
|
|
2027
|
+
keysNewline: " Shift+Enter / Ctrl+J \u63D2\u5165\u6362\u884C\uFF08\u591A\u884C\u63D0\u793A\uFF09",
|
|
2028
|
+
keysContinue: " \\<Enter> bash \u98CE\u683C\u7684\u884C\u7EE7\u7EED",
|
|
2029
|
+
keysArrow: " \u2190 \u2192 \u2191 \u2193 \u79FB\u52A8\u5149\u6807 / \u5728\u7F13\u51B2\u533A\u8FB9\u754C\u53EC\u56DE\u5386\u53F2",
|
|
2030
|
+
keysPage: " PageUp / PageDown \u8DF3\u8F6C\u5230\u6574\u4E2A\u7F13\u51B2\u533A\u7684\u9876\u90E8/\u5E95\u90E8\uFF08\u5927\u6BB5\u7C98\u8D34\u540E\u5F88\u6709\u7528\uFF09",
|
|
2031
|
+
keysHomeEnd: " Ctrl+A / Ctrl+E \u8DF3\u8F6C\u5230\u5F53\u524D\u884C\u7684\u5F00\u5934/\u7ED3\u5C3E",
|
|
2032
|
+
keysClearLine: " Ctrl+U \u6E05\u9664\u6574\u4E2A\u8F93\u5165\u7F13\u51B2\u533A",
|
|
2033
|
+
keysDeleteWord: " Ctrl+W \u5220\u9664\u5149\u6807\u524D\u7684\u5355\u8BCD",
|
|
2034
|
+
keysBackspace: " Backspace \u5411\u5DE6\u5220\u9664\uFF1BDelete \u5220\u9664\u5149\u6807\u4E0B\u7684\u5B57\u7B26",
|
|
2035
|
+
keysEsc: " Esc \u4E2D\u6B62\u6B63\u5728\u8FDB\u884C\u7684\u8F6E\u6B21",
|
|
2036
|
+
keysEditYn: " y / n \u63A5\u53D7/\u62D2\u7EDD\u5F85\u5904\u7406\u7684\u7F16\u8F91\uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09",
|
|
2037
|
+
keysEditTab: " Shift+Tab \u5FAA\u73AF\u7F16\u8F91\u95E8\u63A7\uFF1Areview \u2194 AUTO\uFF08\u4EE3\u7801\u6A21\u5F0F\uFF0C\u6301\u4E45\u5316\u5230\u914D\u7F6E\uFF09",
|
|
2038
|
+
keysEditUndo: " u \u64A4\u6D88\u6700\u8FD1\u672A\u64A4\u6D88\u7684\u7F16\u8F91\u6279\u5904\u7406\uFF08\u4F1A\u8BDD\u8303\u56F4\uFF0C\u975E\u4EC5\u6A2A\u5E45\uFF09",
|
|
2039
|
+
keysPromptTitle: "\u63D0\u793A\u524D\u7F00\uFF1A",
|
|
2040
|
+
keysSlash: " /<name> \u659C\u6760\u547D\u4EE4\uFF1BTab/Enter \u4ECE\u5EFA\u8BAE\u5217\u8868\u4E2D\u9009\u62E9",
|
|
2041
|
+
keysAtFile: " @<path> \u5C06\u6587\u4EF6\u5185\u8054\u5230 [Referenced files] \u4E0B\uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09\u3002",
|
|
2042
|
+
keysAtFilePicker: " \u5C3E\u90E8 `@\u2026` \u6253\u5F00\u6587\u4EF6\u9009\u62E9\u5668\uFF1B\u2191/\u2193 \u5BFC\u822A\uFF0CTab/Enter \u9009\u62E9\u3002",
|
|
2043
|
+
keysAtUrl: " @https://... \u83B7\u53D6 URL\uFF0C\u5265\u79BB HTML\uFF0C\u5185\u8054\u5230 [Referenced URLs] \u4E0B\u3002",
|
|
2044
|
+
keysAtUrlCache: " \u6BCF\u4F1A\u8BDD\u7F13\u5B58 \u2014 \u76F8\u540C URL \u83B7\u53D6\u4E24\u6B21\u53EA\u53D6\u4E00\u6B21\u3002",
|
|
2045
|
+
keysBang: " !<cmd> \u5728\u6C99\u7BB1\u6839\u76EE\u5F55\u8FD0\u884C <cmd>\uFF1B\u8F93\u51FA\u8FDB\u5165\u4E0A\u4E0B\u6587",
|
|
2046
|
+
keysBangDetail: " \u4EE5\u4FBF\u6A21\u578B\u5728\u4E0B\u4E00\u8F6E\u770B\u5230\u3002\u65E0\u5141\u8BB8\u5217\u8868\u9650\u5236\u3002",
|
|
2047
|
+
keysHash: " #<note> \u5C06 <note> \u8FFD\u52A0\u5230 <project>/REASONIX.md\uFF08\u53EF\u63D0\u4EA4\uFF0C\u56E2\u961F\u5171\u4EAB\uFF09\u3002",
|
|
2048
|
+
keysHashGlobal: " #g <note> \u5C06 <note> \u8FFD\u52A0\u5230 ~/.reasonix/REASONIX.md\uFF08\u5168\u5C40\uFF0C\u4E0D\u63D0\u4EA4\uFF09\u3002",
|
|
2049
|
+
keysHashBoth: " \u4E24\u8005\u90FD\u56FA\u5B9A\u5230\u6BCF\u4E2A\u672A\u6765\u4F1A\u8BDD\u7684\u4E0D\u53EF\u53D8\u524D\u7F00\u4E2D\u3002",
|
|
2050
|
+
keysHashEscape: " \u4F7F\u7528 `\\#literal` \u5982\u679C\u60A8\u786E\u5B9E\u60F3\u53D1\u9001 `#` \u6807\u9898\u7ED9\u6A21\u578B\u3002",
|
|
2051
|
+
keysPickersTitle: "\u9009\u62E9\u5668\uFF08\u659C\u6760 + @\u63D0\u53CA\uFF09\uFF1A",
|
|
2052
|
+
keysPickerNav: " \u2191 / \u2193 \u5BFC\u822A\u5EFA\u8BAE\u5217\u8868",
|
|
2053
|
+
keysPickerTab: " Tab \u63D2\u5165\u9AD8\u4EAE\u9879\u76EE\u4F46\u4E0D\u63D0\u4EA4",
|
|
2054
|
+
keysPickerEnter: " Enter \u63D2\u5165\u5E76\uFF08\u659C\u6760\uFF09\u8FD0\u884C\uFF0C\uFF08@\uFF09\u7EE7\u7EED\u7F16\u8F91",
|
|
2055
|
+
keysMcpTitle: "MCP \u63A2\u7D22\uFF1A",
|
|
2056
|
+
keysMcpServers: " /mcp \u670D\u52A1\u5668 + \u5DE5\u5177/\u8D44\u6E90/\u63D0\u793A\u8BA1\u6570",
|
|
2057
|
+
keysMcpResource: " /resource [uri] \u6D4F\u89C8\u5E76\u8BFB\u53D6 MCP \u670D\u52A1\u5668\u66B4\u9732\u7684\u8D44\u6E90",
|
|
2058
|
+
keysMcpPrompt: " /prompt [name] \u6D4F\u89C8\u5E76\u83B7\u53D6 MCP \u670D\u52A1\u5668\u66B4\u9732\u7684\u63D0\u793A",
|
|
2059
|
+
keysUseful: "\u5E38\u7528\u659C\u6760\u547D\u4EE4\uFF1A/help \xB7 /context \xB7 /stats \xB7 /compact \xB7 /new \xB7 /exit",
|
|
2060
|
+
retryNone: "\u6CA1\u6709\u53EF\u91CD\u8BD5\u7684\u5185\u5BB9 \u2014 \u6B64\u4F1A\u8BDD\u65E5\u5FD7\u4E2D\u6CA1\u6709\u5148\u524D\u7684\u7528\u6237\u6D88\u606F\u3002",
|
|
2061
|
+
retryInfo: '\u25B8 \u91CD\u8BD5\u4E2D\uFF1A"{preview}"',
|
|
2062
|
+
loopTuiOnly: "/loop \u4EC5\u5728\u4EA4\u4E92\u5F0F TUI \u4E2D\u53EF\u7528\uFF08\u4E0D\u5728 run/replay \u4E2D\uFF09\u3002",
|
|
2063
|
+
loopStopped: "\u25B8 \u5FAA\u73AF\u5DF2\u505C\u6B62\u3002",
|
|
2064
|
+
loopNoActive: "\u6CA1\u6709\u6D3B\u52A8\u7684\u5FAA\u73AF\u53EF\u505C\u6B62\u3002",
|
|
2065
|
+
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",
|
|
2066
|
+
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'
|
|
2067
|
+
},
|
|
2068
|
+
admin: {
|
|
2069
|
+
doctorNeedsTui: "/doctor \u9700\u8981 TUI \u4E0A\u4E0B\u6587\uFF08postDoctor \u5DF2\u8FDE\u63A5\uFF09\u3002",
|
|
2070
|
+
doctorRunning: "\u2695 \u5065\u5EB7\u68C0\u67E5 \u2014 \u6B63\u5728\u8FD0\u884C\u2026",
|
|
2071
|
+
hooksReloadUnavailable: "/hooks reload \u5728\u6B64\u4E0A\u4E0B\u6587\u4E2D\u4E0D\u53EF\u7528\uFF08\u65E0\u91CD\u8F7D\u56DE\u8C03\uFF09\u3002",
|
|
2072
|
+
hooksReloaded: "\u25B8 \u5DF2\u91CD\u8F7D hooks \xB7 {count} \u4E2A\u6D3B\u8DC3",
|
|
2073
|
+
hooksUsage: "\u7528\u6CD5\uFF1A/hooks \u5217\u51FA\u6D3B\u8DC3\u7684 hooks\n /hooks reload \u91CD\u65B0\u8BFB\u53D6 settings.json \u6587\u4EF6",
|
|
2074
|
+
hooksNone: "\u672A\u914D\u7F6E hooks\u3002",
|
|
2075
|
+
hooksDropHint: "\u5C06\u5305\u542B `hooks` \u952E\u7684 settings.json \u653E\u5165\u4EE5\u4E0B\u4EFB\u4E00\u4F4D\u7F6E\uFF1A",
|
|
2076
|
+
hooksProject: " \xB7 {path}\uFF08\u9879\u76EE\uFF09",
|
|
2077
|
+
hooksProjectFallback: " \xB7 <project>/.reasonix/settings.json\uFF08\u9879\u76EE\uFF09",
|
|
2078
|
+
hooksGlobal: " \xB7 {path}\uFF08\u5168\u5C40\uFF09",
|
|
2079
|
+
hooksEvents: "\u4E8B\u4EF6\uFF1APreToolUse, PostToolUse, UserPromptSubmit, Stop",
|
|
2080
|
+
hooksExitCodes: "exit 0 = \u901A\u8FC7 \xB7 exit 2 = \u963B\u6B62\uFF08Pre*\uFF09\xB7 \u5176\u4ED6 = \u8B66\u544A",
|
|
2081
|
+
hooksLoaded: "\u25B8 \u5DF2\u52A0\u8F7D {count} \u4E2A hook",
|
|
2082
|
+
hooksSources: "\u6765\u6E90\uFF1Aproject={project} \xB7 global={global}",
|
|
2083
|
+
updateCurrent: "\u5F53\u524D\uFF1Areasonix {version}",
|
|
2084
|
+
updateLatestPending: "\u6700\u65B0\uFF1A\uFF08\u5C1A\u672A\u89E3\u6790 \u2014 \u540E\u53F0\u68C0\u67E5\u8FDB\u884C\u4E2D\u6216\u79BB\u7EBF\uFF09",
|
|
2085
|
+
updateRetryHint: "\u5DF2\u89E6\u53D1\u65B0\u7684\u6CE8\u518C\u8868\u83B7\u53D6 \u2014 \u51E0\u79D2\u540E\u91CD\u8BD5 `/update`\uFF0C",
|
|
2086
|
+
updateRetryHint2: "\u6216\u5728\u53E6\u4E00\u4E2A\u7EC8\u7AEF\u8FD0\u884C `reasonix update` \u5F3A\u5236\u540C\u6B65\u6267\u884C\u3002",
|
|
2087
|
+
updateLatest: "\u6700\u65B0\uFF1Areasonix {version}",
|
|
2088
|
+
updateUpToDate: "\u60A8\u5DF2\u662F\u6700\u65B0\u7248\u672C\u3002\u65E0\u9700\u64CD\u4F5C\u3002",
|
|
2089
|
+
updateNpxHint: "\u60A8\u6B63\u5728\u901A\u8FC7 npx \u8FD0\u884C \u2014 \u4E0B\u6B21 `npx reasonix ...` \u542F\u52A8\u65F6\u5C06\u81EA\u52A8\u83B7\u53D6\u3002",
|
|
2090
|
+
updateNpxForce: "\u8981\u5F3A\u5236\u5237\u65B0\uFF1A`npm cache clean --force`\u3002",
|
|
2091
|
+
updateUpgradeHint: "\u8981\u5347\u7EA7\uFF0C\u8BF7\u9000\u51FA\u6B64\u4F1A\u8BDD\u5E76\u8FD0\u884C\uFF1A",
|
|
2092
|
+
updateUpgradeCmd1: " reasonix update \uFF08\u4EA4\u4E92\u5F0F\uFF0C\u652F\u6301 --dry-run \u9884\u89C8\uFF09",
|
|
2093
|
+
updateUpgradeCmd2: " npm install -g reasonix@latest \uFF08\u76F4\u63A5\u5B89\u88C5\uFF09",
|
|
2094
|
+
updateInSessionDisabled: "\u4F1A\u8BDD\u5185\u5B89\u88C5\u88AB\u523B\u610F\u7981\u7528 \u2014 npm spawn \u4F1A",
|
|
2095
|
+
updateInSessionDisabled2: "\u7834\u574F\u6B64 TUI \u7684\u6E32\u67D3\uFF0C\u4E14 Windows \u53EF\u80FD\u9501\u5B9A\u8FD0\u884C\u4E2D\u7684\u4E8C\u8FDB\u5236\u6587\u4EF6\u3002",
|
|
2096
|
+
statsNoData: "\u5C1A\u65E0\u4F7F\u7528\u6570\u636E\u3002",
|
|
2097
|
+
statsEveryTurn: "\u60A8\u5728\u6B64\u8FD0\u884C\u7684\u6BCF\u4E00\u8F6E\u90FD\u4F1A\u8FFD\u52A0\u4E00\u6761\u8BB0\u5F55 \u2014 \u6B64\u4F1A\u8BDD\u7684\u8F6E\u6B21",
|
|
2098
|
+
statsWillAppear: "\u5C06\u5728\u60A8\u53D1\u9001\u6D88\u606F\u540E\u663E\u793A\u5728\u4EEA\u8868\u677F\u4E2D\u3002"
|
|
2099
|
+
},
|
|
2100
|
+
edits: {
|
|
2101
|
+
undoCodeOnly: "/undo \u4EC5\u5728 `reasonix code` \u4E2D\u53EF\u7528 \u2014 \u804A\u5929\u6A21\u5F0F\u4E0D\u5E94\u7528\u7F16\u8F91\u3002",
|
|
2102
|
+
historyCodeOnly: "/history \u4EC5\u5728 `reasonix code` \u4E2D\u53EF\u7528\u3002",
|
|
2103
|
+
showCodeOnly: "/show \u4EC5\u5728 `reasonix code` \u4E2D\u53EF\u7528\u3002",
|
|
2104
|
+
applyCodeOnly: "/apply \u4EC5\u5728 `reasonix code` \u4E2D\u53EF\u7528\uFF08\u6B64\u5904\u65E0\u5185\u5BB9\u53EF\u5E94\u7528\uFF09\u3002",
|
|
2105
|
+
discardCodeOnly: "/discard \u4EC5\u5728 `reasonix code` \u4E2D\u53EF\u7528\u3002",
|
|
2106
|
+
planCodeOnly: "/plan \u4EC5\u5728 `reasonix code` \u4E2D\u53EF\u7528 \u2014 \u804A\u5929\u6A21\u5F0F\u4E0D\u9650\u5236\u5DE5\u5177\u5199\u5165\u3002",
|
|
2107
|
+
planOn: "\u25B8 \u8BA1\u5212\u6A21\u5F0F\u5F00\u542F \u2014 \u5199\u5165\u5DE5\u5177\u88AB\u9650\u5236\uFF1B\u6A21\u578B\u5FC5\u987B\u5148\u8C03\u7528 `submit_plan` \u624D\u80FD\u6267\u884C\u4EFB\u4F55\u64CD\u4F5C\u3002\uFF08\u6A21\u578B\u4E5F\u53EF\u4EE5\u5728\u8BA1\u5212\u6A21\u5F0F\u5173\u95ED\u65F6\u81EA\u4E3B\u8C03\u7528 submit_plan \u5904\u7406\u5927\u578B\u4EFB\u52A1 \u2014 \u6B64\u5F00\u5173\u662F\u66F4\u5F3A\u7684\u663E\u5F0F\u7EA6\u675F\u3002\uFF09\u8F93\u5165 /plan off \u9000\u51FA\u3002",
|
|
2108
|
+
planOff: "\u25B8 \u8BA1\u5212\u6A21\u5F0F\u5173\u95ED \u2014 \u5199\u5165\u5DE5\u5177\u518D\u6B21\u53EF\u7528\u3002\u6A21\u578B\u4ECD\u53EF\u4E3A\u5927\u578B\u4EFB\u52A1\u81EA\u4E3B\u63D0\u51FA\u8BA1\u5212\u3002",
|
|
2109
|
+
applyPlanCodeOnly: "/apply-plan \u4EC5\u5728 `reasonix code` \u4E2D\u53EF\u7528\u3002",
|
|
2110
|
+
applyPlanInfo: "\u25B8 \u8BA1\u5212\u5DF2\u6279\u51C6 \u2014 \u6B63\u5728\u6267\u884C",
|
|
2111
|
+
applyPlanResubmit: "\u4E0A\u65B9\u7684\u8BA1\u5212\u5DF2\u88AB\u6279\u51C6\u3002\u7ACB\u5373\u6267\u884C\u3002\u60A8\u5DF2\u9000\u51FA\u8BA1\u5212\u6A21\u5F0F \u2014 \u6839\u636E\u9700\u8981\u4F7F\u7528 edit_file / write_file / run_command\u3002\u9664\u975E\u53D1\u73B0\u5177\u4F53\u539F\u56E0\uFF0C\u5426\u5219\u8BF7\u9075\u5FAA\u8BA1\u5212\uFF1B\u5982\u679C\u786E\u5B9E\u9700\u8981\u504F\u79BB\uFF0C\u8BF7\u544A\u77E5\u5E76\u7B49\u5F85\u56DE\u590D\u540E\u518D\u8FDB\u884C\u3002",
|
|
2112
|
+
modeCodeOnly: "/mode \u4EC5\u5728 `reasonix code` \u4E2D\u53EF\u7528\u3002",
|
|
2113
|
+
modeUsage: "\u7528\u6CD5\uFF1A/mode <review|auto|yolo> \uFF08Shift+Tab \u4E5F\u53EF\u5FAA\u73AF\uFF09",
|
|
2114
|
+
modeYolo: "\u25B8 \u7F16\u8F91\u6A21\u5F0F\uFF1AYOLO \u2014 \u7F16\u8F91\u548C Shell \u547D\u4EE4\u81EA\u52A8\u8FD0\u884C\uFF0C\u65E0\u63D0\u793A\u3002/undo \u4ECD\u53EF\u56DE\u6EDA\u7F16\u8F91\u3002\u8BF7\u8C28\u614E\u4F7F\u7528\u3002",
|
|
2115
|
+
modeAuto: "\u25B8 \u7F16\u8F91\u6A21\u5F0F\uFF1AAUTO \u2014 \u7F16\u8F91\u7ACB\u5373\u5E94\u7528\uFF1B\u5728 5 \u79D2\u5185\u6309 u \u64A4\u6D88\uFF0C\u6216\u7A0D\u540E\u4F7F\u7528 /undo\u3002Shell \u547D\u4EE4\u4ECD\u4F1A\u8BE2\u95EE\u3002",
|
|
2116
|
+
modeReview: "\u25B8 \u7F16\u8F91\u6A21\u5F0F\uFF1Areview \u2014 \u7F16\u8F91\u6392\u961F\u7B49\u5F85 /apply\uFF08\u6216 y\uFF09/ /discard\uFF08\u6216 n\uFF09",
|
|
2117
|
+
commitCodeOnly: "/commit \u4EC5\u5728 `reasonix code` \u4E2D\u53EF\u7528\uFF08\u9700\u8981\u6709\u6839\u7684 git \u4ED3\u5E93\uFF09\u3002",
|
|
2118
|
+
commitUsage: '\u7528\u6CD5\uFF1A/commit "\u63D0\u4EA4\u6D88\u606F" \u2014 \u5728 {root} \u4E2D\u8FD0\u884C `git add -A && git commit -m "\u2026"`',
|
|
2119
|
+
walkCodeOnly: "/walk \u4EC5\u5728 `reasonix code` \u4E2D\u53EF\u7528\u3002",
|
|
2120
|
+
checkpointCodeOnly: "/checkpoint \u4EC5\u5728 `reasonix code` \u4E2D\u53EF\u7528 \u2014 \u804A\u5929\u6A21\u5F0F\u4E0D\u5E94\u7528\u7F16\u8F91\u3002",
|
|
2121
|
+
checkpointNone: "\u5C1A\u65E0\u68C0\u67E5\u70B9 \u2014 `/checkpoint <name>` \u5FEB\u7167\u4F1A\u8BDD\u6D89\u53CA\u7684\u6BCF\u4E2A\u6587\u4EF6\u3002\u7A0D\u540E\u4F7F\u7528 `/restore <name>` \u6062\u590D\u3002",
|
|
2122
|
+
checkpointHeader: "\u25C8 \u68C0\u67E5\u70B9 \xB7 \u5DF2\u5B58\u50A8 {count} \u4E2A",
|
|
2123
|
+
checkpointRestoreHint: " /restore <name|id> \xB7 /checkpoint forget <id> \xB7 /checkpoint <name> \u6DFB\u52A0",
|
|
2124
|
+
checkpointForgetUsage: "\u7528\u6CD5\uFF1A/checkpoint forget <id|name>",
|
|
2125
|
+
checkpointNoMatch: '\u25B8 \u672A\u627E\u5230\u5339\u914D "{name}" \u7684\u68C0\u67E5\u70B9 \u2014 \u89C1 /checkpoint list',
|
|
2126
|
+
checkpointDeleted: "\u25B8 \u5DF2\u5220\u9664\u68C0\u67E5\u70B9 {id}\uFF08{name}\uFF09",
|
|
2127
|
+
checkpointDeleteFailed: "\u25B8 \u5220\u9664 {id} \u5931\u8D25\uFF08\u5DF2\u6D88\u5931\uFF1F\uFF09",
|
|
2128
|
+
checkpointSaveUsage: "\u7528\u6CD5\uFF1A/checkpoint <name> \uFF08\u6216 /checkpoint list \u67E5\u770B\u73B0\u6709\uFF09",
|
|
2129
|
+
checkpointSavedEmpty: '\u25B8 \u68C0\u67E5\u70B9 "{name}" \u5DF2\u4FDD\u5B58\uFF08{id}\uFF09\u2014 \u4F46\u5C1A\u672A\u6D89\u53CA\u4EFB\u4F55\u6587\u4EF6\uFF0C\u56E0\u6B64\u662F\u7A7A\u57FA\u7EBF\u3002\u6B64\u540E\u7684\u7F16\u8F91\u5C06\u53EF\u64A4\u6D88\u3002',
|
|
2130
|
+
checkpointSaved: '\u25B8 \u68C0\u67E5\u70B9 "{name}" \u5DF2\u4FDD\u5B58\uFF08{id}\uFF09\u2014 {files} \u4E2A\u6587\u4EF6\uFF0C{size} KB\u3002\u6062\u590D\uFF1A/restore {name}',
|
|
2131
|
+
restoreCodeOnly: "/restore \u4EC5\u5728 `reasonix code` \u4E2D\u53EF\u7528\u3002",
|
|
2132
|
+
restoreUsage: "\u7528\u6CD5\uFF1A/restore <name|id> \uFF08\u89C1 /checkpoint list \u83B7\u53D6 ID\uFF09",
|
|
2133
|
+
restoreNoMatch: '\u25B8 \u672A\u627E\u5230\u5339\u914D "{target}" \u7684\u68C0\u67E5\u70B9 \u2014 \u5C1D\u8BD5 /checkpoint list',
|
|
2134
|
+
restoreInfo: '\u25B8 \u5DF2\u6062\u590D "{name}"\uFF08{id}\uFF09\uFF0C\u6765\u81EA {when}',
|
|
2135
|
+
restoreWrote: " \xB7 \u5199\u56DE\u4E86 {count} \u4E2A\u6587\u4EF6",
|
|
2136
|
+
restoreRemoved: " \xB7 \u79FB\u9664\u4E86 {count} \u4E2A\u6587\u4EF6\uFF08\u68C0\u67E5\u70B9\u65F6\u4E0D\u5B58\u5728\uFF09",
|
|
2137
|
+
restoreSkipped: " \u2717 \u8DF3\u8FC7\u4E86 {count} \u4E2A\u6587\u4EF6\uFF1A"
|
|
2138
|
+
},
|
|
2139
|
+
model: {
|
|
2140
|
+
modelHint: "\u5C1D\u8BD5 deepseek-v4-flash \u6216 deepseek-v4-pro \u2014 \u8FD0\u884C /models \u83B7\u53D6\u5B9E\u65F6\u5217\u8868",
|
|
2141
|
+
modelUsage: "\u7528\u6CD5\uFF1A/model <id> \uFF08{hint}\uFF09",
|
|
2142
|
+
modelNotInCatalog: "model \u2192 {id} \uFF08\u26A0 \u4E0D\u5728\u83B7\u53D6\u7684\u76EE\u5F55\u4E2D\uFF1A{list}\u3002\u5982\u679C\u8FD9\u662F\u9519\u8BEF\u7684\uFF0C\u4E0B\u6B21\u8C03\u7528\u5C06\u8FD4\u56DE 400 \u2014 \u8FD0\u884C /models \u5237\u65B0\u3002\uFF09",
|
|
2143
|
+
modelSet: "model \u2192 {id}",
|
|
2144
|
+
modelsFetching: "\u6B63\u5728\u4ECE DeepSeek \u83B7\u53D6 /models\u2026 \u7A0D\u540E\u518D\u8FD0\u884C /models\u3002\u5982\u679C\u6301\u7EED\u4E3A\u7A7A\uFF0C\u60A8\u7684 API \u5BC6\u94A5\u53EF\u80FD\u7F3A\u5C11\u6743\u9650\u6216\u7F51\u7EDC\u88AB\u963B\u6B62\u3002",
|
|
2145
|
+
modelsEmpty: "DeepSeek /models \u8FD4\u56DE\u4E86\u7A7A\u5217\u8868\u3002\u518D\u8BD5 /models\uFF0C\u6216\u5728 api-docs.deepseek.com \u68C0\u67E5\u60A8\u7684\u8D26\u6237\u72B6\u6001\u3002",
|
|
2146
|
+
modelsHeader: "\u53EF\u7528\u6A21\u578B\uFF08DeepSeek /models \xB7 \u5171 {count} \u4E2A\uFF09\uFF1A",
|
|
2147
|
+
modelsCurrent: "\u25B8 {id} \uFF08\u5F53\u524D\uFF09",
|
|
2148
|
+
modelsSwitch: "\u5207\u6362\u65B9\u5F0F\uFF1A/model <id>",
|
|
2149
|
+
harvestOn: "harvest \u2192 \u5F00\u542F \uFF08Pillar-2 \u8BA1\u5212\u72B6\u6001\u63D0\u53D6 \xB7 \u6BCF\u8F6E\u989D\u5916 1 \u6B21\u5EC9\u4EF7 flash \u8C03\u7528 \xB7 \u4EC5\u624B\u52A8\u9009\u62E9\uFF1B\u65E0\u9884\u8BBE\u4F1A\u5F00\u542F\u5B83\uFF09",
|
|
2150
|
+
harvestOff: "harvest \u2192 \u5173\u95ED",
|
|
2151
|
+
presetAuto: "preset \u2192 auto \uFF08v4-flash \u2192 v4-pro \u5728\u56F0\u96BE\u8F6E\u6B21\u5207\u6362 \xB7 \u9ED8\u8BA4\uFF09",
|
|
2152
|
+
presetFlash: "preset \u2192 flash \uFF08\u59CB\u7EC8\u4F7F\u7528 v4-flash \xB7 \u6700\u4FBF\u5B9C \xB7 /pro \u4ECD\u53EF\u4E34\u65F6\u63D0\u5347\u4E00\u8F6E\uFF09",
|
|
2153
|
+
presetPro: "preset \u2192 pro \uFF08\u59CB\u7EC8\u4F7F\u7528 v4-pro \xB7 \u7EA6 3 \u500D flash \xB7 \u7528\u4E8E\u56F0\u96BE\u7684\u591A\u8F6E\u5DE5\u4F5C\uFF09",
|
|
2154
|
+
presetUsage: "\u7528\u6CD5\uFF1A/preset <auto|flash|pro>",
|
|
2155
|
+
branchOff: "branch \u2192 \u5173\u95ED",
|
|
2156
|
+
branchUsage: "\u7528\u6CD5\uFF1A/branch <N> \uFF08N>=2\uFF0C\u6216 'off'\uFF09",
|
|
2157
|
+
branchCapped: "branch \u9884\u7B97\u4E0A\u9650\u4E3A 8\uFF0C\u9632\u6B62\u6210\u672C\u5931\u63A7",
|
|
2158
|
+
branchSet: "branch \u2192 {n} \uFF08\u6BCF\u8F6E\u8FD0\u884C {n} \u4E2A\u5E76\u884C\u91C7\u6837 \xB7 {n} \u500D\u6BCF\u8F6E\u6210\u672C \xB7 \u7981\u7528\u6D41\u5F0F \xB7 \u4EC5\u624B\u52A8\uFF0C\u65E0\u9884\u8BBE\u542F\u7528\u5206\u652F\uFF09",
|
|
2159
|
+
effortStatus: "reasoning_effort \u2192 {effort} \uFF08\u4F7F\u7528 /effort high \u66F4\u4FBF\u5B9C/\u66F4\u5FEB\uFF0C/effort max \u4E3A\u667A\u80FD\u4F53\u7EA7\u9ED8\u8BA4 \xB7 \u8DE8\u91CD\u542F\u6301\u4E45\u5316\uFF09",
|
|
2160
|
+
effortUsage: "\u7528\u6CD5\uFF1A/effort <high|max>",
|
|
2161
|
+
effortSet: "reasoning_effort \u2192 {effort}\uFF08\u5DF2\u6301\u4E45\u5316\uFF09",
|
|
2162
|
+
proNothingArmed: "\u672A\u542F\u7528 \u2014 /pro \u4E0D\u5E26\u53C2\u6570\u5C06\u4E3A\u4E0B\u4E00\u8F6E\u542F\u7528 pro",
|
|
2163
|
+
proDisarmed: "\u25B8 /pro \u5DF2\u89E3\u9664 \u2014 \u4E0B\u4E00\u8F6E\u56DE\u9000\u5230\u5F53\u524D\u9884\u8BBE",
|
|
2164
|
+
proUsage: "\u7528\u6CD5\uFF1A/pro \u4E3A\u4E0B\u4E00\u8F6E\u542F\u7528 pro\uFF08\u4E00\u6B21\u6027\uFF0C\u81EA\u52A8\u89E3\u9664\uFF09\n /pro off \u5728\u4E0B\u4E00\u8F6E\u524D\u53D6\u6D88\u542F\u7528\u72B6\u6001",
|
|
2165
|
+
proArmed: "\u25B8 /pro \u5DF2\u542F\u7528 \u2014 \u60A8\u7684\u4E0B\u4E00\u6761\u6D88\u606F\u5C06\u5728 {model} \u4E0A\u8FD0\u884C\uFF0C\u65E0\u8BBA\u9884\u8BBE\u5982\u4F55\u3002\u4E00\u8F6E\u540E\u81EA\u52A8\u89E3\u9664\u3002\u4F7F\u7528 /preset max \u8FDB\u884C\u6301\u4E45\u5207\u6362\u3002",
|
|
2166
|
+
budgetNoCap: "\u672A\u8BBE\u7F6E\u4F1A\u8BDD\u9884\u7B97 \u2014 Reasonix \u5C06\u6301\u7EED\u8FD0\u884C\u76F4\u5230\u60A8\u505C\u6B62\u3002\u4F7F\u7528\u4EE5\u4E0B\u65B9\u5F0F\u8BBE\u7F6E\uFF1A/budget <usd> \uFF08\u4F8B\u5982 /budget 5\uFF09",
|
|
2167
|
+
budgetStatus: "\u9884\u7B97\uFF1A${spent} / ${cap}\uFF08{pct}%\uFF09\xB7 /budget off \u6E05\u9664\uFF0C/budget <usd> \u66F4\u6539",
|
|
2168
|
+
budgetOff: "budget \u2192 \u5173\u95ED\uFF08\u65E0\u4E0A\u9650\uFF09",
|
|
2169
|
+
budgetUsage: '\u7528\u6CD5\uFF1A/budget <usd> \uFF08\u6536\u5230 "{arg}" \u2014 \u5FC5\u987B\u662F\u6B63\u6570\uFF0C\u4F8B\u5982 /budget 5 \u6216 /budget 12.50\uFF09',
|
|
2170
|
+
budgetExhausted: "\u25B2 budget \u2192 ${cap} \u4F46\u5DF2\u82B1\u8D39 ${spent}\u3002\u4E0B\u4E00\u8F6E\u5C06\u88AB\u62D2\u7EDD \u2014 \u63D0\u9AD8\u4E0A\u9650\u4EE5\u7EE7\u7EED\uFF0C\u6216\u7ED3\u675F\u4F1A\u8BDD\u3002",
|
|
2171
|
+
budgetSet: "budget \u2192 ${cap} \uFF08\u8FC4\u4ECA\uFF1A${spent} \xB7 80% \u65F6\u8B66\u544A\uFF0C100% \u65F6\u62D2\u7EDD\u4E0B\u4E00\u8F6E \xB7 /budget off \u6E05\u9664\uFF09"
|
|
2172
|
+
},
|
|
2173
|
+
sessions: {
|
|
2174
|
+
forgetNoSession: "\u4E0D\u5728\u4F1A\u8BDD\u4E2D \u2014 \u65E0\u5185\u5BB9\u53EF\u9057\u5FD8",
|
|
2175
|
+
forgetInfo: '\u25B8 \u5DF2\u5220\u9664\u4F1A\u8BDD "{name}" \u2014 \u5F53\u524D\u5C4F\u5E55\u4ECD\u663E\u793A\u5BF9\u8BDD\uFF0C\u4F46\u4E0B\u6B21\u542F\u52A8\u5C06\u5168\u65B0\u5F00\u59CB',
|
|
2176
|
+
forgetFailed: '\u65E0\u6CD5\u5220\u9664\u4F1A\u8BDD "{name}"\uFF08\u5DF2\u6D88\u5931\uFF1F\uFF09',
|
|
2177
|
+
renameUsage: "\u7528\u6CD5\uFF1A/rename <new-name>",
|
|
2178
|
+
renameNoSession: "\u4E0D\u5728\u4F1A\u8BDD\u4E2D \u2014 \u65E0\u5185\u5BB9\u53EF\u91CD\u547D\u540D",
|
|
2179
|
+
renameFailed: '\u65E0\u6CD5\u91CD\u547D\u540D \u2014 "{name}" \u5DF2\u5B58\u5728\u6216\u6E05\u7406\u540E\u4E0E\u5F53\u524D\u4F1A\u8BDD ID \u76F8\u540C',
|
|
2180
|
+
renameInfo: '\u25B8 \u4F1A\u8BDD\u5DF2\u91CD\u547D\u540D\u4E3A \u2192 "{name}"\u3002\u91CD\u542F TUI \u4EE5\u4F7F\u7528\u65B0\u540D\u79F0\u3002',
|
|
2181
|
+
resumeUsage: "\u7528\u6CD5\uFF1A/resume <session-name> \u2014 \u4F7F\u7528 /sessions \u5217\u51FA",
|
|
2182
|
+
resumeNotFound: '\u6CA1\u6709\u540D\u4E3A "{name}" \u7684\u4F1A\u8BDD \u2014 \u4F7F\u7528 /sessions \u5217\u51FA',
|
|
2183
|
+
resumeInfo: '\u25B8 \u8981\u6062\u590D "{name}"\uFF0C\u8BF7\u9000\u51FA\u5E76\u8FD0\u884C\uFF1Areasonix chat --session {name}\n \uFF08\u4F1A\u8BDD\u4E2D\u5207\u6362\u9700\u8981\u91CD\u542F\uFF0C\u4EE5\u4FBF\u6D88\u606F\u65E5\u5FD7\u53EF\u4EE5\u5E72\u51C0\u5730\u56DE\u9000\uFF09'
|
|
2184
|
+
},
|
|
2185
|
+
permissions: {
|
|
2186
|
+
mutateCodeOnly: "/permissions add / remove / clear \u4EC5\u5728 `reasonix code` \u4E2D\u53EF\u7528 \u2014 \u5B83\u4EEC\u7F16\u8F91\u9879\u76EE\u8303\u56F4\u7684\u5141\u8BB8\u5217\u8868\uFF08`~/.reasonix/config.json` projects[<root>].shellAllowed\uFF09\u3002",
|
|
2187
|
+
addUsage: '\u7528\u6CD5\uFF1A/permissions add <prefix> \uFF08\u591A token \u53EF\u7528\uFF1A/permissions add "git push origin"\uFF09',
|
|
2188
|
+
addAlready: "\u25B8 \u5DF2\u5141\u8BB8\uFF1A{prefix}",
|
|
2189
|
+
addBuiltin: "\u25B8 `{prefix}` \u5DF2\u5728\u5185\u7F6E\u5141\u8BB8\u5217\u8868\u4E2D \u2014 \u65E0\u9700\u9879\u76EE\u6761\u76EE\u3002\uFF08\u5185\u7F6E\u6761\u76EE\u59CB\u7EC8\u5F00\u542F\u3002\uFF09",
|
|
2190
|
+
addInfo: "\u25B8 \u5DF2\u6DFB\u52A0\uFF1A{prefix}\n \u2192 \u5728\u6B64\u9879\u76EE\u4E2D\uFF0C\u4E0B\u6B21 `{prefix}` \u8C03\u7528\u5C06\u65E0\u9700\u63D0\u793A\u3002",
|
|
2191
|
+
removeUsage: "\u7528\u6CD5\uFF1A/permissions remove <prefix-or-index> \uFF08\u4F8B\u5982 /permissions remove 3\uFF0C\u6216 /permissions remove npm\uFF09",
|
|
2192
|
+
removeEmpty: "\u25B8 \u6CA1\u6709\u9879\u76EE\u5141\u8BB8\u5217\u8868\u6761\u76EE\u53EF\u79FB\u9664\u3002",
|
|
2193
|
+
removeIndexOob: "\u25B8 \u7D22\u5F15\u8D85\u51FA\u8303\u56F4\uFF1A{idx}\uFF08\u9879\u76EE\u5217\u8868\u6709 {count} \u4E2A\u6761\u76EE\uFF09",
|
|
2194
|
+
removeNothing: "\u25B8 \u65E0\u5185\u5BB9\u53EF\u79FB\u9664\u3002",
|
|
2195
|
+
removeBuiltin: "\u25B8 `{prefix}` \u5728\u5185\u7F6E\u5141\u8BB8\u5217\u8868\u4E2D\uFF08\u53EA\u8BFB\uFF09\u3002\u5185\u7F6E\u6761\u76EE\u65E0\u6CD5\u5728\u8FD0\u884C\u65F6\u79FB\u9664 \u2014 \u5B83\u4EEC\u5DF2\u7F16\u8BD1\u5230\u4E8C\u8FDB\u5236\u6587\u4EF6\u4E2D\u3002",
|
|
2196
|
+
removeInfo: "\u25B8 \u5DF2\u79FB\u9664\uFF1A{prefix}",
|
|
2197
|
+
removeNotFound: "\u25B8 \u65E0\u6B64\u9879\u76EE\u6761\u76EE\uFF1A{prefix} \uFF08\u5C1D\u8BD5 /permissions list \u67E5\u770B\u5DF2\u5B58\u50A8\u7684\u5185\u5BB9\uFF09",
|
|
2198
|
+
clearAlready: "\u25B8 \u9879\u76EE\u5141\u8BB8\u5217\u8868\u5DF2\u4E3A\u7A7A\u3002",
|
|
2199
|
+
clearConfirm: "\u5373\u5C06\u4E22\u5F03 {root} \u7684 {count} \u4E2A\u9879\u76EE\u5141\u8BB8\u5217\u8868\u6761\u76EE\u3002\u91CD\u65B0\u8FD0\u884C\u5E76\u9644\u5E26 'confirm' \u4E00\u8BCD\u4EE5\u7EE7\u7EED\uFF1A/permissions clear confirm",
|
|
2200
|
+
clearedNone: "\u25B8 \u9879\u76EE\u5141\u8BB8\u5217\u8868\u5DF2\u4E3A\u7A7A \u2014 \u65E0\u53D8\u5316\u3002",
|
|
2201
|
+
cleared: "\u25B8 \u5DF2\u6E05\u9664 {count} \u4E2A\u9879\u76EE\u5141\u8BB8\u5217\u8868\u6761\u76EE\u3002",
|
|
2202
|
+
usage: '\u7528\u6CD5\uFF1A/permissions [list] \u663E\u793A\u5F53\u524D\u72B6\u6001\n /permissions add <prefix> \u6301\u4E45\u5316\uFF08\u4F8B\u5982 "npm run build"\uFF09\n /permissions remove <prefix-or-N> \u5220\u9664\u4E00\u4E2A\u6761\u76EE\n /permissions clear confirm \u6E05\u9664\u6240\u6709\u9879\u76EE\u6761\u76EE',
|
|
2203
|
+
modeYolo: "\u25B8 \u7F16\u8F91\u6A21\u5F0F\uFF1AYOLO \u2014 \u6BCF\u4E2A shell \u547D\u4EE4\u81EA\u52A8\u8FD0\u884C\uFF0C\u5141\u8BB8\u5217\u8868\u88AB\u7ED5\u8FC7\u3002/mode review \u91CD\u65B0\u542F\u7528\u63D0\u793A\u3002",
|
|
2204
|
+
modeAuto: "\u25B8 \u7F16\u8F91\u6A21\u5F0F\uFF1Aauto \u2014 \u7F16\u8F91\u81EA\u52A8\u5E94\u7528\uFF0Cshell \u4ECD\u53D7\u5141\u8BB8\u5217\u8868\u9650\u5236\uFF08\u6216\u975E\u5141\u8BB8\u5217\u8868\u7684 ShellConfirm \u63D0\u793A\uFF09\u3002",
|
|
2205
|
+
modeReview: "\u25B8 \u7F16\u8F91\u6A21\u5F0F\uFF1Areview \u2014 \u7F16\u8F91\u548C\u975E\u5141\u8BB8\u5217\u8868\u7684 shell \u547D\u4EE4\u5728\u8FD0\u884C\u524D\u90FD\u4F1A\u8BE2\u95EE\u3002",
|
|
2206
|
+
projectHeader: "\u9879\u76EE\u5141\u8BB8\u5217\u8868\uFF08{count}\uFF09\u2014 {root}",
|
|
2207
|
+
projectNone1: ' \uFF08\u65E0 \u2014 \u5728 ShellConfirm \u63D0\u793A\u4E2D\u9009\u62E9 "always allow" \u6DFB\u52A0\u4E00\u4E2A\uFF0C',
|
|
2208
|
+
projectNone2: " \u6216\u76F4\u63A5 `/permissions add <prefix>`\u3002\uFF09",
|
|
2209
|
+
projectNoRoot: "\u9879\u76EE\u5141\u8BB8\u5217\u8868 \u2014 \uFF08\u65E0\u9879\u76EE\u6839\u76EE\u5F55\uFF1B\u804A\u5929\u6A21\u5F0F\u4EC5\u663E\u793A\u5185\u7F6E\u6761\u76EE\uFF09",
|
|
2210
|
+
builtinHeader: "\u5185\u7F6E\u5141\u8BB8\u5217\u8868\uFF08{count}\uFF09\u2014 \u53EA\u8BFB\uFF0C\u5DF2\u7F16\u8BD1",
|
|
2211
|
+
subcommands: "\u5B50\u547D\u4EE4\uFF1A/permissions add <prefix> \xB7 /permissions remove <prefix-or-N> \xB7 /permissions clear confirm"
|
|
2212
|
+
},
|
|
2213
|
+
dashboard: {
|
|
2214
|
+
notAvailable: "/dashboard \u5728\u6B64\u4E0A\u4E0B\u6587\u4E2D\u4E0D\u53EF\u7528\uFF08\u65E0 startDashboard \u56DE\u8C03\uFF09\u3002",
|
|
2215
|
+
stopNoCallback: "/dashboard stop\uFF1A\u65E0\u505C\u6B62\u56DE\u8C03\u3002",
|
|
2216
|
+
notRunning: "\u25B8 \u4EEA\u8868\u677F\u672A\u8FD0\u884C\u3002",
|
|
2217
|
+
stopping: "\u25B8 \u4EEA\u8868\u677F\u6B63\u5728\u505C\u6B62\u2026",
|
|
2218
|
+
alreadyRunning: "\u25B8 \u4EEA\u8868\u677F\u5DF2\u5728\u8FD0\u884C\uFF1A",
|
|
2219
|
+
alreadyRunningHint: "\u5728\u4EFB\u4F55\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00\u5B83\u3002\u8F93\u5165 `/dashboard stop` \u5173\u95ED\u3002",
|
|
2220
|
+
ready: "\u25B8 \u4EEA\u8868\u677F\u5C31\u7EEA\uFF1A",
|
|
2221
|
+
readyHint: "\u4EC5 127.0.0.1 \xB7 token \u4FDD\u62A4\u3002\u8F93\u5165 `/dashboard stop` \u5173\u95ED\u3002",
|
|
2222
|
+
failed: "\u25B8 \u4EEA\u8868\u677F\u542F\u52A8\u5931\u8D25\uFF1A{reason}",
|
|
2223
|
+
starting: "\u25B8 \u6B63\u5728\u542F\u52A8\u4EEA\u8868\u677F\u670D\u52A1\u5668\u2026"
|
|
2224
|
+
},
|
|
2225
|
+
observability: {
|
|
2226
|
+
thinkEmpty: "\u672A\u7F13\u5B58\u63A8\u7406\u5185\u5BB9\u3002`/think` \u663E\u793A\u6700\u8FD1\u4E00\u8F6E\u7684\u5B8C\u6574\u601D\u8003\u6A21\u5F0F\u601D\u7EF4 \u2014 \u4EC5\u601D\u8003\u6A21\u5F0F\u6A21\u578B\uFF08deepseek-v4-flash / -v4-pro / -reasoner\uFF09\u4EA7\u751F\u5B83\uFF0C\u4E14\u4EC5\u5728\u8F6E\u6B21\u5B8C\u6210\u540E\u3002",
|
|
2227
|
+
thinkInfo: "\u21B3 \u5B8C\u6574\u601D\u8003\uFF08{count} \u5B57\u7B26\uFF09\uFF1A",
|
|
2228
|
+
toolEmpty: "\u6B64\u4F1A\u8BDD\u4E2D\u5C1A\u65E0\u5DE5\u5177\u8C03\u7528\u3002`/tool` \u5728\u6A21\u578B\u5B9E\u9645\u4F7F\u7528\u5DE5\u5177\u540E\u5217\u51FA\u5B83\u4EEC\uFF1B`/tool N` \u8F6C\u50A8\u7B2C N \u4E2A\u6700\u8FD1\u7684\u5B8C\u6574\uFF08\u672A\u622A\u65AD\uFF09\u8F93\u51FA\u3002",
|
|
2229
|
+
toolUsage: "\u7528\u6CD5\uFF1A/tool [N] \uFF08\u65E0\u53C2\u6570 \u2192 \u5217\u8868\uFF1BN=1 \u2192 \u6700\u8FD1\u7684\u5B8C\u6574\u7ED3\u679C\uFF0CN=2 \u2192 \u4E0A\u4E00\u4E2A\uFF0C\u2026\uFF09",
|
|
2230
|
+
toolOob: "\u5386\u53F2\u4E2D\u4EC5\u6709 {count} \u6B21\u5DE5\u5177\u8C03\u7528 \u2014 \u8BF7\u6C42\u4E86 #{n}\u3002\u5C1D\u8BD5\u4E0D\u5E26\u53C2\u6570\u7684 /tool \u67E5\u770B\u5217\u8868\u3002",
|
|
2231
|
+
toolNotFound: "\u65E0\u6CD5\u8BFB\u53D6\u5DE5\u5177\u8C03\u7528 #{n}",
|
|
2232
|
+
toolInfo: "\u21B3 tool<{name}> #{n}\uFF08{chars} \u5B57\u7B26\uFF09\uFF1A",
|
|
2233
|
+
contextInfo: "\u4E0A\u4E0B\u6587\uFF1A~{total} / {max}\uFF08{pct}%\uFF09\xB7 \u7CFB\u7EDF {sys} \xB7 \u5DE5\u5177 {tools} \xB7 \u65E5\u5FD7 {log}",
|
|
2234
|
+
compactStarting: "\u25B8 \u6B63\u5728\u6298\u53E0\u65E7\u8F6E\u6B21\u4E3A\u6458\u8981\u2026",
|
|
2235
|
+
compactNoop: "\u25B8 \u65E0\u9700\u6298\u53E0 \u2014 \u65E5\u5FD7\u5DF2\u8DB3\u591F\u5C0F\uFF0C\u6216\u6700\u8FD1\u8F6E\u6B21\u672C\u8EAB\u5DF2\u8D85\u8FC7\u9884\u7B97\u3002",
|
|
2236
|
+
compactDone: "\u25B8 \u5DF2\u6298\u53E0 {before} \u6761\u6D88\u606F \u2192 {after}\uFF08\u6458\u8981 {chars} \u5B57\u7B26\uFF09\u3002\u7EE7\u7EED\u3002",
|
|
2237
|
+
compactFailed: "\u25B8 \u6298\u53E0\u5931\u8D25\uFF1A{reason}",
|
|
2238
|
+
costNoTurn: "\u5C1A\u65E0\u8F6E\u6B21 \u2014 `/cost` \u663E\u793A\u6700\u8FD1\u4E00\u8F6E\u7684 token + \u82B1\u8D39\u660E\u7EC6\u3002",
|
|
2239
|
+
costNeedsTui: "/cost \u9700\u8981 TUI \u4E0A\u4E0B\u6587\uFF08postUsage \u5DF2\u8FDE\u63A5\uFF09\u3002",
|
|
2240
|
+
costNoPricing: '\u25B8 /cost\uFF1A\u6A21\u578B "{model}" \u65E0\u5B9A\u4EF7\u8868\u3002\u8BF7\u5728 telemetry/stats.ts \u4E2D\u6DFB\u52A0\u3002',
|
|
2241
|
+
costEstimate: "\u25B8 /cost \u4F30\u7B97 \xB7 {model} \xB7 {prompt} prompt tokens\uFF08\u7CFB\u7EDF {sys} + \u5DE5\u5177 {tools} + \u65E5\u5FD7 {log} + \u6D88\u606F {msg}\uFF09",
|
|
2242
|
+
costWorstCase: " \u6700\u574F\u60C5\u51B5\uFF08\u5B8C\u5168\u672A\u547D\u4E2D\uFF09\uFF1A{input} \u8F93\u5165 + ~{output} \u8F93\u51FA\uFF08{avg} \u5E73\u5747\uFF09\u2248 {total}",
|
|
2243
|
+
costLikely: " \u53EF\u80FD\uFF08{pct}% \u4F1A\u8BDD\u7F13\u5B58\u547D\u4E2D\uFF09\uFF1A{input} \u8F93\u5165 + ~{output} \u8F93\u51FA \u2248 {total}",
|
|
2244
|
+
costLikelyCold: " \u53EF\u80FD\uFF1A\u5728\u7F13\u5B58\u586B\u5145\u524D\u4E0E\u6700\u574F\u60C5\u51B5\u76F8\u540C\uFF08\u65E0\u5DF2\u5B8C\u6210\u7684\u8F6E\u6B21\uFF09",
|
|
2245
|
+
statusModel: " \u6A21\u578B {model}",
|
|
2246
|
+
statusFlags: " \u6807\u5FD7 harvest={harvest} \xB7 branch={branch} \xB7 stream={stream} \xB7 effort={effort}",
|
|
2247
|
+
statusCtx: " \u4E0A\u4E0B\u6587 {bar} {used}/{max}\uFF08{pct}%\uFF09",
|
|
2248
|
+
statusCtxNone: " \u4E0A\u4E0B\u6587 \u5C1A\u65E0\u8F6E\u6B21",
|
|
2249
|
+
statusCost: " \u6210\u672C ${cost} \xB7 \u7F13\u5B58 {bar} {pct}% \xB7 \u8F6E\u6B21 {turns}",
|
|
2250
|
+
statusCostCold: " \u6210\u672C ${cost} \xB7 \u8F6E\u6B21 {turns}\uFF08\u7F13\u5B58\u9884\u70ED\u4E2D\uFF09",
|
|
2251
|
+
statusBudget: " \u9884\u7B97 ${spent} / ${cap}\uFF08{pct}%\uFF09{tag}",
|
|
2252
|
+
statusSession: ' \u4F1A\u8BDD "{name}" \xB7 \u65E5\u5FD7\u4E2D {count} \u6761\u6D88\u606F\uFF08\u6062\u590D\u4E86 {resumed} \u6761\uFF09',
|
|
2253
|
+
statusSessionEphemeral: " \u4F1A\u8BDD \uFF08\u4E34\u65F6 \u2014 \u65E0\u6301\u4E45\u5316\uFF09",
|
|
2254
|
+
statusWorkspace: " \u5DE5\u4F5C\u533A {path} \xB7 \u542F\u52A8\u65F6\u9501\u5B9A\uFF08\u7528 --dir <path> \u91CD\u65B0\u542F\u52A8\u4EE5\u5207\u6362\uFF09",
|
|
2255
|
+
statusMcp: " MCP {servers} \u4E2A\u670D\u52A1\u5668\uFF0C\u6CE8\u518C\u8868\u4E2D {tools} \u4E2A\u5DE5\u5177",
|
|
2256
|
+
statusEdits: " \u7F16\u8F91 {count} \u4E2A\u5F85\u5904\u7406\uFF08/apply \u63D0\u4EA4\uFF0C/discard \u4E22\u5F03\uFF09",
|
|
2257
|
+
statusPlan: " \u8BA1\u5212 \u5F00\u542F \u2014 \u5199\u5165\u53D7\u9650\uFF08submit_plan + \u5BA1\u6279\uFF09",
|
|
2258
|
+
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",
|
|
2259
|
+
statusModeAuto: " \u6A21\u5F0F AUTO \u2014 \u7F16\u8F91\u7ACB\u5373\u5E94\u7528\uFF085 \u79D2\u5185\u6309 u \u64A4\u6D88 \xB7 Shift+Tab \u5207\u6362\uFF09",
|
|
2260
|
+
statusModeReview: " \u6A21\u5F0F review \u2014 \u7F16\u8F91\u6392\u961F\u7B49\u5F85 /apply \u6216 y\uFF08Shift+Tab \u5207\u6362\uFF09",
|
|
2261
|
+
statusDash: " \u4EEA\u8868\u677F {url}\uFF08\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00 \xB7 /dashboard stop\uFF09"
|
|
2262
|
+
},
|
|
2263
|
+
plans: {
|
|
2264
|
+
noSession: "\u672A\u9644\u52A0\u4F1A\u8BDD \u2014 `/plans` \u662F\u6309\u4F1A\u8BDD\u7684\u3002\u5728\u9879\u76EE\u4E2D\u8FD0\u884C `reasonix code` \u4EE5\u83B7\u53D6\u4F1A\u8BDD\u3002",
|
|
2265
|
+
activePlan: "\u25B8 \u6D3B\u8DC3\u8BA1\u5212{label} \u2014 {done}/{total} \u6B65\u9AA4\u5DF2\u5B8C\u6210 \xB7 \u6700\u540E\u89E6\u53CA {when}",
|
|
2266
|
+
activeNone: "\u25B8 \u6D3B\u8DC3\u8BA1\u5212\uFF1A\uFF08\u65E0\uFF09",
|
|
2267
|
+
noArchives: "\u6B64\u4F1A\u8BDD\u5C1A\u65E0\u5F52\u6863\u8BA1\u5212 \u2014 \u5F53\u6BCF\u4E2A\u6B65\u9AA4\u5B8C\u6210\u65F6\u81EA\u52A8\u5F52\u6863",
|
|
2268
|
+
archivedHeader: "\u5DF2\u5F52\u6863\uFF08{count}\uFF09\uFF1A",
|
|
2269
|
+
replayNoSession: "\u672A\u9644\u52A0\u4F1A\u8BDD \u2014 `/replay` \u662F\u6309\u4F1A\u8BDD\u7684\u3002\u5728\u9879\u76EE\u4E2D\u8FD0\u884C `reasonix code` \u4EE5\u83B7\u53D6\u4F1A\u8BDD\u3002",
|
|
2270
|
+
replayNoArchives: "\u6B64\u4F1A\u8BDD\u5C1A\u65E0\u5F52\u6863\u8BA1\u5212 \u2014 `/replay` \u5728\u8BA1\u5212\u5B8C\u6210\u540E\u542F\u7528\uFF08\u6BCF\u4E2A\u6B65\u9AA4\u5B8C\u6210\u65F6\u81EA\u52A8\u5F52\u6863\uFF09\u3002",
|
|
2271
|
+
replayInvalidIndex: "\u65E0\u6548\u7D22\u5F15 \u2014 `/replay` \u63A5\u53D7 1..{max}\uFF08\u6700\u65B0 = 1\uFF09\u3002\u4F7F\u7528 `/plans` \u67E5\u770B\u5217\u8868\u3002",
|
|
2272
|
+
archivedRow: " \u2713 {when} {total}\u6B65 \xB7 {completion} {label}",
|
|
2273
|
+
completionComplete: "\u5DF2\u5B8C\u6210",
|
|
2274
|
+
stopAborted: "\u25B8 \u8BA1\u5212\u5DF2\u505C\u6B62 \u2014 \u6A21\u578B\u5DF2\u4E2D\u6B62\uFF1B\u8F93\u5165\u540E\u7EED\u5185\u5BB9\u7EE7\u7EED\uFF0C\u6216\u5F00\u59CB\u65B0\u4EFB\u52A1\u3002"
|
|
2275
|
+
},
|
|
2276
|
+
jobs: {
|
|
2277
|
+
codeOnly: "/jobs \u4EC5\u5728 `reasonix code` \u4E2D\u53EF\u7528\u3002",
|
|
2278
|
+
killCodeOnly: "/kill \u4EC5\u5728 `reasonix code` \u4E2D\u53EF\u7528\u3002",
|
|
2279
|
+
logsCodeOnly: "/logs \u4EC5\u5728 `reasonix code` \u4E2D\u53EF\u7528\u3002",
|
|
2280
|
+
empty: "\u25C8 \u4F5C\u4E1A \xB7 0 \u8FD0\u884C\u4E2D \xB7 \u5171 0 \u4E2A\n \uFF08run_background \u751F\u6210\u4E00\u4E2A \u2014 \u5F00\u53D1\u670D\u52A1\u5668\u3001\u76D1\u89C6\u5668\u3001\u957F\u65F6\u95F4\u8FD0\u884C\u7684\u811A\u672C\uFF09",
|
|
2281
|
+
header: "\u25C8 \u4F5C\u4E1A \xB7 {running} \u8FD0\u884C\u4E2D \xB7 \u5171 {total} \u4E2A",
|
|
2282
|
+
footer: " /logs <id> \u8DDF\u8E2A \xB7 /kill <id> SIGTERM \u2192 SIGKILL",
|
|
2283
|
+
killUsage: "\u7528\u6CD5\uFF1A/kill <id> \uFF08\u89C1 /jobs \u83B7\u53D6 ID\uFF09",
|
|
2284
|
+
killNotFound: "\u4F5C\u4E1A {id}\uFF1A\u672A\u627E\u5230",
|
|
2285
|
+
killAlreadyExited: "\u4F5C\u4E1A {id} \u5DF2\u9000\u51FA\uFF08{code}\uFF09",
|
|
2286
|
+
killStopping: "\u25B8 \u6B63\u5728\u505C\u6B62\u4F5C\u4E1A {id}\uFF08\u6811\u7EC8\u6B62\uFF1ASIGTERM \u2192 2 \u79D2\u5BBD\u9650\u671F\u540E SIGKILL\uFF1BWindows\uFF1Ataskkill /T /F\uFF09",
|
|
2287
|
+
killStatus: "\u25B8 \u4F5C\u4E1A {id} {status}",
|
|
2288
|
+
killStillAlive: "SIGKILL \u540E\u4ECD\u5B58\u6D3B (!) \u2014 \u8BF7\u5C06\u6B64\u4F5C\u4E3A bug \u62A5\u544A",
|
|
2289
|
+
logsUsage: "\u7528\u6CD5\uFF1A/logs <id> [lines] \uFF08\u9ED8\u8BA4\u6700\u540E 80 \u884C\uFF09",
|
|
2290
|
+
logsNotFound: "\u4F5C\u4E1A {id}\uFF1A\u672A\u627E\u5230",
|
|
2291
|
+
logsStatus: "[\u4F5C\u4E1A {id} \xB7 {status}]\n$ {command}",
|
|
2292
|
+
logsRunning: "\u8FD0\u884C\u4E2D \xB7 pid {pid}",
|
|
2293
|
+
logsExited: "\u5DF2\u9000\u51FA {code}",
|
|
2294
|
+
logsFailed: "\u5931\u8D25\uFF08{reason}\uFF09",
|
|
2295
|
+
logsStopped: "\u5DF2\u505C\u6B62"
|
|
2296
|
+
},
|
|
2297
|
+
memory: {
|
|
2298
|
+
disabled: "\u8BB0\u5FC6\u5DF2\u7981\u7528\uFF08\u73AF\u5883\u53D8\u91CF REASONIX_MEMORY=off\uFF09\u3002\u53D6\u6D88\u8BBE\u7F6E\u8BE5\u53D8\u91CF\u4EE5\u91CD\u65B0\u542F\u7528 \u2014 \u6B64\u671F\u95F4\u4E0D\u4F1A\u56FA\u5B9A\u4EFB\u4F55 REASONIX.md \u6216 ~/.reasonix/memory \u5185\u5BB9\u3002",
|
|
2299
|
+
noRoot: "\u6B64\u4F1A\u8BDD\u65E0\u5DE5\u4F5C\u76EE\u5F55 \u2014 `/memory` \u9700\u8981\u4E00\u4E2A\u6839\u76EE\u5F55\u6765\u89E3\u6790 REASONIX.md\u3002\uFF08\u5728\u6D4B\u8BD5\u73AF\u5883\u4E2D\u8FD0\u884C\uFF1F\uFF09",
|
|
2300
|
+
listEmpty: "\u5C1A\u65E0\u7528\u6237\u8BB0\u5FC6\u3002\u6A21\u578B\u53EF\u4EE5\u8C03\u7528 `remember` \u4FDD\u5B58\u4E00\u4E2A\uFF0C\u6216\u60A8\u53EF\u4EE5\u5728 ~/.reasonix/memory/global/ \u6216\u9879\u76EE\u5B50\u76EE\u5F55\u4E2D\u624B\u52A8\u521B\u5EFA\u6587\u4EF6\u3002",
|
|
2301
|
+
listHeader: "\u7528\u6237\u8BB0\u5FC6\uFF08{count}\uFF09\uFF1A",
|
|
2302
|
+
listFooter: "\u67E5\u770B\u6B63\u6587\uFF1A/memory show <name> \u5220\u9664\uFF1A/memory forget <name>",
|
|
2303
|
+
showUsage: "\u7528\u6CD5\uFF1A/memory show <name> \u6216 /memory show <scope>/<name>",
|
|
2304
|
+
showNotFound: "\u672A\u627E\u5230\u8BB0\u5FC6\uFF1A{target}",
|
|
2305
|
+
showFailed: "\u663E\u793A\u5931\u8D25\uFF1A{reason}",
|
|
2306
|
+
forgetUsage: "\u7528\u6CD5\uFF1A/memory forget <name> \u6216 /memory forget <scope>/<name>",
|
|
2307
|
+
forgetNotFound: "\u672A\u627E\u5230\u8BB0\u5FC6\uFF1A{target}",
|
|
2308
|
+
forgetInfo: "\u25B8 \u5DF2\u9057\u5FD8 {scope}/{name}\u3002\u4E0B\u6B21 /new \u6216\u542F\u52A8\u65F6\u5C06\u4E0D\u53EF\u89C1\u3002",
|
|
2309
|
+
forgetFailed: "\u65E0\u6CD5\u9057\u5FD8 {scope}/{name}\uFF08\u5DF2\u6D88\u5931\uFF1F\uFF09",
|
|
2310
|
+
forgetError: "\u9057\u5FD8\u5931\u8D25\uFF1A{reason}",
|
|
2311
|
+
clearUsage: "\u7528\u6CD5\uFF1A/memory clear <global|project> confirm",
|
|
2312
|
+
clearConfirm: "\u5373\u5C06\u5220\u9664 scope={scope} \u4E2D\u7684\u6BCF\u4E2A\u8BB0\u5FC6\u3002\u91CD\u65B0\u8FD0\u884C\u5E76\u9644\u5E26 'confirm' \u4E00\u8BCD\u4EE5\u7EE7\u7EED\uFF1A/memory clear {scope} confirm",
|
|
2313
|
+
cleared: "\u25B8 \u5DF2\u6E05\u9664 scope={scope} \u2014 \u5220\u9664\u4E86 {count} \u4E2A\u8BB0\u5FC6\u6587\u4EF6\u3002",
|
|
2314
|
+
noMemory: "\u5728 {root} \u4E2D\u672A\u56FA\u5B9A\u8BB0\u5FC6\u3002",
|
|
2315
|
+
layers: "\u53EF\u7528\u7684\u4E09\u4E2A\u5C42\u7EA7\uFF1A",
|
|
2316
|
+
layerProject: " 1. {file} \u2014 \u53EF\u63D0\u4EA4\u7684\u56E2\u961F\u8BB0\u5FC6\uFF08\u5728\u4ED3\u5E93\u4E2D\uFF09\u3002",
|
|
2317
|
+
layerGlobal: " 2. ~/.reasonix/memory/global/ \u2014 \u60A8\u7684\u8DE8\u9879\u76EE\u79C1\u6709\u8BB0\u5FC6\u3002",
|
|
2318
|
+
layerProjectHash: " 3. ~/.reasonix/memory/<project-hash>/ \u2014 \u6B64\u9879\u76EE\u7684\u79C1\u6709\u8BB0\u5FC6\u3002",
|
|
2319
|
+
askModel: "\u8BA9\u6A21\u578B `remember` \u67D0\u4E9B\u5185\u5BB9\uFF0C\u6216\u76F4\u63A5\u624B\u7F16\u8F91\u6587\u4EF6\u3002",
|
|
2320
|
+
changesNote: "\u66F4\u6539\u5728\u4E0B\u6B21 /new \u6216\u542F\u52A8\u65F6\u751F\u6548 \u2014 \u7CFB\u7EDF\u63D0\u793A\u8BCD\u6BCF\u4F1A\u8BDD\u54C8\u5E0C\u4E00\u6B21\u4EE5\u4FDD\u6301\u524D\u7F00\u7F13\u5B58\u70ED\u5EA6\u3002",
|
|
2321
|
+
subcommands: "\u5B50\u547D\u4EE4\uFF1A/memory list | /memory show <name> | /memory forget <name> | /memory clear <scope> confirm",
|
|
2322
|
+
changesNoteShort: "\u66F4\u6539\u5728\u4E0B\u6B21 /new \u6216\u542F\u52A8\u65F6\u751F\u6548\u3002\u5B50\u547D\u4EE4\uFF1A/memory list | show | forget | clear"
|
|
2323
|
+
},
|
|
2324
|
+
mcp: {
|
|
2325
|
+
noServers: '\u672A\u9644\u52A0 MCP \u670D\u52A1\u5668\u3002\u8FD0\u884C `reasonix setup` \u9009\u62E9\u4E00\u4E9B\uFF0C\u6216\u4F7F\u7528 --mcp "<spec>" \u542F\u52A8\u3002`reasonix mcp list` \u663E\u793A\u76EE\u5F55\u3002',
|
|
2326
|
+
toolsLabel: " \u5DE5\u5177 {count}",
|
|
2327
|
+
resourcesHint: "`/resource` \u6D4F\u89C8+\u8BFB\u53D6",
|
|
2328
|
+
promptsHint: "`/prompt` \u6D4F\u89C8+\u83B7\u53D6",
|
|
2329
|
+
awarenessOnly: "\u804A\u5929\u6A21\u5F0F\u76EE\u524D\u6D88\u8017\u5DE5\u5177\uFF1B\u8D44\u6E90+\u63D0\u793A\u5728\u6B64\u5C55\u793A\u4F9B\u4E86\u89E3\u3002",
|
|
2330
|
+
catalogHint: "\u5B8C\u6574\u76EE\u5F55\uFF1A`reasonix mcp list` \xB7 \u6DF1\u5EA6\u8BCA\u65AD\uFF1A`reasonix mcp inspect <spec>`\u3002",
|
|
2331
|
+
fallbackServers: "MCP \u670D\u52A1\u5668\uFF08{count}\uFF09\uFF1A",
|
|
2332
|
+
fallbackTools: "\u6CE8\u518C\u8868\u4E2D\u7684\u5DE5\u5177\uFF08{count}\uFF09\uFF1A",
|
|
2333
|
+
fallbackChange: "\u8981\u66F4\u6539\u6B64\u8BBE\u7F6E\uFF0C\u8BF7\u9000\u51FA\u5E76\u8FD0\u884C `reasonix setup`\u3002",
|
|
2334
|
+
usageDisableEnable: "\u7528\u6CD5\uFF1A/mcp {action} <name> \xB7 \u4ECE /mcp \u5217\u8868\u4E2D\u6311\u4E00\u4E2A\u540D\u5B57\uFF08\u533F\u540D\u670D\u52A1\u5668\u65E0\u6CD5\u6309\u540D\u5207\u6362\uFF09\u3002",
|
|
2335
|
+
usageReconnect: "\u7528\u6CD5\uFF1A/mcp reconnect <name> \xB7 \u4ECE /mcp \u5217\u8868\u4E2D\u6311\u4E00\u4E2A\u540D\u5B57\u3002",
|
|
2336
|
+
unknownServer: '\u672A\u77E5 MCP \u670D\u52A1\u5668 "{name}"\u3002\u5DF2\u77E5\uFF1A{list}\u3002',
|
|
2337
|
+
noneList: "\uFF08\u65E0\uFF09",
|
|
2338
|
+
reconnectNoTui: "/mcp reconnect \u9700\u8981\u4EA4\u4E92\u5F0F TUI\uFF08postInfo \u672A\u8FDE\u63A5\uFF09\u3002"
|
|
2339
|
+
},
|
|
2340
|
+
init: {
|
|
2341
|
+
codeOnly: "/init \u4EC5\u5728\u4EE3\u7801\u6A21\u5F0F\u4E0B\u5DE5\u4F5C\uFF08\u9700\u8981\u6587\u4EF6\u7CFB\u7EDF\u5DE5\u5177\uFF09\u3002\n\u8FD0\u884C `reasonix code [path]` \u542F\u52A8\u4E00\u4E2A\u4EE5\u60A8\u8981\u521D\u59CB\u5316\u7684\u9879\u76EE\u4E3A\u6839\u7684\u4F1A\u8BDD\uFF0C\n\u7136\u540E\u8FD0\u884C /init\u3002",
|
|
2342
|
+
exists: "\u25B8 REASONIX.md \u5DF2\u5B58\u5728\u4E8E {path}",
|
|
2343
|
+
existsForce: " /init force \u4ECE\u5934\u91CD\u65B0\u751F\u6210\uFF08\u8986\u76D6\uFF09",
|
|
2344
|
+
existsEdit: " \u6216\u624B\u52A8\u7F16\u8F91 \u2014 \u5B83\u53EA\u662F markdown\u3002\u5F53\u524D\u6587\u4EF6\u5DF2",
|
|
2345
|
+
existsPinned: " \u56FA\u5B9A\u5230\u6BCF\u6B21\u542F\u52A8\u7684\u7CFB\u7EDF\u63D0\u793A\u8BCD\u4E2D\u3002",
|
|
2346
|
+
info: "\u25B8 /init \u2014 \u6A21\u578B\u5C06\u626B\u63CF\u9879\u76EE\u5E76\u5408\u6210 REASONIX.md\u3002\n \u7ED3\u679C\u5C06\u4F5C\u4E3A\u5F85\u5904\u7406\u7684\u7F16\u8F91\uFF1B\u4F7F\u7528 /apply \u6216 /walk \u5BA1\u67E5\u3002"
|
|
2347
|
+
},
|
|
2348
|
+
semantic: {
|
|
2349
|
+
codeOnly: "/semantic \u4EC5\u5728 `reasonix code` \u4E2D\u53EF\u7528\uFF08\u9700\u8981\u9879\u76EE\u6839\u76EE\u5F55\uFF09\u3002",
|
|
2350
|
+
checking: "\u25B8 \u6B63\u5728\u68C0\u67E5 semantic_search \u72B6\u6001\u2026"
|
|
2351
|
+
},
|
|
2352
|
+
webSearchEngine: {
|
|
2353
|
+
currentEngine: "\u5F53\u524D\u7F51\u9875\u641C\u7D22\u5F15\u64CE\uFF1A{engine}",
|
|
2354
|
+
endpoint: "SearXNG \u7AEF\u70B9\uFF1A{url}",
|
|
2355
|
+
usageHeader: "\u7528\u6CD5\uFF1A",
|
|
2356
|
+
usageMojeek: " /search-engine mojeek \u4F7F\u7528 Mojeek\uFF08\u9ED8\u8BA4\uFF0C\u65E0\u5916\u90E8\u4F9D\u8D56\uFF09",
|
|
2357
|
+
usageSearxng: " /search-engine searxng \u4F7F\u7528 SearXNG \u9ED8\u8BA4\u7AEF\u70B9",
|
|
2358
|
+
usageSearxngUrl: " /search-engine searxng <url> \u4F7F\u7528 SearXNG \u81EA\u5B9A\u4E49\u7AEF\u70B9",
|
|
2359
|
+
alias: "\u522B\u540D\uFF1A/se",
|
|
2360
|
+
searxngInfo: "SearXNG \u662F\u4E00\u4E2A\u81EA\u6258\u7BA1\u7684\u5143\u641C\u7D22\u5F15\u64CE\uFF08https://github.com/searxng/searxng\uFF09\u3002",
|
|
2361
|
+
searxngInstall: "\u5B89\u88C5\u547D\u4EE4\uFF1A docker run -d -p 8080:8080 searxng/searxng",
|
|
2362
|
+
switched: '\u5DF2\u5207\u6362\u7F51\u9875\u641C\u7D22\u5F15\u64CE\u4E3A "{engine}"\u3002{note}',
|
|
2363
|
+
switchedSearxngNote: " \u8BF7\u786E\u4FDD SearXNG \u5728 {endpoint} \u8FD0\u884C\u3002",
|
|
2364
|
+
confirmed: '\u2713 \u7F51\u9875\u641C\u7D22\u5F15\u64CE\u5DF2\u8BBE\u4E3A "{engine}"{detail}\u3002\u4E0B\u4E00\u8F6E\u6A21\u578B\u8C03\u7528\u5C06\u751F\u6548\u3002',
|
|
2365
|
+
confirmedDetail: "\uFF08{endpoint}\uFF09"
|
|
2366
|
+
},
|
|
2367
|
+
skill: {
|
|
2368
|
+
listEmpty: "\u672A\u627E\u5230\u6280\u80FD\u3002Reasonix \u4ECE\u4EE5\u4E0B\u4F4D\u7F6E\u8BFB\u53D6\u6280\u80FD\uFF1A",
|
|
2369
|
+
listProjectScope: " \xB7 <project>/.reasonix/skills/<name>/SKILL.md \uFF08\u6216 <name>.md\uFF09 \u2014 \u9879\u76EE\u8303\u56F4",
|
|
2370
|
+
listGlobalScope: " \xB7 ~/.reasonix/skills/<name>/SKILL.md \uFF08\u6216 <name>.md\uFF09 \u2014 \u5168\u5C40\u8303\u56F4",
|
|
2371
|
+
listProjectOnly: " \uFF08\u9879\u76EE\u8303\u56F4\u4EC5\u5728 `reasonix code` \u4E2D\u6D3B\u8DC3\uFF09",
|
|
2372
|
+
listFrontmatter: "\u6BCF\u4E2A\u6587\u4EF6\u7684 frontmatter \u81F3\u5C11\u9700\u8981 `name` \u548C `description`\u3002",
|
|
2373
|
+
listInvoke: "\u4F7F\u7528 `/skill <name> [args]` \u8C03\u7528\u6280\u80FD\uFF0C\u6216\u8BA9\u6A21\u578B\u8C03\u7528 `run_skill`\u3002",
|
|
2374
|
+
listHeader: "\u7528\u6237\u6280\u80FD\uFF08{count}\uFF09\uFF1A",
|
|
2375
|
+
listFooter: "\u67E5\u770B\uFF1A/skill show <name> \u8FD0\u884C\uFF1A/skill <name> [args] \u65B0\u5EFA\uFF1A/skill new <name>",
|
|
2376
|
+
listEmptyNewHint: "\u7528 `/skill new <name>` \u5728\u9879\u76EE\u8303\u56F4\u4E0B\u751F\u6210\u4E00\u4E2A\u7A7A\u767D\u6A21\u677F \u2014 \u6682\u65E0\u5728\u7EBF\u5E02\u573A\uFF0C\u6280\u80FD\u9700\u8981\u81EA\u5DF1\u5199\u3002",
|
|
2377
|
+
showUsage: "\u7528\u6CD5\uFF1A/skill show <name>",
|
|
2378
|
+
showNotFound: "\u672A\u627E\u5230\u6280\u80FD\uFF1A{name}",
|
|
2379
|
+
runNotFound: "\u672A\u627E\u5230\u6280\u80FD\uFF1A{name} \uFF08\u5C1D\u8BD5 /skill list\uFF09",
|
|
2380
|
+
runInfo: "\u25B8 \u6B63\u5728\u8FD0\u884C\u6280\u80FD\uFF1A{name}{args}",
|
|
2381
|
+
newUsage: "\u7528\u6CD5\uFF1A/skill new <name> [--global]",
|
|
2382
|
+
newCreated: "\u25B8 \u5DF2\u521B\u5EFA\u6280\u80FD\uFF1A{name}\n {path}\n \u7F16\u8F91\u540E\u7528 `/skill {name}` \u8C03\u7528",
|
|
2383
|
+
newError: "\u25B2 /skill new \u5931\u8D25\uFF1A{reason}"
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
};
|
|
2387
|
+
|
|
2388
|
+
// src/i18n/index.ts
|
|
2389
|
+
var translations = {
|
|
2390
|
+
EN,
|
|
2391
|
+
"zh-CN": zhCN
|
|
2392
|
+
};
|
|
2393
|
+
function detectSystemLanguage(locale = Intl.DateTimeFormat().resolvedOptions().locale) {
|
|
2394
|
+
if (locale.startsWith("zh")) return "zh-CN";
|
|
2395
|
+
if (locale.startsWith("en")) return "EN";
|
|
2396
|
+
return null;
|
|
2397
|
+
}
|
|
2398
|
+
var currentLang = loadLanguage() ?? detectSystemLanguage() ?? "EN";
|
|
2399
|
+
function t(path2, params) {
|
|
2400
|
+
const parts = path2.split(".");
|
|
2401
|
+
let val = translations[currentLang] || translations.EN;
|
|
2402
|
+
for (const part of parts) {
|
|
2403
|
+
val = val?.[part];
|
|
2404
|
+
if (val === void 0) break;
|
|
2405
|
+
}
|
|
2406
|
+
if (val === void 0 && currentLang !== "EN") {
|
|
2407
|
+
val = translations.EN;
|
|
2408
|
+
for (const part of parts) {
|
|
2409
|
+
val = val?.[part];
|
|
2410
|
+
if (val === void 0) break;
|
|
2411
|
+
}
|
|
2412
|
+
}
|
|
2413
|
+
if (typeof val !== "string") {
|
|
2414
|
+
return path2;
|
|
2415
|
+
}
|
|
2416
|
+
if (params) {
|
|
2417
|
+
let result = val;
|
|
2418
|
+
for (const [k, v] of Object.entries(params)) {
|
|
2419
|
+
result = result.replace(new RegExp(`\\{${k}\\}`, "g"), String(v));
|
|
2420
|
+
}
|
|
2421
|
+
return result;
|
|
2422
|
+
}
|
|
2423
|
+
return val;
|
|
2424
|
+
}
|
|
2425
|
+
|
|
2426
|
+
// src/hooks.ts
|
|
551
2427
|
var HOOK_EVENTS = [
|
|
552
2428
|
"PreToolUse",
|
|
553
2429
|
"PostToolUse",
|
|
@@ -564,15 +2440,15 @@ var DEFAULT_TIMEOUTS_MS = {
|
|
|
564
2440
|
var HOOK_SETTINGS_FILENAME = "settings.json";
|
|
565
2441
|
var HOOK_SETTINGS_DIRNAME = ".reasonix";
|
|
566
2442
|
function globalSettingsPath(homeDirOverride) {
|
|
567
|
-
return
|
|
2443
|
+
return join2(homeDirOverride ?? homedir2(), HOOK_SETTINGS_DIRNAME, HOOK_SETTINGS_FILENAME);
|
|
568
2444
|
}
|
|
569
2445
|
function projectSettingsPath(projectRoot) {
|
|
570
|
-
return
|
|
2446
|
+
return join2(projectRoot, HOOK_SETTINGS_DIRNAME, HOOK_SETTINGS_FILENAME);
|
|
571
2447
|
}
|
|
572
2448
|
function readSettingsFile(path2) {
|
|
573
2449
|
if (!existsSync(path2)) return null;
|
|
574
2450
|
try {
|
|
575
|
-
const raw =
|
|
2451
|
+
const raw = readFileSync2(path2, "utf8");
|
|
576
2452
|
const parsed = JSON.parse(raw);
|
|
577
2453
|
if (parsed && typeof parsed === "object") return parsed;
|
|
578
2454
|
} catch {
|
|
@@ -691,9 +2567,12 @@ function formatHookOutcomeMessage(outcome) {
|
|
|
691
2567
|
const detail = (outcome.stderr || outcome.stdout || "").trim();
|
|
692
2568
|
const tag = `${outcome.hook.scope}/${outcome.hook.event}`;
|
|
693
2569
|
const cmd = outcome.hook.command.length > 60 ? `${outcome.hook.command.slice(0, 60)}\u2026` : outcome.hook.command;
|
|
694
|
-
const truncTag = outcome.truncated ? "
|
|
695
|
-
const
|
|
696
|
-
return detail ?
|
|
2570
|
+
const truncTag = outcome.truncated ? t("hooks.truncated") : "";
|
|
2571
|
+
const decision = t(`hooks.decision${capitalize(outcome.decision)}`);
|
|
2572
|
+
return detail ? t("hooks.headWithDetail", { tag, cmd, decision, truncTag, detail }) : t("hooks.head", { tag, cmd, decision, truncTag });
|
|
2573
|
+
}
|
|
2574
|
+
function capitalize(s) {
|
|
2575
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
697
2576
|
}
|
|
698
2577
|
function decideOutcome(event, raw) {
|
|
699
2578
|
if (raw.spawnError) return "error";
|
|
@@ -735,9 +2614,9 @@ async function runHooks(opts) {
|
|
|
735
2614
|
}
|
|
736
2615
|
|
|
737
2616
|
// src/tokenizer.ts
|
|
738
|
-
import { existsSync as existsSync2, readFileSync as
|
|
2617
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
|
|
739
2618
|
import { createRequire } from "module";
|
|
740
|
-
import { dirname, join as
|
|
2619
|
+
import { dirname as dirname2, join as join3 } from "path";
|
|
741
2620
|
import { fileURLToPath } from "url";
|
|
742
2621
|
import { gunzipSync } from "zlib";
|
|
743
2622
|
function buildByteToChar() {
|
|
@@ -765,26 +2644,26 @@ function resolveDataPath() {
|
|
|
765
2644
|
if (process.env.REASONIX_TOKENIZER_PATH) return process.env.REASONIX_TOKENIZER_PATH;
|
|
766
2645
|
const candidates = [];
|
|
767
2646
|
try {
|
|
768
|
-
const here =
|
|
769
|
-
candidates.push(
|
|
770
|
-
candidates.push(
|
|
2647
|
+
const here = dirname2(fileURLToPath(import.meta.url));
|
|
2648
|
+
candidates.push(join3(here, "..", "data", "deepseek-tokenizer.json.gz"));
|
|
2649
|
+
candidates.push(join3(here, "..", "..", "data", "deepseek-tokenizer.json.gz"));
|
|
771
2650
|
} catch {
|
|
772
2651
|
}
|
|
773
2652
|
try {
|
|
774
2653
|
const req = createRequire(import.meta.url);
|
|
775
2654
|
candidates.push(
|
|
776
|
-
|
|
2655
|
+
join3(dirname2(req.resolve("reasonix/package.json")), "data", "deepseek-tokenizer.json.gz")
|
|
777
2656
|
);
|
|
778
2657
|
} catch {
|
|
779
2658
|
}
|
|
780
2659
|
for (const p of candidates) {
|
|
781
2660
|
if (existsSync2(p)) return p;
|
|
782
2661
|
}
|
|
783
|
-
return candidates[0] ??
|
|
2662
|
+
return candidates[0] ?? join3(process.cwd(), "data", "deepseek-tokenizer.json.gz");
|
|
784
2663
|
}
|
|
785
2664
|
function loadTokenizer() {
|
|
786
2665
|
if (cached) return cached;
|
|
787
|
-
const buf =
|
|
2666
|
+
const buf = readFileSync3(resolveDataPath());
|
|
788
2667
|
const json = gunzipSync(buf).toString("utf8");
|
|
789
2668
|
const data = JSON.parse(json);
|
|
790
2669
|
const mergeRank = /* @__PURE__ */ new Map();
|
|
@@ -799,10 +2678,10 @@ function loadTokenizer() {
|
|
|
799
2678
|
}
|
|
800
2679
|
const addedMap = /* @__PURE__ */ new Map();
|
|
801
2680
|
const addedContents = [];
|
|
802
|
-
for (const
|
|
803
|
-
if (!
|
|
804
|
-
addedMap.set(
|
|
805
|
-
addedContents.push(
|
|
2681
|
+
for (const t2 of data.added_tokens) {
|
|
2682
|
+
if (!t2.special) {
|
|
2683
|
+
addedMap.set(t2.content, t2.id);
|
|
2684
|
+
addedContents.push(t2.content);
|
|
806
2685
|
}
|
|
807
2686
|
}
|
|
808
2687
|
addedContents.sort((a, b) => b.length - a.length);
|
|
@@ -869,29 +2748,29 @@ function bpeEncode(piece, mergeRank) {
|
|
|
869
2748
|
}
|
|
870
2749
|
function encode(text) {
|
|
871
2750
|
if (!text) return [];
|
|
872
|
-
const
|
|
2751
|
+
const t2 = loadTokenizer();
|
|
873
2752
|
const ids = [];
|
|
874
2753
|
const process2 = (segment) => {
|
|
875
2754
|
if (!segment) return;
|
|
876
2755
|
let chunks = [segment];
|
|
877
|
-
for (const re of
|
|
2756
|
+
for (const re of t2.splitRegexes) chunks = applySplit(chunks, re);
|
|
878
2757
|
for (const chunk of chunks) {
|
|
879
2758
|
if (!chunk) continue;
|
|
880
|
-
const byteLevel = byteLevelEncode(chunk,
|
|
881
|
-
const pieces = bpeEncode(byteLevel,
|
|
2759
|
+
const byteLevel = byteLevelEncode(chunk, t2.byteToChar);
|
|
2760
|
+
const pieces = bpeEncode(byteLevel, t2.mergeRank);
|
|
882
2761
|
for (const p of pieces) {
|
|
883
|
-
const id =
|
|
2762
|
+
const id = t2.vocab[p];
|
|
884
2763
|
if (id !== void 0) ids.push(id);
|
|
885
2764
|
}
|
|
886
2765
|
}
|
|
887
2766
|
};
|
|
888
|
-
if (
|
|
889
|
-
|
|
2767
|
+
if (t2.addedPattern) {
|
|
2768
|
+
t2.addedPattern.lastIndex = 0;
|
|
890
2769
|
let last = 0;
|
|
891
|
-
for (const m of text.matchAll(
|
|
2770
|
+
for (const m of text.matchAll(t2.addedPattern)) {
|
|
892
2771
|
const idx = m.index ?? 0;
|
|
893
2772
|
if (idx > last) process2(text.slice(last, idx));
|
|
894
|
-
const id =
|
|
2773
|
+
const id = t2.addedMap.get(m[0]);
|
|
895
2774
|
if (id !== void 0) ids.push(id);
|
|
896
2775
|
last = idx + m[0].length;
|
|
897
2776
|
}
|
|
@@ -1051,12 +2930,12 @@ var ToolRegistry = class {
|
|
|
1051
2930
|
return this._tools.get(name)?.parallelSafe === true;
|
|
1052
2931
|
}
|
|
1053
2932
|
specs() {
|
|
1054
|
-
return [...this._tools.values()].map((
|
|
2933
|
+
return [...this._tools.values()].map((t2) => ({
|
|
1055
2934
|
type: "function",
|
|
1056
2935
|
function: {
|
|
1057
|
-
name:
|
|
1058
|
-
description:
|
|
1059
|
-
parameters:
|
|
2936
|
+
name: t2.name,
|
|
2937
|
+
description: t2.description ?? "",
|
|
2938
|
+
parameters: t2.flatSchema ?? t2.parameters ?? { type: "object", properties: {} }
|
|
1060
2939
|
}
|
|
1061
2940
|
}));
|
|
1062
2941
|
}
|
|
@@ -1308,23 +3187,23 @@ function blockToString(block) {
|
|
|
1308
3187
|
import { execFileSync } from "child_process";
|
|
1309
3188
|
import {
|
|
1310
3189
|
appendFileSync,
|
|
1311
|
-
chmodSync,
|
|
3190
|
+
chmodSync as chmodSync2,
|
|
1312
3191
|
existsSync as existsSync3,
|
|
1313
|
-
mkdirSync,
|
|
1314
|
-
readFileSync as
|
|
3192
|
+
mkdirSync as mkdirSync2,
|
|
3193
|
+
readFileSync as readFileSync4,
|
|
1315
3194
|
readdirSync,
|
|
1316
3195
|
renameSync,
|
|
1317
3196
|
statSync,
|
|
1318
3197
|
unlinkSync,
|
|
1319
|
-
writeFileSync
|
|
3198
|
+
writeFileSync as writeFileSync2
|
|
1320
3199
|
} from "fs";
|
|
1321
|
-
import { homedir as
|
|
1322
|
-
import { dirname as
|
|
3200
|
+
import { homedir as homedir3 } from "os";
|
|
3201
|
+
import { dirname as dirname3, join as join4 } from "path";
|
|
1323
3202
|
function sessionsDir() {
|
|
1324
|
-
return
|
|
3203
|
+
return join4(homedir3(), ".reasonix", "sessions");
|
|
1325
3204
|
}
|
|
1326
3205
|
function sessionPath(name) {
|
|
1327
|
-
return
|
|
3206
|
+
return join4(sessionsDir(), `${sanitizeName(name)}.jsonl`);
|
|
1328
3207
|
}
|
|
1329
3208
|
function sanitizeName(name) {
|
|
1330
3209
|
const cleaned = name.replace(/[^\w\-\u4e00-\u9fa5]/g, "_").slice(0, 64);
|
|
@@ -1334,7 +3213,7 @@ function loadSessionMessages(name) {
|
|
|
1334
3213
|
const path2 = sessionPath(name);
|
|
1335
3214
|
if (!existsSync3(path2)) return [];
|
|
1336
3215
|
try {
|
|
1337
|
-
const raw =
|
|
3216
|
+
const raw = readFileSync4(path2, "utf8");
|
|
1338
3217
|
const out = [];
|
|
1339
3218
|
for (const line of raw.split(/\r?\n/)) {
|
|
1340
3219
|
const trimmed = line.trim();
|
|
@@ -1352,11 +3231,11 @@ function loadSessionMessages(name) {
|
|
|
1352
3231
|
}
|
|
1353
3232
|
function appendSessionMessage(name, message) {
|
|
1354
3233
|
const path2 = sessionPath(name);
|
|
1355
|
-
|
|
3234
|
+
mkdirSync2(dirname3(path2), { recursive: true });
|
|
1356
3235
|
appendFileSync(path2, `${JSON.stringify(message)}
|
|
1357
3236
|
`, "utf8");
|
|
1358
3237
|
try {
|
|
1359
|
-
|
|
3238
|
+
chmodSync2(path2, 384);
|
|
1360
3239
|
} catch {
|
|
1361
3240
|
}
|
|
1362
3241
|
}
|
|
@@ -1368,7 +3247,7 @@ function listSessions() {
|
|
|
1368
3247
|
(f) => f.endsWith(".jsonl") && !f.endsWith(".events.jsonl")
|
|
1369
3248
|
);
|
|
1370
3249
|
return files.map((file) => {
|
|
1371
|
-
const path2 =
|
|
3250
|
+
const path2 = join4(dir, file);
|
|
1372
3251
|
const stat2 = statSync(path2);
|
|
1373
3252
|
const name = file.replace(/\.jsonl$/, "");
|
|
1374
3253
|
const messageCount = countLines(path2);
|
|
@@ -1386,13 +3265,13 @@ function listSessions() {
|
|
|
1386
3265
|
}
|
|
1387
3266
|
}
|
|
1388
3267
|
function metaPath(name) {
|
|
1389
|
-
return
|
|
3268
|
+
return join4(sessionsDir(), `${sanitizeName(name)}.meta.json`);
|
|
1390
3269
|
}
|
|
1391
3270
|
function loadSessionMeta(name) {
|
|
1392
3271
|
const p = metaPath(name);
|
|
1393
3272
|
if (!existsSync3(p)) return {};
|
|
1394
3273
|
try {
|
|
1395
|
-
const raw = JSON.parse(
|
|
3274
|
+
const raw = JSON.parse(readFileSync4(p, "utf8"));
|
|
1396
3275
|
return raw && typeof raw === "object" ? raw : {};
|
|
1397
3276
|
} catch {
|
|
1398
3277
|
return {};
|
|
@@ -1416,18 +3295,18 @@ function deleteSession(name) {
|
|
|
1416
3295
|
}
|
|
1417
3296
|
function rewriteSession(name, messages) {
|
|
1418
3297
|
const path2 = sessionPath(name);
|
|
1419
|
-
|
|
3298
|
+
mkdirSync2(dirname3(path2), { recursive: true });
|
|
1420
3299
|
const body = messages.map((m) => JSON.stringify(m)).join("\n");
|
|
1421
|
-
|
|
3300
|
+
writeFileSync2(path2, body ? `${body}
|
|
1422
3301
|
` : "", "utf8");
|
|
1423
3302
|
try {
|
|
1424
|
-
|
|
3303
|
+
chmodSync2(path2, 384);
|
|
1425
3304
|
} catch {
|
|
1426
3305
|
}
|
|
1427
3306
|
}
|
|
1428
3307
|
function countLines(path2) {
|
|
1429
3308
|
try {
|
|
1430
|
-
const raw =
|
|
3309
|
+
const raw = readFileSync4(path2, "utf8");
|
|
1431
3310
|
return raw.split(/\r?\n/).filter((l) => l.trim()).length;
|
|
1432
3311
|
} catch {
|
|
1433
3312
|
return 0;
|
|
@@ -1515,27 +3394,27 @@ var SessionStats = class {
|
|
|
1515
3394
|
return stats;
|
|
1516
3395
|
}
|
|
1517
3396
|
get totalCost() {
|
|
1518
|
-
return this._carryoverCost + this.turns.reduce((sum,
|
|
3397
|
+
return this._carryoverCost + this.turns.reduce((sum, t2) => sum + t2.cost, 0);
|
|
1519
3398
|
}
|
|
1520
3399
|
get totalClaudeEquivalent() {
|
|
1521
|
-
return this.turns.reduce((sum,
|
|
3400
|
+
return this.turns.reduce((sum, t2) => sum + claudeEquivalentCost(t2.usage), 0);
|
|
1522
3401
|
}
|
|
1523
3402
|
get savingsVsClaude() {
|
|
1524
3403
|
const c = this.totalClaudeEquivalent;
|
|
1525
3404
|
return c > 0 ? 1 - this.totalCost / c : 0;
|
|
1526
3405
|
}
|
|
1527
3406
|
get totalInputCost() {
|
|
1528
|
-
return this.turns.reduce((sum,
|
|
3407
|
+
return this.turns.reduce((sum, t2) => sum + inputCostUsd(t2.model, t2.usage), 0);
|
|
1529
3408
|
}
|
|
1530
3409
|
get totalOutputCost() {
|
|
1531
|
-
return this.turns.reduce((sum,
|
|
3410
|
+
return this.turns.reduce((sum, t2) => sum + outputCostUsd(t2.model, t2.usage), 0);
|
|
1532
3411
|
}
|
|
1533
3412
|
get aggregateCacheHitRatio() {
|
|
1534
3413
|
let hit = this._carryoverCacheHit;
|
|
1535
3414
|
let miss = this._carryoverCacheMiss;
|
|
1536
|
-
for (const
|
|
1537
|
-
hit +=
|
|
1538
|
-
miss +=
|
|
3415
|
+
for (const t2 of this.turns) {
|
|
3416
|
+
hit += t2.usage.promptCacheHitTokens;
|
|
3417
|
+
miss += t2.usage.promptCacheMissTokens;
|
|
1539
3418
|
}
|
|
1540
3419
|
const denom = hit + miss;
|
|
1541
3420
|
return denom > 0 ? hit / denom : 0;
|
|
@@ -1711,51 +3590,58 @@ function summarizeBranch(chosen, samples) {
|
|
|
1711
3590
|
}
|
|
1712
3591
|
|
|
1713
3592
|
// src/loop/errors.ts
|
|
1714
|
-
function formatLoopError(err) {
|
|
3593
|
+
function formatLoopError(err, probe) {
|
|
1715
3594
|
const msg = err.message ?? "";
|
|
1716
3595
|
if (msg.includes("maximum context length")) {
|
|
1717
3596
|
const reqMatch = msg.match(/requested\s+(\d+)\s+tokens/);
|
|
1718
|
-
const requested = reqMatch ? `${Number(reqMatch[1]).toLocaleString()} tokens` : "
|
|
1719
|
-
return
|
|
3597
|
+
const requested = reqMatch ? `${Number(reqMatch[1]).toLocaleString()} tokens` : t("errors.contextOverflowTooMany");
|
|
3598
|
+
return t("errors.contextOverflow", { requested });
|
|
1720
3599
|
}
|
|
1721
3600
|
const m = /^DeepSeek (\d{3}):\s*([\s\S]*)$/.exec(msg);
|
|
1722
3601
|
if (!m) return msg;
|
|
1723
3602
|
const status = m[1] ?? "";
|
|
1724
3603
|
const body = m[2] ?? "";
|
|
1725
3604
|
const inner = extractDeepSeekErrorMessage(body);
|
|
1726
|
-
if (status === "401") {
|
|
1727
|
-
|
|
1728
|
-
}
|
|
1729
|
-
if (status === "
|
|
1730
|
-
|
|
1731
|
-
}
|
|
1732
|
-
if (status === "422") {
|
|
1733
|
-
return `Invalid parameter (DeepSeek 422): ${inner}`;
|
|
1734
|
-
}
|
|
1735
|
-
if (status === "400") {
|
|
1736
|
-
return `Bad request (DeepSeek 400): ${inner}`;
|
|
1737
|
-
}
|
|
3605
|
+
if (status === "401") return t("errors.auth401", { inner });
|
|
3606
|
+
if (status === "402") return t("errors.balance402", { inner });
|
|
3607
|
+
if (status === "422") return t("errors.badparam422", { inner });
|
|
3608
|
+
if (status === "400") return t("errors.badrequest400", { inner });
|
|
3609
|
+
if (is5xxStatus(status)) return formatDeepSeek5xx(status, probe);
|
|
1738
3610
|
return msg;
|
|
1739
3611
|
}
|
|
3612
|
+
function is5xxError(err) {
|
|
3613
|
+
if (!(err instanceof Error)) return false;
|
|
3614
|
+
const m = /^DeepSeek (5\d{2}):/.exec(err.message ?? "");
|
|
3615
|
+
return m !== null;
|
|
3616
|
+
}
|
|
3617
|
+
async function probeDeepSeekReachable(client, timeoutMs = 1500) {
|
|
3618
|
+
const balance = await client.getBalance({ signal: AbortSignal.timeout(timeoutMs) });
|
|
3619
|
+
return { reachable: balance !== null };
|
|
3620
|
+
}
|
|
3621
|
+
function is5xxStatus(status) {
|
|
3622
|
+
return status === "500" || status === "502" || status === "503" || status === "504";
|
|
3623
|
+
}
|
|
3624
|
+
function formatDeepSeek5xx(status, probe) {
|
|
3625
|
+
const head = t("errors.deepseek5xxHead", { status });
|
|
3626
|
+
const probeNote = probe === void 0 ? "" : probe.reachable ? t("errors.deepseek5xxReachable") : t("errors.deepseek5xxUnreachable");
|
|
3627
|
+
const action = probe?.reachable === false ? t("errors.deepseek5xxActionNetwork") : t("errors.deepseek5xxActionRetry");
|
|
3628
|
+
return `${head}${probeNote}${action}`;
|
|
3629
|
+
}
|
|
1740
3630
|
function reasonPrefixFor(reason, iterCap) {
|
|
1741
|
-
if (reason === "aborted") return "
|
|
1742
|
-
if (reason === "context-guard")
|
|
1743
|
-
|
|
1744
|
-
}
|
|
1745
|
-
if (reason === "stuck") {
|
|
1746
|
-
return "[stuck on a repeated tool call \u2014 explaining what was tried and what's blocking progress]";
|
|
1747
|
-
}
|
|
1748
|
-
return `[tool-call budget (${iterCap}) reached \u2014 forcing summary from what I found]`;
|
|
3631
|
+
if (reason === "aborted") return t("errors.reasonAborted");
|
|
3632
|
+
if (reason === "context-guard") return t("errors.reasonContextGuard");
|
|
3633
|
+
if (reason === "stuck") return t("errors.reasonStuck");
|
|
3634
|
+
return t("errors.reasonBudget", { iterCap });
|
|
1749
3635
|
}
|
|
1750
3636
|
function errorLabelFor(reason, iterCap) {
|
|
1751
|
-
if (reason === "aborted") return "
|
|
1752
|
-
if (reason === "context-guard") return "
|
|
1753
|
-
if (reason === "stuck") return "
|
|
1754
|
-
return
|
|
3637
|
+
if (reason === "aborted") return t("errors.labelAborted");
|
|
3638
|
+
if (reason === "context-guard") return t("errors.labelContextGuard");
|
|
3639
|
+
if (reason === "stuck") return t("errors.labelStuck");
|
|
3640
|
+
return t("errors.labelBudget", { iterCap });
|
|
1755
3641
|
}
|
|
1756
3642
|
function extractDeepSeekErrorMessage(body) {
|
|
1757
3643
|
const trimmed = body.trim();
|
|
1758
|
-
if (!trimmed) return "
|
|
3644
|
+
if (!trimmed) return t("errors.innerNoMessage");
|
|
1759
3645
|
try {
|
|
1760
3646
|
const parsed = JSON.parse(trimmed);
|
|
1761
3647
|
if (parsed && typeof parsed === "object") {
|
|
@@ -1782,13 +3668,13 @@ function isEscalationRequest(content) {
|
|
|
1782
3668
|
return parseEscalationMarker(content).matched;
|
|
1783
3669
|
}
|
|
1784
3670
|
function looksLikePartialEscalationMarker(buf) {
|
|
1785
|
-
const
|
|
1786
|
-
if (
|
|
1787
|
-
if (
|
|
1788
|
-
return NEEDS_PRO_MARKER_PREFIX.startsWith(
|
|
3671
|
+
const t2 = buf.trimStart();
|
|
3672
|
+
if (t2.length === 0) return true;
|
|
3673
|
+
if (t2.length <= NEEDS_PRO_MARKER_PREFIX.length) {
|
|
3674
|
+
return NEEDS_PRO_MARKER_PREFIX.startsWith(t2);
|
|
1789
3675
|
}
|
|
1790
|
-
if (!
|
|
1791
|
-
const rest =
|
|
3676
|
+
if (!t2.startsWith(NEEDS_PRO_MARKER_PREFIX)) return false;
|
|
3677
|
+
const rest = t2.slice(NEEDS_PRO_MARKER_PREFIX.length);
|
|
1792
3678
|
if (rest[0] !== ">" && rest[0] !== ":") return false;
|
|
1793
3679
|
return true;
|
|
1794
3680
|
}
|
|
@@ -1830,7 +3716,7 @@ function buildSyntheticAssistantMessage(content, fallbackModel) {
|
|
|
1830
3716
|
// src/loop/force-summary.ts
|
|
1831
3717
|
async function* forceSummaryAfterIterLimit(ctx, opts = { reason: "budget" }) {
|
|
1832
3718
|
try {
|
|
1833
|
-
yield { turn: ctx.turn, role: "status", content: "
|
|
3719
|
+
yield { turn: ctx.turn, role: "status", content: t("summary.status") };
|
|
1834
3720
|
const messages = ctx.buildMessages();
|
|
1835
3721
|
messages.push({
|
|
1836
3722
|
role: "user",
|
|
@@ -1847,7 +3733,7 @@ async function* forceSummaryAfterIterLimit(ctx, opts = { reason: "budget" }) {
|
|
|
1847
3733
|
});
|
|
1848
3734
|
const rawContent = resp.content?.trim() ?? "";
|
|
1849
3735
|
const cleaned = stripHallucinatedToolMarkup(rawContent);
|
|
1850
|
-
const summary = cleaned || "
|
|
3736
|
+
const summary = cleaned || t("summary.hallucinatedFallback");
|
|
1851
3737
|
const reasonPrefix = reasonPrefixFor(opts.reason, ctx.maxToolIters);
|
|
1852
3738
|
const annotated = `${reasonPrefix}
|
|
1853
3739
|
|
|
@@ -1868,7 +3754,7 @@ ${summary}`;
|
|
|
1868
3754
|
turn: ctx.turn,
|
|
1869
3755
|
role: "error",
|
|
1870
3756
|
content: "",
|
|
1871
|
-
error:
|
|
3757
|
+
error: t("summary.failedAfterReason", { label, message: err.message })
|
|
1872
3758
|
};
|
|
1873
3759
|
yield { turn: ctx.turn, role: "done", content: "" };
|
|
1874
3760
|
}
|
|
@@ -2058,19 +3944,19 @@ var ImmutablePrefix = class {
|
|
|
2058
3944
|
return [{ role: "system", content: this.system }, ...this.fewShots.map((m) => ({ ...m }))];
|
|
2059
3945
|
}
|
|
2060
3946
|
tools() {
|
|
2061
|
-
return this._toolSpecs.map((
|
|
3947
|
+
return this._toolSpecs.map((t2) => structuredClone(t2));
|
|
2062
3948
|
}
|
|
2063
3949
|
addTool(spec) {
|
|
2064
3950
|
const name = spec.function?.name;
|
|
2065
3951
|
if (!name) return false;
|
|
2066
|
-
if (this._toolSpecs.some((
|
|
3952
|
+
if (this._toolSpecs.some((t2) => t2.function?.name === name)) return false;
|
|
2067
3953
|
this._toolSpecs.push(spec);
|
|
2068
3954
|
this._fingerprintCache = null;
|
|
2069
3955
|
return true;
|
|
2070
3956
|
}
|
|
2071
3957
|
/** Mirror of addTool for MCP hot-unbridge. Same cache-miss cost — prefix changes shape. */
|
|
2072
3958
|
removeTool(name) {
|
|
2073
|
-
const idx = this._toolSpecs.findIndex((
|
|
3959
|
+
const idx = this._toolSpecs.findIndex((t2) => t2.function?.name === name);
|
|
2074
3960
|
if (idx < 0) return false;
|
|
2075
3961
|
this._toolSpecs.splice(idx, 1);
|
|
2076
3962
|
this._fingerprintCache = null;
|
|
@@ -2282,15 +4168,18 @@ var StormBreaker = class {
|
|
|
2282
4168
|
windowSize;
|
|
2283
4169
|
threshold;
|
|
2284
4170
|
isMutating;
|
|
4171
|
+
isStormExempt;
|
|
2285
4172
|
recent = [];
|
|
2286
|
-
constructor(windowSize = 6, threshold = 3, isMutating) {
|
|
4173
|
+
constructor(windowSize = 6, threshold = 3, isMutating, isStormExempt) {
|
|
2287
4174
|
this.windowSize = windowSize;
|
|
2288
4175
|
this.threshold = threshold;
|
|
2289
4176
|
this.isMutating = isMutating;
|
|
4177
|
+
this.isStormExempt = isStormExempt;
|
|
2290
4178
|
}
|
|
2291
4179
|
inspect(call) {
|
|
2292
4180
|
const name = call.function?.name;
|
|
2293
4181
|
if (!name) return { suppress: false };
|
|
4182
|
+
if (this.isStormExempt?.(call)) return { suppress: false };
|
|
2294
4183
|
const args = call.function?.arguments ?? "";
|
|
2295
4184
|
const mutating = this.isMutating ? this.isMutating(call) : false;
|
|
2296
4185
|
const readOnly = !mutating;
|
|
@@ -2391,7 +4280,12 @@ var ToolCallRepair = class {
|
|
|
2391
4280
|
opts;
|
|
2392
4281
|
constructor(opts) {
|
|
2393
4282
|
this.opts = opts;
|
|
2394
|
-
this.storm = new StormBreaker(
|
|
4283
|
+
this.storm = new StormBreaker(
|
|
4284
|
+
opts.stormWindow ?? 6,
|
|
4285
|
+
opts.stormThreshold ?? 3,
|
|
4286
|
+
opts.isMutating,
|
|
4287
|
+
opts.isStormExempt
|
|
4288
|
+
);
|
|
2395
4289
|
}
|
|
2396
4290
|
/** Called at start of every user turn — fresh intent shouldn't inherit old repetition state. */
|
|
2397
4291
|
resetStorm() {
|
|
@@ -2534,9 +4428,15 @@ var CacheFirstLoop = class {
|
|
|
2534
4428
|
}
|
|
2535
4429
|
return def.readOnly !== true;
|
|
2536
4430
|
};
|
|
4431
|
+
const isStormExempt = (call) => {
|
|
4432
|
+
const name = call.function?.name;
|
|
4433
|
+
if (!name) return false;
|
|
4434
|
+
return registry.get(name)?.stormExempt === true;
|
|
4435
|
+
};
|
|
2537
4436
|
this.repair = new ToolCallRepair({
|
|
2538
4437
|
allowedToolNames: allowedNames,
|
|
2539
4438
|
isMutating,
|
|
4439
|
+
isStormExempt,
|
|
2540
4440
|
stormThreshold: parsePositiveIntEnv(process.env.REASONIX_STORM_THRESHOLD),
|
|
2541
4441
|
stormWindow: parsePositiveIntEnv(process.env.REASONIX_STORM_WINDOW)
|
|
2542
4442
|
});
|
|
@@ -2670,6 +4570,10 @@ var CacheFirstLoop = class {
|
|
|
2670
4570
|
get escalatedThisTurn() {
|
|
2671
4571
|
return this._escalateThisTurn;
|
|
2672
4572
|
}
|
|
4573
|
+
/** UI surface — model id of the call about to run (or running) right now, including escalation. */
|
|
4574
|
+
get currentCallModel() {
|
|
4575
|
+
return this.modelForCurrentCall();
|
|
4576
|
+
}
|
|
2673
4577
|
modelForCurrentCall() {
|
|
2674
4578
|
return this._escalateThisTurn ? ESCALATION_MODEL : this.model;
|
|
2675
4579
|
}
|
|
@@ -2762,7 +4666,10 @@ ${reason}`
|
|
|
2762
4666
|
turn: this._turn,
|
|
2763
4667
|
role: "error",
|
|
2764
4668
|
content: "",
|
|
2765
|
-
error:
|
|
4669
|
+
error: t("loop.budgetExhausted", {
|
|
4670
|
+
spent: spent.toFixed(4),
|
|
4671
|
+
cap: this.budgetUsd.toFixed(2)
|
|
4672
|
+
})
|
|
2766
4673
|
};
|
|
2767
4674
|
return;
|
|
2768
4675
|
}
|
|
@@ -2771,7 +4678,10 @@ ${reason}`
|
|
|
2771
4678
|
yield {
|
|
2772
4679
|
turn: this._turn,
|
|
2773
4680
|
role: "warning",
|
|
2774
|
-
content:
|
|
4681
|
+
content: t("loop.budget80Pct", {
|
|
4682
|
+
spent: spent.toFixed(4),
|
|
4683
|
+
cap: this.budgetUsd.toFixed(2)
|
|
4684
|
+
})
|
|
2775
4685
|
};
|
|
2776
4686
|
}
|
|
2777
4687
|
}
|
|
@@ -2796,7 +4706,7 @@ ${reason}`
|
|
|
2796
4706
|
yield {
|
|
2797
4707
|
turn: this._turn,
|
|
2798
4708
|
role: "warning",
|
|
2799
|
-
content: "
|
|
4709
|
+
content: t("loop.proArmed")
|
|
2800
4710
|
};
|
|
2801
4711
|
}
|
|
2802
4712
|
let pendingUser = userInput;
|
|
@@ -2808,7 +4718,7 @@ ${reason}`
|
|
|
2808
4718
|
yield {
|
|
2809
4719
|
turn: this._turn,
|
|
2810
4720
|
role: "warning",
|
|
2811
|
-
content:
|
|
4721
|
+
content: t("loop.abortedAtIter", { iter, cap: this.maxToolIters })
|
|
2812
4722
|
};
|
|
2813
4723
|
const stoppedMsg = "[aborted by user (Esc) \u2014 no summary produced. Ask again or /retry when ready; prior tool output is still in the log.]";
|
|
2814
4724
|
this.appendAndPersist(buildSyntheticAssistantMessage(stoppedMsg, this.model));
|
|
@@ -2826,7 +4736,7 @@ ${reason}`
|
|
|
2826
4736
|
yield {
|
|
2827
4737
|
turn: this._turn,
|
|
2828
4738
|
role: "status",
|
|
2829
|
-
content: "
|
|
4739
|
+
content: t("loop.toolUploadStatus")
|
|
2830
4740
|
};
|
|
2831
4741
|
}
|
|
2832
4742
|
if (!warnedForIterBudget && iter >= warnAt) {
|
|
@@ -2834,7 +4744,7 @@ ${reason}`
|
|
|
2834
4744
|
yield {
|
|
2835
4745
|
turn: this._turn,
|
|
2836
4746
|
role: "warning",
|
|
2837
|
-
content:
|
|
4747
|
+
content: t("loop.toolBudgetWarning", { iter, cap: this.maxToolIters })
|
|
2838
4748
|
};
|
|
2839
4749
|
}
|
|
2840
4750
|
let messages = this.buildMessages(pendingUser);
|
|
@@ -2845,25 +4755,32 @@ ${reason}`
|
|
|
2845
4755
|
yield {
|
|
2846
4756
|
turn: this._turn,
|
|
2847
4757
|
role: "status",
|
|
2848
|
-
content: "
|
|
4758
|
+
content: t("loop.preflightFoldStatus")
|
|
2849
4759
|
};
|
|
2850
4760
|
const result = await this.context.fold(this.model);
|
|
2851
4761
|
if (result.folded) {
|
|
2852
4762
|
yield {
|
|
2853
4763
|
turn: this._turn,
|
|
2854
4764
|
role: "warning",
|
|
2855
|
-
content:
|
|
2856
|
-
estimate
|
|
2857
|
-
|
|
4765
|
+
content: t("loop.preflightFolded", {
|
|
4766
|
+
estimate: estimate.toLocaleString(),
|
|
4767
|
+
ctxMax: ctxMax.toLocaleString(),
|
|
4768
|
+
pct: Math.round(estimate / ctxMax * 100),
|
|
4769
|
+
beforeMessages: result.beforeMessages,
|
|
4770
|
+
afterMessages: result.afterMessages,
|
|
4771
|
+
summaryChars: result.summaryChars
|
|
4772
|
+
})
|
|
2858
4773
|
};
|
|
2859
4774
|
messages = this.buildMessages(pendingUser);
|
|
2860
4775
|
} else {
|
|
2861
4776
|
yield {
|
|
2862
4777
|
turn: this._turn,
|
|
2863
4778
|
role: "warning",
|
|
2864
|
-
content:
|
|
2865
|
-
estimate
|
|
2866
|
-
|
|
4779
|
+
content: t("loop.preflightNoFold", {
|
|
4780
|
+
estimate: estimate.toLocaleString(),
|
|
4781
|
+
ctxMax: ctxMax.toLocaleString(),
|
|
4782
|
+
pct: Math.round(estimate / ctxMax * 100)
|
|
4783
|
+
})
|
|
2867
4784
|
};
|
|
2868
4785
|
}
|
|
2869
4786
|
}
|
|
@@ -3062,11 +4979,12 @@ ${reason}`
|
|
|
3062
4979
|
this._turnAbort = new AbortController();
|
|
3063
4980
|
return;
|
|
3064
4981
|
}
|
|
4982
|
+
const probe = is5xxError(err) ? await probeDeepSeekReachable(this.client) : void 0;
|
|
3065
4983
|
yield {
|
|
3066
4984
|
turn: this._turn,
|
|
3067
4985
|
role: "error",
|
|
3068
4986
|
content: "",
|
|
3069
|
-
error: formatLoopError(err)
|
|
4987
|
+
error: formatLoopError(err, probe)
|
|
3070
4988
|
};
|
|
3071
4989
|
return;
|
|
3072
4990
|
}
|
|
@@ -3077,7 +4995,7 @@ ${reason}`
|
|
|
3077
4995
|
yield {
|
|
3078
4996
|
turn: this._turn,
|
|
3079
4997
|
role: "warning",
|
|
3080
|
-
content:
|
|
4998
|
+
content: t("loop.flashEscalation", { model: ESCALATION_MODEL, reasonSuffix })
|
|
3081
4999
|
};
|
|
3082
5000
|
assistantContent = "";
|
|
3083
5001
|
reasoningContent = "";
|
|
@@ -3102,7 +5020,7 @@ ${reason}`
|
|
|
3102
5020
|
yield {
|
|
3103
5021
|
turn: this._turn,
|
|
3104
5022
|
role: "status",
|
|
3105
|
-
content: "
|
|
5023
|
+
content: t("loop.harvestStatus")
|
|
3106
5024
|
};
|
|
3107
5025
|
}
|
|
3108
5026
|
const planState = preHarvestedPlanState ? preHarvestedPlanState : this.harvestEnabled ? await harvest(reasoningContent || null, this.client, this.harvestOptions, signal) : emptyPlanState();
|
|
@@ -3132,7 +5050,11 @@ ${reason}`
|
|
|
3132
5050
|
yield {
|
|
3133
5051
|
turn: this._turn,
|
|
3134
5052
|
role: "warning",
|
|
3135
|
-
content:
|
|
5053
|
+
content: t("loop.autoEscalation", {
|
|
5054
|
+
model: ESCALATION_MODEL,
|
|
5055
|
+
breakdown: this._turnFailures.formatBreakdown(),
|
|
5056
|
+
fallback: this.model
|
|
5057
|
+
})
|
|
3136
5058
|
};
|
|
3137
5059
|
}
|
|
3138
5060
|
const allSuppressed = report.stormsBroken > 0 && repairedCalls.length === 0 && toolCalls.length > 0;
|
|
@@ -3157,13 +5079,13 @@ ${reason}`
|
|
|
3157
5079
|
yield {
|
|
3158
5080
|
turn: this._turn,
|
|
3159
5081
|
role: "warning",
|
|
3160
|
-
content: "
|
|
5082
|
+
content: t("loop.repeatToolCallWarning")
|
|
3161
5083
|
};
|
|
3162
5084
|
continue;
|
|
3163
5085
|
}
|
|
3164
5086
|
if (report.stormsBroken > 0) {
|
|
3165
5087
|
const noteTail = report.notes.length ? ` \u2014 ${report.notes[report.notes.length - 1]}` : "";
|
|
3166
|
-
const phrase = allSuppressed ? "
|
|
5088
|
+
const phrase = allSuppressed ? t("loop.stormStuck") : t("loop.stormSuppressed", { count: report.stormsBroken });
|
|
3167
5089
|
yield {
|
|
3168
5090
|
turn: this._turn,
|
|
3169
5091
|
role: "warning",
|
|
@@ -3183,20 +5105,28 @@ ${reason}`
|
|
|
3183
5105
|
this._foldedThisTurn = true;
|
|
3184
5106
|
const before = decision.promptTokens;
|
|
3185
5107
|
const ctxMax = decision.ctxMax;
|
|
3186
|
-
const aggressiveTag = decision.aggressive ? "
|
|
5108
|
+
const aggressiveTag = decision.aggressive ? t("loop.aggressiveTag") : "";
|
|
3187
5109
|
yield {
|
|
3188
5110
|
turn: this._turn,
|
|
3189
5111
|
role: "status",
|
|
3190
|
-
content:
|
|
5112
|
+
content: t("loop.compactingHistoryStatus", { aggressiveTag })
|
|
3191
5113
|
};
|
|
3192
5114
|
const result = await this.compactHistory({ keepRecentTokens: decision.tailBudget });
|
|
3193
5115
|
if (result.folded) {
|
|
3194
5116
|
yield {
|
|
3195
5117
|
turn: this._turn,
|
|
3196
5118
|
role: "warning",
|
|
3197
|
-
content:
|
|
3198
|
-
|
|
3199
|
-
|
|
5119
|
+
content: t(
|
|
5120
|
+
decision.aggressive ? "loop.aggressivelyFoldedHistory" : "loop.foldedHistory",
|
|
5121
|
+
{
|
|
5122
|
+
before: before.toLocaleString(),
|
|
5123
|
+
ctxMax: ctxMax.toLocaleString(),
|
|
5124
|
+
pct: Math.round(before / ctxMax * 100),
|
|
5125
|
+
beforeMessages: result.beforeMessages,
|
|
5126
|
+
afterMessages: result.afterMessages,
|
|
5127
|
+
summaryChars: result.summaryChars
|
|
5128
|
+
}
|
|
5129
|
+
)
|
|
3200
5130
|
};
|
|
3201
5131
|
}
|
|
3202
5132
|
} else if (decision.kind === "exit-with-summary") {
|
|
@@ -3205,9 +5135,11 @@ ${reason}`
|
|
|
3205
5135
|
yield {
|
|
3206
5136
|
turn: this._turn,
|
|
3207
5137
|
role: "warning",
|
|
3208
|
-
content:
|
|
3209
|
-
before
|
|
3210
|
-
|
|
5138
|
+
content: t("loop.forcingSummary", {
|
|
5139
|
+
before: before.toLocaleString(),
|
|
5140
|
+
ctxMax: ctxMax.toLocaleString(),
|
|
5141
|
+
pct: Math.round(before / ctxMax * 100)
|
|
5142
|
+
})
|
|
3211
5143
|
};
|
|
3212
5144
|
this.context.trimTrailingToolCalls();
|
|
3213
5145
|
yield* forceSummaryAfterIterLimit(this.summaryContext(), { reason: "context-guard" });
|
|
@@ -3265,7 +5197,11 @@ ${reason}`
|
|
|
3265
5197
|
yield {
|
|
3266
5198
|
turn: this._turn,
|
|
3267
5199
|
role: "warning",
|
|
3268
|
-
content:
|
|
5200
|
+
content: t("loop.autoEscalation", {
|
|
5201
|
+
model: ESCALATION_MODEL,
|
|
5202
|
+
breakdown: this._turnFailures.formatBreakdown(),
|
|
5203
|
+
fallback: this.model
|
|
5204
|
+
})
|
|
3269
5205
|
};
|
|
3270
5206
|
}
|
|
3271
5207
|
yield {
|
|
@@ -3308,12 +5244,12 @@ function parsePositiveIntEnv(raw) {
|
|
|
3308
5244
|
}
|
|
3309
5245
|
|
|
3310
5246
|
// src/at-mentions.ts
|
|
3311
|
-
import { existsSync as existsSync4, readFileSync as
|
|
5247
|
+
import { existsSync as existsSync4, readFileSync as readFileSync6, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
3312
5248
|
import { readdir, stat } from "fs/promises";
|
|
3313
|
-
import { isAbsolute, join as
|
|
5249
|
+
import { isAbsolute, join as join5, relative, resolve } from "path";
|
|
3314
5250
|
|
|
3315
5251
|
// src/gitignore.ts
|
|
3316
|
-
import { readFileSync as
|
|
5252
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
3317
5253
|
import { readFile } from "fs/promises";
|
|
3318
5254
|
import path from "path";
|
|
3319
5255
|
import ignore from "ignore";
|
|
@@ -3326,7 +5262,7 @@ async function loadGitignoreAt(dirAbs) {
|
|
|
3326
5262
|
}
|
|
3327
5263
|
function loadGitignoreAtSync(dirAbs) {
|
|
3328
5264
|
try {
|
|
3329
|
-
return ignore().add(
|
|
5265
|
+
return ignore().add(readFileSync5(path.join(dirAbs, ".gitignore"), "utf8"));
|
|
3330
5266
|
} catch {
|
|
3331
5267
|
return null;
|
|
3332
5268
|
}
|
|
@@ -3384,7 +5320,7 @@ function listFilesWithStatsSync(root, opts = {}) {
|
|
|
3384
5320
|
for (const ent of entries) {
|
|
3385
5321
|
if (out.length >= maxResults) return;
|
|
3386
5322
|
const relPath = dirRel ? `${dirRel}/${ent.name}` : ent.name;
|
|
3387
|
-
const absPath =
|
|
5323
|
+
const absPath = join5(dirAbs, ent.name);
|
|
3388
5324
|
if (ent.isDirectory()) {
|
|
3389
5325
|
if (ent.name.startsWith(".") || ignoreDirs.has(ent.name)) continue;
|
|
3390
5326
|
if (ignoredByLayers(effectiveLayers, absPath, true)) continue;
|
|
@@ -3427,7 +5363,7 @@ async function listFilesWithStatsAsync(root, opts = {}) {
|
|
|
3427
5363
|
for (const ent of entries) {
|
|
3428
5364
|
if (out.length >= maxResults) break;
|
|
3429
5365
|
const relPath = dirRel ? `${dirRel}/${ent.name}` : ent.name;
|
|
3430
|
-
const absPath =
|
|
5366
|
+
const absPath = join5(dirAbs, ent.name);
|
|
3431
5367
|
if (ent.isDirectory()) {
|
|
3432
5368
|
if (ent.name.startsWith(".") || ignoreDirs.has(ent.name)) continue;
|
|
3433
5369
|
if (ignoredByLayers(effectiveLayers, absPath, true)) continue;
|
|
@@ -3452,12 +5388,12 @@ async function statBatch(ents, dirAbs, dirRel, out, maxResults, layers) {
|
|
|
3452
5388
|
const accepted = [];
|
|
3453
5389
|
for (const e of ents) {
|
|
3454
5390
|
if (out.length + accepted.length >= maxResults) break;
|
|
3455
|
-
if (ignoredByLayers(layers,
|
|
5391
|
+
if (ignoredByLayers(layers, join5(dirAbs, e.name), false)) continue;
|
|
3456
5392
|
accepted.push(e);
|
|
3457
5393
|
}
|
|
3458
5394
|
const stats = await Promise.all(
|
|
3459
5395
|
accepted.map(
|
|
3460
|
-
(e) => stat(
|
|
5396
|
+
(e) => stat(join5(dirAbs, e.name)).then((s) => s.mtimeMs).catch(() => 0)
|
|
3461
5397
|
)
|
|
3462
5398
|
);
|
|
3463
5399
|
for (let i = 0; i < accepted.length; i++) {
|
|
@@ -3603,20 +5539,20 @@ var defaultFs = {
|
|
|
3603
5539
|
return 0;
|
|
3604
5540
|
}
|
|
3605
5541
|
},
|
|
3606
|
-
read: (p) =>
|
|
5542
|
+
read: (p) => readFileSync6(p, "utf8")
|
|
3607
5543
|
};
|
|
3608
5544
|
|
|
3609
5545
|
// src/memory/project.ts
|
|
3610
|
-
import { existsSync as existsSync5, readFileSync as
|
|
3611
|
-
import { join as
|
|
5546
|
+
import { existsSync as existsSync5, readFileSync as readFileSync7 } from "fs";
|
|
5547
|
+
import { join as join6 } from "path";
|
|
3612
5548
|
var PROJECT_MEMORY_FILE = "REASONIX.md";
|
|
3613
5549
|
var PROJECT_MEMORY_MAX_CHARS = 8e3;
|
|
3614
5550
|
function readProjectMemory(rootDir) {
|
|
3615
|
-
const path2 =
|
|
5551
|
+
const path2 = join6(rootDir, PROJECT_MEMORY_FILE);
|
|
3616
5552
|
if (!existsSync5(path2)) return null;
|
|
3617
5553
|
let raw;
|
|
3618
5554
|
try {
|
|
3619
|
-
raw =
|
|
5555
|
+
raw = readFileSync7(path2, "utf8");
|
|
3620
5556
|
} catch {
|
|
3621
5557
|
return null;
|
|
3622
5558
|
}
|
|
@@ -3653,19 +5589,19 @@ ${mem.content}
|
|
|
3653
5589
|
import { createHash as createHash2 } from "crypto";
|
|
3654
5590
|
import {
|
|
3655
5591
|
existsSync as existsSync7,
|
|
3656
|
-
mkdirSync as
|
|
3657
|
-
readFileSync as
|
|
5592
|
+
mkdirSync as mkdirSync4,
|
|
5593
|
+
readFileSync as readFileSync9,
|
|
3658
5594
|
readdirSync as readdirSync4,
|
|
3659
5595
|
unlinkSync as unlinkSync2,
|
|
3660
|
-
writeFileSync as
|
|
5596
|
+
writeFileSync as writeFileSync4
|
|
3661
5597
|
} from "fs";
|
|
3662
|
-
import { homedir as
|
|
3663
|
-
import { join as
|
|
5598
|
+
import { homedir as homedir5 } from "os";
|
|
5599
|
+
import { join as join8, resolve as resolve3 } from "path";
|
|
3664
5600
|
|
|
3665
5601
|
// src/skills.ts
|
|
3666
|
-
import { existsSync as existsSync6, readFileSync as
|
|
3667
|
-
import { homedir as
|
|
3668
|
-
import { join as
|
|
5602
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync8, readdirSync as readdirSync3, statSync as statSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
5603
|
+
import { homedir as homedir4 } from "os";
|
|
5604
|
+
import { dirname as dirname4, join as join7, resolve as resolve2 } from "path";
|
|
3669
5605
|
|
|
3670
5606
|
// src/prompt-fragments.ts
|
|
3671
5607
|
var TUI_FORMATTING_RULES = `Formatting (rendered in a TUI with a real markdown renderer):
|
|
@@ -3726,7 +5662,7 @@ var SkillStore = class {
|
|
|
3726
5662
|
projectRoot;
|
|
3727
5663
|
disableBuiltins;
|
|
3728
5664
|
constructor(opts = {}) {
|
|
3729
|
-
this.homeDir = opts.homeDir ??
|
|
5665
|
+
this.homeDir = opts.homeDir ?? homedir4();
|
|
3730
5666
|
this.projectRoot = opts.projectRoot ? resolve2(opts.projectRoot) : void 0;
|
|
3731
5667
|
this.disableBuiltins = opts.disableBuiltins === true;
|
|
3732
5668
|
}
|
|
@@ -3739,11 +5675,11 @@ var SkillStore = class {
|
|
|
3739
5675
|
const out = [];
|
|
3740
5676
|
if (this.projectRoot) {
|
|
3741
5677
|
out.push({
|
|
3742
|
-
dir:
|
|
5678
|
+
dir: join7(this.projectRoot, ".reasonix", SKILLS_DIRNAME),
|
|
3743
5679
|
scope: "project"
|
|
3744
5680
|
});
|
|
3745
5681
|
}
|
|
3746
|
-
out.push({ dir:
|
|
5682
|
+
out.push({ dir: join7(this.homeDir, ".reasonix", SKILLS_DIRNAME), scope: "global" });
|
|
3747
5683
|
return out;
|
|
3748
5684
|
}
|
|
3749
5685
|
/** Higher-priority root wins on collision (project > global > builtin); sorted for stable prefix hash. */
|
|
@@ -3770,16 +5706,41 @@ var SkillStore = class {
|
|
|
3770
5706
|
}
|
|
3771
5707
|
return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
3772
5708
|
}
|
|
5709
|
+
/** Scaffold a new skill stub at the chosen scope. Refuses to overwrite. */
|
|
5710
|
+
create(name, scope) {
|
|
5711
|
+
if (!isValidSkillName(name)) {
|
|
5712
|
+
return { error: `invalid skill name: "${name}" \u2014 use letters, digits, _, -, .` };
|
|
5713
|
+
}
|
|
5714
|
+
if (scope === "project" && !this.projectRoot) {
|
|
5715
|
+
return { error: "project scope requires a workspace \u2014 run from `reasonix code`" };
|
|
5716
|
+
}
|
|
5717
|
+
const root = scope === "project" ? join7(this.projectRoot ?? "", ".reasonix", SKILLS_DIRNAME) : join7(this.homeDir, ".reasonix", SKILLS_DIRNAME);
|
|
5718
|
+
const flat = join7(root, `${name}.md`);
|
|
5719
|
+
const folder = join7(root, name, SKILL_FILE);
|
|
5720
|
+
if (existsSync6(folder)) {
|
|
5721
|
+
return { error: `skill "${name}" already exists at ${folder}` };
|
|
5722
|
+
}
|
|
5723
|
+
mkdirSync3(dirname4(flat), { recursive: true });
|
|
5724
|
+
try {
|
|
5725
|
+
writeFileSync3(flat, skillStubBody(name), { encoding: "utf8", flag: "wx" });
|
|
5726
|
+
} catch (err) {
|
|
5727
|
+
if (err.code === "EEXIST") {
|
|
5728
|
+
return { error: `skill "${name}" already exists at ${flat}` };
|
|
5729
|
+
}
|
|
5730
|
+
throw err;
|
|
5731
|
+
}
|
|
5732
|
+
return { path: flat };
|
|
5733
|
+
}
|
|
3773
5734
|
/** Resolve one skill by name. Returns `null` if not found or malformed. */
|
|
3774
5735
|
read(name) {
|
|
3775
5736
|
if (!isValidSkillName(name)) return null;
|
|
3776
5737
|
for (const { dir, scope } of this.roots()) {
|
|
3777
5738
|
if (!existsSync6(dir)) continue;
|
|
3778
|
-
const dirCandidate =
|
|
5739
|
+
const dirCandidate = join7(dir, name, SKILL_FILE);
|
|
3779
5740
|
if (existsSync6(dirCandidate) && statSync3(dirCandidate).isFile()) {
|
|
3780
5741
|
return this.parse(dirCandidate, name, scope);
|
|
3781
5742
|
}
|
|
3782
|
-
const flatCandidate =
|
|
5743
|
+
const flatCandidate = join7(dir, `${name}.md`);
|
|
3783
5744
|
if (existsSync6(flatCandidate) && statSync3(flatCandidate).isFile()) {
|
|
3784
5745
|
return this.parse(flatCandidate, name, scope);
|
|
3785
5746
|
}
|
|
@@ -3794,21 +5755,21 @@ var SkillStore = class {
|
|
|
3794
5755
|
readEntry(dir, scope, entry) {
|
|
3795
5756
|
if (entry.isDirectory()) {
|
|
3796
5757
|
if (!isValidSkillName(entry.name)) return null;
|
|
3797
|
-
const file =
|
|
5758
|
+
const file = join7(dir, entry.name, SKILL_FILE);
|
|
3798
5759
|
if (!existsSync6(file)) return null;
|
|
3799
5760
|
return this.parse(file, entry.name, scope);
|
|
3800
5761
|
}
|
|
3801
5762
|
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
3802
5763
|
const stem = entry.name.slice(0, -3);
|
|
3803
5764
|
if (!isValidSkillName(stem)) return null;
|
|
3804
|
-
return this.parse(
|
|
5765
|
+
return this.parse(join7(dir, entry.name), stem, scope);
|
|
3805
5766
|
}
|
|
3806
5767
|
return null;
|
|
3807
5768
|
}
|
|
3808
5769
|
parse(path2, stem, scope) {
|
|
3809
5770
|
let raw;
|
|
3810
5771
|
try {
|
|
3811
|
-
raw =
|
|
5772
|
+
raw = readFileSync8(path2, "utf8");
|
|
3812
5773
|
} catch {
|
|
3813
5774
|
return null;
|
|
3814
5775
|
}
|
|
@@ -3829,6 +5790,22 @@ var SkillStore = class {
|
|
|
3829
5790
|
function parseRunAs(raw) {
|
|
3830
5791
|
return raw?.trim() === "subagent" ? "subagent" : "inline";
|
|
3831
5792
|
}
|
|
5793
|
+
function skillStubBody(name) {
|
|
5794
|
+
return `---
|
|
5795
|
+
name: ${name}
|
|
5796
|
+
description: One-liner \u2014 what does this skill do?
|
|
5797
|
+
---
|
|
5798
|
+
|
|
5799
|
+
# ${name}
|
|
5800
|
+
|
|
5801
|
+
Replace this body with the playbook the model should follow when this skill is invoked.
|
|
5802
|
+
|
|
5803
|
+
Tips:
|
|
5804
|
+
- Reference tools by name (run_command, edit_file, search_content, ...)
|
|
5805
|
+
- Add \`runAs: subagent\` to frontmatter to spawn an isolated subagent loop
|
|
5806
|
+
- Add \`allowed-tools: read_file, search_content\` to scope a subagent's tools
|
|
5807
|
+
`;
|
|
5808
|
+
}
|
|
3832
5809
|
function skillIndexLine(s) {
|
|
3833
5810
|
const safeDesc = s.description.replace(/\n/g, " ").trim();
|
|
3834
5811
|
const tag = s.runAs === "subagent" ? " [\u{1F9EC} subagent]" : "";
|
|
@@ -4063,15 +6040,15 @@ function projectHash(rootDir) {
|
|
|
4063
6040
|
}
|
|
4064
6041
|
function scopeDir(opts) {
|
|
4065
6042
|
if (opts.scope === "global") {
|
|
4066
|
-
return
|
|
6043
|
+
return join8(opts.homeDir, USER_MEMORY_DIR, "global");
|
|
4067
6044
|
}
|
|
4068
6045
|
if (!opts.projectRoot) {
|
|
4069
6046
|
throw new Error("scope=project requires a projectRoot on MemoryStore");
|
|
4070
6047
|
}
|
|
4071
|
-
return
|
|
6048
|
+
return join8(opts.homeDir, USER_MEMORY_DIR, projectHash(opts.projectRoot));
|
|
4072
6049
|
}
|
|
4073
6050
|
function ensureDir(p) {
|
|
4074
|
-
if (!existsSync7(p))
|
|
6051
|
+
if (!existsSync7(p)) mkdirSync4(p, { recursive: true });
|
|
4075
6052
|
}
|
|
4076
6053
|
function parseFrontmatter2(raw) {
|
|
4077
6054
|
const lines = raw.split(/\r?\n/);
|
|
@@ -4116,7 +6093,7 @@ var MemoryStore = class {
|
|
|
4116
6093
|
homeDir;
|
|
4117
6094
|
projectRoot;
|
|
4118
6095
|
constructor(opts = {}) {
|
|
4119
|
-
this.homeDir = opts.homeDir ??
|
|
6096
|
+
this.homeDir = opts.homeDir ?? join8(homedir5(), ".reasonix");
|
|
4120
6097
|
this.projectRoot = opts.projectRoot ? resolve3(opts.projectRoot) : void 0;
|
|
4121
6098
|
}
|
|
4122
6099
|
/** Directory this store writes `scope` files into, creating it if needed. */
|
|
@@ -4127,7 +6104,7 @@ var MemoryStore = class {
|
|
|
4127
6104
|
}
|
|
4128
6105
|
/** Absolute path to a memory file (no existence check). */
|
|
4129
6106
|
pathFor(scope, name) {
|
|
4130
|
-
return
|
|
6107
|
+
return join8(this.dir(scope), `${sanitizeMemoryName(name)}.md`);
|
|
4131
6108
|
}
|
|
4132
6109
|
/** True iff this store is configured with a project scope available. */
|
|
4133
6110
|
hasProjectScope() {
|
|
@@ -4135,14 +6112,14 @@ var MemoryStore = class {
|
|
|
4135
6112
|
}
|
|
4136
6113
|
loadIndex(scope) {
|
|
4137
6114
|
if (scope === "project" && !this.projectRoot) return null;
|
|
4138
|
-
const file =
|
|
6115
|
+
const file = join8(
|
|
4139
6116
|
scopeDir({ homeDir: this.homeDir, scope, projectRoot: this.projectRoot }),
|
|
4140
6117
|
MEMORY_INDEX_FILE
|
|
4141
6118
|
);
|
|
4142
6119
|
if (!existsSync7(file)) return null;
|
|
4143
6120
|
let raw;
|
|
4144
6121
|
try {
|
|
4145
|
-
raw =
|
|
6122
|
+
raw = readFileSync9(file, "utf8");
|
|
4146
6123
|
} catch {
|
|
4147
6124
|
return null;
|
|
4148
6125
|
}
|
|
@@ -4160,7 +6137,7 @@ var MemoryStore = class {
|
|
|
4160
6137
|
if (!existsSync7(file)) {
|
|
4161
6138
|
throw new Error(`memory not found: scope=${scope} name=${name}`);
|
|
4162
6139
|
}
|
|
4163
|
-
const raw =
|
|
6140
|
+
const raw = readFileSync9(file, "utf8");
|
|
4164
6141
|
const { data, body } = parseFrontmatter2(raw);
|
|
4165
6142
|
return {
|
|
4166
6143
|
name: data.name ?? name,
|
|
@@ -4213,10 +6190,10 @@ var MemoryStore = class {
|
|
|
4213
6190
|
createdAt: todayIso()
|
|
4214
6191
|
};
|
|
4215
6192
|
const dir = this.dir(input.scope);
|
|
4216
|
-
const file =
|
|
6193
|
+
const file = join8(dir, `${name}.md`);
|
|
4217
6194
|
const content = `${formatFrontmatter(entry)}${body}
|
|
4218
6195
|
`;
|
|
4219
|
-
|
|
6196
|
+
writeFileSync4(file, content, "utf8");
|
|
4220
6197
|
this.regenerateIndex(input.scope);
|
|
4221
6198
|
return file;
|
|
4222
6199
|
}
|
|
@@ -4242,7 +6219,7 @@ var MemoryStore = class {
|
|
|
4242
6219
|
return;
|
|
4243
6220
|
}
|
|
4244
6221
|
const mdFiles = files.filter((f) => f !== MEMORY_INDEX_FILE && f.endsWith(".md")).sort((a, b) => a.localeCompare(b));
|
|
4245
|
-
const indexPath =
|
|
6222
|
+
const indexPath = join8(dir, MEMORY_INDEX_FILE);
|
|
4246
6223
|
if (mdFiles.length === 0) {
|
|
4247
6224
|
if (existsSync7(indexPath)) unlinkSync2(indexPath);
|
|
4248
6225
|
return;
|
|
@@ -4257,16 +6234,16 @@ var MemoryStore = class {
|
|
|
4257
6234
|
lines.push(`- [${name}](${name}.md) \u2014 (malformed, check frontmatter)`);
|
|
4258
6235
|
}
|
|
4259
6236
|
}
|
|
4260
|
-
|
|
6237
|
+
writeFileSync4(indexPath, `${lines.join("\n")}
|
|
4261
6238
|
`, "utf8");
|
|
4262
6239
|
}
|
|
4263
6240
|
};
|
|
4264
|
-
function readGlobalReasonixMemory(homeDir =
|
|
4265
|
-
const path2 =
|
|
6241
|
+
function readGlobalReasonixMemory(homeDir = join8(homedir5(), ".reasonix")) {
|
|
6242
|
+
const path2 = join8(homeDir, "REASONIX.md");
|
|
4266
6243
|
if (!existsSync7(path2)) return null;
|
|
4267
6244
|
let raw;
|
|
4268
6245
|
try {
|
|
4269
|
-
raw =
|
|
6246
|
+
raw = readFileSync9(path2, "utf8");
|
|
4270
6247
|
} catch {
|
|
4271
6248
|
return null;
|
|
4272
6249
|
}
|
|
@@ -4280,7 +6257,7 @@ function readGlobalReasonixMemory(homeDir = join7(homedir4(), ".reasonix")) {
|
|
|
4280
6257
|
}
|
|
4281
6258
|
function applyGlobalReasonixMemory(basePrompt, homeDir) {
|
|
4282
6259
|
if (!memoryEnabled()) return basePrompt;
|
|
4283
|
-
const dir = homeDir ??
|
|
6260
|
+
const dir = homeDir ?? join8(homedir5(), ".reasonix");
|
|
4284
6261
|
const mem = readGlobalReasonixMemory(dir);
|
|
4285
6262
|
if (!mem) return basePrompt;
|
|
4286
6263
|
return [
|
|
@@ -4340,91 +6317,6 @@ import { promises as fs3 } from "fs";
|
|
|
4340
6317
|
import * as pathMod3 from "path";
|
|
4341
6318
|
import picomatch2 from "picomatch";
|
|
4342
6319
|
|
|
4343
|
-
// src/index/config.ts
|
|
4344
|
-
import picomatch from "picomatch";
|
|
4345
|
-
var DEFAULT_INDEX_EXCLUDES = {
|
|
4346
|
-
dirs: [
|
|
4347
|
-
"node_modules",
|
|
4348
|
-
".git",
|
|
4349
|
-
".hg",
|
|
4350
|
-
".svn",
|
|
4351
|
-
"dist",
|
|
4352
|
-
"build",
|
|
4353
|
-
"out",
|
|
4354
|
-
".next",
|
|
4355
|
-
".nuxt",
|
|
4356
|
-
"target",
|
|
4357
|
-
".venv",
|
|
4358
|
-
"venv",
|
|
4359
|
-
"__pycache__",
|
|
4360
|
-
".pytest_cache",
|
|
4361
|
-
".mypy_cache",
|
|
4362
|
-
".cache",
|
|
4363
|
-
"coverage",
|
|
4364
|
-
".turbo",
|
|
4365
|
-
".vercel",
|
|
4366
|
-
".reasonix"
|
|
4367
|
-
],
|
|
4368
|
-
files: [
|
|
4369
|
-
"package-lock.json",
|
|
4370
|
-
"yarn.lock",
|
|
4371
|
-
"pnpm-lock.yaml",
|
|
4372
|
-
"Cargo.lock",
|
|
4373
|
-
"poetry.lock",
|
|
4374
|
-
"Pipfile.lock",
|
|
4375
|
-
"go.sum",
|
|
4376
|
-
".DS_Store"
|
|
4377
|
-
],
|
|
4378
|
-
exts: [
|
|
4379
|
-
".png",
|
|
4380
|
-
".jpg",
|
|
4381
|
-
".jpeg",
|
|
4382
|
-
".gif",
|
|
4383
|
-
".webp",
|
|
4384
|
-
".bmp",
|
|
4385
|
-
".ico",
|
|
4386
|
-
".tiff",
|
|
4387
|
-
".woff",
|
|
4388
|
-
".woff2",
|
|
4389
|
-
".ttf",
|
|
4390
|
-
".otf",
|
|
4391
|
-
".eot",
|
|
4392
|
-
".zip",
|
|
4393
|
-
".tar",
|
|
4394
|
-
".gz",
|
|
4395
|
-
".bz2",
|
|
4396
|
-
".xz",
|
|
4397
|
-
".rar",
|
|
4398
|
-
".7z",
|
|
4399
|
-
".exe",
|
|
4400
|
-
".dll",
|
|
4401
|
-
".so",
|
|
4402
|
-
".dylib",
|
|
4403
|
-
".bin",
|
|
4404
|
-
".class",
|
|
4405
|
-
".jar",
|
|
4406
|
-
".war",
|
|
4407
|
-
".wasm",
|
|
4408
|
-
".o",
|
|
4409
|
-
".obj",
|
|
4410
|
-
".lib",
|
|
4411
|
-
".a",
|
|
4412
|
-
".pyc",
|
|
4413
|
-
".pyo",
|
|
4414
|
-
".mp3",
|
|
4415
|
-
".mp4",
|
|
4416
|
-
".wav",
|
|
4417
|
-
".ogg",
|
|
4418
|
-
".webm",
|
|
4419
|
-
".mov",
|
|
4420
|
-
".avi",
|
|
4421
|
-
".pdf",
|
|
4422
|
-
".sqlite",
|
|
4423
|
-
".db"
|
|
4424
|
-
]
|
|
4425
|
-
};
|
|
4426
|
-
var DEFAULT_MAX_FILE_BYTES = 256 * 1024;
|
|
4427
|
-
|
|
4428
6320
|
// src/tools/fs/edit.ts
|
|
4429
6321
|
import { promises as fs } from "fs";
|
|
4430
6322
|
import * as pathMod from "path";
|
|
@@ -4507,10 +6399,15 @@ function lineDiff(a, b) {
|
|
|
4507
6399
|
// src/tools/fs/search.ts
|
|
4508
6400
|
import { promises as fs2 } from "fs";
|
|
4509
6401
|
import * as pathMod2 from "path";
|
|
6402
|
+
function throwIfAborted(signal) {
|
|
6403
|
+
if (!signal?.aborted) return;
|
|
6404
|
+
throw new DOMException("search aborted by user", "AbortError");
|
|
6405
|
+
}
|
|
4510
6406
|
function displayRel2(rootDir, full) {
|
|
4511
6407
|
return pathMod2.relative(rootDir, full).replaceAll("\\", "/");
|
|
4512
6408
|
}
|
|
4513
6409
|
async function searchFiles(ctx, startAbs, args) {
|
|
6410
|
+
throwIfAborted(args.signal);
|
|
4514
6411
|
const needle = args.pattern.toLowerCase();
|
|
4515
6412
|
const includeDeps = args.include_deps === true;
|
|
4516
6413
|
let re = null;
|
|
@@ -4522,6 +6419,7 @@ async function searchFiles(ctx, startAbs, args) {
|
|
|
4522
6419
|
const matches = [];
|
|
4523
6420
|
let totalBytes = 0;
|
|
4524
6421
|
const walk2 = async (dir) => {
|
|
6422
|
+
throwIfAborted(args.signal);
|
|
4525
6423
|
let entries;
|
|
4526
6424
|
try {
|
|
4527
6425
|
entries = await fs2.readdir(dir, { withFileTypes: true });
|
|
@@ -4529,6 +6427,7 @@ async function searchFiles(ctx, startAbs, args) {
|
|
|
4529
6427
|
return;
|
|
4530
6428
|
}
|
|
4531
6429
|
for (const e of entries) {
|
|
6430
|
+
throwIfAborted(args.signal);
|
|
4532
6431
|
const full = pathMod2.join(dir, e.name);
|
|
4533
6432
|
const lower = e.name.toLowerCase();
|
|
4534
6433
|
const hit = re ? re.test(e.name) : lower.includes(needle);
|
|
@@ -4551,6 +6450,7 @@ async function searchFiles(ctx, startAbs, args) {
|
|
|
4551
6450
|
return matches.length === 0 ? "(no matches)" : matches.join("\n");
|
|
4552
6451
|
}
|
|
4553
6452
|
async function searchContent(ctx, startAbs, args) {
|
|
6453
|
+
throwIfAborted(args.signal);
|
|
4554
6454
|
const caseSensitive = args.case_sensitive === true;
|
|
4555
6455
|
const includeDeps = args.include_deps === true;
|
|
4556
6456
|
let re = null;
|
|
@@ -4566,6 +6466,7 @@ async function searchContent(ctx, startAbs, args) {
|
|
|
4566
6466
|
let truncated = false;
|
|
4567
6467
|
const walk2 = async (dir) => {
|
|
4568
6468
|
if (truncated) return;
|
|
6469
|
+
throwIfAborted(args.signal);
|
|
4569
6470
|
let entries;
|
|
4570
6471
|
try {
|
|
4571
6472
|
entries = await fs2.readdir(dir, { withFileTypes: true });
|
|
@@ -4574,6 +6475,7 @@ async function searchContent(ctx, startAbs, args) {
|
|
|
4574
6475
|
}
|
|
4575
6476
|
for (const e of entries) {
|
|
4576
6477
|
if (truncated) return;
|
|
6478
|
+
throwIfAborted(args.signal);
|
|
4577
6479
|
if (e.isDirectory()) {
|
|
4578
6480
|
if (!includeDeps && ctx.skipDirNames.has(e.name)) continue;
|
|
4579
6481
|
await walk2(pathMod2.join(dir, e.name));
|
|
@@ -4591,6 +6493,7 @@ async function searchContent(ctx, startAbs, args) {
|
|
|
4591
6493
|
}
|
|
4592
6494
|
let raw;
|
|
4593
6495
|
try {
|
|
6496
|
+
throwIfAborted(args.signal);
|
|
4594
6497
|
const st = await fh.stat();
|
|
4595
6498
|
if (st.size > 2 * 1024 * 1024) {
|
|
4596
6499
|
await fh.close();
|
|
@@ -4603,12 +6506,14 @@ async function searchContent(ctx, startAbs, args) {
|
|
|
4603
6506
|
continue;
|
|
4604
6507
|
}
|
|
4605
6508
|
await fh.close();
|
|
6509
|
+
throwIfAborted(args.signal);
|
|
4606
6510
|
const firstNul = raw.indexOf(0);
|
|
4607
6511
|
if (firstNul !== -1 && firstNul < 8 * 1024) continue;
|
|
4608
6512
|
const text = raw.toString("utf8");
|
|
4609
6513
|
const rel = displayRel2(ctx.rootDir, full);
|
|
4610
6514
|
const lines = text.split(/\r?\n/);
|
|
4611
6515
|
for (let li = 0; li < lines.length; li++) {
|
|
6516
|
+
throwIfAborted(args.signal);
|
|
4612
6517
|
const line = lines[li];
|
|
4613
6518
|
const lineForCheck = caseSensitive ? line : line.toLowerCase();
|
|
4614
6519
|
const hit = re ? re.test(line) : lineForCheck.includes(needle);
|
|
@@ -4693,6 +6598,7 @@ function registerFilesystemTools(registry, opts) {
|
|
|
4693
6598
|
- range: "A-B" \u2192 inclusive line range A..B, 1-indexed (e.g. "120-180" around an edit site)
|
|
4694
6599
|
When none of these is given AND the file is longer than ${DEFAULT_AUTO_PREVIEW_LINES} lines, the tool auto-returns a head+tail preview with an "N lines omitted" marker rather than dumping everything. If you need the middle, re-call with a range. Prefer search_content to locate a symbol first, then read_file with a range around the hit \u2014 one scoped read beats three full-file reads.`,
|
|
4695
6600
|
readOnly: true,
|
|
6601
|
+
stormExempt: true,
|
|
4696
6602
|
parameters: {
|
|
4697
6603
|
type: "object",
|
|
4698
6604
|
properties: {
|
|
@@ -4773,6 +6679,7 @@ ${slice.join("\n")}`;
|
|
|
4773
6679
|
parallelSafe: true,
|
|
4774
6680
|
description: "List entries in a directory under the sandbox root. Returns one line per entry, marking directories with a trailing slash. Not recursive \u2014 use directory_tree for that.",
|
|
4775
6681
|
readOnly: true,
|
|
6682
|
+
stormExempt: true,
|
|
4776
6683
|
parameters: {
|
|
4777
6684
|
type: "object",
|
|
4778
6685
|
properties: {
|
|
@@ -4888,10 +6795,10 @@ Prefer \`list_directory\` for a single-level view, \`search_files\` to find spec
|
|
|
4888
6795
|
},
|
|
4889
6796
|
required: ["pattern"]
|
|
4890
6797
|
},
|
|
4891
|
-
fn: async (args) => searchFiles(
|
|
6798
|
+
fn: async (args, toolCtx) => searchFiles(
|
|
4892
6799
|
{ rootDir, maxListBytes, skipDirNames: SKIP_DIR_NAMES },
|
|
4893
6800
|
safePath(args.path ?? "."),
|
|
4894
|
-
args
|
|
6801
|
+
{ ...args, signal: toolCtx?.signal }
|
|
4895
6802
|
)
|
|
4896
6803
|
});
|
|
4897
6804
|
registry.register({
|
|
@@ -4925,7 +6832,7 @@ Prefer \`list_directory\` for a single-level view, \`search_files\` to find spec
|
|
|
4925
6832
|
},
|
|
4926
6833
|
required: ["pattern"]
|
|
4927
6834
|
},
|
|
4928
|
-
fn: async (args) => searchContent(
|
|
6835
|
+
fn: async (args, toolCtx) => searchContent(
|
|
4929
6836
|
{
|
|
4930
6837
|
rootDir,
|
|
4931
6838
|
maxListBytes,
|
|
@@ -4934,7 +6841,7 @@ Prefer \`list_directory\` for a single-level view, \`search_files\` to find spec
|
|
|
4934
6841
|
nameMatch: compileNameFilter(typeof args.glob === "string" ? args.glob : null)
|
|
4935
6842
|
},
|
|
4936
6843
|
safePath(args.path ?? "."),
|
|
4937
|
-
args
|
|
6844
|
+
{ ...args, signal: toolCtx?.signal }
|
|
4938
6845
|
)
|
|
4939
6846
|
});
|
|
4940
6847
|
registry.register({
|
|
@@ -5741,12 +7648,12 @@ async function spawnSubagent(opts) {
|
|
|
5741
7648
|
}
|
|
5742
7649
|
function aggregateChildUsage(loop) {
|
|
5743
7650
|
const agg = new Usage();
|
|
5744
|
-
for (const
|
|
5745
|
-
agg.promptTokens +=
|
|
5746
|
-
agg.completionTokens +=
|
|
5747
|
-
agg.totalTokens +=
|
|
5748
|
-
agg.promptCacheHitTokens +=
|
|
5749
|
-
agg.promptCacheMissTokens +=
|
|
7651
|
+
for (const t2 of loop.stats.turns) {
|
|
7652
|
+
agg.promptTokens += t2.usage.promptTokens;
|
|
7653
|
+
agg.completionTokens += t2.usage.completionTokens;
|
|
7654
|
+
agg.totalTokens += t2.usage.totalTokens;
|
|
7655
|
+
agg.promptCacheHitTokens += t2.usage.promptCacheHitTokens;
|
|
7656
|
+
agg.promptCacheMissTokens += t2.usage.promptCacheMissTokens;
|
|
5750
7657
|
}
|
|
5751
7658
|
return agg;
|
|
5752
7659
|
}
|
|
@@ -5873,70 +7780,6 @@ function forkRegistryWithAllowList(parent, allow, alsoExclude) {
|
|
|
5873
7780
|
// src/tools/shell.ts
|
|
5874
7781
|
import * as pathMod7 from "path";
|
|
5875
7782
|
|
|
5876
|
-
// src/config.ts
|
|
5877
|
-
import { chmodSync as chmodSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync9, writeFileSync as writeFileSync3 } from "fs";
|
|
5878
|
-
import { homedir as homedir5 } from "os";
|
|
5879
|
-
import { dirname as dirname4, join as join10 } from "path";
|
|
5880
|
-
function defaultConfigPath() {
|
|
5881
|
-
return join10(homedir5(), ".reasonix", "config.json");
|
|
5882
|
-
}
|
|
5883
|
-
function readConfig(path2 = defaultConfigPath()) {
|
|
5884
|
-
try {
|
|
5885
|
-
const raw = readFileSync9(path2, "utf8");
|
|
5886
|
-
const parsed = JSON.parse(raw);
|
|
5887
|
-
if (parsed && typeof parsed === "object") return parsed;
|
|
5888
|
-
} catch {
|
|
5889
|
-
}
|
|
5890
|
-
return {};
|
|
5891
|
-
}
|
|
5892
|
-
function writeConfig(cfg, path2 = defaultConfigPath()) {
|
|
5893
|
-
mkdirSync3(dirname4(path2), { recursive: true });
|
|
5894
|
-
writeFileSync3(path2, JSON.stringify(cfg, null, 2), "utf8");
|
|
5895
|
-
try {
|
|
5896
|
-
chmodSync2(path2, 384);
|
|
5897
|
-
} catch {
|
|
5898
|
-
}
|
|
5899
|
-
}
|
|
5900
|
-
function loadApiKey(path2 = defaultConfigPath()) {
|
|
5901
|
-
if (process.env.DEEPSEEK_API_KEY) return process.env.DEEPSEEK_API_KEY;
|
|
5902
|
-
return readConfig(path2).apiKey;
|
|
5903
|
-
}
|
|
5904
|
-
function webSearchEngine(path2 = defaultConfigPath()) {
|
|
5905
|
-
const cfg = readConfig(path2).webSearchEngine;
|
|
5906
|
-
if (cfg === "searxng") return "searxng";
|
|
5907
|
-
return "mojeek";
|
|
5908
|
-
}
|
|
5909
|
-
function webSearchEndpoint(path2 = defaultConfigPath()) {
|
|
5910
|
-
const cfg = readConfig(path2).webSearchEndpoint;
|
|
5911
|
-
if (cfg && typeof cfg === "string") return cfg;
|
|
5912
|
-
return "http://localhost:8080";
|
|
5913
|
-
}
|
|
5914
|
-
function saveApiKey(key, path2 = defaultConfigPath()) {
|
|
5915
|
-
const cfg = readConfig(path2);
|
|
5916
|
-
cfg.apiKey = key.trim();
|
|
5917
|
-
writeConfig(cfg, path2);
|
|
5918
|
-
}
|
|
5919
|
-
function addProjectShellAllowed(rootDir, prefix, path2 = defaultConfigPath()) {
|
|
5920
|
-
const trimmed = prefix.trim();
|
|
5921
|
-
if (!trimmed) return;
|
|
5922
|
-
const cfg = readConfig(path2);
|
|
5923
|
-
if (!cfg.projects) cfg.projects = {};
|
|
5924
|
-
if (!cfg.projects[rootDir]) cfg.projects[rootDir] = {};
|
|
5925
|
-
const existing = cfg.projects[rootDir].shellAllowed ?? [];
|
|
5926
|
-
if (existing.includes(trimmed)) return;
|
|
5927
|
-
cfg.projects[rootDir].shellAllowed = [...existing, trimmed];
|
|
5928
|
-
writeConfig(cfg, path2);
|
|
5929
|
-
}
|
|
5930
|
-
function isPlausibleKey(key) {
|
|
5931
|
-
const trimmed = key.trim();
|
|
5932
|
-
return /^sk-[A-Za-z0-9_-]{16,}$/.test(trimmed);
|
|
5933
|
-
}
|
|
5934
|
-
function redactKey(key) {
|
|
5935
|
-
if (!key) return "";
|
|
5936
|
-
if (key.length <= 12) return "****";
|
|
5937
|
-
return `${key.slice(0, 6)}\u2026${key.slice(-4)}`;
|
|
5938
|
-
}
|
|
5939
|
-
|
|
5940
7783
|
// src/tools/jobs.ts
|
|
5941
7784
|
import { spawn as spawn2 } from "child_process";
|
|
5942
7785
|
import * as pathMod4 from "path";
|
|
@@ -6033,7 +7876,8 @@ var JobRegistry = class {
|
|
|
6033
7876
|
},
|
|
6034
7877
|
closedPromise: Promise.resolve(),
|
|
6035
7878
|
signalClosed: () => {
|
|
6036
|
-
}
|
|
7879
|
+
},
|
|
7880
|
+
outputWaiters: /* @__PURE__ */ new Set()
|
|
6037
7881
|
};
|
|
6038
7882
|
this.jobs.set(id2, job2);
|
|
6039
7883
|
return {
|
|
@@ -6069,7 +7913,8 @@ var JobRegistry = class {
|
|
|
6069
7913
|
readyPromise,
|
|
6070
7914
|
signalReady: readyResolve,
|
|
6071
7915
|
closedPromise,
|
|
6072
|
-
signalClosed: closedResolve
|
|
7916
|
+
signalClosed: closedResolve,
|
|
7917
|
+
outputWaiters: /* @__PURE__ */ new Set()
|
|
6073
7918
|
};
|
|
6074
7919
|
this.jobs.set(id, job);
|
|
6075
7920
|
let readyMatched = false;
|
|
@@ -6096,6 +7941,11 @@ ${job.output.slice(start)}`;
|
|
|
6096
7941
|
}
|
|
6097
7942
|
}
|
|
6098
7943
|
}
|
|
7944
|
+
if (job.outputWaiters.size > 0) {
|
|
7945
|
+
const waiters = [...job.outputWaiters];
|
|
7946
|
+
job.outputWaiters.clear();
|
|
7947
|
+
for (const wake of waiters) wake();
|
|
7948
|
+
}
|
|
6099
7949
|
};
|
|
6100
7950
|
child.stdout?.on("data", onData);
|
|
6101
7951
|
child.stderr?.on("data", onData);
|
|
@@ -6157,6 +8007,39 @@ ${job.output.slice(start)}`;
|
|
|
6157
8007
|
spawnError: job.spawnError
|
|
6158
8008
|
};
|
|
6159
8009
|
}
|
|
8010
|
+
async waitForJob(id, opts = {}) {
|
|
8011
|
+
const job = this.jobs.get(id);
|
|
8012
|
+
if (!job) return null;
|
|
8013
|
+
if (!job.running) {
|
|
8014
|
+
return {
|
|
8015
|
+
exited: true,
|
|
8016
|
+
exitCode: job.exitCode,
|
|
8017
|
+
latestOutput: job.output
|
|
8018
|
+
};
|
|
8019
|
+
}
|
|
8020
|
+
const timeoutMs = Math.max(0, Math.min(3e4, opts.timeoutMs ?? 5e3));
|
|
8021
|
+
const startOutput = job.output;
|
|
8022
|
+
let wakeOutput = null;
|
|
8023
|
+
const outputPromise = new Promise((resolve10) => {
|
|
8024
|
+
wakeOutput = resolve10;
|
|
8025
|
+
job.outputWaiters.add(resolve10);
|
|
8026
|
+
});
|
|
8027
|
+
let timer = null;
|
|
8028
|
+
await Promise.race([
|
|
8029
|
+
job.closedPromise,
|
|
8030
|
+
outputPromise,
|
|
8031
|
+
new Promise((resolve10) => {
|
|
8032
|
+
timer = setTimeout(resolve10, timeoutMs);
|
|
8033
|
+
})
|
|
8034
|
+
]);
|
|
8035
|
+
if (timer) clearTimeout(timer);
|
|
8036
|
+
if (wakeOutput) job.outputWaiters.delete(wakeOutput);
|
|
8037
|
+
return {
|
|
8038
|
+
exited: !job.running,
|
|
8039
|
+
exitCode: job.exitCode,
|
|
8040
|
+
latestOutput: latestOutputSince(startOutput, job.output)
|
|
8041
|
+
};
|
|
8042
|
+
}
|
|
6160
8043
|
/** SIGTERM, wait graceMs, then SIGKILL. Idempotent on already-exited jobs. */
|
|
6161
8044
|
async stop(id, opts = {}) {
|
|
6162
8045
|
const job = this.jobs.get(id);
|
|
@@ -6236,6 +8119,11 @@ function snapshot(job) {
|
|
|
6236
8119
|
spawnError: job.spawnError
|
|
6237
8120
|
};
|
|
6238
8121
|
}
|
|
8122
|
+
function latestOutputSince(before, after) {
|
|
8123
|
+
if (!before) return after;
|
|
8124
|
+
if (after.startsWith(before)) return after.slice(before.length);
|
|
8125
|
+
return after;
|
|
8126
|
+
}
|
|
6239
8127
|
|
|
6240
8128
|
// src/tools/shell/exec.ts
|
|
6241
8129
|
import { spawn as spawn4, spawnSync } from "child_process";
|
|
@@ -7215,6 +9103,7 @@ function registerShellTools(registry, opts) {
|
|
|
7215
9103
|
description: "Read the latest output of a background job started with `run_background`. By default returns the tail of the buffer (last 80 lines). Pass `since` (the `byteLength` from a previous call) to stream only new content incrementally. Tells you whether the job is still running, so you can stop polling when it's done.",
|
|
7216
9104
|
readOnly: true,
|
|
7217
9105
|
parallelSafe: true,
|
|
9106
|
+
stormExempt: true,
|
|
7218
9107
|
parameters: {
|
|
7219
9108
|
type: "object",
|
|
7220
9109
|
properties: {
|
|
@@ -7239,6 +9128,32 @@ function registerShellTools(registry, opts) {
|
|
|
7239
9128
|
return formatJobRead(args.jobId, out);
|
|
7240
9129
|
}
|
|
7241
9130
|
});
|
|
9131
|
+
registry.register({
|
|
9132
|
+
name: "wait_for_job",
|
|
9133
|
+
description: "Block until a background job exits or produces new output, bounded by `timeoutMs`. Use this instead of polling `job_output` with identical args when you're intentionally waiting for state to change. Returns JSON with `exited`, `exitCode`, and `latestOutput`.",
|
|
9134
|
+
readOnly: true,
|
|
9135
|
+
parameters: {
|
|
9136
|
+
type: "object",
|
|
9137
|
+
properties: {
|
|
9138
|
+
jobId: { type: "integer", description: "Job id returned by run_background." },
|
|
9139
|
+
timeoutMs: {
|
|
9140
|
+
type: "integer",
|
|
9141
|
+
description: "Max time to block before returning if nothing changes. Clamped to 0..30000. Default 5000."
|
|
9142
|
+
}
|
|
9143
|
+
},
|
|
9144
|
+
required: ["jobId"]
|
|
9145
|
+
},
|
|
9146
|
+
fn: async (args) => {
|
|
9147
|
+
const out = await jobs.waitForJob(args.jobId, { timeoutMs: args.timeoutMs });
|
|
9148
|
+
if (!out) return `job ${args.jobId}: not found (use list_jobs)`;
|
|
9149
|
+
return {
|
|
9150
|
+
jobId: args.jobId,
|
|
9151
|
+
exited: out.exited,
|
|
9152
|
+
exitCode: out.exitCode,
|
|
9153
|
+
latestOutput: out.latestOutput
|
|
9154
|
+
};
|
|
9155
|
+
}
|
|
9156
|
+
});
|
|
7242
9157
|
registry.register({
|
|
7243
9158
|
name: "stop_job",
|
|
7244
9159
|
description: "Stop a background job started with `run_background`. SIGTERM first; SIGKILL after a short grace period if it doesn't exit cleanly. Returns the final output + exit code. Safe to call on an already-exited job.",
|
|
@@ -7260,6 +9175,7 @@ function registerShellTools(registry, opts) {
|
|
|
7260
9175
|
description: "List every background job started this session \u2014 running and exited \u2014 with id, command, pid, status. Use when you've lost track of which job_id corresponds to which process, or to see what's still alive.",
|
|
7261
9176
|
readOnly: true,
|
|
7262
9177
|
parallelSafe: true,
|
|
9178
|
+
stormExempt: true,
|
|
7263
9179
|
parameters: { type: "object", properties: {} },
|
|
7264
9180
|
fn: async () => {
|
|
7265
9181
|
const all = jobs.list();
|
|
@@ -7834,15 +9750,15 @@ function computeReplayStats(records) {
|
|
|
7834
9750
|
};
|
|
7835
9751
|
}
|
|
7836
9752
|
function summarizeTurns(turns) {
|
|
7837
|
-
const totalCost = turns.reduce((s,
|
|
7838
|
-
const totalInput = turns.reduce((s,
|
|
7839
|
-
const totalOutput = turns.reduce((s,
|
|
7840
|
-
const totalClaude = turns.reduce((s,
|
|
9753
|
+
const totalCost = turns.reduce((s, t2) => s + t2.cost, 0);
|
|
9754
|
+
const totalInput = turns.reduce((s, t2) => s + inputCostUsd(t2.model, t2.usage), 0);
|
|
9755
|
+
const totalOutput = turns.reduce((s, t2) => s + outputCostUsd(t2.model, t2.usage), 0);
|
|
9756
|
+
const totalClaude = turns.reduce((s, t2) => s + claudeEquivalentCost(t2.usage), 0);
|
|
7841
9757
|
let hit = 0;
|
|
7842
9758
|
let miss = 0;
|
|
7843
|
-
for (const
|
|
7844
|
-
hit +=
|
|
7845
|
-
miss +=
|
|
9759
|
+
for (const t2 of turns) {
|
|
9760
|
+
hit += t2.usage.promptCacheHitTokens;
|
|
9761
|
+
miss += t2.usage.promptCacheMissTokens;
|
|
7846
9762
|
}
|
|
7847
9763
|
const cacheHitRatio = hit + miss > 0 ? hit / (hit + miss) : 0;
|
|
7848
9764
|
const savingsVsClaude = totalClaude > 0 ? 1 - totalCost / totalClaude : 0;
|
|
@@ -7906,8 +9822,8 @@ function diffTranscripts(a, b) {
|
|
|
7906
9822
|
return { a: aSide, b: bSide, pairs, firstDivergenceTurn };
|
|
7907
9823
|
}
|
|
7908
9824
|
function classifyDivergence(a, b, aTools, bTools) {
|
|
7909
|
-
const aNames = aTools.map((
|
|
7910
|
-
const bNames = bTools.map((
|
|
9825
|
+
const aNames = aTools.map((t2) => t2.tool ?? "").sort();
|
|
9826
|
+
const bNames = bTools.map((t2) => t2.tool ?? "").sort();
|
|
7911
9827
|
if (aNames.join(",") !== bNames.join(",")) {
|
|
7912
9828
|
return `tool calls differ: A=[${aNames.join(",") || "\u2014"}] B=[${bNames.join(",") || "\u2014"}]`;
|
|
7913
9829
|
}
|
|
@@ -7937,7 +9853,7 @@ function tokenOverlap(a, b) {
|
|
|
7937
9853
|
const tb = new Set(b.toLowerCase().split(/\s+/).filter(Boolean));
|
|
7938
9854
|
if (ta.size === 0 && tb.size === 0) return 1;
|
|
7939
9855
|
let shared = 0;
|
|
7940
|
-
for (const
|
|
9856
|
+
for (const t2 of ta) if (tb.has(t2)) shared++;
|
|
7941
9857
|
return 2 * shared / (ta.size + tb.size);
|
|
7942
9858
|
}
|
|
7943
9859
|
function levenshtein(a, b) {
|
|
@@ -8130,8 +10046,8 @@ function renderMarkdown(report) {
|
|
|
8130
10046
|
out.push(`| turn | kind | ${a.label} tool calls | ${b.label} tool calls | note |`);
|
|
8131
10047
|
out.push("|---:|:---:|---|---|---|");
|
|
8132
10048
|
for (const p of report.pairs) {
|
|
8133
|
-
const aTools = p.aTools.map((
|
|
8134
|
-
const bTools = p.bTools.map((
|
|
10049
|
+
const aTools = p.aTools.map((t2) => t2.tool).filter(Boolean).join(", ") || "\u2014";
|
|
10050
|
+
const bTools = p.bTools.map((t2) => t2.tool).filter(Boolean).join(", ") || "\u2014";
|
|
8135
10051
|
out.push(`| ${p.turn} | ${p.kind} | ${aTools} | ${bTools} | ${p.divergenceNote ?? ""} |`);
|
|
8136
10052
|
}
|
|
8137
10053
|
out.push("");
|
|
@@ -8192,16 +10108,16 @@ function truncate(s, n) {
|
|
|
8192
10108
|
}
|
|
8193
10109
|
|
|
8194
10110
|
// src/version.ts
|
|
8195
|
-
import { existsSync as existsSync9, mkdirSync as
|
|
10111
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync12, writeFileSync as writeFileSync5 } from "fs";
|
|
8196
10112
|
import { homedir as homedir6 } from "os";
|
|
8197
|
-
import { dirname as
|
|
10113
|
+
import { dirname as dirname6, join as join11 } from "path";
|
|
8198
10114
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
8199
10115
|
var REGISTRY_URL = "https://registry.npmjs.org/reasonix/latest";
|
|
8200
10116
|
var LATEST_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
8201
10117
|
var LATEST_FETCH_TIMEOUT_MS = 2e3;
|
|
8202
10118
|
function readPackageVersion() {
|
|
8203
10119
|
try {
|
|
8204
|
-
let dir =
|
|
10120
|
+
let dir = dirname6(fileURLToPath2(import.meta.url));
|
|
8205
10121
|
for (let i = 0; i < 6; i++) {
|
|
8206
10122
|
const p = join11(dir, "package.json");
|
|
8207
10123
|
if (existsSync9(p)) {
|
|
@@ -8210,7 +10126,7 @@ function readPackageVersion() {
|
|
|
8210
10126
|
return pkg.version;
|
|
8211
10127
|
}
|
|
8212
10128
|
}
|
|
8213
|
-
const parent =
|
|
10129
|
+
const parent = dirname6(dir);
|
|
8214
10130
|
if (parent === dir) break;
|
|
8215
10131
|
dir = parent;
|
|
8216
10132
|
}
|
|
@@ -8236,8 +10152,8 @@ function readCache(homeDirOverride) {
|
|
|
8236
10152
|
function writeCache(entry, homeDirOverride) {
|
|
8237
10153
|
try {
|
|
8238
10154
|
const p = cachePath(homeDirOverride);
|
|
8239
|
-
|
|
8240
|
-
|
|
10155
|
+
mkdirSync5(dirname6(p), { recursive: true });
|
|
10156
|
+
writeFileSync5(p, JSON.stringify(entry), "utf8");
|
|
8241
10157
|
} catch {
|
|
8242
10158
|
}
|
|
8243
10159
|
}
|
|
@@ -9041,15 +10957,15 @@ import {
|
|
|
9041
10957
|
existsSync as existsSync10,
|
|
9042
10958
|
fstatSync,
|
|
9043
10959
|
ftruncateSync,
|
|
9044
|
-
mkdirSync as
|
|
10960
|
+
mkdirSync as mkdirSync6,
|
|
9045
10961
|
openSync as openSync2,
|
|
9046
10962
|
readFileSync as readFileSync13,
|
|
9047
10963
|
readSync,
|
|
9048
10964
|
unlinkSync as unlinkSync3,
|
|
9049
|
-
writeFileSync as
|
|
10965
|
+
writeFileSync as writeFileSync6,
|
|
9050
10966
|
writeSync
|
|
9051
10967
|
} from "fs";
|
|
9052
|
-
import { dirname as
|
|
10968
|
+
import { dirname as dirname7, resolve as resolve9 } from "path";
|
|
9053
10969
|
var BLOCK_RE = /^(\S[^\n]*)\n<{7} SEARCH\n([\s\S]*?)\n?={7}\n([\s\S]*?)\n?>{7} REPLACE/gm;
|
|
9054
10970
|
function parseEditBlocks(text) {
|
|
9055
10971
|
const out = [];
|
|
@@ -9079,7 +10995,7 @@ function applyEditBlock(block, rootDir) {
|
|
|
9079
10995
|
const searchEmpty = block.search.length === 0;
|
|
9080
10996
|
if (searchEmpty) {
|
|
9081
10997
|
try {
|
|
9082
|
-
|
|
10998
|
+
mkdirSync6(dirname7(absTarget), { recursive: true });
|
|
9083
10999
|
const fd = openSync2(absTarget, "wx");
|
|
9084
11000
|
try {
|
|
9085
11001
|
writeSync(fd, block.replace);
|
|
@@ -9194,7 +11110,7 @@ function restoreSnapshots(snapshots, rootDir) {
|
|
|
9194
11110
|
message: "removed (the edit had created it)"
|
|
9195
11111
|
};
|
|
9196
11112
|
}
|
|
9197
|
-
|
|
11113
|
+
writeFileSync6(abs, snap.prevContent, "utf8");
|
|
9198
11114
|
return {
|
|
9199
11115
|
path: snap.path,
|
|
9200
11116
|
status: "applied",
|
|
@@ -9370,6 +11286,7 @@ You have TWO tools for running shell commands, and picking the right one is non-
|
|
|
9370
11286
|
|
|
9371
11287
|
After \`run_background\`, tools available to you:
|
|
9372
11288
|
- \`job_output(jobId, tailLines?)\` \u2014 read recent logs to verify startup / debug errors.
|
|
11289
|
+
- \`wait_for_job(jobId, timeoutMs?)\` \u2014 block until the job exits or emits new output. Prefer this over repeating identical \`job_output\` calls while you're intentionally waiting.
|
|
9373
11290
|
- \`list_jobs\` \u2014 see every job this session (running + exited).
|
|
9374
11291
|
- \`stop_job(jobId)\` \u2014 SIGTERM \u2192 SIGKILL after grace. Stop before switching port / config.
|
|
9375
11292
|
|
|
@@ -9457,17 +11374,17 @@ import {
|
|
|
9457
11374
|
closeSync as closeSync3,
|
|
9458
11375
|
existsSync as existsSync12,
|
|
9459
11376
|
fstatSync as fstatSync2,
|
|
9460
|
-
mkdirSync as
|
|
11377
|
+
mkdirSync as mkdirSync7,
|
|
9461
11378
|
openSync as openSync3,
|
|
9462
11379
|
readFileSync as readFileSync15,
|
|
9463
11380
|
readSync as readSync2,
|
|
9464
11381
|
renameSync as renameSync2,
|
|
9465
11382
|
statSync as statSync5,
|
|
9466
11383
|
unlinkSync as unlinkSync4,
|
|
9467
|
-
writeFileSync as
|
|
11384
|
+
writeFileSync as writeFileSync7
|
|
9468
11385
|
} from "fs";
|
|
9469
11386
|
import { homedir as homedir7 } from "os";
|
|
9470
|
-
import { dirname as
|
|
11387
|
+
import { dirname as dirname8, join as join13 } from "path";
|
|
9471
11388
|
function defaultUsageLogPath(homeDirOverride) {
|
|
9472
11389
|
return join13(homeDirOverride ?? homedir7(), ".reasonix", "usage.jsonl");
|
|
9473
11390
|
}
|
|
@@ -9508,7 +11425,7 @@ function compactUsageLogIfLarge(path2, now) {
|
|
|
9508
11425
|
if (kept.length === lines.filter((l) => l.trim()).length) return;
|
|
9509
11426
|
const tmp = `${path2}.compacting`;
|
|
9510
11427
|
try {
|
|
9511
|
-
|
|
11428
|
+
writeFileSync7(tmp, kept.length > 0 ? `${kept.join("\n")}
|
|
9512
11429
|
` : "", "utf8");
|
|
9513
11430
|
renameSync2(tmp, path2);
|
|
9514
11431
|
} catch {
|
|
@@ -9534,7 +11451,7 @@ function appendUsage(input) {
|
|
|
9534
11451
|
if (input.subagent) record.subagent = input.subagent;
|
|
9535
11452
|
const path2 = input.path ?? defaultUsageLogPath();
|
|
9536
11453
|
try {
|
|
9537
|
-
|
|
11454
|
+
mkdirSync7(dirname8(path2), { recursive: true });
|
|
9538
11455
|
appendFileSync2(path2, `${JSON.stringify(record)}
|
|
9539
11456
|
`, "utf8");
|
|
9540
11457
|
compactUsageLogIfLarge(path2, record.ts);
|