reasonix 0.36.2 → 0.38.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 +48 -75
- package/README.zh-CN.md +48 -32
- package/dist/cli/{chat-QSM6JKUA.js → chat-FPEYKTMI.js} +16 -17
- package/dist/cli/{chunk-T52GAWPP.js → chunk-3VTV4WAH.js} +2 -2
- package/dist/cli/{chunk-NHV5YGTB.js → chunk-4PNXH2MH.js} +1860 -1249
- package/dist/cli/chunk-4PNXH2MH.js.map +1 -0
- package/dist/cli/{chunk-DFP4YSVM.js → chunk-6CXT5JRM.js} +17 -2
- package/dist/cli/{chunk-DFP4YSVM.js.map → chunk-6CXT5JRM.js.map} +1 -1
- package/dist/cli/{chunk-G3XNWSFN.js → chunk-6NMWJSES.js} +2 -2
- package/dist/cli/{chunk-4D6TT2IB.js → chunk-A63QT566.js} +36 -15
- package/dist/cli/chunk-A63QT566.js.map +1 -0
- package/dist/cli/{chunk-4Q3GRJIU.js → chunk-AATCLE5N.js} +2 -2
- package/dist/cli/{chunk-BHLHOS5Y.js → chunk-BW2HWSYH.js} +315 -5
- package/dist/cli/chunk-BW2HWSYH.js.map +1 -0
- package/dist/cli/{chunk-ZJR4QLXB.js → chunk-FB46F6H4.js} +2 -2
- package/dist/cli/{chunk-MLXUGPJE.js → chunk-FYKZB6TX.js} +490 -8
- package/dist/cli/chunk-FYKZB6TX.js.map +1 -0
- package/dist/cli/{chunk-XQIFIB3U.js → chunk-JOFZ6AW5.js} +2 -2
- package/dist/cli/{chunk-IPCPEZWQ.js → chunk-LMNAMITH.js} +2 -2
- package/dist/cli/{chunk-S4GF3HPO.js → chunk-LY352GTC.js} +6 -4
- package/dist/cli/chunk-LY352GTC.js.map +1 -0
- package/dist/cli/{chunk-C5543CRX.js → chunk-NYP2DDDV.js} +41 -2
- package/dist/cli/chunk-NYP2DDDV.js.map +1 -0
- package/dist/cli/{chunk-BJ376EN3.js → chunk-T5U5JO7Q.js} +12 -9
- package/dist/cli/chunk-T5U5JO7Q.js.map +1 -0
- package/dist/cli/{chunk-K6W64QVE.js → chunk-XOIDSPMQ.js} +27 -7
- package/dist/cli/chunk-XOIDSPMQ.js.map +1 -0
- package/dist/cli/{chunk-RNSZYYGB.js → chunk-YJKLNYCP.js} +122 -33
- package/dist/cli/chunk-YJKLNYCP.js.map +1 -0
- package/dist/cli/{code-6C5A2CY3.js → code-GTE65OUT.js} +28 -21
- package/dist/cli/code-GTE65OUT.js.map +1 -0
- package/dist/cli/{commands-FE2UDFBC.js → commands-R4JWISND.js} +3 -4
- package/dist/cli/{commands-FE2UDFBC.js.map → commands-R4JWISND.js.map} +1 -1
- package/dist/cli/{commit-3IAGB22T.js → commit-TQ4DMUNS.js} +2 -3
- package/dist/cli/{commit-3IAGB22T.js.map → commit-TQ4DMUNS.js.map} +1 -1
- package/dist/cli/{doctor-DKD34EFD.js → doctor-GGK2JKTA.js} +7 -8
- package/dist/cli/{events-P27CX7LN.js → events-SQXPVV7B.js} +3 -3
- package/dist/cli/index.js +38 -37
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/{mcp-2RDEQST6.js → mcp-M7I23TQ7.js} +2 -3
- package/dist/cli/{mcp-2RDEQST6.js.map → mcp-M7I23TQ7.js.map} +1 -1
- package/dist/cli/{mcp-browse-VM5GLRBQ.js → mcp-browse-TWO7RYT4.js} +2 -3
- package/dist/cli/{mcp-browse-VM5GLRBQ.js.map → mcp-browse-TWO7RYT4.js.map} +1 -1
- package/dist/cli/prompt-ODPFOKSH.js +13 -0
- package/dist/cli/{prune-sessions-ERL6B4G5.js → prune-sessions-FCFOYCBP.js} +2 -2
- package/dist/cli/{replay-D7RT2DR7.js → replay-R3QRXPI2.js} +13 -9
- package/dist/cli/replay-R3QRXPI2.js.map +1 -0
- package/dist/cli/{run-AG4Y45X7.js → run-WGSPYYOJ.js} +9 -10
- package/dist/cli/{run-AG4Y45X7.js.map → run-WGSPYYOJ.js.map} +1 -1
- package/dist/cli/{server-GNHR5K3N.js → server-IZPWQYG3.js} +98 -53
- package/dist/cli/{server-GNHR5K3N.js.map → server-IZPWQYG3.js.map} +1 -1
- package/dist/cli/{sessions-MHRF3GU4.js → sessions-E4UH5JYL.js} +9 -10
- package/dist/cli/{sessions-MHRF3GU4.js.map → sessions-E4UH5JYL.js.map} +1 -1
- package/dist/cli/{setup-IIAJXHP4.js → setup-FTZNN3TZ.js} +60 -15
- package/dist/cli/setup-FTZNN3TZ.js.map +1 -0
- package/dist/cli/{version-7AL4JZ63.js → version-MDVCFTKA.js} +9 -10
- package/dist/cli/{version-7AL4JZ63.js.map → version-MDVCFTKA.js.map} +1 -1
- package/dist/index.d.ts +9 -2
- package/dist/index.js +714 -54
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/cli/chunk-4D6TT2IB.js.map +0 -1
- package/dist/cli/chunk-BHLHOS5Y.js.map +0 -1
- package/dist/cli/chunk-BJ376EN3.js.map +0 -1
- package/dist/cli/chunk-C5543CRX.js.map +0 -1
- package/dist/cli/chunk-K6W64QVE.js.map +0 -1
- package/dist/cli/chunk-MLXUGPJE.js.map +0 -1
- package/dist/cli/chunk-NHV5YGTB.js.map +0 -1
- package/dist/cli/chunk-RNSZYYGB.js.map +0 -1
- package/dist/cli/chunk-S4GF3HPO.js.map +0 -1
- package/dist/cli/chunk-WUI3P4RA.js +0 -319
- package/dist/cli/chunk-WUI3P4RA.js.map +0 -1
- package/dist/cli/code-6C5A2CY3.js.map +0 -1
- package/dist/cli/prompt-QSEB7HNQ.js +0 -11
- package/dist/cli/replay-D7RT2DR7.js.map +0 -1
- package/dist/cli/setup-IIAJXHP4.js.map +0 -1
- /package/dist/cli/{chat-QSM6JKUA.js.map → chat-FPEYKTMI.js.map} +0 -0
- /package/dist/cli/{chunk-T52GAWPP.js.map → chunk-3VTV4WAH.js.map} +0 -0
- /package/dist/cli/{chunk-G3XNWSFN.js.map → chunk-6NMWJSES.js.map} +0 -0
- /package/dist/cli/{chunk-4Q3GRJIU.js.map → chunk-AATCLE5N.js.map} +0 -0
- /package/dist/cli/{chunk-ZJR4QLXB.js.map → chunk-FB46F6H4.js.map} +0 -0
- /package/dist/cli/{chunk-XQIFIB3U.js.map → chunk-JOFZ6AW5.js.map} +0 -0
- /package/dist/cli/{chunk-IPCPEZWQ.js.map → chunk-LMNAMITH.js.map} +0 -0
- /package/dist/cli/{doctor-DKD34EFD.js.map → doctor-GGK2JKTA.js.map} +0 -0
- /package/dist/cli/{events-P27CX7LN.js.map → events-SQXPVV7B.js.map} +0 -0
- /package/dist/cli/{prompt-QSEB7HNQ.js.map → prompt-ODPFOKSH.js.map} +0 -0
- /package/dist/cli/{prune-sessions-ERL6B4G5.js.map → prune-sessions-FCFOYCBP.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -980,6 +980,10 @@ var EN = {
|
|
|
980
980
|
title: "copy / paste",
|
|
981
981
|
rows: [
|
|
982
982
|
{ key: "select text", text: "drag to select \u2014 terminal-native (no modifier needed)" },
|
|
983
|
+
{
|
|
984
|
+
key: "/copy",
|
|
985
|
+
text: "vim/tmux-style copy mode \u2014 works in SSH/mosh/tmux where drag-select can't extend past the viewport"
|
|
986
|
+
},
|
|
983
987
|
{
|
|
984
988
|
key: "copy",
|
|
985
989
|
text: "Ctrl+Shift+C (Win/Linux) \xB7 Cmd+C (macOS) \u2014 or auto-copy-on-select if your terminal does it"
|
|
@@ -1062,6 +1066,9 @@ var EN = {
|
|
|
1062
1066
|
},
|
|
1063
1067
|
slash: {
|
|
1064
1068
|
help: { description: "show the full command reference" },
|
|
1069
|
+
copy: {
|
|
1070
|
+
description: "open vim/tmux-style copy mode \u2014 j/k navigate, v select, y yank to clipboard"
|
|
1071
|
+
},
|
|
1065
1072
|
status: { description: "current model, flags, context, session" },
|
|
1066
1073
|
preset: {
|
|
1067
1074
|
description: "model bundle \u2014 auto escalates flash \u2192 pro, flash/pro lock",
|
|
@@ -1069,6 +1076,10 @@ var EN = {
|
|
|
1069
1076
|
},
|
|
1070
1077
|
model: { description: "switch DeepSeek model id", argsHint: "<id>" },
|
|
1071
1078
|
models: { description: "list available models fetched from DeepSeek /models" },
|
|
1079
|
+
theme: {
|
|
1080
|
+
description: "show or persist the terminal theme preference. Bare opens picker.",
|
|
1081
|
+
argsHint: "[auto|default|dark|light|tokyo-night|github-dark|github-light|high-contrast]"
|
|
1082
|
+
},
|
|
1072
1083
|
language: {
|
|
1073
1084
|
description: "switch the runtime language",
|
|
1074
1085
|
argsHint: "<EN|zh-CN>",
|
|
@@ -1124,9 +1135,15 @@ var EN = {
|
|
|
1124
1135
|
context: { description: "show context-window breakdown (system / tools / log / input)" },
|
|
1125
1136
|
retry: { description: "truncate & resend your last message (fresh sample)" },
|
|
1126
1137
|
compact: {
|
|
1127
|
-
description: "
|
|
1138
|
+
description: "narrow oversized tool results + tool-call args in the log; cap at tokens, default 4000",
|
|
1128
1139
|
argsHint: "[tokens]"
|
|
1129
1140
|
},
|
|
1141
|
+
cwd: {
|
|
1142
|
+
description: "switch the workspace root mid-session \u2014 re-points fs / shell / memory tools, reloads project hooks, refreshes the at-mention walker",
|
|
1143
|
+
argsHint: "<path>"
|
|
1144
|
+
},
|
|
1145
|
+
stop: { description: "abort the current model turn (typed alternative to Esc)" },
|
|
1146
|
+
feedback: { description: "open a GitHub issue with diagnostic info copied to clipboard" },
|
|
1130
1147
|
keys: { description: "keyboard + mouse + copy/paste reference" },
|
|
1131
1148
|
plans: { description: "list this session's active + archived plans, newest first" },
|
|
1132
1149
|
replay: {
|
|
@@ -1202,6 +1219,9 @@ var EN = {
|
|
|
1202
1219
|
apiKeySavedLocally: "Saved locally to {path}",
|
|
1203
1220
|
apiKeyInputLabel: "key \u203A ",
|
|
1204
1221
|
apiKeyInvalid: "Key looks too short \u2014 paste the full token (16+ chars, no spaces).",
|
|
1222
|
+
apiKeyChecking: "Checking API key\u2026",
|
|
1223
|
+
apiKeyRejected: "DeepSeek rejected this API key. Paste a valid key, or press Esc to cancel setup.",
|
|
1224
|
+
apiKeyCheckFailed: "Could not verify this API key right now ({message}). Check your network or try again.",
|
|
1205
1225
|
apiKeyPreview: "preview: {redacted}",
|
|
1206
1226
|
themeTitle: "Choose a theme",
|
|
1207
1227
|
themeSubtitle: "Preview updates live as you navigate. Change later with /theme.",
|
|
@@ -1399,6 +1419,7 @@ var EN = {
|
|
|
1399
1419
|
handlers: {
|
|
1400
1420
|
basic: {
|
|
1401
1421
|
newInfo: "\u25B8 new conversation \u2014 dropped {count} message(s) from context. Same session, fresh slate.",
|
|
1422
|
+
newInfoArchived: '\u25B8 new conversation \u2014 dropped {count} message(s) from context. Prior transcript archived as "{archived}" (visible under Sessions).',
|
|
1402
1423
|
helpTitle: "Commands:",
|
|
1403
1424
|
helpShellTitle: "Shell shortcut:",
|
|
1404
1425
|
helpShell: " !<cmd> run <cmd> in the sandbox root; output goes into",
|
|
@@ -1716,6 +1737,189 @@ var EN = {
|
|
|
1716
1737
|
newError: "\u25B2 /skill new failed: {reason}"
|
|
1717
1738
|
}
|
|
1718
1739
|
},
|
|
1740
|
+
statusBar: {
|
|
1741
|
+
turn: "turn",
|
|
1742
|
+
cache: "cache",
|
|
1743
|
+
spent: "spent",
|
|
1744
|
+
left: " left",
|
|
1745
|
+
slow: "slow",
|
|
1746
|
+
disconnect: "disconnect",
|
|
1747
|
+
reconnecting: "reconnecting\u2026",
|
|
1748
|
+
approvingIn: "approving in ",
|
|
1749
|
+
escToInterrupt: "s \xB7 esc to interrupt",
|
|
1750
|
+
recordingGlyph: "\u25CFREC",
|
|
1751
|
+
mb: " MB",
|
|
1752
|
+
evt: " evt"
|
|
1753
|
+
},
|
|
1754
|
+
editMode: {
|
|
1755
|
+
plan: "PLAN MODE",
|
|
1756
|
+
yolo: "YOLO",
|
|
1757
|
+
auto: "AUTO",
|
|
1758
|
+
review: "REVIEW",
|
|
1759
|
+
writesGated: " writes gated \xB7 /plan off to leave",
|
|
1760
|
+
editsShellAuto: "edits + shell auto \xB7 /undo to roll back",
|
|
1761
|
+
editsLandNow: "edits land now \xB7 u to undo",
|
|
1762
|
+
queuedApplyDiscard: "{count} queued \xB7 y apply \xB7 n discard",
|
|
1763
|
+
editsQueued: "edits queued \xB7 y apply \xB7 n discard",
|
|
1764
|
+
shiftTabFlip: " {mid} \xB7 Shift+Tab to flip",
|
|
1765
|
+
queuedDots: "queued\u2026"
|
|
1766
|
+
},
|
|
1767
|
+
composer: {
|
|
1768
|
+
placeholder: "ask anything \xB7 slash for commands \xB7 at-sign for files",
|
|
1769
|
+
waitingForResponse: "\u2026waiting for response\u2026",
|
|
1770
|
+
hintSend: "send",
|
|
1771
|
+
hintNewline: "newline",
|
|
1772
|
+
hintClear: "clear",
|
|
1773
|
+
hintScroll: "scroll",
|
|
1774
|
+
hintHistory: "history",
|
|
1775
|
+
hintAbort: "abort",
|
|
1776
|
+
hintQuit: "quit",
|
|
1777
|
+
abortedHint: "turn aborted by user \xB7 esc again to clear \xB7 \u23CE to ask a follow-up"
|
|
1778
|
+
},
|
|
1779
|
+
shellConfirm: {
|
|
1780
|
+
title: "Shell command",
|
|
1781
|
+
bgTitle: "Background process",
|
|
1782
|
+
subtitle: "model wants to run a shell command",
|
|
1783
|
+
bgSubtitle: "long-running process \u2014 keeps running after approval, /kill to stop",
|
|
1784
|
+
denyTitle: "Deny \u2014 provide context",
|
|
1785
|
+
optional: "optional",
|
|
1786
|
+
denyFooter: "type context \xB7 \u23CE submit with reason \xB7 esc skip (deny without reason)",
|
|
1787
|
+
awaiting: "awaiting",
|
|
1788
|
+
pickFooter: "\u2191\u2193 pick \xB7 \u23CE confirm \xB7 Tab add context \xB7 esc cancel",
|
|
1789
|
+
allowOnce: "allow once",
|
|
1790
|
+
allowOnceDesc: "run this command, ask again next time",
|
|
1791
|
+
allowAlways: "allow always",
|
|
1792
|
+
allowAlwaysDesc: "remember `{prefix}` for this project",
|
|
1793
|
+
deny: "deny",
|
|
1794
|
+
denyDesc: "press Tab to add context telling the model why"
|
|
1795
|
+
},
|
|
1796
|
+
editConfirm: {
|
|
1797
|
+
footer: "[y/Enter] apply \xB7 [n] reject with reason \xB7 [a] apply rest \xB7 [A] flip AUTO \xB7 [\u2191\u2193/Space] scroll \xB7 [Esc] abort",
|
|
1798
|
+
newTag: "NEW",
|
|
1799
|
+
editTag: "EDIT",
|
|
1800
|
+
linesCount: "-{removed} +{added} lines",
|
|
1801
|
+
viewingRange: "viewing {start}-{end}/{total}",
|
|
1802
|
+
denyFooter: "\u23CE submit \xB7 esc skip (deny without reason)",
|
|
1803
|
+
oldLabel: " - old",
|
|
1804
|
+
newLabel: " + new",
|
|
1805
|
+
sideBySide: " side-by-side \xB7 removed lines on the left, added on the right \xB7 paired by offset",
|
|
1806
|
+
linesAbove: " \u2191 {count} line above (\u2191/k or PgUp)",
|
|
1807
|
+
linesAbovePlural: " \u2191 {count} lines above (\u2191/k or PgUp)",
|
|
1808
|
+
linesBelow: " \u2193 {count} line below (\u2193/j or Space/PgDn)",
|
|
1809
|
+
linesBelowPlural: " \u2193 {count} lines below (\u2193/j or Space/PgDn)"
|
|
1810
|
+
},
|
|
1811
|
+
sessionPicker: {
|
|
1812
|
+
header: " \u25C8 REASONIX \xB7 pick a session ",
|
|
1813
|
+
title: "pick a session \u2014 {workspace}",
|
|
1814
|
+
messages: "{count} message",
|
|
1815
|
+
messagesPlural: "{count} messages",
|
|
1816
|
+
turns: "{count} turns",
|
|
1817
|
+
pickerHint: "\u2191\u2193 pick \xB7 \u23CE open \xB7 [n] new \xB7 [d] delete \xB7 [r] rename \xB7 esc quit",
|
|
1818
|
+
empty: " no saved sessions in this workspace yet \u2014 press ",
|
|
1819
|
+
emptyNew: " to start a new one",
|
|
1820
|
+
renamePrompt: ' rename "{from}" \u2192 ',
|
|
1821
|
+
renameHint: " \u23CE confirm rename \xB7 esc cancel",
|
|
1822
|
+
emptyHint: " \u23CE new session \xB7 esc quit",
|
|
1823
|
+
justNow: "just now",
|
|
1824
|
+
minAgo: "{count} min ago",
|
|
1825
|
+
yesterday: "yesterday",
|
|
1826
|
+
hoursAgo: "{count}h ago",
|
|
1827
|
+
daysAgo: "{count} days ago"
|
|
1828
|
+
},
|
|
1829
|
+
modelPicker: {
|
|
1830
|
+
header: " \u25C8 REASONIX \xB7 pick a setup ",
|
|
1831
|
+
loading: " \xB7 loading catalog\u2026",
|
|
1832
|
+
catalogEmpty: " \xB7 catalog empty \u2014 using known fallbacks",
|
|
1833
|
+
modelsAvailable: " \xB7 {count} models available",
|
|
1834
|
+
presetsHeader: " PRESETS \xB7 recommended \u2014 model + effort + auto-escalate",
|
|
1835
|
+
modelsHeader: " MODELS \xB7 raw pick \u2014 auto-escalate stays as-is",
|
|
1836
|
+
pickerFooter: " \u2191\u2193 pick \xB7 \u23CE confirm \xB7 [r] refresh \xB7 esc cancel",
|
|
1837
|
+
currentLabel: " \xB7 current"
|
|
1838
|
+
},
|
|
1839
|
+
slashSuggestions: {
|
|
1840
|
+
noMatch: "no slash command matches that prefix",
|
|
1841
|
+
backspaceHint: " \u2014 Backspace to edit, or /help for the full list",
|
|
1842
|
+
commandCount: "{count} command",
|
|
1843
|
+
commandCountPlural: "{count} commands",
|
|
1844
|
+
aboveLabel: " \u2191 {count} above",
|
|
1845
|
+
belowLabel: " \u2193 {count} below",
|
|
1846
|
+
advancedHint: " + {count} advanced \xB7 type a letter to search",
|
|
1847
|
+
footerHint: " \u2191\u2193 navigate \xB7 Tab / \u23CE pick \xB7 esc cancel",
|
|
1848
|
+
groupChat: "CHAT",
|
|
1849
|
+
groupSetup: "SETUP",
|
|
1850
|
+
groupInfo: "INFO",
|
|
1851
|
+
groupSession: "SESSION",
|
|
1852
|
+
groupExtend: "EXTEND",
|
|
1853
|
+
groupCode: "CODE",
|
|
1854
|
+
groupJobs: "JOBS",
|
|
1855
|
+
groupAdvanced: "ADVANCED"
|
|
1856
|
+
},
|
|
1857
|
+
atMentions: {
|
|
1858
|
+
loading: "loading\u2026",
|
|
1859
|
+
entrySingular: "{count} entry",
|
|
1860
|
+
entryPlural: "{count} entries",
|
|
1861
|
+
searching: "searching\u2026",
|
|
1862
|
+
scanned: "scanned",
|
|
1863
|
+
match: "match",
|
|
1864
|
+
matches: "matches",
|
|
1865
|
+
forFilter: 'for "{filter}"',
|
|
1866
|
+
noMatch: 'no files match "{filter}"',
|
|
1867
|
+
emptyDir: "empty directory",
|
|
1868
|
+
scanning: "scanning the tree\u2026",
|
|
1869
|
+
footerBrowse: "\u2191\u2193 navigate \xB7 Tab drill into folder \xB7 \u23CE insert \xB7 esc cancel",
|
|
1870
|
+
footerBrowseSearch: "\u2191\u2193 navigate \xB7 Tab / \u23CE insert as @path \xB7 esc cancel",
|
|
1871
|
+
footerInsert: "\u2191\u2193 navigate \xB7 Tab / \u23CE insert as @path \xB7 esc cancel"
|
|
1872
|
+
},
|
|
1873
|
+
statsPanel: {
|
|
1874
|
+
modePlan: "PLAN",
|
|
1875
|
+
modeYolo: "yolo",
|
|
1876
|
+
modeAuto: "auto",
|
|
1877
|
+
modeReview: "review",
|
|
1878
|
+
pro: "\u21E7 pro",
|
|
1879
|
+
budget: " budget "
|
|
1880
|
+
},
|
|
1881
|
+
welcomeBanner: {
|
|
1882
|
+
workspace: "\u25B8 workspace",
|
|
1883
|
+
relaunchHint: " (relaunch with --dir <path> to switch)",
|
|
1884
|
+
dashboard: "\u25B8 web"
|
|
1885
|
+
},
|
|
1886
|
+
ctxBreakdown: {
|
|
1887
|
+
title: "\u25A3 context",
|
|
1888
|
+
compactHint: " /compact folds (auto at 50%) \xB7 /new wipes log",
|
|
1889
|
+
topTools: " top tool results by cost ({count}):",
|
|
1890
|
+
msg: "msg",
|
|
1891
|
+
turnLabel: "turn"
|
|
1892
|
+
},
|
|
1893
|
+
startup: {
|
|
1894
|
+
codeRooted: '\u25B8 reasonix code: rooted at {rootDir}, session "{session}" \xB7 {tools} native tool(s){semantic}',
|
|
1895
|
+
ephemeral: "(ephemeral)",
|
|
1896
|
+
semanticOn: " \xB7 semantic_search on"
|
|
1897
|
+
},
|
|
1898
|
+
doctorErrors: {
|
|
1899
|
+
unreadable: "{path} unreadable \u2014 {message}",
|
|
1900
|
+
cannotList: "cannot list \u2014 {message}",
|
|
1901
|
+
parseFailed: "couldn't parse settings.json \u2014 {message}",
|
|
1902
|
+
probeFailed: "probe failed \u2014 {message}"
|
|
1903
|
+
},
|
|
1904
|
+
webErrors: {
|
|
1905
|
+
status: "web_search {status}",
|
|
1906
|
+
mojeekBlocked: "web_search: Mojeek anti-bot page \u2014 rate-limited or blocked",
|
|
1907
|
+
mojeekNoResults: "web_search: 0 results but response doesn't look like a real empty page ({chars} chars, first 120: {preview})",
|
|
1908
|
+
invalidEndpoint: 'web_search: invalid SearXNG endpoint "{endpoint}"',
|
|
1909
|
+
endpointMustBeHttp: "web_search: SearXNG endpoint must be http(s), got {protocol}",
|
|
1910
|
+
cannotReach: "web_search: Cannot reach SearXNG server at {endpoint}. Please install SearXNG (https://github.com/searxng/searxng) and start it (e.g. `docker run -d -p 8080:8080 searxng/searxng`), or switch to the default engine with /search-engine mojeek.",
|
|
1911
|
+
searxngNoResults: "web_search: 0 results but SearXNG response doesn't look like an empty results page ({chars} chars)",
|
|
1912
|
+
fetchStatus: "web_fetch {status} for {url}",
|
|
1913
|
+
fetchTooLarge: "web_fetch refused: content-length {len} bytes exceeds {cap}-byte cap ({url})",
|
|
1914
|
+
fetchBodyTooLarge: "web_fetch refused: response body exceeded {cap}-byte cap ({seen} bytes seen)",
|
|
1915
|
+
fetchInvalidUrl: "web_fetch: url must start with http:// or https://"
|
|
1916
|
+
},
|
|
1917
|
+
choiceConfirm: {
|
|
1918
|
+
customLabel: "Let me type my own answer",
|
|
1919
|
+
customDesc: "None of the above fits \u2014 type a free-form reply. The model reads it verbatim.",
|
|
1920
|
+
cancelLabel: "Cancel \u2014 drop the question",
|
|
1921
|
+
cancelDesc: "Model stops and asks what you want instead."
|
|
1922
|
+
},
|
|
1719
1923
|
cardTitles: {
|
|
1720
1924
|
usage: "usage",
|
|
1721
1925
|
context: "context",
|
|
@@ -1725,7 +1929,9 @@ var EN = {
|
|
|
1725
1929
|
reasoning: "reasoning",
|
|
1726
1930
|
reasoningAborted: "reasoning (aborted)",
|
|
1727
1931
|
reasoningEllipsis: "reasoning\u2026",
|
|
1728
|
-
error: "error"
|
|
1932
|
+
error: "error",
|
|
1933
|
+
doctor: "doctor",
|
|
1934
|
+
you: "you"
|
|
1729
1935
|
},
|
|
1730
1936
|
cardLabels: {
|
|
1731
1937
|
prompt: "prompt",
|
|
@@ -1764,7 +1970,42 @@ var EN = {
|
|
|
1764
1970
|
retries: "retries",
|
|
1765
1971
|
reasoningLabel: "reasoning \xB7 {count} \xB6",
|
|
1766
1972
|
runningLabel: "running",
|
|
1767
|
-
workingLabel: "working"
|
|
1973
|
+
workingLabel: "working",
|
|
1974
|
+
defaultFooter: "\u2191\u2193 pick \xB7 \u23CE confirm \xB7 esc cancel",
|
|
1975
|
+
applyAction: "[a] apply",
|
|
1976
|
+
skipAction: "[s] skip",
|
|
1977
|
+
rejectAction: "[r] reject",
|
|
1978
|
+
levelOk: "OK",
|
|
1979
|
+
levelWarn: "warn",
|
|
1980
|
+
levelFail: "FAIL",
|
|
1981
|
+
checksLabel: "checks",
|
|
1982
|
+
passed: "passed",
|
|
1983
|
+
warnTag: "warn",
|
|
1984
|
+
failTag: "fail",
|
|
1985
|
+
stepLabel: "step",
|
|
1986
|
+
done: "done",
|
|
1987
|
+
inProgress: "\u2190 in progress",
|
|
1988
|
+
upcoming: "upcoming",
|
|
1989
|
+
resumed: "resumed \xB7 ",
|
|
1990
|
+
archive: "\u23EA archive \xB7 ",
|
|
1991
|
+
more: "\u22EE +{count} more",
|
|
1992
|
+
categoryUser: "user",
|
|
1993
|
+
categoryFeedback: "feedback",
|
|
1994
|
+
categoryProject: "project",
|
|
1995
|
+
categoryReference: "reference"
|
|
1996
|
+
},
|
|
1997
|
+
copyMode: {
|
|
1998
|
+
title: "\u2500\u2500 COPY MODE \u2500\u2500",
|
|
1999
|
+
help: "j/k or \u2191/\u2193 move \xB7 v select \xB7 y yank \xB7 g/G top/bottom \xB7 q quit",
|
|
2000
|
+
statusBar: "line {cur}/{total} \xB7 selection: {sel}",
|
|
2001
|
+
statusYanked: "yanked {size} chars (osc52={osc52})",
|
|
2002
|
+
statusEmpty: "nothing selected",
|
|
2003
|
+
empty: "(no chat content yet \u2014 say something to the model first)",
|
|
2004
|
+
labelUser: "you",
|
|
2005
|
+
labelAssistant: "assistant",
|
|
2006
|
+
labelReasoning: "reasoning",
|
|
2007
|
+
yankedToast: "\u25B8 copied {size} chars to clipboard (osc52)",
|
|
2008
|
+
yankedToastFile: "\u25B8 copied {size} chars \xB7 file: {path}"
|
|
1768
2009
|
}
|
|
1769
2010
|
};
|
|
1770
2011
|
|
|
@@ -1891,6 +2132,10 @@ var zhCN = {
|
|
|
1891
2132
|
title: "\u590D\u5236 / \u7C98\u8D34",
|
|
1892
2133
|
rows: [
|
|
1893
2134
|
{ key: "\u9009\u4E2D\u6587\u5B57", text: "\u76F4\u63A5\u62D6\u52A8 \u2014 \u7EC8\u7AEF\u539F\u751F\uFF08\u4E0D\u9700\u8981\u4EFB\u4F55\u4FEE\u9970\u952E\uFF09" },
|
|
2135
|
+
{
|
|
2136
|
+
key: "/copy",
|
|
2137
|
+
text: "vim/tmux \u98CE\u683C\u590D\u5236\u6A21\u5F0F \u2014 SSH / mosh / tmux \u4E0B\u62D6\u9009\u8D8A\u8FC7\u53EF\u89C6\u533A\u65E0\u6548\u65F6\u7528\u8FD9\u4E2A"
|
|
2138
|
+
},
|
|
1894
2139
|
{
|
|
1895
2140
|
key: "\u590D\u5236",
|
|
1896
2141
|
text: "Ctrl+Shift+C\uFF08Win/Linux\uFF09\xB7 Cmd+C\uFF08macOS\uFF09\u2014 \u6216\u9009\u4E2D\u5373\u590D\u5236\uFF08\u770B\u7EC8\u7AEF\u8BBE\u7F6E\uFF09"
|
|
@@ -1973,6 +2218,9 @@ var zhCN = {
|
|
|
1973
2218
|
},
|
|
1974
2219
|
slash: {
|
|
1975
2220
|
help: { description: "\u663E\u793A\u5B8C\u6574\u547D\u4EE4\u53C2\u8003" },
|
|
2221
|
+
copy: {
|
|
2222
|
+
description: "\u8FDB\u5165 vim/tmux \u98CE\u683C\u590D\u5236\u6A21\u5F0F \u2014 j/k \u79FB\u52A8\u3001v \u8D77\u9009\u533A\u3001y \u590D\u5236\u5230\u526A\u8D34\u677F"
|
|
2223
|
+
},
|
|
1976
2224
|
status: { description: "\u5F53\u524D\u6A21\u578B\u3001\u6807\u5FD7\u3001\u4E0A\u4E0B\u6587\u3001\u4F1A\u8BDD" },
|
|
1977
2225
|
preset: {
|
|
1978
2226
|
description: "\u6A21\u578B\u7EC4\u5408 \u2014 \u81EA\u52A8\u5728 flash \u2192 pro \u4E4B\u95F4\u5207\u6362\uFF0C\u6216\u9501\u5B9A flash/pro",
|
|
@@ -1980,6 +2228,10 @@ var zhCN = {
|
|
|
1980
2228
|
},
|
|
1981
2229
|
model: { description: "\u5207\u6362 DeepSeek \u6A21\u578B ID", argsHint: "<id>" },
|
|
1982
2230
|
models: { description: "\u5217\u51FA\u4ECE DeepSeek /models \u83B7\u53D6\u7684\u53EF\u7528\u6A21\u578B" },
|
|
2231
|
+
theme: {
|
|
2232
|
+
description: "\u663E\u793A\u6216\u6301\u4E45\u5316\u7EC8\u7AEF\u4E3B\u9898\u504F\u597D\u3002\u65E0\u53C2\u6570\u65F6\u6253\u5F00\u9009\u62E9\u5668\u3002",
|
|
2233
|
+
argsHint: "[auto|default|dark|light|tokyo-night|github-dark|github-light|high-contrast]"
|
|
2234
|
+
},
|
|
1983
2235
|
language: {
|
|
1984
2236
|
description: "\u5207\u6362\u8FD0\u884C\u65F6\u8BED\u8A00",
|
|
1985
2237
|
argsHint: "<en|zh-CN>",
|
|
@@ -2041,6 +2293,12 @@ var zhCN = {
|
|
|
2041
2293
|
argsHint: "[tokens]"
|
|
2042
2294
|
},
|
|
2043
2295
|
keys: { description: "\u952E\u76D8 + \u9F20\u6807 + \u590D\u5236\u7C98\u8D34\u53C2\u8003" },
|
|
2296
|
+
cwd: {
|
|
2297
|
+
description: "\u5207\u6362\u5DE5\u4F5C\u533A\u6839\u76EE\u5F55 \u2014 \u91CD\u65B0\u6307\u5411\u6587\u4EF6/Shell/\u8BB0\u5FC6\u5DE5\u5177\uFF0C\u91CD\u8F7D\u9879\u76EE hooks\uFF0C\u5237\u65B0 @ \u5F15\u7528\u904D\u5386\u5668",
|
|
2298
|
+
argsHint: "<path>"
|
|
2299
|
+
},
|
|
2300
|
+
stop: { description: "\u4E2D\u6B62\u5F53\u524D\u6A21\u578B\u56DE\u5408\uFF08\u6309 Esc \u7684\u66FF\u4EE3\u65B9\u5F0F\uFF09" },
|
|
2301
|
+
feedback: { description: "\u6253\u5F00 GitHub Issue\uFF0C\u8BCA\u65AD\u4FE1\u606F\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F" },
|
|
2044
2302
|
plans: { description: "\u5217\u51FA\u6B64\u4F1A\u8BDD\u7684\u6D3B\u8DC3 + \u5F52\u6863\u8BA1\u5212\uFF08\u6700\u65B0\u5728\u524D\uFF09" },
|
|
2045
2303
|
replay: {
|
|
2046
2304
|
description: "\u52A0\u8F7D\u5F52\u6863\u8BA1\u5212\u4E3A\u53EA\u8BFB\u7684\u65F6\u95F4\u65C5\u884C\u5FEB\u7167\uFF08\u9ED8\u8BA4\uFF1A\u6700\u65B0\uFF09",
|
|
@@ -2117,6 +2375,9 @@ var zhCN = {
|
|
|
2117
2375
|
apiKeySavedLocally: "\u4FDD\u5B58\u5728\u672C\u5730\uFF1A{path}",
|
|
2118
2376
|
apiKeyInputLabel: "key \u203A ",
|
|
2119
2377
|
apiKeyInvalid: "key \u957F\u5EA6\u4E0D\u8DB3\u2014\u2014\u8BF7\u7C98\u8D34\u5B8C\u6574 token\uFF0816+ \u5B57\u7B26\uFF0C\u4E0D\u542B\u7A7A\u683C\uFF09\u3002",
|
|
2378
|
+
apiKeyChecking: "\u6B63\u5728\u68C0\u67E5 API key\u2026",
|
|
2379
|
+
apiKeyRejected: "DeepSeek \u62D2\u7EDD\u4E86\u8FD9\u4E2A API key\u3002\u8BF7\u7C98\u8D34\u6709\u6548 key\uFF0C\u6216\u6309 Esc \u53D6\u6D88\u8BBE\u7F6E\u3002",
|
|
2380
|
+
apiKeyCheckFailed: "\u6682\u65F6\u65E0\u6CD5\u9A8C\u8BC1 API key\uFF08{message}\uFF09\u3002\u8BF7\u68C0\u67E5\u7F51\u7EDC\u540E\u91CD\u8BD5\u3002",
|
|
2120
2381
|
apiKeyPreview: "\u9884\u89C8\uFF1A{redacted}",
|
|
2121
2382
|
themeTitle: "\u9009\u62E9\u4E3B\u9898",
|
|
2122
2383
|
themeSubtitle: "\u65B9\u5411\u952E\u5207\u6362\u65F6\u5373\u65F6\u9884\u89C8\u6548\u679C\uFF0C\u4E4B\u540E\u53EF\u7528 /theme \u66F4\u6539\u3002",
|
|
@@ -2314,6 +2575,7 @@ var zhCN = {
|
|
|
2314
2575
|
handlers: {
|
|
2315
2576
|
basic: {
|
|
2316
2577
|
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",
|
|
2578
|
+
newInfoArchived: "\u25B8 \u65B0\u5BF9\u8BDD \u2014 \u5DF2\u4ECE\u4E0A\u4E0B\u6587\u4E2D\u4E22\u5F03 {count} \u6761\u6D88\u606F\u3002\u539F\u5BF9\u8BDD\u5DF2\u5F52\u6863\u4E3A\u300C{archived}\u300D\uFF0C\u53EF\u5728 Sessions \u9762\u677F\u67E5\u770B\u3002",
|
|
2317
2579
|
helpTitle: "\u547D\u4EE4\uFF1A",
|
|
2318
2580
|
helpShellTitle: "Shell \u5FEB\u6377\u65B9\u5F0F\uFF1A",
|
|
2319
2581
|
helpShell: " !<cmd> \u5728\u6C99\u7BB1\u6839\u76EE\u5F55\u8FD0\u884C <cmd>\uFF1B\u8F93\u51FA\u8FDB\u5165\u5BF9\u8BDD",
|
|
@@ -2631,6 +2893,189 @@ var zhCN = {
|
|
|
2631
2893
|
newError: "\u25B2 /skill new \u5931\u8D25\uFF1A{reason}"
|
|
2632
2894
|
}
|
|
2633
2895
|
},
|
|
2896
|
+
statusBar: {
|
|
2897
|
+
turn: "\u8F6E",
|
|
2898
|
+
cache: "\u7F13\u5B58",
|
|
2899
|
+
spent: "\u5DF2\u82B1\u8D39",
|
|
2900
|
+
left: " \u5269\u4F59",
|
|
2901
|
+
slow: "\u6162\u901F",
|
|
2902
|
+
disconnect: "\u65AD\u5F00",
|
|
2903
|
+
reconnecting: "\u91CD\u8FDE\u4E2D\u2026",
|
|
2904
|
+
approvingIn: "\u5373\u5C06\u6279\u51C6\uFF0C",
|
|
2905
|
+
escToInterrupt: "\u79D2 \xB7 Esc \u4E2D\u65AD",
|
|
2906
|
+
recordingGlyph: "\u25CFREC",
|
|
2907
|
+
mb: " MB",
|
|
2908
|
+
evt: " \u4E8B\u4EF6"
|
|
2909
|
+
},
|
|
2910
|
+
editMode: {
|
|
2911
|
+
plan: "\u8BA1\u5212",
|
|
2912
|
+
yolo: "\u81EA\u7531",
|
|
2913
|
+
auto: "\u81EA\u52A8",
|
|
2914
|
+
review: "\u5BA1\u67E5",
|
|
2915
|
+
writesGated: " \u5DF2\u9650\u5236\u5199\u5165 \xB7 /plan off \u89E3\u9664",
|
|
2916
|
+
editsShellAuto: "\u7F16\u8F91 + Shell \u81EA\u52A8 \xB7 /undo \u53EF\u56DE\u6EDA",
|
|
2917
|
+
editsLandNow: "\u7F16\u8F91\u5DF2\u751F\u6548 \xB7 \u6309 u \u64A4\u6D88",
|
|
2918
|
+
queuedApplyDiscard: "{count} \u4E2A\u5F85\u5904\u7406 \xB7 y \u5E94\u7528 \xB7 n \u4E22\u5F03",
|
|
2919
|
+
editsQueued: "\u7F16\u8F91\u5DF2\u6392\u961F \xB7 y \u5E94\u7528 \xB7 n \u4E22\u5F03",
|
|
2920
|
+
shiftTabFlip: " {mid} \xB7 Shift+Tab \u5207\u6362",
|
|
2921
|
+
queuedDots: "\u6392\u961F\u4E2D\u2026"
|
|
2922
|
+
},
|
|
2923
|
+
composer: {
|
|
2924
|
+
placeholder: "\u8F93\u5165\u4EFB\u4F55\u5185\u5BB9 \xB7 / \u4F7F\u7528\u547D\u4EE4 \xB7 @ \u5F15\u7528\u6587\u4EF6",
|
|
2925
|
+
waitingForResponse: "\u2026\u7B49\u5F85\u54CD\u5E94\u2026",
|
|
2926
|
+
hintSend: "\u53D1\u9001",
|
|
2927
|
+
hintNewline: "\u6362\u884C",
|
|
2928
|
+
hintClear: "\u6E05\u7A7A",
|
|
2929
|
+
hintScroll: "\u6EDA\u52A8",
|
|
2930
|
+
hintHistory: "\u5386\u53F2",
|
|
2931
|
+
hintAbort: "\u4E2D\u6B62",
|
|
2932
|
+
hintQuit: "\u9000\u51FA",
|
|
2933
|
+
abortedHint: "\u7528\u6237\u5DF2\u4E2D\u6B62\u672C\u8F6E \xB7 \u518D\u6309 Esc \u6E05\u9664 \xB7 \u23CE \u7EE7\u7EED\u63D0\u95EE"
|
|
2934
|
+
},
|
|
2935
|
+
shellConfirm: {
|
|
2936
|
+
title: "Shell \u547D\u4EE4",
|
|
2937
|
+
bgTitle: "\u540E\u53F0\u8FDB\u7A0B",
|
|
2938
|
+
subtitle: "\u6A21\u578B\u8BF7\u6C42\u6267\u884C Shell \u547D\u4EE4",
|
|
2939
|
+
bgSubtitle: "\u957F\u65F6\u95F4\u8FD0\u884C \u2014 \u6279\u51C6\u540E\u6301\u7EED\u8FD0\u884C\uFF0C/kill \u53EF\u505C\u6B62",
|
|
2940
|
+
denyTitle: "\u62D2\u7EDD \u2014 \u63D0\u4F9B\u539F\u56E0",
|
|
2941
|
+
optional: "\u53EF\u9009",
|
|
2942
|
+
denyFooter: "\u8F93\u5165\u539F\u56E0 \xB7 \u23CE \u63D0\u4EA4 \xB7 Esc \u8DF3\u8FC7\uFF08\u76F4\u63A5\u62D2\u7EDD\uFF09",
|
|
2943
|
+
awaiting: "\u7B49\u5F85\u4E2D",
|
|
2944
|
+
pickFooter: "\u2191\u2193 \u9009\u62E9 \xB7 \u23CE \u786E\u8BA4 \xB7 Tab \u6DFB\u52A0\u8BF4\u660E \xB7 Esc \u53D6\u6D88",
|
|
2945
|
+
allowOnce: "\u5141\u8BB8\u4E00\u6B21",
|
|
2946
|
+
allowOnceDesc: "\u6267\u884C\u6B64\u547D\u4EE4\uFF0C\u4E0B\u6B21\u518D\u95EE",
|
|
2947
|
+
allowAlways: "\u59CB\u7EC8\u5141\u8BB8",
|
|
2948
|
+
allowAlwaysDesc: "\u8BB0\u4F4F `{prefix}`\uFF0C\u672C\u9879\u76EE\u5185\u4E0D\u518D\u8BE2\u95EE",
|
|
2949
|
+
deny: "\u62D2\u7EDD",
|
|
2950
|
+
denyDesc: "\u6309 Tab \u6DFB\u52A0\u8BF4\u660E\uFF0C\u544A\u8BC9\u6A21\u578B\u539F\u56E0"
|
|
2951
|
+
},
|
|
2952
|
+
editConfirm: {
|
|
2953
|
+
footer: "[y/Enter] \u5E94\u7528 \xB7 [n] \u62D2\u7EDD\u5E76\u8BF4\u660E \xB7 [a] \u5E94\u7528\u5269\u4F59 \xB7 [A] \u5207\u6362 AUTO \xB7 [\u2191\u2193/Space] \u6EDA\u52A8 \xB7 [Esc] \u4E2D\u6B62",
|
|
2954
|
+
newTag: "\u65B0\u589E",
|
|
2955
|
+
editTag: "\u7F16\u8F91",
|
|
2956
|
+
linesCount: "-{removed} +{added} \u884C",
|
|
2957
|
+
viewingRange: "\u6B63\u5728\u67E5\u770B {start}-{end}/{total}",
|
|
2958
|
+
denyFooter: "\u23CE \u63D0\u4EA4 \xB7 Esc \u8DF3\u8FC7\uFF08\u76F4\u63A5\u62D2\u7EDD\uFF09",
|
|
2959
|
+
oldLabel: " \u65E7\u5185\u5BB9",
|
|
2960
|
+
newLabel: " \u65B0\u5185\u5BB9",
|
|
2961
|
+
sideBySide: " \u5DE6\u53F3\u5BF9\u6BD4 \xB7 \u5DE6\u4FA7\u5220\u9664\uFF0C\u53F3\u4FA7\u65B0\u589E \xB7 \u6309\u504F\u79FB\u914D\u5BF9",
|
|
2962
|
+
linesAbove: " \u2191 \u4E0A\u65B9 {count} \u884C\uFF08\u2191/k \u6216 PgUp\uFF09",
|
|
2963
|
+
linesAbovePlural: " \u2191 \u4E0A\u65B9 {count} \u884C\uFF08\u2191/k \u6216 PgUp\uFF09",
|
|
2964
|
+
linesBelow: " \u2193 \u4E0B\u65B9 {count} \u884C\uFF08\u2193/j \u6216 Space/PgDn\uFF09",
|
|
2965
|
+
linesBelowPlural: " \u2193 \u4E0B\u65B9 {count} \u884C\uFF08\u2193/j \u6216 Space/PgDn\uFF09"
|
|
2966
|
+
},
|
|
2967
|
+
sessionPicker: {
|
|
2968
|
+
header: " \u25C8 REASONIX \xB7 \u9009\u62E9\u4F1A\u8BDD ",
|
|
2969
|
+
title: "\u9009\u62E9\u4F1A\u8BDD \u2014 {workspace}",
|
|
2970
|
+
messages: "{count} \u6761\u6D88\u606F",
|
|
2971
|
+
messagesPlural: "{count} \u6761\u6D88\u606F",
|
|
2972
|
+
turns: "{count} \u8F6E",
|
|
2973
|
+
pickerHint: "\u2191\u2193 \u9009\u62E9 \xB7 \u23CE \u6253\u5F00 \xB7 [n] \u65B0\u5EFA \xB7 [d] \u5220\u9664 \xB7 [r] \u91CD\u547D\u540D \xB7 Esc \u9000\u51FA",
|
|
2974
|
+
empty: " \u6B64\u5DE5\u4F5C\u533A\u6682\u65E0\u5DF2\u4FDD\u5B58\u7684\u4F1A\u8BDD \u2014 \u6309 ",
|
|
2975
|
+
emptyNew: " \u5F00\u59CB\u65B0\u4F1A\u8BDD",
|
|
2976
|
+
renamePrompt: ' \u91CD\u547D\u540D "{from}" \u2192 ',
|
|
2977
|
+
renameHint: " \u23CE \u786E\u8BA4\u91CD\u547D\u540D \xB7 Esc \u53D6\u6D88",
|
|
2978
|
+
emptyHint: " \u23CE \u65B0\u5EFA\u4F1A\u8BDD \xB7 Esc \u9000\u51FA",
|
|
2979
|
+
justNow: "\u521A\u521A",
|
|
2980
|
+
minAgo: "{count} \u5206\u949F\u524D",
|
|
2981
|
+
yesterday: "\u6628\u5929",
|
|
2982
|
+
hoursAgo: "{count} \u5C0F\u65F6\u524D",
|
|
2983
|
+
daysAgo: "{count} \u5929\u524D"
|
|
2984
|
+
},
|
|
2985
|
+
modelPicker: {
|
|
2986
|
+
header: " \u25C8 REASONIX \xB7 \u9009\u62E9\u914D\u7F6E ",
|
|
2987
|
+
loading: " \xB7 \u52A0\u8F7D\u76EE\u5F55\u2026",
|
|
2988
|
+
catalogEmpty: " \xB7 \u76EE\u5F55\u4E3A\u7A7A \u2014 \u4F7F\u7528\u5DF2\u77E5\u5907\u9009",
|
|
2989
|
+
modelsAvailable: " \xB7 {count} \u4E2A\u6A21\u578B\u53EF\u7528",
|
|
2990
|
+
presetsHeader: " \u9884\u8BBE \xB7 \u63A8\u8350 \u2014 \u6A21\u578B + \u5F3A\u5EA6 + \u81EA\u52A8\u5347\u7EA7",
|
|
2991
|
+
modelsHeader: " \u6A21\u578B \xB7 \u76F4\u63A5\u9009\u62E9 \u2014 \u81EA\u52A8\u5347\u7EA7\u4FDD\u6301\u4E0D\u53D8",
|
|
2992
|
+
pickerFooter: " \u2191\u2193 \u9009\u62E9 \xB7 \u23CE \u786E\u8BA4 \xB7 [r] \u5237\u65B0 \xB7 Esc \u53D6\u6D88",
|
|
2993
|
+
currentLabel: " \xB7 \u5F53\u524D"
|
|
2994
|
+
},
|
|
2995
|
+
slashSuggestions: {
|
|
2996
|
+
noMatch: "\u6CA1\u6709\u5339\u914D\u6B64\u524D\u7F00\u7684\u659C\u6760\u547D\u4EE4",
|
|
2997
|
+
backspaceHint: " \u2014 \u6309 Backspace \u4FEE\u6539\uFF0C\u6216 /help \u67E5\u770B\u5B8C\u6574\u5217\u8868",
|
|
2998
|
+
commandCount: "{count} \u4E2A\u547D\u4EE4",
|
|
2999
|
+
commandCountPlural: "{count} \u4E2A\u547D\u4EE4",
|
|
3000
|
+
aboveLabel: " \u2191 {count} \u4E2A\u4EE5\u4E0A",
|
|
3001
|
+
belowLabel: " \u2193 {count} \u4E2A\u4EE5\u4E0B",
|
|
3002
|
+
advancedHint: " + {count} \u4E2A\u9AD8\u7EA7\u547D\u4EE4 \xB7 \u8F93\u5165\u5B57\u6BCD\u641C\u7D22",
|
|
3003
|
+
footerHint: " \u2191\u2193 \u5BFC\u822A \xB7 Tab / \u23CE \u9009\u62E9 \xB7 Esc \u53D6\u6D88",
|
|
3004
|
+
groupChat: "\u804A\u5929",
|
|
3005
|
+
groupSetup: "\u8BBE\u7F6E",
|
|
3006
|
+
groupInfo: "\u4FE1\u606F",
|
|
3007
|
+
groupSession: "\u4F1A\u8BDD",
|
|
3008
|
+
groupExtend: "\u6269\u5C55",
|
|
3009
|
+
groupCode: "\u4EE3\u7801",
|
|
3010
|
+
groupJobs: "\u4EFB\u52A1",
|
|
3011
|
+
groupAdvanced: "\u9AD8\u7EA7"
|
|
3012
|
+
},
|
|
3013
|
+
atMentions: {
|
|
3014
|
+
loading: "\u52A0\u8F7D\u4E2D\u2026",
|
|
3015
|
+
entrySingular: "{count} \u6761",
|
|
3016
|
+
entryPlural: "{count} \u6761",
|
|
3017
|
+
searching: "\u641C\u7D22\u4E2D\u2026",
|
|
3018
|
+
scanned: "\u5DF2\u626B\u63CF",
|
|
3019
|
+
match: "\u4E2A\u5339\u914D",
|
|
3020
|
+
matches: "\u4E2A\u5339\u914D",
|
|
3021
|
+
forFilter: '\u5339\u914D "{filter}"',
|
|
3022
|
+
noMatch: '\u6CA1\u6709\u5339\u914D "{filter}" \u7684\u6587\u4EF6',
|
|
3023
|
+
emptyDir: "\u7A7A\u76EE\u5F55",
|
|
3024
|
+
scanning: "\u6B63\u5728\u626B\u63CF\u76EE\u5F55\u6811\u2026",
|
|
3025
|
+
footerBrowse: "\u2191\u2193 \u5BFC\u822A \xB7 Tab \u8FDB\u5165\u6587\u4EF6\u5939 \xB7 \u23CE \u63D2\u5165 \xB7 Esc \u53D6\u6D88",
|
|
3026
|
+
footerBrowseSearch: "\u2191\u2193 \u5BFC\u822A \xB7 Tab / \u23CE \u4EE5 @path \u63D2\u5165 \xB7 Esc \u53D6\u6D88",
|
|
3027
|
+
footerInsert: "\u2191\u2193 \u5BFC\u822A \xB7 Tab / \u23CE \u4EE5 @path \u63D2\u5165 \xB7 Esc \u53D6\u6D88"
|
|
3028
|
+
},
|
|
3029
|
+
statsPanel: {
|
|
3030
|
+
modePlan: "\u8BA1\u5212",
|
|
3031
|
+
modeYolo: "\u81EA\u7531",
|
|
3032
|
+
modeAuto: "\u81EA\u52A8",
|
|
3033
|
+
modeReview: "\u5BA1\u67E5",
|
|
3034
|
+
pro: "\u21E7 \u4E13\u4E1A",
|
|
3035
|
+
budget: " \u9884\u7B97 "
|
|
3036
|
+
},
|
|
3037
|
+
welcomeBanner: {
|
|
3038
|
+
workspace: "\u25B8 \u5DE5\u4F5C\u533A",
|
|
3039
|
+
relaunchHint: "\uFF08\u91CD\u542F\u65F6\u7528 --dir <path> \u5207\u6362\uFF09",
|
|
3040
|
+
dashboard: "\u25B8 \u7F51\u9875"
|
|
3041
|
+
},
|
|
3042
|
+
ctxBreakdown: {
|
|
3043
|
+
title: "\u25A3 \u4E0A\u4E0B\u6587",
|
|
3044
|
+
compactHint: " /compact \u6298\u53E0\uFF08\u8D85\u8FC7 50% \u81EA\u52A8\u89E6\u53D1\uFF09\xB7 /new \u6E05\u7A7A\u65E5\u5FD7",
|
|
3045
|
+
topTools: " \u5E38\u7528\u5DE5\u5177\uFF08\u6309\u6210\u672C\u6392\u5E8F\uFF0C{count} \u4E2A\uFF09\uFF1A",
|
|
3046
|
+
msg: "\u6761",
|
|
3047
|
+
turnLabel: "\u8F6E"
|
|
3048
|
+
},
|
|
3049
|
+
startup: {
|
|
3050
|
+
codeRooted: '\u25B8 reasonix code\uFF1A\u6839\u76EE\u5F55 {rootDir}\uFF0C\u4F1A\u8BDD "{session}" \xB7 {tools} \u4E2A\u539F\u751F\u5DE5\u5177{semantic}',
|
|
3051
|
+
ephemeral: "\uFF08\u4E34\u65F6\uFF09",
|
|
3052
|
+
semanticOn: " \xB7 \u8BED\u4E49\u641C\u7D22\u5DF2\u5F00\u542F"
|
|
3053
|
+
},
|
|
3054
|
+
doctorErrors: {
|
|
3055
|
+
unreadable: "{path} \u65E0\u6CD5\u8BFB\u53D6 \u2014 {message}",
|
|
3056
|
+
cannotList: "\u65E0\u6CD5\u5217\u51FA \u2014 {message}",
|
|
3057
|
+
parseFailed: "\u65E0\u6CD5\u89E3\u6790 settings.json \u2014 {message}",
|
|
3058
|
+
probeFailed: "\u63A2\u6D4B\u5931\u8D25 \u2014 {message}"
|
|
3059
|
+
},
|
|
3060
|
+
webErrors: {
|
|
3061
|
+
status: "web_search \u72B6\u6001\u7801 {status}",
|
|
3062
|
+
mojeekBlocked: "web_search: Mojeek \u53CD\u722C\u9875\u9762 \u2014 \u9891\u7387\u9650\u5236\u6216\u88AB\u5C4F\u853D",
|
|
3063
|
+
mojeekNoResults: "web_search: \u8FD4\u56DE 0 \u6761\u7ED3\u679C\u4F46\u54CD\u5E94\u770B\u8D77\u6765\u4E0D\u662F\u6B63\u5E38\u7A7A\u7ED3\u679C\u9875\uFF08{chars} \u5B57\u7B26\uFF0C\u524D 120 \u5B57\u7B26\uFF1A{preview}\uFF09",
|
|
3064
|
+
invalidEndpoint: 'web_search: \u65E0\u6548\u7684 SearXNG \u7AEF\u70B9 "{endpoint}"',
|
|
3065
|
+
endpointMustBeHttp: "web_search: SearXNG \u7AEF\u70B9\u5FC5\u987B\u662F http(s) \u534F\u8BAE\uFF0C\u5F53\u524D\u4E3A {protocol}",
|
|
3066
|
+
cannotReach: "web_search: \u65E0\u6CD5\u8BBF\u95EE SearXNG \u670D\u52A1\u5668 {endpoint}\u3002\u8BF7\u5B89\u88C5 SearXNG\uFF08https://github.com/searxng/searxng\uFF09\u5E76\u542F\u52A8\uFF08\u4F8B\u5982 `docker run -d -p 8080:8080 searxng/searxng`\uFF09\uFF0C\u6216\u4F7F\u7528 /search-engine mojeek \u5207\u6362\u5230\u9ED8\u8BA4\u5F15\u64CE\u3002",
|
|
3067
|
+
searxngNoResults: "web_search: \u8FD4\u56DE 0 \u6761\u7ED3\u679C\u4F46 SearXNG \u54CD\u5E94\u770B\u8D77\u6765\u4E0D\u662F\u6B63\u5E38\u7A7A\u7ED3\u679C\u9875\uFF08{chars} \u5B57\u7B26\uFF09",
|
|
3068
|
+
fetchStatus: "web_fetch \u72B6\u6001\u7801 {status}\uFF08{url}\uFF09",
|
|
3069
|
+
fetchTooLarge: "web_fetch \u62D2\u7EDD\uFF1Acontent-length {len} \u5B57\u8282\u8D85\u8FC7\u4E0A\u9650 {cap} \u5B57\u8282\uFF08{url}\uFF09",
|
|
3070
|
+
fetchBodyTooLarge: "web_fetch \u62D2\u7EDD\uFF1A\u54CD\u5E94\u4F53\u8D85\u8FC7 {cap} \u5B57\u8282\u4E0A\u9650\uFF08\u5DF2\u63A5\u6536 {seen} \u5B57\u8282\uFF09",
|
|
3071
|
+
fetchInvalidUrl: "web_fetch: URL \u5FC5\u987B\u4EE5 http:// \u6216 https:// \u5F00\u5934"
|
|
3072
|
+
},
|
|
3073
|
+
choiceConfirm: {
|
|
3074
|
+
customLabel: "\u81EA\u5B9A\u4E49\u56DE\u7B54",
|
|
3075
|
+
customDesc: "\u4EE5\u4E0A\u9009\u9879\u90FD\u4E0D\u5408\u9002 \u2014 \u8F93\u5165\u81EA\u7531\u683C\u5F0F\u56DE\u590D\uFF0C\u6A21\u578B\u4F1A\u539F\u6837\u8BFB\u53D6",
|
|
3076
|
+
cancelLabel: "\u53D6\u6D88 \u2014 \u653E\u5F03\u95EE\u9898",
|
|
3077
|
+
cancelDesc: "\u6A21\u578B\u505C\u6B62\u5E76\u8BE2\u95EE\u4F60\u771F\u6B63\u7684\u9700\u6C42"
|
|
3078
|
+
},
|
|
2634
3079
|
cardTitles: {
|
|
2635
3080
|
usage: "\u7528\u91CF",
|
|
2636
3081
|
context: "\u4E0A\u4E0B\u6587",
|
|
@@ -2640,7 +3085,9 @@ var zhCN = {
|
|
|
2640
3085
|
reasoning: "\u63A8\u7406\u4E2D",
|
|
2641
3086
|
reasoningAborted: "\u63A8\u7406\uFF08\u5DF2\u4E2D\u6B62\uFF09",
|
|
2642
3087
|
reasoningEllipsis: "\u63A8\u7406\u4E2D\u2026",
|
|
2643
|
-
error: "\u9519\u8BEF"
|
|
3088
|
+
error: "\u9519\u8BEF",
|
|
3089
|
+
doctor: "\u73AF\u5883\u8BCA\u65AD",
|
|
3090
|
+
you: "\u4F60"
|
|
2644
3091
|
},
|
|
2645
3092
|
cardLabels: {
|
|
2646
3093
|
prompt: "\u63D0\u793A",
|
|
@@ -2654,7 +3101,7 @@ var zhCN = {
|
|
|
2654
3101
|
tools: "\u5DE5\u5177",
|
|
2655
3102
|
log: "\u65E5\u5FD7",
|
|
2656
3103
|
input: "\u8F93\u5165",
|
|
2657
|
-
topTools: "
|
|
3104
|
+
topTools: "\u5E38\u7528\u5DE5\u5177",
|
|
2658
3105
|
logMsgs: "\u65E5\u5FD7\u6D88\u606F",
|
|
2659
3106
|
hitSingular: "{count} \u6761\u7ED3\u679C \xB7 {files} \u4E2A\u6587\u4EF6",
|
|
2660
3107
|
hitsPlural: "{count} \u6761\u7ED3\u679C \xB7 {files} \u4E2A\u6587\u4EF6",
|
|
@@ -2679,7 +3126,42 @@ var zhCN = {
|
|
|
2679
3126
|
retries: "\u6B21\u91CD\u8BD5",
|
|
2680
3127
|
reasoningLabel: "\u63A8\u7406 \xB7 {count} \xB6",
|
|
2681
3128
|
runningLabel: "\u8FD0\u884C\u4E2D",
|
|
2682
|
-
workingLabel: "\
|
|
3129
|
+
workingLabel: "\u5904\u7406\u4E2D",
|
|
3130
|
+
defaultFooter: "\u2191\u2193 \u9009\u62E9 \xB7 \u23CE \u786E\u8BA4 \xB7 Esc \u53D6\u6D88",
|
|
3131
|
+
applyAction: "[a] \u5E94\u7528",
|
|
3132
|
+
skipAction: "[s] \u8DF3\u8FC7",
|
|
3133
|
+
rejectAction: "[r] \u62D2\u7EDD",
|
|
3134
|
+
levelOk: "\u6B63\u5E38",
|
|
3135
|
+
levelWarn: "\u8B66\u544A",
|
|
3136
|
+
levelFail: "\u5931\u8D25",
|
|
3137
|
+
checksLabel: "\u68C0\u67E5\u9879",
|
|
3138
|
+
passed: "\u901A\u8FC7",
|
|
3139
|
+
warnTag: "\u8B66\u544A",
|
|
3140
|
+
failTag: "\u5931\u8D25",
|
|
3141
|
+
stepLabel: "\u6B65\u9AA4",
|
|
3142
|
+
done: "\u5DF2\u5B8C\u6210",
|
|
3143
|
+
inProgress: "\u2190 \u8FDB\u884C\u4E2D",
|
|
3144
|
+
upcoming: "\u5F85\u5904\u7406",
|
|
3145
|
+
resumed: "\u5DF2\u6062\u590D \xB7 ",
|
|
3146
|
+
archive: "\u23EA \u5F52\u6863 \xB7 ",
|
|
3147
|
+
more: "\u22EE +{count} \u66F4\u591A",
|
|
3148
|
+
categoryUser: "\u7528\u6237",
|
|
3149
|
+
categoryFeedback: "\u53CD\u9988",
|
|
3150
|
+
categoryProject: "\u9879\u76EE",
|
|
3151
|
+
categoryReference: "\u53C2\u8003"
|
|
3152
|
+
},
|
|
3153
|
+
copyMode: {
|
|
3154
|
+
title: "\u2500\u2500 \u590D\u5236\u6A21\u5F0F \u2500\u2500",
|
|
3155
|
+
help: "j/k \u6216 \u2191/\u2193 \u79FB\u52A8 \xB7 v \u8D77\u9009\u533A \xB7 y \u590D\u5236 \xB7 g/G \u9876/\u5E95 \xB7 q \u9000\u51FA",
|
|
3156
|
+
statusBar: "\u7B2C {cur}/{total} \u884C \xB7 \u9009\u533A\uFF1A{sel}",
|
|
3157
|
+
statusYanked: "\u5DF2\u590D\u5236 {size} \u5B57\u7B26\uFF08osc52={osc52}\uFF09",
|
|
3158
|
+
statusEmpty: "\u672A\u9009\u4E2D\u5185\u5BB9",
|
|
3159
|
+
empty: "\uFF08\u8FD8\u6CA1\u6709\u804A\u5929\u5185\u5BB9 \u2014 \u5148\u548C\u6A21\u578B\u8BF4\u70B9\u4EC0\u4E48\uFF09",
|
|
3160
|
+
labelUser: "\u4F60",
|
|
3161
|
+
labelAssistant: "\u52A9\u624B",
|
|
3162
|
+
labelReasoning: "\u63A8\u7406",
|
|
3163
|
+
yankedToast: "\u25B8 \u5DF2\u590D\u5236 {size} \u5B57\u7B26\u5230\u526A\u8D34\u677F (osc52)",
|
|
3164
|
+
yankedToastFile: "\u25B8 \u5DF2\u590D\u5236 {size} \u5B57\u7B26 \xB7 \u6587\u4EF6\uFF1A{path}"
|
|
2683
3165
|
}
|
|
2684
3166
|
};
|
|
2685
3167
|
|
|
@@ -3199,6 +3681,10 @@ var ToolRegistry = class {
|
|
|
3199
3681
|
setResultAugmenter(fn) {
|
|
3200
3682
|
this._resultAugmenter = fn;
|
|
3201
3683
|
}
|
|
3684
|
+
/** True when an augmenter is already wired — lets late-installing callers skip clobbering an earlier one. */
|
|
3685
|
+
get hasResultAugmenter() {
|
|
3686
|
+
return this._resultAugmenter !== null;
|
|
3687
|
+
}
|
|
3202
3688
|
register(def) {
|
|
3203
3689
|
if (!def.name) throw new Error("tool requires a name");
|
|
3204
3690
|
const internal = { ...def };
|
|
@@ -3520,6 +4006,9 @@ function sanitizeName(name) {
|
|
|
3520
4006
|
const cleaned = name.replace(/[^\w\-\u4e00-\u9fa5]/g, "_").slice(0, 64);
|
|
3521
4007
|
return cleaned || "default";
|
|
3522
4008
|
}
|
|
4009
|
+
function timestampSuffix() {
|
|
4010
|
+
return (/* @__PURE__ */ new Date()).toISOString().replace(/[^\d]/g, "").slice(0, 12);
|
|
4011
|
+
}
|
|
3523
4012
|
function loadSessionMessages(name) {
|
|
3524
4013
|
const path2 = sessionPath(name);
|
|
3525
4014
|
if (!existsSync3(path2)) return [];
|
|
@@ -3588,6 +4077,26 @@ function loadSessionMeta(name) {
|
|
|
3588
4077
|
return {};
|
|
3589
4078
|
}
|
|
3590
4079
|
}
|
|
4080
|
+
function renameSession(oldName, newName) {
|
|
4081
|
+
const safeOld = sanitizeName(oldName);
|
|
4082
|
+
const safeNew = sanitizeName(newName);
|
|
4083
|
+
if (safeOld === safeNew) return false;
|
|
4084
|
+
const oldJsonl = sessionPath(oldName);
|
|
4085
|
+
const newJsonl = sessionPath(newName);
|
|
4086
|
+
if (!existsSync3(oldJsonl) || existsSync3(newJsonl)) return false;
|
|
4087
|
+
renameSync(oldJsonl, newJsonl);
|
|
4088
|
+
for (const ext of [".events.jsonl", ".meta.json", ".pending.json", ".plan.json"]) {
|
|
4089
|
+
const oldP = oldJsonl.replace(/\.jsonl$/, ext);
|
|
4090
|
+
const newP = newJsonl.replace(/\.jsonl$/, ext);
|
|
4091
|
+
if (existsSync3(oldP)) {
|
|
4092
|
+
try {
|
|
4093
|
+
renameSync(oldP, newP);
|
|
4094
|
+
} catch {
|
|
4095
|
+
}
|
|
4096
|
+
}
|
|
4097
|
+
}
|
|
4098
|
+
return true;
|
|
4099
|
+
}
|
|
3591
4100
|
function deleteSession(name) {
|
|
3592
4101
|
const path2 = sessionPath(name);
|
|
3593
4102
|
try {
|
|
@@ -3615,6 +4124,20 @@ function rewriteSession(name, messages) {
|
|
|
3615
4124
|
} catch {
|
|
3616
4125
|
}
|
|
3617
4126
|
}
|
|
4127
|
+
function archiveSession(name) {
|
|
4128
|
+
const path2 = sessionPath(name);
|
|
4129
|
+
if (!existsSync3(path2)) return null;
|
|
4130
|
+
try {
|
|
4131
|
+
if (statSync(path2).size === 0) return null;
|
|
4132
|
+
} catch {
|
|
4133
|
+
return null;
|
|
4134
|
+
}
|
|
4135
|
+
for (let attempt = 0; attempt < 5; attempt++) {
|
|
4136
|
+
const target = `${name}__archive_${timestampSuffix()}${attempt > 0 ? `_${attempt}` : ""}`;
|
|
4137
|
+
if (renameSession(name, target)) return target;
|
|
4138
|
+
}
|
|
4139
|
+
return null;
|
|
4140
|
+
}
|
|
3618
4141
|
function countLines(path2) {
|
|
3619
4142
|
try {
|
|
3620
4143
|
const raw = readFileSync4(path2, "utf8");
|
|
@@ -4684,6 +5207,7 @@ function signature(call) {
|
|
|
4684
5207
|
|
|
4685
5208
|
// src/loop.ts
|
|
4686
5209
|
var ESCALATION_MODEL = "deepseek-v4-pro";
|
|
5210
|
+
var PARENT_BUDGET_WARN_THRESHOLD = 5;
|
|
4687
5211
|
var CacheFirstLoop = class {
|
|
4688
5212
|
client;
|
|
4689
5213
|
prefix;
|
|
@@ -4720,6 +5244,7 @@ var CacheFirstLoop = class {
|
|
|
4720
5244
|
_turnFailures = new TurnFailureTracker();
|
|
4721
5245
|
_turnSelfCorrected = false;
|
|
4722
5246
|
_foldedThisTurn = false;
|
|
5247
|
+
_toolDispatchesThisStep = 0;
|
|
4723
5248
|
context;
|
|
4724
5249
|
/** Subscribe API so UI hooks can derive `running` from finally-guaranteed insertions. */
|
|
4725
5250
|
get inflight() {
|
|
@@ -4774,6 +5299,23 @@ var CacheFirstLoop = class {
|
|
|
4774
5299
|
stormThreshold: parsePositiveIntEnv(process.env.REASONIX_STORM_THRESHOLD),
|
|
4775
5300
|
stormWindow: parsePositiveIntEnv(process.env.REASONIX_STORM_WINDOW)
|
|
4776
5301
|
});
|
|
5302
|
+
if (!this.tools.hasResultAugmenter) {
|
|
5303
|
+
this.tools.setResultAugmenter((_name, _args, result) => {
|
|
5304
|
+
this._toolDispatchesThisStep++;
|
|
5305
|
+
const remaining = this.maxToolIters - this._toolDispatchesThisStep;
|
|
5306
|
+
if (remaining <= 0) {
|
|
5307
|
+
return `${result}
|
|
5308
|
+
|
|
5309
|
+
[budget: 0 of ${this.maxToolIters} tool calls left this turn \u2014 finalize NOW; the next iter forces a summary]`;
|
|
5310
|
+
}
|
|
5311
|
+
if (remaining <= PARENT_BUDGET_WARN_THRESHOLD) {
|
|
5312
|
+
return `${result}
|
|
5313
|
+
|
|
5314
|
+
[budget: ${remaining} of ${this.maxToolIters} tool calls left this turn \u2014 wrap up soon]`;
|
|
5315
|
+
}
|
|
5316
|
+
return result;
|
|
5317
|
+
});
|
|
5318
|
+
}
|
|
4777
5319
|
this.sessionName = opts.session ?? null;
|
|
4778
5320
|
if (this.sessionName) {
|
|
4779
5321
|
const prior = loadSessionMessages(this.sessionName);
|
|
@@ -4844,19 +5386,21 @@ var CacheFirstLoop = class {
|
|
|
4844
5386
|
}
|
|
4845
5387
|
}
|
|
4846
5388
|
}
|
|
4847
|
-
/** "New chat" — drops messages
|
|
5389
|
+
/** "New chat" — drops in-memory messages, archives the on-disk transcript so it survives in Sessions, keeps sessionName so the prefix cache stays warm. */
|
|
4848
5390
|
clearLog() {
|
|
4849
5391
|
const dropped = this.log.length;
|
|
4850
5392
|
this.log.compactInPlace([]);
|
|
5393
|
+
let archived = null;
|
|
4851
5394
|
if (this.sessionName) {
|
|
4852
5395
|
try {
|
|
4853
|
-
|
|
5396
|
+
archived = archiveSession(this.sessionName);
|
|
5397
|
+
if (archived === null) rewriteSession(this.sessionName, []);
|
|
4854
5398
|
} catch {
|
|
4855
5399
|
}
|
|
4856
5400
|
}
|
|
4857
5401
|
this.scratch.reset();
|
|
4858
5402
|
this._inflight.clear();
|
|
4859
|
-
return { dropped };
|
|
5403
|
+
return { dropped, archived };
|
|
4860
5404
|
}
|
|
4861
5405
|
configure(opts) {
|
|
4862
5406
|
if (opts.model !== void 0) this.model = opts.model;
|
|
@@ -5025,6 +5569,7 @@ ${reason}`
|
|
|
5025
5569
|
this._turnSelfCorrected = false;
|
|
5026
5570
|
this._escalateThisTurn = false;
|
|
5027
5571
|
this._foldedThisTurn = false;
|
|
5572
|
+
this._toolDispatchesThisStep = 0;
|
|
5028
5573
|
let armedConsumed = false;
|
|
5029
5574
|
if (this._proArmedForNextTurn) {
|
|
5030
5575
|
this._escalateThisTurn = true;
|
|
@@ -6042,15 +6587,21 @@ var TUI_FORMATTING_RULES = `Formatting (rendered in a TUI with a real markdown r
|
|
|
6042
6587
|
- Code, file paths with line ranges, and shell commands \u2192 fenced code blocks (\`\`\`).
|
|
6043
6588
|
- Do NOT draw decorative frames around content with \`\u250C\u2500\u2500\u2510 \u2502 \u2514\u2500\u2500\u2518\` characters. The renderer adds its own borders; extra ASCII art adds noise and shatters at narrow widths.
|
|
6044
6589
|
- For flow charts and diagrams: a plain bullet list with \`\u2192\` or \`\u2193\` between steps. Don't try to draw boxes-and-arrows in ASCII; it never survives word-wrap.`;
|
|
6045
|
-
|
|
6590
|
+
function escalationContract(modelId) {
|
|
6591
|
+
if (modelId === "deepseek-v4-pro") {
|
|
6592
|
+
return `Cost-aware escalation note: you are running on \`${modelId}\` \u2014 the escalation tier. There is no higher tier to escalate to, so the \`<<<NEEDS_PRO>>>\` marker is a no-op for you; deliver the strongest answer you can directly. If asked which model you are, answer \`${modelId}\`.`;
|
|
6593
|
+
}
|
|
6594
|
+
return `Cost-aware escalation (you are running on \`${modelId}\`):
|
|
6046
6595
|
|
|
6047
|
-
If a task CLEARLY exceeds what
|
|
6596
|
+
If a task CLEARLY exceeds what this tier can do well \u2014 complex cross-file architecture refactors, subtle concurrency / security / correctness invariants you can't resolve with confidence, or a design trade-off you'd be guessing at \u2014 output the marker as the FIRST line of your response (nothing before it, not even whitespace on a separate line). This aborts the current call and retries this turn on deepseek-v4-pro, one shot.
|
|
6048
6597
|
|
|
6049
6598
|
Two accepted forms:
|
|
6050
6599
|
- \`<<<NEEDS_PRO>>>\` \u2014 bare marker, no rationale.
|
|
6051
6600
|
- \`<<<NEEDS_PRO: <one-sentence reason>>>>\` \u2014 preferred. The reason text appears in the user-visible warning ("\u21E7 flash requested escalation \u2014 <your reason>"), so they understand WHY a more expensive call is happening. Keep it under ~150 chars, no newlines, no nested \`>\` characters. Examples: \`<<<NEEDS_PRO: cross-file refactor across 6 modules with circular imports>>>\` or \`<<<NEEDS_PRO: subtle session-token race; flash would likely miss the locking invariant>>>\`.
|
|
6052
6601
|
|
|
6053
|
-
Do NOT emit any other content in the same response when you request escalation. Use this sparingly: normal tasks \u2014 reading files, small edits, clear bug fixes, straightforward feature additions \u2014 stay on
|
|
6602
|
+
Do NOT emit any other content in the same response when you request escalation. Use this sparingly: normal tasks \u2014 reading files, small edits, clear bug fixes, straightforward feature additions \u2014 stay on this tier. Request escalation ONLY when you would otherwise produce a guess or a visibly-mediocre answer. If in doubt, attempt the task here first; the system also escalates automatically if you hit 3+ repair / SEARCH-mismatch errors in a single turn (the user sees a typed breakdown). If asked which model you are, answer \`${modelId}\`.`;
|
|
6603
|
+
}
|
|
6604
|
+
var ESCALATION_CONTRACT = escalationContract("deepseek-v4-flash");
|
|
6054
6605
|
var NEGATIVE_CLAIM_RULE = `Negative claims ("X is missing", "Y isn't implemented", "there's no Z") are the #1 hallucination shape. They feel safe to write because no citation seems possible \u2014 but that's exactly why you must NOT write them on instinct.
|
|
6055
6606
|
|
|
6056
6607
|
If you have a search tool (\`search_content\`, \`grep\`, web search), call it FIRST before asserting absence:
|
|
@@ -6249,11 +6800,14 @@ function skillIndexLine(s) {
|
|
|
6249
6800
|
const clipped = safeDesc.length > max ? `${safeDesc.slice(0, Math.max(1, max - 1))}\u2026` : safeDesc;
|
|
6250
6801
|
return clipped ? `- ${s.name}${tag} \u2014 ${clipped}` : `- ${s.name}${tag}`;
|
|
6251
6802
|
}
|
|
6803
|
+
var MISSING_DESCRIPTION_PLACEHOLDER = '(no description \u2014 frontmatter is missing a "description:" line; tell the user to add one)';
|
|
6252
6804
|
function applySkillsIndex(basePrompt, opts = {}) {
|
|
6253
6805
|
const store = new SkillStore(opts);
|
|
6254
|
-
const skills = store.list()
|
|
6806
|
+
const skills = store.list();
|
|
6255
6807
|
if (skills.length === 0) return basePrompt;
|
|
6256
|
-
const lines = skills.map(
|
|
6808
|
+
const lines = skills.map(
|
|
6809
|
+
(s) => skillIndexLine(s.description ? s : { ...s, description: MISSING_DESCRIPTION_PLACEHOLDER })
|
|
6810
|
+
);
|
|
6257
6811
|
const joined = lines.join("\n");
|
|
6258
6812
|
const truncated = joined.length > SKILLS_INDEX_MAX_CHARS ? `${joined.slice(0, SKILLS_INDEX_MAX_CHARS)}
|
|
6259
6813
|
\u2026 (truncated ${joined.length - SKILLS_INDEX_MAX_CHARS} chars)` : joined;
|
|
@@ -7697,6 +8251,74 @@ Prefer \`list_directory\` for a single-level view, \`search_files\` to find spec
|
|
|
7697
8251
|
return `moved ${displayRel4(rootDir, src)} \u2192 ${displayRel4(rootDir, dst)}`;
|
|
7698
8252
|
}
|
|
7699
8253
|
});
|
|
8254
|
+
registry.register({
|
|
8255
|
+
name: "delete_file",
|
|
8256
|
+
description: "Delete one file under the sandbox root. Refuses directories \u2014 use delete_directory for those. Errors if the path doesn't exist.",
|
|
8257
|
+
parameters: {
|
|
8258
|
+
type: "object",
|
|
8259
|
+
properties: { path: { type: "string" } },
|
|
8260
|
+
required: ["path"]
|
|
8261
|
+
},
|
|
8262
|
+
fn: async (args) => {
|
|
8263
|
+
const abs = safePath(args.path);
|
|
8264
|
+
const st = await fs4.lstat(abs);
|
|
8265
|
+
if (st.isDirectory()) {
|
|
8266
|
+
throw new Error(
|
|
8267
|
+
`delete_file: ${args.path} is a directory \u2014 use delete_directory to remove it`
|
|
8268
|
+
);
|
|
8269
|
+
}
|
|
8270
|
+
await fs4.unlink(abs);
|
|
8271
|
+
return `deleted ${displayRel4(rootDir, abs)}`;
|
|
8272
|
+
}
|
|
8273
|
+
});
|
|
8274
|
+
registry.register({
|
|
8275
|
+
name: "delete_directory",
|
|
8276
|
+
description: "Recursively delete a directory under the sandbox root. Pass `recursive:false` to refuse non-empty directories. Errors if the path doesn't exist.",
|
|
8277
|
+
parameters: {
|
|
8278
|
+
type: "object",
|
|
8279
|
+
properties: {
|
|
8280
|
+
path: { type: "string" },
|
|
8281
|
+
recursive: {
|
|
8282
|
+
type: "boolean",
|
|
8283
|
+
description: "When true (default) deletes the directory and all its contents. When false, only removes empty directories \u2014 non-empty refuses with an error."
|
|
8284
|
+
}
|
|
8285
|
+
},
|
|
8286
|
+
required: ["path"]
|
|
8287
|
+
},
|
|
8288
|
+
fn: async (args) => {
|
|
8289
|
+
const abs = safePath(args.path);
|
|
8290
|
+
const st = await fs4.lstat(abs);
|
|
8291
|
+
if (!st.isDirectory()) {
|
|
8292
|
+
throw new Error(`delete_directory: ${args.path} is a file \u2014 use delete_file to remove it`);
|
|
8293
|
+
}
|
|
8294
|
+
const recursive = args.recursive !== false;
|
|
8295
|
+
if (recursive) {
|
|
8296
|
+
await fs4.rm(abs, { recursive: true, force: false });
|
|
8297
|
+
} else {
|
|
8298
|
+
await fs4.rmdir(abs);
|
|
8299
|
+
}
|
|
8300
|
+
return `deleted ${displayRel4(rootDir, abs)}/${recursive ? " (recursive)" : ""}`;
|
|
8301
|
+
}
|
|
8302
|
+
});
|
|
8303
|
+
registry.register({
|
|
8304
|
+
name: "copy_file",
|
|
8305
|
+
description: "Copy a file or directory under the sandbox root. Both source and destination resolve under the sandbox. Parent directories of the destination are created as needed. Refuses to overwrite an existing destination \u2014 delete it first if you want to replace it.",
|
|
8306
|
+
parameters: {
|
|
8307
|
+
type: "object",
|
|
8308
|
+
properties: {
|
|
8309
|
+
source: { type: "string" },
|
|
8310
|
+
destination: { type: "string" }
|
|
8311
|
+
},
|
|
8312
|
+
required: ["source", "destination"]
|
|
8313
|
+
},
|
|
8314
|
+
fn: async (args) => {
|
|
8315
|
+
const src = safePath(args.source);
|
|
8316
|
+
const dst = safePath(args.destination);
|
|
8317
|
+
await fs4.mkdir(pathMod4.dirname(dst), { recursive: true });
|
|
8318
|
+
await fs4.cp(src, dst, { recursive: true, force: false, errorOnExist: true });
|
|
8319
|
+
return `copied ${displayRel4(rootDir, src)} \u2192 ${displayRel4(rootDir, dst)}`;
|
|
8320
|
+
}
|
|
8321
|
+
});
|
|
7700
8322
|
return registry;
|
|
7701
8323
|
}
|
|
7702
8324
|
|
|
@@ -8330,7 +8952,7 @@ function nextRunId() {
|
|
|
8330
8952
|
runIdCounter++;
|
|
8331
8953
|
return `sub-${runIdCounter.toString(36)}`;
|
|
8332
8954
|
}
|
|
8333
|
-
var
|
|
8955
|
+
var SUBAGENT_BASE_SYSTEM = `You are a Reasonix subagent. The parent agent spawned you to handle one focused subtask, then return.
|
|
8334
8956
|
|
|
8335
8957
|
Rules:
|
|
8336
8958
|
- Stay on the task you were given. Do not expand scope.
|
|
@@ -8340,8 +8962,6 @@ Rules:
|
|
|
8340
8962
|
|
|
8341
8963
|
${NEGATIVE_CLAIM_RULE}
|
|
8342
8964
|
|
|
8343
|
-
${ESCALATION_CONTRACT}
|
|
8344
|
-
|
|
8345
8965
|
${TUI_FORMATTING_RULES}`;
|
|
8346
8966
|
var DEFAULT_MAX_RESULT_CHARS2 = 8e3;
|
|
8347
8967
|
var DEFAULT_MAX_ITERS = 16;
|
|
@@ -8355,6 +8975,18 @@ var DEFAULT_SUBAGENT_MODEL = "deepseek-v4-flash";
|
|
|
8355
8975
|
var DEFAULT_SUBAGENT_EFFORT = "high";
|
|
8356
8976
|
var SUBAGENT_TOOL_NAME = "spawn_subagent";
|
|
8357
8977
|
var NEVER_INHERITED_TOOLS = /* @__PURE__ */ new Set([SUBAGENT_TOOL_NAME, "submit_plan"]);
|
|
8978
|
+
var SOFT_HINT_AFTER_SPAWNS = 1;
|
|
8979
|
+
var STRONG_HINT_AFTER_SPAWNS = 4;
|
|
8980
|
+
var STRONG_HINT_TOKEN_THRESHOLD = 5e4;
|
|
8981
|
+
function subagentBudgetHint(spawnCount, totalTokens) {
|
|
8982
|
+
if (spawnCount > STRONG_HINT_AFTER_SPAWNS || totalTokens >= STRONG_HINT_TOKEN_THRESHOLD) {
|
|
8983
|
+
return `[budget: this session has now spawned ${spawnCount} subagents totalling ${totalTokens} tokens. Each spawn pays a fresh prefix-cache miss plus a full child loop \u2014 confirm the next spawn is genuinely needed (parallel fan-out or >10-read context blow-up) before calling spawn_subagent again. If you can answer with direct tools, do that instead.]`;
|
|
8984
|
+
}
|
|
8985
|
+
if (spawnCount > SOFT_HINT_AFTER_SPAWNS) {
|
|
8986
|
+
return `[note: this session has spawned ${spawnCount} subagents totalling ${totalTokens} tokens; confirm this one is worth it.]`;
|
|
8987
|
+
}
|
|
8988
|
+
return null;
|
|
8989
|
+
}
|
|
8358
8990
|
async function spawnSubagent(opts) {
|
|
8359
8991
|
const model = opts.model ?? DEFAULT_SUBAGENT_MODEL;
|
|
8360
8992
|
const maxToolIters = opts.maxToolIters ?? DEFAULT_MAX_ITERS;
|
|
@@ -8570,16 +9202,18 @@ function formatSubagentResult(r) {
|
|
|
8570
9202
|
});
|
|
8571
9203
|
}
|
|
8572
9204
|
function registerSubagentTool(parentRegistry, opts) {
|
|
8573
|
-
const baseSystem = opts.defaultSystem ??
|
|
8574
|
-
const
|
|
9205
|
+
const baseSystem = opts.defaultSystem ?? SUBAGENT_BASE_SYSTEM;
|
|
9206
|
+
const defaultSystemBase = opts.projectRoot ? applyProjectMemory(baseSystem, opts.projectRoot) : baseSystem;
|
|
8575
9207
|
const defaultModel = opts.defaultModel ?? DEFAULT_SUBAGENT_MODEL;
|
|
8576
9208
|
const maxToolIters = opts.maxToolIters ?? DEFAULT_MAX_ITERS;
|
|
8577
9209
|
const maxResultChars = opts.maxResultChars ?? DEFAULT_MAX_RESULT_CHARS2;
|
|
8578
9210
|
const sink = opts.sink;
|
|
9211
|
+
let sessionSpawnCount = 0;
|
|
9212
|
+
let sessionSpawnTokens = 0;
|
|
8579
9213
|
parentRegistry.register({
|
|
8580
9214
|
name: SUBAGENT_TOOL_NAME,
|
|
8581
9215
|
parallelSafe: true,
|
|
8582
|
-
description: "Spawn an isolated subagent to handle a self-contained subtask in a fresh context, returning only its final answer.
|
|
9216
|
+
description: "Spawn an isolated subagent to handle a self-contained subtask in a fresh context, returning only its final answer. **Prefer direct tools.** Spawn primarily for parallel fan-out (2+ independent investigations issued in one tool batch) or when the work would otherwise need >10 file reads/searches whose trail you don't need to keep. Single greps, 1-3 file cross-references, and 'keep my context clean for one question' are NOT good reasons to spawn \u2014 direct tools are cheaper and let you reference the evidence later. Each spawn pays a fresh prefix-cache miss plus a full child loop. The subagent inherits your tools but runs in its own isolated message log; only the final assistant message comes back. Keep tasks focused; the subagent has a stricter iter budget than you do.",
|
|
8583
9217
|
parameters: {
|
|
8584
9218
|
type: "object",
|
|
8585
9219
|
properties: {
|
|
@@ -8618,8 +9252,10 @@ function registerSubagentTool(parentRegistry, opts) {
|
|
|
8618
9252
|
});
|
|
8619
9253
|
}
|
|
8620
9254
|
const typeSpec = getSubagentType(args.type);
|
|
8621
|
-
const system = typeof args.system === "string" && args.system.trim().length > 0 ? args.system.trim() : typeSpec?.system ?? defaultSystem;
|
|
8622
9255
|
const model = typeof args.model === "string" && args.model.startsWith("deepseek-") ? args.model : defaultModel;
|
|
9256
|
+
const system = typeof args.system === "string" && args.system.trim().length > 0 ? args.system.trim() : typeSpec?.system ?? `${defaultSystemBase}
|
|
9257
|
+
|
|
9258
|
+
${escalationContract(model)}`;
|
|
8623
9259
|
const callerIters = clampMaxIters(args.max_iters);
|
|
8624
9260
|
const result = await spawnSubagent({
|
|
8625
9261
|
client: opts.client,
|
|
@@ -8632,7 +9268,12 @@ function registerSubagentTool(parentRegistry, opts) {
|
|
|
8632
9268
|
sink,
|
|
8633
9269
|
parentSignal: ctx?.signal
|
|
8634
9270
|
});
|
|
8635
|
-
|
|
9271
|
+
sessionSpawnCount++;
|
|
9272
|
+
sessionSpawnTokens += result.usage.totalTokens;
|
|
9273
|
+
const formatted = formatSubagentResult(result);
|
|
9274
|
+
const hint = subagentBudgetHint(sessionSpawnCount, sessionSpawnTokens);
|
|
9275
|
+
return hint ? `${formatted}
|
|
9276
|
+
${hint}` : formatted;
|
|
8636
9277
|
}
|
|
8637
9278
|
});
|
|
8638
9279
|
return parentRegistry;
|
|
@@ -9948,7 +10589,7 @@ function registerShellTools(registry, opts) {
|
|
|
9948
10589
|
const isAllowAll = typeof opts.allowAll === "function" ? opts.allowAll : () => opts.allowAll === true;
|
|
9949
10590
|
registry.register({
|
|
9950
10591
|
name: "run_command",
|
|
9951
|
-
description: "Run a shell command in the project root
|
|
10592
|
+
description: "Run a shell command in the project root; returns combined stdout+stderr. Allowlisted read-only / test / lint / typecheck commands run immediately; anything that could mutate state, install deps, or touch the network is gated by user confirmation. Prefer this over asking the user to run a command manually \u2014 after edits, run the project's tests to verify.\n\nConstraints (no real shell \u2014 argv is parsed natively for cross-platform parity):\n\u2022 Supported: chain ops `|` / `||` / `&&` / `;` (each segment allowlist-checked individually), file redirects `>` / `>>` / `<` / `2>` / `2>>` / `2>&1` / `&>` (target paths resolve relative to project root, max one redirect per fd per segment).\n\u2022 NOT supported: background `&`, heredoc `<<`, command substitution `$(\u2026)`, subshells `(\u2026)`, process substitution `<(\u2026)`, `$VAR` env expansion, glob expansion. To pass an operator char as literal arg, quote it (`grep \"a|b\" file`).\n\u2022 `cd` does NOT persist \u2014 between calls OR within a chain like `cd dir && cmd`. Use the binary's own cwd flag: `npm --prefix <dir>`, `git -C <dir>`, `cargo -C <dir>`, `pytest <dir>/tests`.\n\u2022 Filter at source \u2014 unbounded output (`netstat -ano`, `find /`) wastes tokens. Use `grep -c`, `wc -l`, narrower paths, etc.",
|
|
9952
10593
|
// Plan-mode gate: allow allowlisted commands through (git status,
|
|
9953
10594
|
// cargo check, ls, grep …) so the model can actually investigate
|
|
9954
10595
|
// during planning. Anything that would otherwise trigger a
|
|
@@ -10000,7 +10641,7 @@ function registerShellTools(registry, opts) {
|
|
|
10000
10641
|
});
|
|
10001
10642
|
registry.register({
|
|
10002
10643
|
name: "run_background",
|
|
10003
|
-
description: "Spawn a long-running process (dev server, watcher
|
|
10644
|
+
description: "Spawn a long-running process (dev server, watcher) and detach. Waits up to `waitSec` for startup or a readiness signal ('Local:', 'listening on', 'compiled successfully'), then returns the job id + startup preview. Tail logs with `job_output`, kill with `stop_job`, list with `list_jobs`.\n\nSingle process only \u2014 chains / redirects / `cd` work as in run_command, but a typical dev-server invocation is one binary. Use the binary's own --cwd / --prefix flag for subdirectories. Vite gotcha: npm's `--prefix` only finds package.json; vite's server root still uses process cwd \u2014 pass `vite <project-dir>` instead.\n\nUSE THIS \u2014 not run_command \u2014 for: npm/yarn/pnpm dev, uvicorn / flask run, cargo watch, tsc --watch, webpack serve, anything with dev/serve/watch in the name.",
|
|
10004
10645
|
parameters: {
|
|
10005
10646
|
type: "object",
|
|
10006
10647
|
properties: {
|
|
@@ -10072,6 +10713,8 @@ function registerShellTools(registry, opts) {
|
|
|
10072
10713
|
name: "wait_for_job",
|
|
10073
10714
|
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`.",
|
|
10074
10715
|
readOnly: true,
|
|
10716
|
+
parallelSafe: true,
|
|
10717
|
+
stormExempt: true,
|
|
10075
10718
|
parameters: {
|
|
10076
10719
|
type: "object",
|
|
10077
10720
|
properties: {
|
|
@@ -10190,16 +10833,19 @@ async function searchMojeek(query, opts = {}) {
|
|
|
10190
10833
|
signal: opts.signal,
|
|
10191
10834
|
redirect: "follow"
|
|
10192
10835
|
});
|
|
10193
|
-
if (!resp.ok) throw new Error(
|
|
10836
|
+
if (!resp.ok) throw new Error(t("webErrors.status", { status: resp.status }));
|
|
10194
10837
|
const html = await resp.text();
|
|
10195
10838
|
const results = parseMojeekResults(html).slice(0, topK);
|
|
10196
10839
|
if (results.length === 0) {
|
|
10197
10840
|
if (/no results found|did not match any documents/i.test(html)) return [];
|
|
10198
10841
|
if (/captcha|verify you are human|access denied|forbidden/i.test(html)) {
|
|
10199
|
-
throw new Error("
|
|
10842
|
+
throw new Error(t("webErrors.mojeekBlocked"));
|
|
10200
10843
|
}
|
|
10201
10844
|
throw new Error(
|
|
10202
|
-
|
|
10845
|
+
t("webErrors.mojeekNoResults", {
|
|
10846
|
+
chars: html.length,
|
|
10847
|
+
preview: html.slice(0, 120).replace(/\s+/g, " ")
|
|
10848
|
+
})
|
|
10203
10849
|
);
|
|
10204
10850
|
}
|
|
10205
10851
|
return results;
|
|
@@ -10209,10 +10855,10 @@ function normalizeSearxngEndpoint(raw) {
|
|
|
10209
10855
|
try {
|
|
10210
10856
|
url = new URL(raw.includes("://") ? raw : `http://${raw}`);
|
|
10211
10857
|
} catch {
|
|
10212
|
-
throw new Error(
|
|
10858
|
+
throw new Error(t("webErrors.invalidEndpoint", { endpoint: raw }));
|
|
10213
10859
|
}
|
|
10214
10860
|
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
10215
|
-
throw new Error(
|
|
10861
|
+
throw new Error(t("webErrors.endpointMustBeHttp", { protocol: url.protocol }));
|
|
10216
10862
|
}
|
|
10217
10863
|
return url.origin;
|
|
10218
10864
|
}
|
|
@@ -10232,19 +10878,17 @@ async function searchSearxng(query, opts = {}) {
|
|
|
10232
10878
|
} catch (err) {
|
|
10233
10879
|
if (err instanceof TypeError && err.message.includes("fetch")) {
|
|
10234
10880
|
throw new Error(
|
|
10235
|
-
|
|
10881
|
+
t("webErrors.cannotReach", { endpoint: opts.endpoint ?? "http://localhost:8080" })
|
|
10236
10882
|
);
|
|
10237
10883
|
}
|
|
10238
10884
|
throw err;
|
|
10239
10885
|
}
|
|
10240
|
-
if (!resp.ok) throw new Error(
|
|
10886
|
+
if (!resp.ok) throw new Error(t("webErrors.status", { status: resp.status }));
|
|
10241
10887
|
const html = await resp.text();
|
|
10242
10888
|
const results = parseSearxngHtmlResults(html).slice(0, topK);
|
|
10243
10889
|
if (results.length === 0) {
|
|
10244
10890
|
if (/no results found|did not match any documents/i.test(html)) return [];
|
|
10245
|
-
throw new Error(
|
|
10246
|
-
`web_search: 0 results but SearXNG response doesn't look like an empty results page (${html.length} chars)`
|
|
10247
|
-
);
|
|
10891
|
+
throw new Error(t("webErrors.searxngNoResults", { chars: html.length }));
|
|
10248
10892
|
}
|
|
10249
10893
|
return results;
|
|
10250
10894
|
}
|
|
@@ -10338,13 +10982,11 @@ async function webFetch(url, opts = {}) {
|
|
|
10338
10982
|
clearTimeout(timer);
|
|
10339
10983
|
opts.signal?.removeEventListener("abort", cancel);
|
|
10340
10984
|
}
|
|
10341
|
-
if (!resp.ok) throw new Error(
|
|
10985
|
+
if (!resp.ok) throw new Error(t("webErrors.fetchStatus", { status: resp.status, url }));
|
|
10342
10986
|
const contentType = resp.headers.get("content-type") ?? "";
|
|
10343
10987
|
const declaredLen = Number(resp.headers.get("content-length") ?? "");
|
|
10344
10988
|
if (Number.isFinite(declaredLen) && declaredLen > FETCH_MAX_BYTES) {
|
|
10345
|
-
throw new Error(
|
|
10346
|
-
`web_fetch refused: content-length ${declaredLen} bytes exceeds ${FETCH_MAX_BYTES}-byte cap (${url})`
|
|
10347
|
-
);
|
|
10989
|
+
throw new Error(t("webErrors.fetchTooLarge", { len: declaredLen, cap: FETCH_MAX_BYTES, url }));
|
|
10348
10990
|
}
|
|
10349
10991
|
const raw = await readBodyCapped(resp, FETCH_MAX_BYTES);
|
|
10350
10992
|
const title = extractTitle(raw);
|
|
@@ -10371,9 +11013,7 @@ async function readBodyCapped(resp, maxBytes) {
|
|
|
10371
11013
|
await reader.cancel();
|
|
10372
11014
|
} catch {
|
|
10373
11015
|
}
|
|
10374
|
-
throw new Error(
|
|
10375
|
-
`web_fetch refused: response body exceeded ${maxBytes}-byte cap (${total} bytes seen)`
|
|
10376
|
-
);
|
|
11016
|
+
throw new Error(t("webErrors.fetchBodyTooLarge", { cap: maxBytes, seen: total }));
|
|
10377
11017
|
}
|
|
10378
11018
|
out += decoder.decode(value, { stream: true });
|
|
10379
11019
|
}
|
|
@@ -10501,7 +11141,7 @@ function registerWebTools(registry, opts = {}) {
|
|
|
10501
11141
|
},
|
|
10502
11142
|
fn: async (args, ctx) => {
|
|
10503
11143
|
if (!/^https?:\/\//i.test(args.url)) {
|
|
10504
|
-
throw new Error("
|
|
11144
|
+
throw new Error(t("webErrors.fetchInvalidUrl"));
|
|
10505
11145
|
}
|
|
10506
11146
|
const page = await webFetch(args.url, { maxChars: maxFetchChars, signal: ctx?.signal });
|
|
10507
11147
|
const header = page.title ? `${page.title}
|
|
@@ -12022,7 +12662,11 @@ function lineEndingOf(text) {
|
|
|
12022
12662
|
// src/code/prompt.ts
|
|
12023
12663
|
import { existsSync as existsSync11, readFileSync as readFileSync14 } from "fs";
|
|
12024
12664
|
import { join as join13 } from "path";
|
|
12025
|
-
var
|
|
12665
|
+
var DEFAULT_CODE_MODEL = "deepseek-v4-flash";
|
|
12666
|
+
function codeSystemBase(modelId) {
|
|
12667
|
+
return CODE_SYSTEM_TEMPLATE.replace("__ESCALATION_CONTRACT__", escalationContract(modelId));
|
|
12668
|
+
}
|
|
12669
|
+
var CODE_SYSTEM_TEMPLATE = `You are Reasonix Code, a coding assistant. You have filesystem tools (read_file, write_file, edit_file, multi_edit, list_directory, directory_tree, search_files, search_content, glob, get_file_info) rooted at the user's working directory, plus run_command / run_background for shell, plus \`todo_write\` for in-session multi-step tracking.
|
|
12026
12670
|
|
|
12027
12671
|
# Identity is fixed by this prompt \u2014 never inferred from the workspace
|
|
12028
12672
|
|
|
@@ -12050,6 +12694,17 @@ If you are about to write "X is missing" or "Y is not implemented" \u2014 **STOP
|
|
|
12050
12694
|
|
|
12051
12695
|
Asserting absence without a search is the #1 way evaluative answers go wrong. Treat the urge to write "missing" as a red flag in your own reasoning.
|
|
12052
12696
|
|
|
12697
|
+
# When auditing or reviewing this codebase
|
|
12698
|
+
|
|
12699
|
+
When you're asked to audit / review / critique Reasonix itself ("what tools are missing?", "review the prompt system", "anything wrong with how X works?"), the failure mode isn't hallucinating absences \u2014 it's building confident, well-structured proposals on factually wrong premises. Six rails:
|
|
12700
|
+
|
|
12701
|
+
- **Auto-preview is for locating, not auditing.** Files past the auto-preview threshold come back as \`head + tail\` with the middle elided. Don't conclude what's in the elided section \u2014 runtime behavior, current architectural state, whether a plan doc is still accurate \u2014 off the preview. Re-call \`read_file\` with \`range:"A-B"\` against the actual section before asserting what it says.
|
|
12702
|
+
- **Flag \u2192 consumer trace.** Reading a type field (\`parallelSafe?: boolean\`, \`stormExempt?: boolean\`) is not understanding behavior. Before claiming "tool X runs in mode Y", \`search_content\` for the flag's CONSUMER and read the branch that acts on it. **For inventory claims** ("which tools have flag F?"), grep the flag \u2014 don't enumerate from memory; the field is set per-tool and easily mis-recalled.
|
|
12703
|
+
- **No fabricated percentages.** "Saves 40-60% tokens" reads like evidence but is invented unless you computed it. Ground numbers in a cited transcript / token count, or use hedged language ("small but non-zero", "may compound") \u2014 never present an unmeasured number as a measured one.
|
|
12704
|
+
- **Schema cost is real.** Every tool's description ships in every request. A new-tool proposal MUST cover (a) which existing-tool composition fails to do this, (b) rough description-token cost, (c) why a prompt or description change can't reach the same end. Default to "tighten prompt / existing tool" before "add tool".
|
|
12705
|
+
- **MEMORY.md is part of the design space.** The pinned memory blocks above are loaded user feedback \u2014 recommendations contradicting them ("auto-commit checkpoints", "free-credit messaging", anything the user has explicitly ruled out) are wrong by construction. Cross-check before proposing.
|
|
12706
|
+
- **User-facing \u2260 model-facing \u2260 library-facing.** Reasonix has four action surfaces: slash commands (user), tools (model), UI (user), and library exports (\`src/index.ts\`). Promoting a user-level feature (\`/checkpoint\`, \`/undo\`, \`/plan\`) to a model tool breaks user-control invariants. Treating a library export as "dead code" because the CLI doesn't register it to the model misreads the design \u2014 embedders consume \`src/index.ts\` directly.
|
|
12707
|
+
|
|
12053
12708
|
# When to propose a plan (submit_plan)
|
|
12054
12709
|
|
|
12055
12710
|
You have a \`submit_plan\` tool that shows the user a markdown plan and lets them Approve / Refine / Cancel before you execute. Use it proactively when the task is large enough to deserve a review gate:
|
|
@@ -12094,7 +12749,7 @@ Call shape: \`{ todos: [{ content, activeForm, status }, ...] }\` \u2014 \`conte
|
|
|
12094
12749
|
# Plan mode (/plan)
|
|
12095
12750
|
|
|
12096
12751
|
The user can ALSO enter "plan mode" via /plan, which is a stronger, explicit constraint:
|
|
12097
|
-
- Write tools (edit_file, multi_edit, write_file, create_directory, move_file) and non-allowlisted run_command calls are BOUNCED at dispatch \u2014 you'll get a tool result like "unavailable in plan mode". Don't retry them.
|
|
12752
|
+
- Write tools (edit_file, multi_edit, write_file, create_directory, move_file, copy_file, delete_file, delete_directory) and non-allowlisted run_command calls are BOUNCED at dispatch \u2014 you'll get a tool result like "unavailable in plan mode". Don't retry them.
|
|
12098
12753
|
- Read tools (read_file, list_directory, search_files, directory_tree, get_file_info) and allowlisted read-only / test shell commands still work \u2014 use them to investigate.
|
|
12099
12754
|
- You MUST call submit_plan before anything will execute. Approve exits plan mode; Refine stays in; Cancel exits without implementing.
|
|
12100
12755
|
|
|
@@ -12109,15 +12764,18 @@ Two built-ins ship by default:
|
|
|
12109
12764
|
- **explore** \`[\u{1F9EC} subagent]\` \u2014 read-only investigation across the codebase. Use when the user says things like "find all places that...", "how does X work across the project", "survey the code for Y". Pass \`arguments\` describing the concrete question.
|
|
12110
12765
|
- **research** \`[\u{1F9EC} subagent]\` \u2014 combines web search + code reading. Use for "is X supported by lib Y", "what's the canonical way to Z", "compare our impl to the spec".
|
|
12111
12766
|
|
|
12112
|
-
|
|
12113
|
-
|
|
12114
|
-
|
|
12115
|
-
|
|
12767
|
+
**Default: don't delegate.** Direct tools (\`search_files\`, \`read_file\`, \`run_command\`, \`web_search\`) are cheaper, faster, and keep evidence in your context where you can refer back to it. A subagent spawn pays a fresh prefix-cache miss and a full child loop \u2014 hundreds of ms of overhead and full input pricing for the child's first turn. For most questions the spawn costs more than it saves.
|
|
12768
|
+
|
|
12769
|
+
Spawn ONLY in these two cases:
|
|
12770
|
+
1. **True parallelism** \u2014 you have 2+ independent investigations that can run concurrently in the same tool batch. The wall-time win is real and only achievable via fan-out.
|
|
12771
|
+
2. **Context blow-up** \u2014 the work would otherwise need >10 file reads/searches and you only need the conclusion. Keeping the trail out of your context is the actual saving.
|
|
12116
12772
|
|
|
12117
|
-
|
|
12118
|
-
-
|
|
12119
|
-
-
|
|
12120
|
-
-
|
|
12773
|
+
Anti-patterns \u2014 do NOT spawn for any of these:
|
|
12774
|
+
- single grep / single file read \u2192 call the tool directly
|
|
12775
|
+
- 1-3 file cross-reference \u2192 read them directly
|
|
12776
|
+
- "to keep my context clean for one question" \u2192 not enough saving to justify the spawn
|
|
12777
|
+
- anything that needs user interaction (subagents can't submit plans or ask for clarification)
|
|
12778
|
+
- anything where you need to track intermediate results yourself (planning, multi-step edits)
|
|
12121
12779
|
|
|
12122
12780
|
Always pass a clear, self-contained \`arguments\` \u2014 that text is the **only** context the subagent gets.
|
|
12123
12781
|
|
|
@@ -12229,10 +12887,11 @@ If you notice an obvious issue, MENTION it in one sentence and wait for the user
|
|
|
12229
12887
|
- One short paragraph explaining *why*, then the blocks.
|
|
12230
12888
|
- If you need to explore first (list / read / search), do it with tool calls before writing any prose \u2014 silence while exploring is fine.
|
|
12231
12889
|
|
|
12232
|
-
|
|
12890
|
+
__ESCALATION_CONTRACT__
|
|
12233
12891
|
|
|
12234
12892
|
${TUI_FORMATTING_RULES}
|
|
12235
12893
|
`;
|
|
12894
|
+
var CODE_SYSTEM_PROMPT = codeSystemBase(DEFAULT_CODE_MODEL);
|
|
12236
12895
|
var SEMANTIC_SEARCH_ROUTING = `
|
|
12237
12896
|
|
|
12238
12897
|
# Search routing
|
|
@@ -12244,7 +12903,8 @@ You have BOTH \`semantic_search\` (vector index) and \`search_content\` (literal
|
|
|
12244
12903
|
|
|
12245
12904
|
If \`semantic_search\` returns nothing useful (low scores, off-topic), THEN fall back to \`search_content\`. Don't go the other way \u2014 grepping a paraphrased question wastes turns.`;
|
|
12246
12905
|
function codeSystemPrompt(rootDir, opts = {}) {
|
|
12247
|
-
const
|
|
12906
|
+
const codeBase = codeSystemBase(opts.modelId ?? DEFAULT_CODE_MODEL);
|
|
12907
|
+
const base = opts.hasSemanticSearch ? `${codeBase}${SEMANTIC_SEARCH_ROUTING}` : codeBase;
|
|
12248
12908
|
const withMemory = applyMemoryStack(base, rootDir);
|
|
12249
12909
|
const gitignorePath = join13(rootDir, ".gitignore");
|
|
12250
12910
|
let result = withMemory;
|