reasonix 0.50.0 → 0.51.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/dashboard/dist/app.css +1 -1
- package/dashboard/dist/app.js +24 -22
- package/dashboard/dist/app.js.map +1 -1
- package/dist/cli/{acp-6B25WIFF.js → acp-XEUHGG7X.js} +34 -31
- package/dist/cli/acp-XEUHGG7X.js.map +1 -0
- package/dist/cli/chat-NJ2Q5KHG.js +50 -0
- package/dist/cli/{chunk-OPGWCKKU.js → chunk-2HVTBFCI.js} +3 -3
- package/dist/cli/{chunk-AJIZ5KFK.js → chunk-2WUEAI2I.js} +3 -3
- package/dist/cli/{chunk-I4Q3QT4W.js → chunk-36BM7INR.js} +2 -2
- package/dist/cli/{chunk-3RNFYDDM.js → chunk-3BTK5BHI.js} +11 -7
- package/dist/cli/chunk-3BTK5BHI.js.map +1 -0
- package/dist/cli/{chunk-GMSAB2TC.js → chunk-3YRTIWFX.js} +2 -2
- package/dist/cli/{chunk-NLRC3DWQ.js → chunk-544J4PXD.js} +5 -5
- package/dist/cli/{chunk-7WITYWKN.js → chunk-5AIDYVH2.js} +2 -2
- package/dist/cli/{chunk-ALCOQP6R.js → chunk-5BBC6YMV.js} +5 -5
- package/dist/cli/{chunk-S4XVGLRW.js → chunk-6UNHNVJR.js} +72 -5
- package/dist/cli/chunk-6UNHNVJR.js.map +1 -0
- package/dist/cli/{chunk-IK6WWRIX.js → chunk-6XWXIVQ3.js} +38 -22
- package/dist/cli/chunk-6XWXIVQ3.js.map +1 -0
- package/dist/cli/{chunk-AAHB2PFX.js → chunk-7YB26OQO.js} +4 -4
- package/dist/cli/chunk-7YB26OQO.js.map +1 -0
- package/dist/cli/{chunk-MXWPAPZW.js → chunk-A5PBEIJ7.js} +53 -10
- package/dist/cli/chunk-A5PBEIJ7.js.map +1 -0
- package/dist/cli/{chunk-FQSQFCBI.js → chunk-BA5R6BAE.js} +2 -2
- package/dist/cli/{chunk-XWPZHWC2.js → chunk-BM6BBFAV.js} +2 -2
- package/dist/cli/{chunk-CAGKEGNE.js → chunk-BOWSNGQC.js} +52 -140
- package/dist/cli/chunk-BOWSNGQC.js.map +1 -0
- package/dist/cli/{chunk-EZ57UEZQ.js → chunk-C2MRSJTV.js} +2 -2
- package/dist/cli/{chunk-PYIZZAVQ.js → chunk-DVD67FXQ.js} +1716 -4
- package/dist/cli/chunk-DVD67FXQ.js.map +1 -0
- package/dist/cli/{chunk-ZAXMJANP.js → chunk-EAMXOWUW.js} +3 -3
- package/dist/cli/{chunk-TX652NBA.js → chunk-EWVFGYT6.js} +2 -2
- package/dist/cli/{chunk-IBRTU5WO.js → chunk-FP7IOWBQ.js} +18 -1182
- package/dist/cli/chunk-FP7IOWBQ.js.map +1 -0
- package/dist/cli/{chunk-I6FBSTTR.js → chunk-HGK57NBN.js} +9 -353
- package/dist/cli/chunk-HGK57NBN.js.map +1 -0
- package/dist/cli/chunk-JHWQDJZA.js +80 -0
- package/dist/cli/chunk-JHWQDJZA.js.map +1 -0
- package/dist/cli/{chunk-X2BQZQEE.js → chunk-K3QJ3GKI.js} +3 -3
- package/dist/cli/{chunk-GPUH2BNM.js → chunk-K4YQFULP.js} +612 -254
- package/dist/cli/chunk-K4YQFULP.js.map +1 -0
- package/dist/cli/chunk-L3VPEESB.js +31 -0
- package/dist/cli/chunk-L3VPEESB.js.map +1 -0
- package/dist/cli/{chunk-ENFBF6HI.js → chunk-N4SEBLU4.js} +383 -5
- package/dist/cli/chunk-N4SEBLU4.js.map +1 -0
- package/dist/cli/chunk-NRROJXXT.js +879 -0
- package/dist/cli/chunk-NRROJXXT.js.map +1 -0
- package/dist/cli/{chunk-3KRRTLC5.js → chunk-R6KIHEF3.js} +1619 -1036
- package/dist/cli/chunk-R6KIHEF3.js.map +1 -0
- package/dist/cli/{chunk-VVMY4M7J.js → chunk-SBHF5NWD.js} +27 -4
- package/dist/cli/chunk-SBHF5NWD.js.map +1 -0
- package/dist/cli/{chunk-OWA42BKS.js → chunk-SXSAWOB7.js} +14 -14
- package/dist/cli/{chunk-6IUMTRFP.js → chunk-UMZ6KHTS.js} +2 -2
- package/dist/cli/{chunk-7X4JJOO7.js → chunk-UO6E7FN3.js} +69 -5
- package/dist/cli/{chunk-7X4JJOO7.js.map → chunk-UO6E7FN3.js.map} +1 -1
- package/dist/cli/{chunk-3ZZXQ3CZ.js → chunk-UPW544V3.js} +2 -2
- package/dist/cli/{chunk-XJZWMU5P.js → chunk-WPOKBW5E.js} +2 -2
- package/dist/cli/{chunk-WSBFVOCO.js → chunk-Z3MKG7MQ.js} +2 -2
- package/dist/cli/{code-TBK2TASK.js → code-BMXLBC7D.js} +37 -36
- package/dist/cli/{code-TBK2TASK.js.map → code-BMXLBC7D.js.map} +1 -1
- package/dist/cli/{commands-NXTKSQTN.js → commands-E4RZXMF6.js} +5 -5
- package/dist/cli/{commit-IR5SPP7A.js → commit-KSRQ64IL.js} +3 -3
- package/dist/cli/{config-XK5WQGTS.js → config-QNDONOTU.js} +4 -2
- package/dist/cli/{desktop-5NTQBADL.js → desktop-H3ZHIMDA.js} +83 -37
- package/dist/cli/desktop-H3ZHIMDA.js.map +1 -0
- package/dist/cli/{diff-JNYX5BSZ.js → diff-I4PYI43W.js} +9 -9
- package/dist/cli/{doctor-IKYLUFXX.js → doctor-Y2E4MY2F.js} +12 -12
- package/dist/cli/{events-HSC57ONU.js → events-47HOT7ZA.js} +5 -5
- package/dist/cli/find-in-code-YLEIK5FK.js +145 -0
- package/dist/cli/find-in-code-YLEIK5FK.js.map +1 -0
- package/dist/cli/index.js +95 -44
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/{mcp-BDJJWOCD.js → mcp-76DK63ZB.js} +3 -3
- package/dist/cli/{mcp-browse-NJRZDI6V.js → mcp-browse-SDNUGO74.js} +3 -3
- package/dist/cli/{mcp-inspect-Y62NWZQL.js → mcp-inspect-BL5DEO5M.js} +3 -3
- package/dist/cli/{prompt-UTOIFUQC.js → prompt-JLATI3P7.js} +5 -5
- package/dist/cli/{prune-sessions-UCUD4XAP.js → prune-sessions-WHZDFUKD.js} +4 -4
- package/dist/cli/{replay-VVIN64MN.js → replay-MHXS7C7Z.js} +10 -10
- package/dist/cli/{run-76OBDZFB.js → run-SXNCPRJE.js} +22 -22
- package/dist/cli/{server-SZZDKTH2.js → server-GEHOE6CO.js} +61 -35
- package/dist/cli/server-GEHOE6CO.js.map +1 -0
- package/dist/cli/{sessions-FZTGRCM5.js → sessions-EPBFYISL.js} +18 -18
- package/dist/cli/{setup-4UNENGOE.js → setup-IW2XR5XI.js} +8 -7
- package/dist/cli/setup-IW2XR5XI.js.map +1 -0
- package/dist/cli/{stats-F4NDOD7D.js → stats-4WB4XHBP.js} +6 -6
- package/dist/cli/symbols-UQ274IOB.js +167 -0
- package/dist/cli/symbols-UQ274IOB.js.map +1 -0
- package/dist/cli/version-4SP3DLLH.js +33 -0
- package/dist/index.d.ts +25 -6
- package/dist/index.js +2700 -578
- package/dist/index.js.map +1 -1
- package/package.json +6 -3
- package/scripts/postinstall.mjs +10 -0
- package/dist/cli/acp-6B25WIFF.js.map +0 -1
- package/dist/cli/chat-7WASPB4O.js +0 -50
- package/dist/cli/chunk-3KRRTLC5.js.map +0 -1
- package/dist/cli/chunk-3RNFYDDM.js.map +0 -1
- package/dist/cli/chunk-AAHB2PFX.js.map +0 -1
- package/dist/cli/chunk-CAGKEGNE.js.map +0 -1
- package/dist/cli/chunk-ENFBF6HI.js.map +0 -1
- package/dist/cli/chunk-GPUH2BNM.js.map +0 -1
- package/dist/cli/chunk-I6FBSTTR.js.map +0 -1
- package/dist/cli/chunk-IBRTU5WO.js.map +0 -1
- package/dist/cli/chunk-IK6WWRIX.js.map +0 -1
- package/dist/cli/chunk-MXWPAPZW.js.map +0 -1
- package/dist/cli/chunk-PYIZZAVQ.js.map +0 -1
- package/dist/cli/chunk-S4XVGLRW.js.map +0 -1
- package/dist/cli/chunk-VVMY4M7J.js.map +0 -1
- package/dist/cli/desktop-5NTQBADL.js.map +0 -1
- package/dist/cli/server-SZZDKTH2.js.map +0 -1
- package/dist/cli/setup-4UNENGOE.js.map +0 -1
- package/dist/cli/version-LUVTWHLL.js +0 -33
- /package/dist/cli/{chat-7WASPB4O.js.map → chat-NJ2Q5KHG.js.map} +0 -0
- /package/dist/cli/{chunk-OPGWCKKU.js.map → chunk-2HVTBFCI.js.map} +0 -0
- /package/dist/cli/{chunk-AJIZ5KFK.js.map → chunk-2WUEAI2I.js.map} +0 -0
- /package/dist/cli/{chunk-I4Q3QT4W.js.map → chunk-36BM7INR.js.map} +0 -0
- /package/dist/cli/{chunk-GMSAB2TC.js.map → chunk-3YRTIWFX.js.map} +0 -0
- /package/dist/cli/{chunk-NLRC3DWQ.js.map → chunk-544J4PXD.js.map} +0 -0
- /package/dist/cli/{chunk-7WITYWKN.js.map → chunk-5AIDYVH2.js.map} +0 -0
- /package/dist/cli/{chunk-ALCOQP6R.js.map → chunk-5BBC6YMV.js.map} +0 -0
- /package/dist/cli/{chunk-FQSQFCBI.js.map → chunk-BA5R6BAE.js.map} +0 -0
- /package/dist/cli/{chunk-XWPZHWC2.js.map → chunk-BM6BBFAV.js.map} +0 -0
- /package/dist/cli/{chunk-EZ57UEZQ.js.map → chunk-C2MRSJTV.js.map} +0 -0
- /package/dist/cli/{chunk-ZAXMJANP.js.map → chunk-EAMXOWUW.js.map} +0 -0
- /package/dist/cli/{chunk-TX652NBA.js.map → chunk-EWVFGYT6.js.map} +0 -0
- /package/dist/cli/{chunk-X2BQZQEE.js.map → chunk-K3QJ3GKI.js.map} +0 -0
- /package/dist/cli/{chunk-OWA42BKS.js.map → chunk-SXSAWOB7.js.map} +0 -0
- /package/dist/cli/{chunk-6IUMTRFP.js.map → chunk-UMZ6KHTS.js.map} +0 -0
- /package/dist/cli/{chunk-3ZZXQ3CZ.js.map → chunk-UPW544V3.js.map} +0 -0
- /package/dist/cli/{chunk-XJZWMU5P.js.map → chunk-WPOKBW5E.js.map} +0 -0
- /package/dist/cli/{chunk-WSBFVOCO.js.map → chunk-Z3MKG7MQ.js.map} +0 -0
- /package/dist/cli/{commands-NXTKSQTN.js.map → commands-E4RZXMF6.js.map} +0 -0
- /package/dist/cli/{commit-IR5SPP7A.js.map → commit-KSRQ64IL.js.map} +0 -0
- /package/dist/cli/{config-XK5WQGTS.js.map → config-QNDONOTU.js.map} +0 -0
- /package/dist/cli/{diff-JNYX5BSZ.js.map → diff-I4PYI43W.js.map} +0 -0
- /package/dist/cli/{doctor-IKYLUFXX.js.map → doctor-Y2E4MY2F.js.map} +0 -0
- /package/dist/cli/{events-HSC57ONU.js.map → events-47HOT7ZA.js.map} +0 -0
- /package/dist/cli/{mcp-BDJJWOCD.js.map → mcp-76DK63ZB.js.map} +0 -0
- /package/dist/cli/{mcp-browse-NJRZDI6V.js.map → mcp-browse-SDNUGO74.js.map} +0 -0
- /package/dist/cli/{mcp-inspect-Y62NWZQL.js.map → mcp-inspect-BL5DEO5M.js.map} +0 -0
- /package/dist/cli/{prompt-UTOIFUQC.js.map → prompt-JLATI3P7.js.map} +0 -0
- /package/dist/cli/{prune-sessions-UCUD4XAP.js.map → prune-sessions-WHZDFUKD.js.map} +0 -0
- /package/dist/cli/{replay-VVIN64MN.js.map → replay-MHXS7C7Z.js.map} +0 -0
- /package/dist/cli/{run-76OBDZFB.js.map → run-SXNCPRJE.js.map} +0 -0
- /package/dist/cli/{sessions-FZTGRCM5.js.map → sessions-EPBFYISL.js.map} +0 -0
- /package/dist/cli/{stats-F4NDOD7D.js.map → stats-4WB4XHBP.js.map} +0 -0
- /package/dist/cli/{version-LUVTWHLL.js.map → version-4SP3DLLH.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createParser } from "eventsource-parser";
|
|
|
3
3
|
|
|
4
4
|
// src/config.ts
|
|
5
5
|
import { randomBytes } from "crypto";
|
|
6
|
-
import {
|
|
6
|
+
import { mkdirSync, readFileSync } from "fs";
|
|
7
7
|
import { homedir } from "os";
|
|
8
8
|
import { dirname, isAbsolute, join, resolve } from "path";
|
|
9
9
|
import { z } from "zod";
|
|
@@ -231,11 +231,52 @@ var TONE_ACTIVE = proxyTokens((theme) => theme.toneActive);
|
|
|
231
231
|
var SURFACE = proxyTokens((theme) => theme.surface);
|
|
232
232
|
var CARD = proxyTokens((theme) => theme.card);
|
|
233
233
|
|
|
234
|
+
// src/core/atomic-write.ts
|
|
235
|
+
import { chmodSync, copyFileSync, renameSync, unlinkSync, writeFileSync } from "fs";
|
|
236
|
+
var defaultFs = {
|
|
237
|
+
writeFileSync,
|
|
238
|
+
chmodSync,
|
|
239
|
+
renameSync,
|
|
240
|
+
copyFileSync,
|
|
241
|
+
unlinkSync
|
|
242
|
+
};
|
|
243
|
+
function atomicWriteSync(path2, body, tmp, mode = 384, fs5 = defaultFs) {
|
|
244
|
+
try {
|
|
245
|
+
fs5.writeFileSync(tmp, body, "utf8");
|
|
246
|
+
try {
|
|
247
|
+
fs5.chmodSync(tmp, mode);
|
|
248
|
+
} catch {
|
|
249
|
+
}
|
|
250
|
+
try {
|
|
251
|
+
fs5.renameSync(tmp, path2);
|
|
252
|
+
} catch (err) {
|
|
253
|
+
if (err.code !== "EXDEV") throw err;
|
|
254
|
+
fs5.copyFileSync(tmp, path2);
|
|
255
|
+
try {
|
|
256
|
+
fs5.chmodSync(path2, mode);
|
|
257
|
+
} catch {
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
} catch (err) {
|
|
261
|
+
try {
|
|
262
|
+
fs5.unlinkSync(tmp);
|
|
263
|
+
} catch {
|
|
264
|
+
}
|
|
265
|
+
throw err;
|
|
266
|
+
}
|
|
267
|
+
try {
|
|
268
|
+
fs5.unlinkSync(tmp);
|
|
269
|
+
} catch {
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
234
273
|
// src/index/config.ts
|
|
235
274
|
import picomatch from "picomatch";
|
|
236
275
|
var DEFAULT_INDEX_EXCLUDES = {
|
|
237
276
|
dirs: [
|
|
238
277
|
"node_modules",
|
|
278
|
+
".devenv",
|
|
279
|
+
".direnv",
|
|
239
280
|
".git",
|
|
240
281
|
".hg",
|
|
241
282
|
".svn",
|
|
@@ -621,12 +662,7 @@ function readConfig(path2 = defaultConfigPath()) {
|
|
|
621
662
|
function writeConfig(cfg, path2 = defaultConfigPath()) {
|
|
622
663
|
mkdirSync(dirname(path2), { recursive: true });
|
|
623
664
|
const tmp = `${path2}.${process.pid}.tmp`;
|
|
624
|
-
|
|
625
|
-
try {
|
|
626
|
-
chmodSync(tmp, 384);
|
|
627
|
-
} catch {
|
|
628
|
-
}
|
|
629
|
-
renameSync(tmp, path2);
|
|
665
|
+
atomicWriteSync(path2, JSON.stringify(cfg, null, 2), tmp);
|
|
630
666
|
}
|
|
631
667
|
function loadLanguage(path2 = defaultConfigPath()) {
|
|
632
668
|
return readConfig(path2).lang;
|
|
@@ -840,8 +876,8 @@ function computeWait(attempt, initial, cap, retryAfter) {
|
|
|
840
876
|
}
|
|
841
877
|
function sleep(ms, signal) {
|
|
842
878
|
if (ms <= 0) return Promise.resolve();
|
|
843
|
-
return new Promise((
|
|
844
|
-
const timer = setTimeout(
|
|
879
|
+
return new Promise((resolve16, reject) => {
|
|
880
|
+
const timer = setTimeout(resolve16, ms);
|
|
845
881
|
if (signal) {
|
|
846
882
|
const onAbort = () => {
|
|
847
883
|
clearTimeout(timer);
|
|
@@ -929,8 +965,8 @@ var DeepSeekClient = class {
|
|
|
929
965
|
const waitMs = Math.max(0, this.nextChatRequestAt - now);
|
|
930
966
|
this.nextChatRequestAt = Math.max(now, this.nextChatRequestAt) + this.minChatIntervalMs;
|
|
931
967
|
if (waitMs <= 0) return;
|
|
932
|
-
await new Promise((
|
|
933
|
-
const timer = setTimeout(
|
|
968
|
+
await new Promise((resolve16, reject) => {
|
|
969
|
+
const timer = setTimeout(resolve16, waitMs);
|
|
934
970
|
signal?.addEventListener(
|
|
935
971
|
"abort",
|
|
936
972
|
() => {
|
|
@@ -1146,10 +1182,10 @@ var PauseGate = class {
|
|
|
1146
1182
|
`${kind}: no confirmation listener registered \u2014 cannot prompt the user. This tool can only be used inside an interactive Reasonix session.`
|
|
1147
1183
|
);
|
|
1148
1184
|
}
|
|
1149
|
-
return new Promise((
|
|
1185
|
+
return new Promise((resolve16) => {
|
|
1150
1186
|
const id = this._nextId++;
|
|
1151
1187
|
const request = { id, kind, payload };
|
|
1152
|
-
this._pending.set(id, { resolve:
|
|
1188
|
+
this._pending.set(id, { resolve: resolve16, request });
|
|
1153
1189
|
for (const fn of this._listeners) {
|
|
1154
1190
|
try {
|
|
1155
1191
|
fn(request);
|
|
@@ -1920,6 +1956,8 @@ var EN = {
|
|
|
1920
1956
|
deepseek5xxUnreachable: " DeepSeek API is unreachable from your network \u2014 could be a wider DS outage or a local network issue.",
|
|
1921
1957
|
deepseek5xxActionNetwork: " Try: (1) check your network, (2) wait 30s and retry, (3) status page: https://status.deepseek.com.",
|
|
1922
1958
|
deepseek5xxActionRetry: " Try: (1) wait 30s and retry, (2) /model to switch model, (3) status page: https://status.deepseek.com.",
|
|
1959
|
+
upstream5xxHead: "Upstream service unavailable ({status}) at {host} \u2014 the configured API endpoint returned a server error, not a Reasonix bug. Already retried 4\xD7 with backoff.",
|
|
1960
|
+
upstream5xxActionRetry: " Try: (1) check that the local/proxy model server is up, (2) wait and retry, (3) /model to switch model.",
|
|
1923
1961
|
innerNoMessage: "(no message)",
|
|
1924
1962
|
reasonAborted: "[aborted by user (Esc) \u2014 summarizing what I found so far]",
|
|
1925
1963
|
reasonContextGuard: "[context budget running low \u2014 summarizing before the next call would overflow]",
|
|
@@ -2100,6 +2138,7 @@ var EN = {
|
|
|
2100
2138
|
modelSet: "model \u2192 {id}",
|
|
2101
2139
|
effortStatus: "effort \u2192 {current} (pick: {list})",
|
|
2102
2140
|
effortUsage: "usage: /effort <{list}> (high is the safe default; max is a DeepSeek extension)",
|
|
2141
|
+
effortUsageNoMax: "usage: /effort <{list}>",
|
|
2103
2142
|
effortSet: "effort \u2192 {effort}",
|
|
2104
2143
|
budgetNoCap: "no session budget set \u2014 Reasonix will keep going until you stop it. Set one with: /budget <usd> (e.g. /budget 5)",
|
|
2105
2144
|
budgetStatus: "budget: ${spent} of ${cap} ({pct}%) \xB7 /budget off to clear, /budget <usd> to change",
|
|
@@ -2912,6 +2951,1707 @@ var EN = {
|
|
|
2912
2951
|
}
|
|
2913
2952
|
};
|
|
2914
2953
|
|
|
2954
|
+
// src/i18n/de.ts
|
|
2955
|
+
var de = {
|
|
2956
|
+
...EN,
|
|
2957
|
+
common: {
|
|
2958
|
+
...EN.common,
|
|
2959
|
+
error: "Fehler",
|
|
2960
|
+
warning: "Warnung",
|
|
2961
|
+
loading: "Wird geladen...",
|
|
2962
|
+
done: "Fertig",
|
|
2963
|
+
cancel: "Abbrechen",
|
|
2964
|
+
confirm: "Best\xE4tigen",
|
|
2965
|
+
back: "Zur\xFCck",
|
|
2966
|
+
next: "Weiter",
|
|
2967
|
+
tool: "Werkzeug",
|
|
2968
|
+
running: "l\xE4uft",
|
|
2969
|
+
noTurns: "(noch keine Turns)"
|
|
2970
|
+
},
|
|
2971
|
+
cli: {
|
|
2972
|
+
...EN.cli,
|
|
2973
|
+
description: "DeepSeek-natives Agent-Framework, gebaut f\xFCr Cache-Treffer und g\xFCnstige Tokens.",
|
|
2974
|
+
continue: "Die zuletzt verwendete Chat-Sitzung fortsetzen, ohne die Auswahl anzuzeigen.",
|
|
2975
|
+
setup: "Interaktiver Assistent f\xFCr API-Schl\xFCssel und MCP-Server. Jederzeit erneut ausf\xFChrbar.",
|
|
2976
|
+
chat: "Interaktive Ink-TUI mit Live-Cache- und Kostenanzeige.",
|
|
2977
|
+
run: "Eine einzelne Aufgabe nicht-interaktiv ausf\xFChren, Ausgabe wird gestreamt.",
|
|
2978
|
+
stats: "Nutzungsdashboard anzeigen.",
|
|
2979
|
+
doctor: "Gesundheitscheck mit einem Befehl.",
|
|
2980
|
+
code: "Code-Editor-Chat \u2014 Dateisystem-Werkzeuge mit Wurzel in <dir> (Standard: cwd), Coding-System-Prompt, v4-flash-Baseline.",
|
|
2981
|
+
commit: "Commit-Nachricht aus der gestagten Diff entwerfen.",
|
|
2982
|
+
sessions: "Gespeicherte Chat-Sitzungen auflisten oder nach Name anzeigen.",
|
|
2983
|
+
pruneSessions: "Inaktive Sitzungen ab N Tagen l\xF6schen (Standard 90). Mit --dry-run zur Vorschau.",
|
|
2984
|
+
events: "Kernel-Event-Log-Seite lesbar ausgeben.",
|
|
2985
|
+
replay: "Interaktive Ink-TUI zum Durchbl\xE4ttern eines Transkripts.",
|
|
2986
|
+
diff: "Zwei Transkripte in einer geteilten Ink-TUI vergleichen.",
|
|
2987
|
+
mcp: "Model-Context-Protocol-Hilfsprogramme \u2014 Server entdecken, Setup testen.",
|
|
2988
|
+
index: "Lokalen semantischen Suchindex erstellen (oder inkrementell aktualisieren).",
|
|
2989
|
+
version: "Reasonix-Version ausgeben.",
|
|
2990
|
+
update: "Nach einer neueren Reasonix-Version suchen und installieren."
|
|
2991
|
+
},
|
|
2992
|
+
stats: {
|
|
2993
|
+
...EN.stats,
|
|
2994
|
+
usageHint: "F\xFChre `reasonix chat`, `reasonix code` oder `reasonix run <task>` aus \u2013 jeden Turn",
|
|
2995
|
+
usageDetail: "H\xE4ngt eine Zeile an das Log an; `reasonix stats` fasst sie zusammen."
|
|
2996
|
+
},
|
|
2997
|
+
run: {
|
|
2998
|
+
...EN.run,
|
|
2999
|
+
missingApiKey: "DEEPSEEK_API_KEY ist nicht gesetzt und stdin ist kein TTY (Nachfrage nicht m\xF6glich).\nSetze die Umgebungsvariable oder starte einmal interaktiv `reasonix chat`, um einen Schl\xFCssel zu speichern.\n"
|
|
3000
|
+
},
|
|
3001
|
+
sessions: {
|
|
3002
|
+
...EN.sessions,
|
|
3003
|
+
emptyHint: "noch keine gespeicherten Sitzungen \u2013 starte `reasonix chat` (Sitzungen werden automatisch gespeichert, au\xDFer mit --no-session).",
|
|
3004
|
+
listHeader: "Gespeicherte Sitzungen (~/.reasonix/sessions/):",
|
|
3005
|
+
inspectHint: "Ansehen: reasonix sessions <name>",
|
|
3006
|
+
resumeHint: "Fortsetzen: reasonix chat --session <name>",
|
|
3007
|
+
noSession: 'keine Sitzung namens "{name}" (oder sie ist leer).',
|
|
3008
|
+
lookedAt: "Angesehen: {path}",
|
|
3009
|
+
noIdleSessions: "Keine Sitzungen seit >= {days} Tagen inaktiv. Nichts bereinigt.",
|
|
3010
|
+
wouldPrune: "W\xFCrde {count} Sitzung(en) bereinigen, die >= {days} Tage inaktiv sind:",
|
|
3011
|
+
dryRunHint: "Ohne --dry-run erneut ausf\xFChren, um wirklich zu l\xF6schen.",
|
|
3012
|
+
prunedCount: "{count} Sitzung(en) bereinigt, die >= {days} Tage inaktiv waren:",
|
|
3013
|
+
daysInvalid: "--days muss eine positive ganze Zahl sein (erhalten: {days})."
|
|
3014
|
+
},
|
|
3015
|
+
ui: {
|
|
3016
|
+
...EN.ui,
|
|
3017
|
+
tipShownOnce: "einmal angezeigt",
|
|
3018
|
+
modelOverride: "das Standardmodell \xFCberschreiben",
|
|
3019
|
+
noSession: "Sitzungsspeicherung f\xFCr diesen Durchlauf deaktivieren",
|
|
3020
|
+
noMouseHint: "SGR-Mausverfolgung deaktivieren; stellt die native Auswahl per Ziehen und Rechtsklick wieder her",
|
|
3021
|
+
noProxyHint: "HTTPS_PROXY / HTTP_PROXY f\xFCr diesen Durchlauf ignorieren; direkt verbinden",
|
|
3022
|
+
resumeHint: "die angegebene Sitzung zwangsweise fortsetzen (auch wenn sie inaktiv ist)",
|
|
3023
|
+
newHint: "Eine neue Sitzung erzwingen (--session / --continue ignorieren)",
|
|
3024
|
+
transcriptHint: "Pfad zum Speichern der JSONL-Ausgabe",
|
|
3025
|
+
budgetHint: "Sitzungs-USD-Obergrenze \u2013 warnt bei 80 %, verweigert den n\xE4chsten Zug bei 100 %",
|
|
3026
|
+
modelIdHint: "DeepSeek-Modell-ID (z. B. deepseek-v4-flash)",
|
|
3027
|
+
systemPromptHint: "die Standard-Systemeingabeaufforderung \xFCberschreiben",
|
|
3028
|
+
effortHint: "Denkaufwand \u2013 niedrig|mittel|hoch|maximal",
|
|
3029
|
+
sessionNameHint: "Sitzungsname (Standard: \u201Edefault\u201C)",
|
|
3030
|
+
ephemeralHint: "Sitzungsspeicherung f\xFCr diesen Durchlauf deaktivieren",
|
|
3031
|
+
mcpSpecHint: "MCP-Server-Spezifikation (wiederholbar)",
|
|
3032
|
+
mcpPrefixHint: "Stelle diesen String vor die Namen der MCP-Tools",
|
|
3033
|
+
noConfigHint: "Ignoriere bei diesem Durchlauf die Datei ~/.reasonix/config.json",
|
|
3034
|
+
effortHintShort: "Denkaufwand \u2013 niedrig|mittel|hoch|maximal",
|
|
3035
|
+
budgetHintShort: "Sitzungs-USD-Obergrenze",
|
|
3036
|
+
transcriptHintShort: "Pfad zum JSONL-Transkript",
|
|
3037
|
+
mcpSpecHintShort: "MCP-Server-Spezifikation (wiederholbar)",
|
|
3038
|
+
mcpPrefixHintShort: "Pr\xE4fix f\xFCr MCP-Toolnamen",
|
|
3039
|
+
dryRunHint: "anzeigen, was installiert w\xFCrde, ohne es tats\xE4chlich zu installieren",
|
|
3040
|
+
rebuildHint: "den Index komplett neu erstellen",
|
|
3041
|
+
embedModelHint: "Name des Einbettungsmodells",
|
|
3042
|
+
projectDirHint: "Projektstammverzeichnis",
|
|
3043
|
+
ollamaUrlHint: "Ollama-Server-URL",
|
|
3044
|
+
skipPromptsHint: "Best\xE4tigungsaufforderungen \xFCberspringen",
|
|
3045
|
+
verboseHint: "Alle Metadaten der Sitzung anzeigen",
|
|
3046
|
+
pruneDaysHint: "Sitzungen l\xF6schen, die seit mindestens dieser Anzahl von Tagen inaktiv sind (Standard: 90)",
|
|
3047
|
+
pruneDryRunHint: "Liste auf, was gel\xF6scht w\xFCrde, ohne etwas zu entfernen",
|
|
3048
|
+
eventTypeHint: "Nach Veranstaltungstyp filtern",
|
|
3049
|
+
eventSinceHint: "Beginne mit dieser Ereignis-ID",
|
|
3050
|
+
eventTailHint: "Nur die letzten N Ereignisse anzeigen",
|
|
3051
|
+
jsonHint: "Ausgabe als JSON",
|
|
3052
|
+
projectionHint: "Zeige den voraussichtlichen Zustand bei jedem Ereignis an",
|
|
3053
|
+
printHint: "Anzeige \xFCber stdout statt \xFCber die TUI",
|
|
3054
|
+
headHint: "Zeige nur die ersten N Ereignisse an",
|
|
3055
|
+
tailHint: "Nur die letzten N Ereignisse anzeigen",
|
|
3056
|
+
mdReportHint: "Erstelle einen Markdown-Diff-Bericht unter diesem Pfad",
|
|
3057
|
+
printHintTable: "Eine Tabelle auf die Standardausgabe ausgeben",
|
|
3058
|
+
tuiHint: "\xD6ffne die interaktive TUI",
|
|
3059
|
+
labelAHint: "Bezeichnung f\xFCr den linken Bereich",
|
|
3060
|
+
labelBHint: "Bezeichnung f\xFCr den rechten Bereich",
|
|
3061
|
+
mcpListDescription: "Durchsuche das MCP-Register (offiziell \u2192 smithery \u2192 lokaler Fallback)",
|
|
3062
|
+
mcpInspectDescription: "die Spezifikationen eines MCP-Servers pr\xFCfen (Tools, Ressourcen, Eingabeaufforderungen)",
|
|
3063
|
+
mcpSearchDescription: "Suche in der MCP-Registrierung nach Servern, die einer Suchanfrage entsprechen",
|
|
3064
|
+
mcpInstallDescription: "Einen MCP-Server anhand seines Namens installieren (schreibt dessen Spezifikation in deine Konfiguration)",
|
|
3065
|
+
mcpBrowseDescription: "Interaktiver Marktplatz-Browser \u2013 tippe, um zu filtern, dr\xFCcke die Eingabetaste, um zu installieren",
|
|
3066
|
+
mcpLocalHint: "Nur den mitgelieferten Offline-Katalog anzeigen",
|
|
3067
|
+
mcpRefreshHint: "den 24-Stunden-Cache umgehen und neu abrufen",
|
|
3068
|
+
mcpLimitHint: "Maximale Anzahl der anzuzeigenden Eintr\xE4ge",
|
|
3069
|
+
mcpPagesHint: "Lade gleich so viele Seiten (Standard: 1)",
|
|
3070
|
+
mcpAllHint: "Jede Seite laden (beim ersten Mal etwas langsam)",
|
|
3071
|
+
mcpMaxPagesHint: "Begrenze die Anzahl der Seiten, die bei der Suche durchsucht werden sollen (Standard: 20)",
|
|
3072
|
+
jsonHintCatalog: "Ausgabe als JSON",
|
|
3073
|
+
jsonHintReport: "Gib den Inspektionsbericht als JSON aus",
|
|
3074
|
+
modelOverrideFlash: "das Modell \xFCberschreiben (Standard: deepseek-v4-flash)",
|
|
3075
|
+
skipConfirmHint: "Die Best\xE4tigungsabfrage \xFCberspringen",
|
|
3076
|
+
welcome: "Starte jederzeit `reasonix`, um zu chatten \u2013 deine Einstellungen bleiben gespeichert.",
|
|
3077
|
+
taglineChat: "DeepSeek-nativer Agent",
|
|
3078
|
+
taglineCode: "DeepSeek-nativer Coding-Agent",
|
|
3079
|
+
taglineSub: "cache-first \xB7 flash-first",
|
|
3080
|
+
startSessionHint: "Tippe eine Nachricht, um deine Sitzung zu starten",
|
|
3081
|
+
inputPlaceholder: "Frag etwas... (tippe / f\xFCr Befehle, @ f\xFCr Dateien)",
|
|
3082
|
+
busy: "Denke nach...",
|
|
3083
|
+
thinking: "\u25B8 denke nach...",
|
|
3084
|
+
undo: "R\xFCckg\xE4ngig",
|
|
3085
|
+
undoHint: "Dr\xFCcke innerhalb von 5s zum R\xFCckg\xE4ngig machen",
|
|
3086
|
+
applied: "angewendet",
|
|
3087
|
+
rejected: "abgelehnt",
|
|
3088
|
+
noDashboard: "Automatisch gestartetes eingebettetes Web-Dashboard unterdr\xFCcken.",
|
|
3089
|
+
openDashboardHint: "Dashboard-URL sofort im Standard-Browser \xF6ffnen, sobald der Server bereit ist. Keine Wirkung bei --no-dashboard.",
|
|
3090
|
+
dashboardPortHint: "Dashboard auf einen festen Port (1\u201365535) festlegen. Stabil \xFCber Neustarts hinweg \u2014 erforderlich f\xFCr SSH-Tunnel. Standard: ephemeral.",
|
|
3091
|
+
dashboardPortInvalid: "\u25B2 --dashboard-port={value} wird ignoriert (muss eine ganze Zahl 1\u201365535 sein) \u2014 R\xFCckfall auf ephemeral",
|
|
3092
|
+
dashboardAutoStartFailed: "\u25B2 Dashboard-Autostart fehlgeschlagen ({reason}) \u2014 /dashboard versuchen oder --no-dashboard zum Unterdr\xFCcken",
|
|
3093
|
+
systemAppendHint: "Anweisungen an den Code-System-Prompt anh\xE4ngen. Ersetzt NICHT den Standard-Prompt \u2014 wird danach eingef\xFCgt.",
|
|
3094
|
+
systemAppendFileHint: "Dateiinhalte an den Code-System-Prompt anh\xE4ngen. Ersetzt NICHT den Standard-Prompt. UTF-8, relativ zu cwd oder absolut.",
|
|
3095
|
+
resumedSession: '\u25B8 Sitzung "{name}" fortgesetzt mit {count} vorherigen Nachrichten \xB7 /new f\xFCr frischen Start \xB7 /sessions zum Verwalten',
|
|
3096
|
+
newSession: '\u25B8 Sitzung "{name}" (neu) \u2014 automatisch gespeichert w\xE4hrend des Chattens \xB7 /sessions zum Umbenennen oder L\xF6schen',
|
|
3097
|
+
ephemeralSession: "\u25B8 ephemerer Chat (keine Sitzungspersistenz) \u2014 --no-session weglassen zum Aktivieren",
|
|
3098
|
+
restoredEdits: "\u25B8 {count} ausstehende Edit-Block(s) aus einem unterbrochenen vorherigen Durchlauf wiederhergestellt \u2014 /apply zum \xDCbernehmen oder /discard zum Verwerfen.",
|
|
3099
|
+
resumedPlan: "Fortgesetzter Plan \xB7 {when}{summary}"
|
|
3100
|
+
},
|
|
3101
|
+
code: {
|
|
3102
|
+
...EN.code,
|
|
3103
|
+
workspaceConflict: "\u26A0 Arbeitsbereich enth\xE4lt Dateien einer anderen Agent-Plattform ({platforms}). Reasonix Code kann sie als Projektinhalt lesen; starte mit --dir <dein-projekt> neu, falls das nicht gew\xFCnscht ist.\n",
|
|
3104
|
+
systemAppendEmpty: "--system-append ist leer \u2014 kein Prompt-Text wird angeh\xE4ngt\n",
|
|
3105
|
+
systemAppendFileReadError: 'Fehler: kann --system-append-file "{filePath}" nicht lesen: {errorDetails}\n'
|
|
3106
|
+
},
|
|
3107
|
+
slash: {
|
|
3108
|
+
...EN.slash,
|
|
3109
|
+
help: { ...EN.slash.help, description: "Vollst\xE4ndige Befehlsreferenz anzeigen" },
|
|
3110
|
+
status: { ...EN.slash.status, description: "Aktuelles Modell, Flags, Kontext und Sitzung" },
|
|
3111
|
+
effort: {
|
|
3112
|
+
...EN.slash.effort,
|
|
3113
|
+
argsHint: "<niedrig|mittel|hoch|max>",
|
|
3114
|
+
description: "Reasoning-Effort-Grenze (low|medium|high|max); high ist der sichere Standard f\xFCr vLLM/Azure"
|
|
3115
|
+
},
|
|
3116
|
+
model: {
|
|
3117
|
+
...EN.slash.model,
|
|
3118
|
+
description: "DeepSeek-Modell-ID wechseln"
|
|
3119
|
+
},
|
|
3120
|
+
models: {
|
|
3121
|
+
...EN.slash.models,
|
|
3122
|
+
description: "Verf\xFCgbare Modelle von DeepSeek /models abrufen"
|
|
3123
|
+
},
|
|
3124
|
+
language: {
|
|
3125
|
+
description: "Laufzeitsprache wechseln",
|
|
3126
|
+
argsHint: "<EN|zh-CN|de>",
|
|
3127
|
+
success: "Sprache auf Deutsch umgestellt.",
|
|
3128
|
+
unsupported: "Nicht unterst\xFCtzter Sprachcode: {code}. Unterst\xFCtzt: {supported}."
|
|
3129
|
+
},
|
|
3130
|
+
budget: {
|
|
3131
|
+
...EN.slash.budget,
|
|
3132
|
+
description: "Session-USD-Grenze \u2014 warnt bei 80 %, verweigert n\xE4chsten Turn bei 100 %. Standardm\xE4\xDFig aus. /budget allein zeigt Status."
|
|
3133
|
+
},
|
|
3134
|
+
mcp: { ...EN.slash.mcp, description: "MCP-Server + Tools dieser Sitzung auflisten" },
|
|
3135
|
+
resource: {
|
|
3136
|
+
...EN.slash.resource,
|
|
3137
|
+
description: "MCP-Ressourcen durchsuchen + lesen (kein Arg \u2192 URIs auflisten; <uri> \u2192 Inhalt abrufen)"
|
|
3138
|
+
},
|
|
3139
|
+
prompt: {
|
|
3140
|
+
...EN.slash.prompt,
|
|
3141
|
+
argsHint: "[Name]",
|
|
3142
|
+
description: "MCP-Prompts durchsuchen + abrufen (kein Arg \u2192 Namen auflisten; <name> \u2192 Prompt rendern)"
|
|
3143
|
+
},
|
|
3144
|
+
memory: {
|
|
3145
|
+
...EN.slash.memory,
|
|
3146
|
+
argsHint: "[Liste|<Name> anzeigen|<Name> vergessen|<Bereich> l\xF6schen \u2013 Best\xE4tigen]",
|
|
3147
|
+
description: "Pinned Memory anzeigen / verwalten (REASONIX.md + ~/.reasonix/memory)"
|
|
3148
|
+
},
|
|
3149
|
+
skill: {
|
|
3150
|
+
...EN.slash.skill,
|
|
3151
|
+
description: "Benutzer-Skills auflisten / ausf\xFChren (Projekt + benutzerdefiniert + global + builtin)"
|
|
3152
|
+
},
|
|
3153
|
+
hooks: {
|
|
3154
|
+
...EN.slash.hooks,
|
|
3155
|
+
argsHint: "[Neu laden]",
|
|
3156
|
+
description: "Aktive Hooks auflisten (settings.json unter .reasonix/) \xB7 reload liest von Platte neu"
|
|
3157
|
+
},
|
|
3158
|
+
permissions: {
|
|
3159
|
+
...EN.slash.permissions,
|
|
3160
|
+
argsHint: "[Liste|<Pr\xE4fix> hinzuf\xFCgen|<Pr\xE4fix|N> entfernen|L\xF6schen (Best\xE4tigung erforderlich)]",
|
|
3161
|
+
description: "Shell-Allowlist anzeigen / bearbeiten (builtin schreibgesch\xFCtzt \xB7 pro Projekt: ~/.reasonix/config.json)"
|
|
3162
|
+
},
|
|
3163
|
+
dashboard: {
|
|
3164
|
+
...EN.slash.dashboard,
|
|
3165
|
+
argsHint: "[Stopp]",
|
|
3166
|
+
description: "Eingebettetes Web-Dashboard starten (127.0.0.1, token-gesichert)"
|
|
3167
|
+
},
|
|
3168
|
+
update: {
|
|
3169
|
+
...EN.slash.update,
|
|
3170
|
+
description: "Aktuelle vs. neueste Version anzeigen + Upgrade-Befehl"
|
|
3171
|
+
},
|
|
3172
|
+
stats: {
|
|
3173
|
+
...EN.slash.stats,
|
|
3174
|
+
description: "Sitzungs\xFCbergreifendes Kosten-Dashboard (heute / Woche / Monat / gesamt \xB7 Cache-Treffer \xB7 vs. Claude)"
|
|
3175
|
+
},
|
|
3176
|
+
cost: {
|
|
3177
|
+
...EN.slash.cost,
|
|
3178
|
+
argsHint: "[Text]",
|
|
3179
|
+
description: "ohne Text \u2192 Ausgaben letzter Turn (Kostenkarte); mit Text \u2192 Kostensch\xE4tzung f\xFCr als n\xE4chster Senden (worst-case + likely-cache)"
|
|
3180
|
+
},
|
|
3181
|
+
doctor: {
|
|
3182
|
+
...EN.slash.doctor,
|
|
3183
|
+
description: "Gesundheitscheck (API / Config / API-Reichweite / Index / Hooks / Projekt)"
|
|
3184
|
+
},
|
|
3185
|
+
context: {
|
|
3186
|
+
...EN.slash.context,
|
|
3187
|
+
description: "Context-Window-Aufschl\xFCsselung (System / Tools / Log / Input)"
|
|
3188
|
+
},
|
|
3189
|
+
retry: {
|
|
3190
|
+
...EN.slash.retry,
|
|
3191
|
+
description: "Letzte Nachricht k\xFCrzen & erneut senden (frischer Sample)"
|
|
3192
|
+
},
|
|
3193
|
+
compact: {
|
|
3194
|
+
...EN.slash.compact,
|
|
3195
|
+
argsHint: "[Token]",
|
|
3196
|
+
description: "\xDCberdimensionierte Tool-Ergebnisse + Tool-Call-Args im Log k\xFCrzen; Grenze in Tokens, Standard 4000"
|
|
3197
|
+
},
|
|
3198
|
+
cwd: {
|
|
3199
|
+
...EN.slash.cwd,
|
|
3200
|
+
argsHint: "[Pfad]",
|
|
3201
|
+
description: "Workspace-Root mid-Session wechseln \u2014 FS-/Shell-/Memory-Tools neu ausrichten, Projekt-Hooks neu laden, @-Mention-Walker aktualisieren"
|
|
3202
|
+
},
|
|
3203
|
+
stop: {
|
|
3204
|
+
...EN.slash.stop,
|
|
3205
|
+
description: "Aktuellen Modell-Turn abbrechen (getippte Alternative zu Esc)"
|
|
3206
|
+
},
|
|
3207
|
+
feedback: {
|
|
3208
|
+
...EN.slash.feedback,
|
|
3209
|
+
description: "GitHub-Issue mit Diagnoseinfo \xF6ffnen (in Zwischenablage kopiert)"
|
|
3210
|
+
},
|
|
3211
|
+
about: { ...EN.slash.about, description: "Projektinfo \u2014 Version, Website, Repo, Lizenz" },
|
|
3212
|
+
keys: { ...EN.slash.keys, description: "Tastatur + Maus + Kopieren/Einf\xFCgen-Referenz" },
|
|
3213
|
+
plans: {
|
|
3214
|
+
...EN.slash.plans,
|
|
3215
|
+
description: "Aktive + archivierte Pl\xE4ne dieser Sitzung auflisten, neueste zuerst"
|
|
3216
|
+
},
|
|
3217
|
+
replay: {
|
|
3218
|
+
...EN.slash.replay,
|
|
3219
|
+
description: "Archivierten Plan als schreibgesch\xFCtzte Time-Travel-Schnappschuss laden (Standard: neuester)"
|
|
3220
|
+
},
|
|
3221
|
+
sessions: {
|
|
3222
|
+
...EN.slash.sessions,
|
|
3223
|
+
description: "Gespeicherte Sitzungen auflisten (aktuelle mit \u25B8 markiert)"
|
|
3224
|
+
},
|
|
3225
|
+
title: {
|
|
3226
|
+
...EN.slash.title,
|
|
3227
|
+
description: "Modell bitten, diese Sitzung anhand des Gespr\xE4chs umzubenennen"
|
|
3228
|
+
},
|
|
3229
|
+
qq: {
|
|
3230
|
+
...EN.slash.qq,
|
|
3231
|
+
description: "QQ-Kanal verbinden, inspizieren oder trennen (erste Verbindung f\xFChrt durch App-ID / App-Secret-Setup)"
|
|
3232
|
+
},
|
|
3233
|
+
setup: { ...EN.slash.setup, description: "Erinnert dich daran, `reasonix setup` auszuf\xFChren" },
|
|
3234
|
+
semantic: {
|
|
3235
|
+
...EN.slash.semantic,
|
|
3236
|
+
description: "Semantic-Search-Status anzeigen \u2014 Index erstellt? Ollama installiert? Wie aktivieren?"
|
|
3237
|
+
},
|
|
3238
|
+
clear: {
|
|
3239
|
+
...EN.slash.clear,
|
|
3240
|
+
description: "Nur sichtbaren Scrollback leeren (Log/Kontext bleibt)"
|
|
3241
|
+
},
|
|
3242
|
+
new: {
|
|
3243
|
+
...EN.slash.new,
|
|
3244
|
+
description: "Frisches Gespr\xE4ch beginnen (Kontext + Scrollback l\xF6schen)"
|
|
3245
|
+
},
|
|
3246
|
+
loop: {
|
|
3247
|
+
...EN.slash.loop,
|
|
3248
|
+
argsHint: "<5s..6h> <Eingabeaufforderung> \xB7 Stopp \xB7 (keine Argumente = Status)",
|
|
3249
|
+
description: "Prompt automatisch alle <intervall> erneut senden, bis du etwas eingibst / Esc / /loop stop"
|
|
3250
|
+
},
|
|
3251
|
+
init: {
|
|
3252
|
+
...EN.slash.init,
|
|
3253
|
+
description: "Projekt scannen und eine REASONIX.md-Baseline erstellen (Modell schreibt; mit /apply reviewen). `force` \xFCberschreibt vorhandene Datei."
|
|
3254
|
+
},
|
|
3255
|
+
apply: {
|
|
3256
|
+
...EN.slash.apply,
|
|
3257
|
+
description: "Ausstehende Edit-Blocks auf Platte schreiben (kein Arg \u2192 alle; `1`, `1,3` oder `1-4` \u2192 diese Teilmenge, Rest bleibt ausstehend)"
|
|
3258
|
+
},
|
|
3259
|
+
discard: {
|
|
3260
|
+
...EN.slash.discard,
|
|
3261
|
+
description: "Ausstehende Edit-Blocks ohne Schreiben verwerfen (kein Arg \u2192 alle; Indizes \u2192 diese Teilmenge)"
|
|
3262
|
+
},
|
|
3263
|
+
walk: {
|
|
3264
|
+
...EN.slash.walk,
|
|
3265
|
+
description: "Schrittweise durch ausstehende Edits gehen (git-add-p-Stil: y/n pro Block, a = Rest anwenden, A = AUTO umschalten)"
|
|
3266
|
+
},
|
|
3267
|
+
undo: { ...EN.slash.undo, description: "Letzten angewandten Edit-Batch r\xFCckg\xE4ngig machen" },
|
|
3268
|
+
history: {
|
|
3269
|
+
...EN.slash.history,
|
|
3270
|
+
description: "Jeden Edit-Batch dieser Sitzung auflisten (IDs f\xFCr /show, r\xFCckg\xE4ngig-Markierungen)"
|
|
3271
|
+
},
|
|
3272
|
+
show: {
|
|
3273
|
+
...EN.slash.show,
|
|
3274
|
+
description: "Gespeicherte Edit-Diff ausgeben (ID weglassen f\xFCr neuesten nicht-r\xFCckg\xE4ngigen)"
|
|
3275
|
+
},
|
|
3276
|
+
commit: { ...EN.slash.commit, description: "git add -A && git commit -m ..." },
|
|
3277
|
+
checkpoint: {
|
|
3278
|
+
...EN.slash.checkpoint,
|
|
3279
|
+
argsHint: "[Name|Liste|<ID> l\xF6schen]",
|
|
3280
|
+
description: "Jede Datei, die die Sitzung ber\xFChrt hat, als Schnappschuss sichern (Cursor-artiger interner Speicher, nicht Git). /checkpoint allein listet auf."
|
|
3281
|
+
},
|
|
3282
|
+
restore: {
|
|
3283
|
+
...EN.slash.restore,
|
|
3284
|
+
description: "Dateien auf einen benannten Checkpoint zur\xFCcksetzen (siehe /checkpoint list)"
|
|
3285
|
+
},
|
|
3286
|
+
plan: {
|
|
3287
|
+
...EN.slash.plan,
|
|
3288
|
+
argsHint: "[Ein|Aus]",
|
|
3289
|
+
description: "Schreibgesch\xFCtzten Plan-Modus umschalten (Schreibzugriffe blockiert bis submit_plan + Genehmigung)"
|
|
3290
|
+
},
|
|
3291
|
+
mode: {
|
|
3292
|
+
...EN.slash.mode,
|
|
3293
|
+
argsHint: "[Rezension|Auto|YOLO]",
|
|
3294
|
+
description: "Edit-Gate: review (Warteschlange) \xB7 auto (anwenden+r\xFCckg\xE4ngig) \xB7 yolo (anwenden+auto-shell). Shift+Tab schaltet um."
|
|
3295
|
+
},
|
|
3296
|
+
jobs: {
|
|
3297
|
+
...EN.slash.jobs,
|
|
3298
|
+
description: "Hintergrund-Jobs auflisten, die mit run_background gestartet wurden"
|
|
3299
|
+
},
|
|
3300
|
+
kill: {
|
|
3301
|
+
...EN.slash.kill,
|
|
3302
|
+
argsHint: "Bezeichner",
|
|
3303
|
+
description: "Hintergrund-Job nach ID beenden (SIGTERM \u2192 SIGKILL nach Gnadenfrist)"
|
|
3304
|
+
},
|
|
3305
|
+
logs: {
|
|
3306
|
+
...EN.slash.logs,
|
|
3307
|
+
argsHint: "<id> [Zeilen]",
|
|
3308
|
+
description: "Ausgabe eines Hintergrund-Jobs anzeigen (Standard letzte 80 Zeilen)"
|
|
3309
|
+
},
|
|
3310
|
+
btw: {
|
|
3311
|
+
...EN.slash.btw,
|
|
3312
|
+
argsHint: "<Frage>",
|
|
3313
|
+
description: "Kurze Randfrage stellen \u2014 wird von Grund auf beantwortet, nie zum Gespr\xE4chskontext hinzugef\xFCgt"
|
|
3314
|
+
},
|
|
3315
|
+
"search-engine": {
|
|
3316
|
+
...EN.slash["search-engine"],
|
|
3317
|
+
description: "Web-Search-Backend wechseln \u2014 bing (Standard, funktioniert von CN ohne Proxy), searxng (selbst gehostet), metaso (kostenlos 100/Tag), tavily (kostenlos 1000/Monat), perplexity (AI-native) oder exa (AI-native)"
|
|
3318
|
+
},
|
|
3319
|
+
theme: {
|
|
3320
|
+
...EN.slash.theme,
|
|
3321
|
+
argsHint: "[auto|dunkel|hell|mitternachtsblau|tiefblau|hoher Kontrast]",
|
|
3322
|
+
description: "Terminal-Theme anzeigen oder speichern. Ohne Argument \xF6ffnet die Auswahl."
|
|
3323
|
+
},
|
|
3324
|
+
exit: { ...EN.slash.exit, description: "TUI beenden" }
|
|
3325
|
+
},
|
|
3326
|
+
wizard: {
|
|
3327
|
+
...EN.wizard,
|
|
3328
|
+
languageTitle: "Sprache ausw\xE4hlen",
|
|
3329
|
+
languageSubtitle: "Aus der Systemsprache erkannt. Sp\xE4ter mit /language wechselbar.",
|
|
3330
|
+
welcomeTitle: "Willkommen bei Reasonix.",
|
|
3331
|
+
apiKeyPrompt: "F\xFCge deinen DeepSeek-API-Schl\xFCssel ein, um loszulegen.",
|
|
3332
|
+
apiKeyGetOne: "Erhalte einen unter: https://platform.deepseek.com/api_keys",
|
|
3333
|
+
apiKeySavedLocally: "Lokal gespeichert unter {path}",
|
|
3334
|
+
apiKeyInputLabel: "Schl\xFCssel > ",
|
|
3335
|
+
apiKeyPlaceholder: "sk-...",
|
|
3336
|
+
apiKeyInvalid: "Der Schl\xFCssel wirkt zu kurz \u2013 f\xFCge den vollst\xE4ndigen Token ein (16+ Zeichen, keine Leerzeichen).",
|
|
3337
|
+
apiKeyChecking: "API-Schl\xFCssel wird gepr\xFCft...",
|
|
3338
|
+
apiKeyRejected: "DeepSeek hat diesen API-Schl\xFCssel abgelehnt. F\xFCge einen g\xFCltigen Schl\xFCssel ein oder brich das Setup mit Esc ab.",
|
|
3339
|
+
apiKeyCheckFailed: "Konnte diesen API-Schl\xFCssel gerade nicht verifizieren ({message}). \xDCberpr\xFCfe deine Netzwerkverbindung oder versuche es erneut.",
|
|
3340
|
+
apiKeyPreview: "Vorschau: {redacted}",
|
|
3341
|
+
themeTitle: "Theme ausw\xE4hlen",
|
|
3342
|
+
themeSubtitle: "Die Vorschau aktualisiert sich beim Navigieren. Sp\xE4ter mit /theme \xE4nderbar.",
|
|
3343
|
+
themeSampleHeading: "Beispiel",
|
|
3344
|
+
themeFooter: "[\u2191\u2193] navigieren \xB7 [Enter] best\xE4tigen \xB7 [Esc] abbrechen",
|
|
3345
|
+
themeCaption: {
|
|
3346
|
+
...EN.wizard.themeCaption,
|
|
3347
|
+
dark: "K\xFChle dunkle T\xF6ne (Standard)",
|
|
3348
|
+
light: "Helle klare Ansicht",
|
|
3349
|
+
midnight: "Tokyo-Night-Palette",
|
|
3350
|
+
"deep-blue": "Tiefblau auf Schwarz",
|
|
3351
|
+
"high-contrast": "Barrierefreiheit"
|
|
3352
|
+
},
|
|
3353
|
+
mcpTitle: "Welche MCP-Server soll Reasonix f\xFCr dich einrichten?",
|
|
3354
|
+
mcpUserArgsHint: "(du wirst {arg} bereitstellen)",
|
|
3355
|
+
mcpFooterMulti: "[\u2191\u2193] navigieren \xB7 [Leertaste] umschalten \xB7 [Enter] best\xE4tigen \xB7 [Esc] abbrechen \xB7 leer = \xFCberspringen",
|
|
3356
|
+
mcpArgsTitle: "{name} konfigurieren",
|
|
3357
|
+
mcpArgsDirMissing: "Verzeichnis {path} existiert nicht.",
|
|
3358
|
+
mcpArgsDirCreateHint: "[Y/Enter] erstellen (mkdir -p) \xB7 [N/Esc] anderen Pfad eingeben",
|
|
3359
|
+
mcpArgsDirCreateFailed: "Konnte {path} nicht erstellen: {message}",
|
|
3360
|
+
mcpArgsRequiredParam: "Erforderlicher Parameter: ",
|
|
3361
|
+
mcpArgsEmpty: "{name} ben\xF6tigt einen Wert \u2014 leere Zeichenkette erhalten.",
|
|
3362
|
+
mcpArgsNotADir: "{path} existiert, ist aber kein Verzeichnis.",
|
|
3363
|
+
reviewTitle: "Bereit zum Speichern",
|
|
3364
|
+
reviewLabelApiKey: "API-Schl\xFCssel",
|
|
3365
|
+
reviewLabelLanguage: "Sprache",
|
|
3366
|
+
reviewLabelTheme: "Theme",
|
|
3367
|
+
reviewLabelMcp: "MCP",
|
|
3368
|
+
reviewMcpNone: "(keine)",
|
|
3369
|
+
reviewMcpServers: "{count} Server",
|
|
3370
|
+
reviewSavesTo: "Speichert nach {path}",
|
|
3371
|
+
reviewSaveError: "Konfiguration konnte nicht gespeichert werden: {message}",
|
|
3372
|
+
reviewFooter: "[Enter] speichern \xB7 [Esc] abbrechen",
|
|
3373
|
+
savedTitle: "\u25B8 Gespeichert.",
|
|
3374
|
+
savedShellHint: 'Shell-Befehle, die das Modell ausf\xFChren m\xF6chte, fragen jedes Mal nach \u2013 w\xE4hle \xBBimmer erlauben" in der Eingabeaufforderung, um diesen genauen Befehl f\xFCr dieses Projekt auf die Whitelist zu setzen. Kein globales Allow-All-Flag (designbedingt).',
|
|
3375
|
+
savedFooter: "[Enter] zum Beenden",
|
|
3376
|
+
selectFooter: "[\u2191\u2193] navigieren \xB7 [Enter] best\xE4tigen \xB7 [Esc] abbrechen",
|
|
3377
|
+
stepCounter: "Schritt {step}/{total} \xB7 ",
|
|
3378
|
+
exitHint: "/exit zum Abbrechen",
|
|
3379
|
+
themeSampleReasoning: "Denken"
|
|
3380
|
+
},
|
|
3381
|
+
themePicker: {
|
|
3382
|
+
...EN.themePicker,
|
|
3383
|
+
header: "Theme",
|
|
3384
|
+
footer: "\u2191\u2193 ausw\xE4hlen \xB7 \u23CE best\xE4tigen \xB7 Esc abbrechen",
|
|
3385
|
+
currentPref: "Aktuelle Einstellung",
|
|
3386
|
+
activeNow: "Jetzt aktiv",
|
|
3387
|
+
autoDesc: "REASONIX_THEME oder Standard verwenden"
|
|
3388
|
+
},
|
|
3389
|
+
planFlow: {
|
|
3390
|
+
...EN.planFlow,
|
|
3391
|
+
approveCardTitle: "Plan genehmigen",
|
|
3392
|
+
approveCardMetaRight: "wartet",
|
|
3393
|
+
openQuestionsBanner: "\u25B2 der Plan zeigt offene Fragen oder Risiken \u2014 w\xE4hle {refine}, um konkrete Antworten zu schreiben, bevor das Modell fortf\xE4hrt.",
|
|
3394
|
+
openQuestionsHeader: "Offene Fragen / Risiken",
|
|
3395
|
+
truncatedBodyMore: "\u2026 {n} weitere Zeile oben im Scrollback",
|
|
3396
|
+
truncatedBodyMorePlural: "\u2026 {n} weitere Zeilen oben im Scrollback",
|
|
3397
|
+
picker: {
|
|
3398
|
+
...EN.planFlow.picker,
|
|
3399
|
+
accept: "akzeptieren",
|
|
3400
|
+
acceptHint: "Jetzt ausf\xFChren, in Reihenfolge",
|
|
3401
|
+
refine: "verfeinern",
|
|
3402
|
+
refineHint: "Dem Agenten mehr Anweisungen geben, neuen Plan entwerfen",
|
|
3403
|
+
revise: "\xFCberarbeiten",
|
|
3404
|
+
reviseHint: "Plan inline bearbeiten vor der Ausf\xFChrung (Schritte \xFCberspringen/neu ordnen)",
|
|
3405
|
+
reject: "ablehnen",
|
|
3406
|
+
rejectHint: "Verwerfen, Agent versucht von Grund auf neu"
|
|
3407
|
+
},
|
|
3408
|
+
refineFooter: "\u23CE senden \xB7 Esc zur\xFCck zur Auswahl",
|
|
3409
|
+
refineQuestionsHeading: "Beantworte diese oder beschreibe die gew\xFCnschte \xC4nderung:",
|
|
3410
|
+
modes: {
|
|
3411
|
+
...EN.planFlow.modes,
|
|
3412
|
+
approve: {
|
|
3413
|
+
...EN.planFlow.modes.approve,
|
|
3414
|
+
title: "Genehmigen \u2014 letzte Anweisungen?",
|
|
3415
|
+
hint: "Beantworte Fragen aus dem Plan, f\xFCge Einschr\xE4nkungen hinzu oder dr\xFCcke einfach Enter zur Genehmigung.",
|
|
3416
|
+
blankHint: " (Enter ohne Text = ohne Zusatzanweisungen genehmigen.)"
|
|
3417
|
+
},
|
|
3418
|
+
refine: {
|
|
3419
|
+
...EN.planFlow.modes.refine,
|
|
3420
|
+
title: "Verfeinern \u2014 was soll das Modell \xE4ndern?",
|
|
3421
|
+
hint: "Beschreibe, was falsch ist oder fehlt, oder beantworte Fragen aus dem Plan.",
|
|
3422
|
+
blankHint: " (Enter ohne Text = Modell w\xE4hlt sichere Standardwerte f\xFCr offene Fragen.)"
|
|
3423
|
+
},
|
|
3424
|
+
reject: {
|
|
3425
|
+
...EN.planFlow.modes.reject,
|
|
3426
|
+
title: "Ablehnen \u2014 sag dem Modell warum (optional)",
|
|
3427
|
+
hint: "Sag dem Modell, was es an deinem Ziel falsch verstanden hat oder was du stattdessen m\xF6chtest.",
|
|
3428
|
+
blankHint: " (Enter ohne Text = ohne Erkl\xE4rung abbrechen; das Modell fragt, was du m\xF6chtest.)"
|
|
3429
|
+
},
|
|
3430
|
+
"checkpoint-revise": {
|
|
3431
|
+
...EN.planFlow.modes["checkpoint-revise"],
|
|
3432
|
+
title: "\xDCberarbeiten \u2014 was soll sich vor dem n\xE4chsten Schritt \xE4ndern?",
|
|
3433
|
+
hint: "Umfangs\xE4nderung, Schritte \xFCberspringen, alternativer Ansatz \u2014 das Modell passt den Restplan an.",
|
|
3434
|
+
blankHint: " (Enter ohne Text = mit aktuellem Plan fortfahren.)"
|
|
3435
|
+
},
|
|
3436
|
+
"choice-custom": {
|
|
3437
|
+
...EN.planFlow.modes["choice-custom"],
|
|
3438
|
+
title: "Benutzerdefinierte Antwort \u2014 schreibe, was passt",
|
|
3439
|
+
hint: "Freitext-Antwort. Das Modell liest sie w\xF6rtlich und f\xE4hrt fort \u2014 keine Notwendigkeit, die aufgef\xFChrten Optionen zu treffen.",
|
|
3440
|
+
blankHint: " (Enter ohne Text = Modell fragen, was du eigentlich m\xF6chtest.)"
|
|
3441
|
+
}
|
|
3442
|
+
},
|
|
3443
|
+
checkpoint: {
|
|
3444
|
+
...EN.planFlow.checkpoint,
|
|
3445
|
+
title: "Checkpoint \u2014 Schritt erledigt",
|
|
3446
|
+
continue: "Fortfahren \u2014 n\xE4chsten Schritt ausf\xFChren",
|
|
3447
|
+
continueHint: "Modell f\xE4hrt mit dem n\xE4chsten Schritt fort.",
|
|
3448
|
+
finish: "Abschlie\xDFen \u2014 zusammenfassen und beenden",
|
|
3449
|
+
finishHint: "Modell zeichnet den letzten Schritt auf und fasst den abgeschlossenen Plan zusammen.",
|
|
3450
|
+
revise: "\xDCberarbeiten \u2014 Feedback vor dem n\xE4chsten Schritt geben",
|
|
3451
|
+
reviseHint: "Bleibe pausiert, tippe Anweisungen; Modell passt den Restplan an.",
|
|
3452
|
+
stop: "Anhalten \u2014 Plan hier beenden",
|
|
3453
|
+
stopHint: "Modell fasst zusammen, was getan wurde, und beendet."
|
|
3454
|
+
},
|
|
3455
|
+
stepList: {
|
|
3456
|
+
...EN.planFlow.stepList,
|
|
3457
|
+
counter: "{total} Schritte",
|
|
3458
|
+
counterSingular: "{total} Schritt",
|
|
3459
|
+
counterDone: "{done}/{total} erledigt ({pct}%) \xB7 {total} Schritte",
|
|
3460
|
+
counterDoneSingular: "{done}/{total} erledigt ({pct}%) \xB7 {total} Schritt"
|
|
3461
|
+
},
|
|
3462
|
+
noPlanSummary: "Noch kein Plan-Body \xFCbermittelt.",
|
|
3463
|
+
detailCollapsedHint: "Strg+P erweitert die vollst\xE4ndigen Plan-Details.",
|
|
3464
|
+
detailExpandedHint: "Strg+P klappt Details ein.",
|
|
3465
|
+
detailHeader: "Plan-Details",
|
|
3466
|
+
detailWindow: "Zeige Zeilen {start}-{end} von {total}",
|
|
3467
|
+
detailScrollHint: "Bild\u2191/Bild\u2193 scrollt Details \xB7 Pos1/Ende springt",
|
|
3468
|
+
reviseTitle: "Plan \xFCberarbeiten",
|
|
3469
|
+
reviseSteps: "{count} Schritte",
|
|
3470
|
+
reviseFooter: "\u2191\u2193 fokussieren \xB7 Leertaste \xFCberspringen umschalten \xB7 k/j verschieben \xB7 \u23CE akzeptieren \xB7 Esc abbrechen",
|
|
3471
|
+
riskMed: " mittel",
|
|
3472
|
+
riskHigh: " hoch",
|
|
3473
|
+
completeMsg: "\u25B8 Plan abgeschlossen \u2014 alle {total} Schritt{e} erledigt \xB7 archiviert"
|
|
3474
|
+
},
|
|
3475
|
+
app: {
|
|
3476
|
+
...EN.app,
|
|
3477
|
+
dashboardStopped: "\u25B8 Dashboard gestoppt.",
|
|
3478
|
+
notedScopeProject: "Projekt",
|
|
3479
|
+
notedScopeGlobal: "global",
|
|
3480
|
+
commandFailed: "! Befehl fehlgeschlagen",
|
|
3481
|
+
btwFailed: "/btw fehlgeschlagen",
|
|
3482
|
+
walkCancelledRemaining: "\u25B8 Walk abgebrochen \u2014 {count} Block(s) noch ausstehend.",
|
|
3483
|
+
walkCancelled: "\u25B8 Walk abgebrochen.",
|
|
3484
|
+
editModeYolo: "\u25B8 Edit-Modus: YOLO \u2014 Edits UND Shell-Befehle auto-ausf\xFChren. /undo macht Edits immer noch r\xFCckg\xE4ngig. Vorsicht.",
|
|
3485
|
+
editModeAuto: "\u25B8 Edit-Modus: AUTO \u2014 Edits werden sofort angewandt; dr\xFCcke u innerhalb von 5s zum R\xFCckg\xE4ngigmachen (Leertaste pausiert den Timer). Shell-Befehle fragen weiterhin.",
|
|
3486
|
+
editModeReview: "\u25B8 Edit-Modus: review \u2014 Edits warten auf /apply (oder y) / /discard (oder n)",
|
|
3487
|
+
rejectedEdit: "\u25B8 Edit abgelehnt: {path}{context}",
|
|
3488
|
+
autoApprovingRest: "\u25B8 Restliche Edits f\xFCr diesen Turn werden automatisch genehmigt",
|
|
3489
|
+
flippedAutoSession: "\u25B8 F\xFCr den Rest der Sitzung auf AUTO umgeschaltet (gespeichert)",
|
|
3490
|
+
flippedAutoWalk: "\u25B8 Auf AUTO umgeschaltet \u2014 zuk\xFCnftige Edits werden sofort angewandt. Walk beendet.",
|
|
3491
|
+
notedMemory: "\u25B8 vermerkt ({scope}) \u2014 {verb} {path}",
|
|
3492
|
+
notedVerbCreated: "erstellt",
|
|
3493
|
+
notedVerbAppended: "Angeh\xE4ngt an",
|
|
3494
|
+
memoryWriteFailed: "# Speicherschreibfehler",
|
|
3495
|
+
verboseOn: "\u25B8 Ausf\xFChrlicher Modus an \u2014 vollst\xE4ndiges Reasoning + Tool-Ausgabe",
|
|
3496
|
+
verboseOff: "\u25B8 Ausf\xFChrlicher Modus aus \u2014 head/tail-K\xFCrzung wiederhergestellt",
|
|
3497
|
+
steerInjected: "\u25B8 Steuerung in Warteschlange \u2014 wird nach dem aktuellen Schritt hinzugef\xFCgt",
|
|
3498
|
+
steerCommandRejected: "\u25B8 Befehle sind deaktiviert, w\xE4hrend ein Turn gesteuert wird",
|
|
3499
|
+
btwUsage: "\u25B8 /btw <Frage> \u2014 eine Randfrage stellen, ohne den Gespr\xE4chskontext zu verschmutzen.",
|
|
3500
|
+
btwHeader: "\u226B btw",
|
|
3501
|
+
restoreCodeOnly: "\u25B8 /restore ist nur im Code-Modus verf\xFCgbar",
|
|
3502
|
+
hookUserPromptSubmit: "UserPromptSubmit-Hook",
|
|
3503
|
+
hookStop: "Stop-Hook",
|
|
3504
|
+
atMentions: "\u25B8 @mentions: {parts}",
|
|
3505
|
+
atUrl: "\u25B8 @url: {parts}",
|
|
3506
|
+
atUrlFailed: "@url Erweiterung fehlgeschlagen",
|
|
3507
|
+
sessionTitleNoSession: "\u25B8 Keine persistierte Sitzung aktiv, also nichts umzubenennen.",
|
|
3508
|
+
sessionTitleNoContent: "\u25B8 Noch nicht genug Gespr\xE4chsinhalt, um diese Sitzung zu benennen.",
|
|
3509
|
+
sessionTitleNoTitle: "\u25B8 Das Modell hat keinen brauchbaren Sitzungstitel zur\xFCckgegeben.",
|
|
3510
|
+
sessionTitleUpdated: '\u25B8 Sitzungstitel aktualisiert: "{title}"',
|
|
3511
|
+
sessionTitleRenameFailed: '\u25B8 Sitzung konnte nicht f\xFCr Titel "{title}" umbenannt werden.',
|
|
3512
|
+
sessionTitleRenamed: '\u25B8 Sitzung umbenannt in "{name}" \u2014 {title}',
|
|
3513
|
+
sessionTitleAutoRenamed: '\u25B8 Automatisch benannte Sitzung "{name}" \u2014 {title}',
|
|
3514
|
+
workspaceSwitched: "\u25B8 Arbeitsbereich gewechselt zu {root}",
|
|
3515
|
+
semanticRepointed: "\u25B8 Semantic-Search umgeleitet nach {root}",
|
|
3516
|
+
semanticDisabledForRoot: "\u25B8 Semantic-Search deaktiviert (kein kompatibler Index in {root})",
|
|
3517
|
+
semanticRebootstrapFailed: "\u25B8 Semantic-Search-Neustart fehlgeschlagen: {reason}",
|
|
3518
|
+
denied: "\u25B8 verweigert: {cmd}{context}",
|
|
3519
|
+
alwaysAllowed: '\u25B8 "{prefix}" f\xFCr {dir} dauerhaft erlaubt',
|
|
3520
|
+
runningCommand: "\u25B8 f\xFChre aus: {cmd}",
|
|
3521
|
+
startingBackground: "\u25B8 starte (Hintergrund): {cmd}",
|
|
3522
|
+
checkpointSaved: "\u26C1 Checkpoint gespeichert \xB7 {id} \xB7 {count} Datei{en} \xB7 /restore {id} zum Zur\xFCcksetzen",
|
|
3523
|
+
continuingAfter: "\u25B8 fortgesetzen nach {label}{counter}",
|
|
3524
|
+
planStoppedAt: "\u25B8 Plan angehalten bei {label}{counter}",
|
|
3525
|
+
revisingAfter: "\u25B8 \xFCberarbeite nach {label} \u2014 {feedback}",
|
|
3526
|
+
historyScrollHint: " \u2191 lese Verlauf \xB7 Ende / Bild\u2193 zur\xFCck zum Ende \xB7 \u2193 eine Zeile vor",
|
|
3527
|
+
editHistoryTitle: "Edit-Verlauf (\xE4lteste zuerst):",
|
|
3528
|
+
editHistoryNoCodeMode: "Nicht im Code-Modus",
|
|
3529
|
+
editHistoryNoEdits: "Noch keine Edits in dieser Sitzung aufgezeichnet",
|
|
3530
|
+
editHistoryNoShowId: "Verwendung: /show [id] [pfad] (ID weglassen f\xFCr neueste; Pfad aus der Datei-Zusammenfassung)",
|
|
3531
|
+
editHistoryIdNotFound: "Kein Edit #{id} \u2014 /history ausf\xFChren f\xFCr g\xFCltige IDs",
|
|
3532
|
+
editHistoryLookupFailed: "Unerwartet: History-Lookup fehlgeschlagen",
|
|
3533
|
+
editHistoryBatchNoFile: 'Batch #{id} enth\xE4lt kein "{path}" \u2014 Dateien in diesem Batch: {files}',
|
|
3534
|
+
editHistoryNoEdits2: "Keine Edits in dieser Sitzung aufgezeichnet \u2014 /history ist leer",
|
|
3535
|
+
editHistoryStatusApplied: "angewandt",
|
|
3536
|
+
editHistoryStatusPartial: "TEILWEISE",
|
|
3537
|
+
editHistoryStatusUndone: "R\xDCCKG\xC4NGIG",
|
|
3538
|
+
editHistoryHelpShow: "/show <id> \u2192 Zusammenfassung pro Datei \xB7 /show <id> <pfad> \u2192 vollst\xE4ndige Diff einer Datei",
|
|
3539
|
+
editHistoryHelpUndo: "/undo \u2192 neueste nicht-r\xFCckg\xE4ngige \xB7 /undo <id> [pfad] \u2192 gezielten Batch oder Datei r\xFCckg\xE4ngig machen",
|
|
3540
|
+
editHistoryAlreadyReverted: "(bereits r\xFCckg\xE4ngig gemacht \u2014 /history zeigt den batch-level Status)",
|
|
3541
|
+
editHistoryRevertFile: "/undo {id} {path} \u2192 nur diese Datei r\xFCckg\xE4ngig machen",
|
|
3542
|
+
mcpFailed: "MCP {name} fehlgeschlagen",
|
|
3543
|
+
mcpWarn: "MCP {name} Warnung",
|
|
3544
|
+
unknownTheme: "Unbekanntes Theme: {name}\nVerf\xFCgbar: {choices}",
|
|
3545
|
+
themeSaved: "Theme gespeichert: {name}\nAktiv beim n\xE4chsten Start: {active}",
|
|
3546
|
+
noPendingEdits: "Nichts ausstehend \u2014 das Modell hat seit dem letzten /apply oder /discard keine Edits vorgeschlagen.",
|
|
3547
|
+
noMatchedApply: "\u25B8 Keine Edits mit diesen Indizes gefunden \u2014 nichts angewandt. Verwende /apply ohne Argumente, um alle zu \xFCbernehmen.",
|
|
3548
|
+
noPendingDiscard: "Nichts ausstehend zum Verwerfen.",
|
|
3549
|
+
noMatchedDiscard: "\u25B8 Keine Edits mit diesen Indizes gefunden \u2014 nichts verworfen.",
|
|
3550
|
+
blocksStillPending: "\u25B8 {count} Edit-Block(s) noch ausstehend \u2014 /apply oder /discard zum Bereinigen.",
|
|
3551
|
+
nothingWritten: ". Nichts auf Platte geschrieben.",
|
|
3552
|
+
discardedCount: "\u25B8 {count} ausstehende Edit-Block(s) verworfen",
|
|
3553
|
+
noEventsFor: 'Keine Ereignisse f\xFCr Sitzung "{name}"',
|
|
3554
|
+
lookedAtFile: "Angesehen: {path}",
|
|
3555
|
+
sidecarHint: "(Sitzungen erstellen den Sidecar automatisch beim ersten Turn \u2014 wurde diese Sitzung bereits ausgef\xFChrt?)"
|
|
3556
|
+
},
|
|
3557
|
+
hooks: {
|
|
3558
|
+
...EN.hooks,
|
|
3559
|
+
head: "Hook {tag} `{cmd}` {decision}{truncTag}",
|
|
3560
|
+
headWithDetail: "Hook {tag} `{cmd}` {decision}{truncTag}: {detail}",
|
|
3561
|
+
truncated: " (Ausgabe bei 256 KB gek\xFCrzt)",
|
|
3562
|
+
decisionBlock: "blockieren",
|
|
3563
|
+
decisionWarn: "warnen",
|
|
3564
|
+
decisionTimeout: "Timeout",
|
|
3565
|
+
decisionError: "Fehler"
|
|
3566
|
+
},
|
|
3567
|
+
summary: {
|
|
3568
|
+
...EN.summary,
|
|
3569
|
+
status: "Zusammenfassung der gesammelten Informationen...",
|
|
3570
|
+
hallucinatedFallback: "(Modell hat gef\xE4lschte Tool-Call-Markup statt einer Prosa-Zusammenfassung ausgegeben \u2014 versuche /retry mit einer engeren Frage, oder /think zur Inspektion von R1s Reasoning)",
|
|
3571
|
+
failedAfterReason: "{label} und der Fallback-Summary-Aufruf sind fehlgeschlagen: {message}. F\xFChre /clear aus und versuche es mit einer engeren Frage, oder erh\xF6he --max-tool-iters."
|
|
3572
|
+
},
|
|
3573
|
+
loop: {
|
|
3574
|
+
...EN.loop,
|
|
3575
|
+
budgetExhausted: "Sitzungsbudget ersch\xF6pft \u2014 ${spent} ausgegeben \u2265 Grenze ${cap}. Erh\xF6he die Grenze mit /budget <usd>, schalte sie mit /budget off aus oder beende die Sitzung.",
|
|
3576
|
+
budget80Pct: "\u25B2 Budget zu 80 % verbraucht \u2014 ${spent} von ${cap}. Der n\xE4chste oder \xFCbern\xE4chste Turn erreicht wahrscheinlich die Grenze.",
|
|
3577
|
+
proArmed: "\u21E7 /pro aktiviert \u2014 dieser Turn l\xE4uft auf deepseek-v4-pro (einmalig \xB7 deaktiviert nach dem Turn)",
|
|
3578
|
+
toolUploadStatus: "Tool-Ergebnis hochgeladen \u2013 Modell denkt vor der n\xE4chsten Antwort...",
|
|
3579
|
+
turnStartFoldStatus: "Turn-Start: Kontext n\xE4hert sich Grenze, komprimiere Verlauf...",
|
|
3580
|
+
turnStartFolded: "Turn-Start: Anfrage ~{estimate}/{ctxMax} Tokens ({pct}%) \u2014 {beforeMessages} Nachrichten \u2192 {afterMessages} komprimiert. Sende.",
|
|
3581
|
+
harvestStatus: "Planstatus wird aus dem Reasoning extrahiert...",
|
|
3582
|
+
repeatToolCallWarning: "Wiederholten Tool-Aufruf erkannt \u2014 lasse das Modell das Problem sehen und es mit einem anderen Ansatz erneut versuchen.",
|
|
3583
|
+
stormStuck: "Festgefahrene Wiederholungsschleife gestoppt \u2014 das Modell rief dasselbe Tool mit identischen Argumenten auf, selbst nach einem Selbstkorrektur-Hinweis. Versuche /retry, umformulieren oder schlie\xDFe den zugrunde liegenden Blocker aus.",
|
|
3584
|
+
stormSuppressed: "{count} wiederholte Tool-Aufrufe unterdr\xFCckt \u2014 gleicher Name + Argumente 3+ Mal gesendet.",
|
|
3585
|
+
compactingHistoryStatus: "Komprimiere Verlauf{aggressiveTag}...",
|
|
3586
|
+
aggressiveTag: " (aggressiv)",
|
|
3587
|
+
foldedHistory: "Kontext {before}/{ctxMax} ({pct}%) \u2014 {beforeMessages} Nachrichten \u2192 {afterMessages} gefaltet (Zusammenfassung {summaryChars} Zeichen). Fahre fort.",
|
|
3588
|
+
aggressivelyFoldedHistory: "Kontext {before}/{ctxMax} ({pct}%) \u2014 {beforeMessages} Nachrichten \u2192 {afterMessages} aggressiv gefaltet (Zusammenfassung {summaryChars} Zeichen). Fahre fort.",
|
|
3589
|
+
forcingSummary: "Kontext {before}/{ctxMax} ({pct}%) \u2014 erzwinge Zusammenfassung aus dem Gesammelten. F\xFChre /compact, /clear oder /new aus, um zur\xFCckzusetzen."
|
|
3590
|
+
},
|
|
3591
|
+
errors: {
|
|
3592
|
+
...EN.errors,
|
|
3593
|
+
contextOverflow: "Context-\xDCberlauf (DeepSeek 400): Sitzungsverlauf ist {requested}, \xFCber dem Prompt-Limit des Modells (V4: 1M Tokens; legacy chat/reasoner: 131k). Meist ist ein einzelnes Tool-Ergebnis zu gro\xDF geworden. Reasonix begrenzt neue Tool-Ergebnisse auf 8k Tokens und heilt \xFCberdimensionierte Verl\xE4ufe automatisch beim Sitzungsladen \u2013 ein Neustart behebt es oft. Falls es weiterhin \xFCberl\xE4uft, f\xFChre /new f\xFCr einen frischen Start aus oder \xF6ffne /sessions und dr\xFCcke [d], um diese Sitzung zu l\xF6schen.",
|
|
3594
|
+
contextOverflowTooMany: "Zu viele Tokens",
|
|
3595
|
+
auth401: "Authentifizierung fehlgeschlagen (DeepSeek 401): {inner}. Dein API-Schl\xFCssel wird abgewiesen. Behebe mit `reasonix setup` oder `export DEEPSEEK_API_KEY=sk-...`. Erhalte einen unter https://platform.deepseek.com/api_keys.",
|
|
3596
|
+
balance402: "Kontoguthaben aufgebraucht (DeepSeek 402): {inner}. Lade auf unter https://platform.deepseek.com/top_up \u2014 der Panel-Header zeigt dein Guthaben, sobald es nicht Null ist.",
|
|
3597
|
+
badparam422: "Ung\xFCltiger Parameter (DeepSeek 422): {inner}",
|
|
3598
|
+
badrequest400: "Fehlerhafte Anfrage (DeepSeek 400): {inner}",
|
|
3599
|
+
concurrency429: "DeepSeek-Gleichzeitigkeitslimit erreicht (429): {inner}. Das Konto hat zu viele gleichzeitige Anfragen (Grenze: 500 f\xFCr v4-pro, 2500 f\xFCr v4-flash, summiert \xFCber alle API-Schl\xFCssel des Kontos). Meist l\xE4uft ein weiterer Reasonix-Prozess mit demselben Schl\xFCssel oder ein paralleler Subagent-Fan-out hat \xFCberzogen. Warte einige Sekunden und wiederhole, reduziere die Parallelit\xE4t oder beantrage eine h\xF6here Grenze unter https://platform.deepseek.com.",
|
|
3600
|
+
deepseek5xxHead: "DeepSeek-Dienst nicht verf\xFCgbar ({status}) \u2014 dies ist ein DeepSeek-seitiges Problem, nicht Reasonix. Bereits 4\xD7 mit Backoff wiederholt.",
|
|
3601
|
+
deepseek5xxReachable: " DeepSeek's Haupt-API hat auf unseren Health-Check geantwortet, aber /chat/completions schl\xE4gt fehl \u2014 partieller Ausfall auf ihrer Seite.",
|
|
3602
|
+
deepseek5xxUnreachable: " DeepSeek-API ist von deinem Netzwerk aus nicht erreichbar \u2014 k\xF6nnte ein gr\xF6\xDFerer DS-Ausfall oder ein lokales Netzwerkproblem sein.",
|
|
3603
|
+
deepseek5xxActionNetwork: " Versuche: (1) Netzwerk pr\xFCfen, (2) 30s warten und wiederholen, (3) Statusseite: https://status.deepseek.com.",
|
|
3604
|
+
deepseek5xxActionRetry: " Versuche: (1) 30s warten und wiederholen, (2) /model zum Modellwechsel, (3) Statusseite: https://status.deepseek.com.",
|
|
3605
|
+
upstream5xxHead: "Upstream-Dienst nicht verf\xFCgbar ({status}) bei {host} \u2014 der konfigurierte API-Endpunkt hat einen Serverfehler zur\xFCckgegeben, kein Reasonix-Fehler. Bereits 4\xD7 mit Backoff wiederholt.",
|
|
3606
|
+
upstream5xxActionRetry: " Versuche: (1) Pr\xFCfen, ob der lokale/Proxy-Modell-Server l\xE4uft, (2) warten und wiederholen, (3) /model zum Modellwechsel.",
|
|
3607
|
+
innerNoMessage: "(keine Nachricht)",
|
|
3608
|
+
reasonAborted: "[vom Benutzer abgebrochen (Esc) \u2014 fasse zusammen, was ich bisher gefunden habe]",
|
|
3609
|
+
reasonContextGuard: "[Context-Budget wird knapp \u2014 fasse zusammen, bevor der n\xE4chste Aufruf \xFCberl\xE4uft]",
|
|
3610
|
+
reasonStuck: "[festgefahren bei wiederholtem Tool-Aufruf \u2014 erkl\xE4re, was versucht wurde und was den Fortschritt blockiert]",
|
|
3611
|
+
labelAborted: "Vom Benutzer abgebrochen",
|
|
3612
|
+
labelContextGuard: "Context-Guard ausgel\xF6st (Prompt > 80 % des Fensters)",
|
|
3613
|
+
labelStuck: "Festgefahren (wiederholter Tool-Aufruf durch Storm-Breaker unterdr\xFCckt)"
|
|
3614
|
+
},
|
|
3615
|
+
handlers: {
|
|
3616
|
+
...EN.handlers,
|
|
3617
|
+
basic: {
|
|
3618
|
+
...EN.handlers.basic,
|
|
3619
|
+
newInfo: "\u25B8 neues Gespr\xE4ch \u2014 {count} Nachricht(en) aus dem Kontext entfernt. Gleiche Sitzung, frische Grundlage.",
|
|
3620
|
+
newInfoArchived: '\u25B8 neues Gespr\xE4ch \u2014 {count} Nachricht(en) aus dem Kontext entfernt. Vorheriges Transkript als "{archived}" archiviert (sichtbar unter Sitzungen).',
|
|
3621
|
+
newInfoSystemReloaded: " \xB7 REASONIX.md / Projekt-Memory neu geladen (n\xE4chster Turn zahlt einen Cache-Fehler)",
|
|
3622
|
+
helpTitle: "Befehle:",
|
|
3623
|
+
helpShellTitle: "Shell-K\xFCrzel:",
|
|
3624
|
+
helpShell: " !<befehl> <befehl> im Sandbox-Root ausf\xFChren; Ausgabe kommt",
|
|
3625
|
+
helpShellDetail: " in die Konversation, sodass das Modell sie im n\xE4chsten Turn sieht.",
|
|
3626
|
+
helpShellConsent: " Kein Allowlist-Gate \u2014 vom Benutzer getippt = explizite Zustimmung.",
|
|
3627
|
+
helpShellExample: " Beispiel: !git status !ls src/ !npm test",
|
|
3628
|
+
helpShellGateTitle: "Vom Modell aufgerufene Shell-Befehle (pro Aufruf Genehmigung):",
|
|
3629
|
+
helpShellGate: " \u2191\u2193 + \u23CE jeder Aufruf zeigt eine Eingabeaufforderung mit \xBBEinmal erlauben\xAB / \xBBImmer erlauben\xAB",
|
|
3630
|
+
helpShellGateDetail: " / \xBBAblehnen\xAB. W\xE4hle \xBBImmer erlauben\xAB, um diesen genauen",
|
|
3631
|
+
helpShellGatePolicy: " Befehlspr\xE4fix f\xFCr dieses Projekt auf die Whitelist zu setzen. Kein globales Allow-All-Flag.",
|
|
3632
|
+
helpMemoryTitle: "Kurzzeit-Memory:",
|
|
3633
|
+
helpMemoryPin: " #<notiz> <notiz> an <projekt>/REASONIX.md anh\xE4ngen (commitierbar).",
|
|
3634
|
+
helpMemoryPinEx: " Beispiel: #findByEmail muss case-insensitive sein",
|
|
3635
|
+
helpMemoryGlobal: " #g <notiz> <notiz> an ~/.reasonix/REASONIX.md anh\xE4ngen (global, niemals committed).",
|
|
3636
|
+
helpMemoryGlobalEx: " Beispiel: #g immer pnpm, nicht npm verwenden",
|
|
3637
|
+
helpMemoryPinBoth: " Beide werden in jedes zuk\xFCnftige Sitzungs-Pr\xE4fix eingef\xFCgt. Schneller als /memory.",
|
|
3638
|
+
helpMemoryEscape: " Verwende `\\#text`, um ein literales `#text` an das Modell zu senden.",
|
|
3639
|
+
helpFileTitle: "Dateiverweise (Code-Modus):",
|
|
3640
|
+
helpFile: " @pfad/zu/datei Dateiinhalt unter [Referenzierte Dateien] beim Senden einf\xFCgen.",
|
|
3641
|
+
helpFilePicker: " Tippe `@`, um die Auswahl zu \xF6ffnen (\u2191\u2193 navigieren, Tab/Enter ausw\xE4hlen).",
|
|
3642
|
+
helpUrlTitle: "URL-Verweise:",
|
|
3643
|
+
helpUrl: " @https://example.com URL abrufen, HTML entfernen, unter [Referenzierte URLs] einf\xFCgen.",
|
|
3644
|
+
helpUrlCache: " Gleiche URL zweimal in einer Sitzung wird nur einmal abgerufen (In-Mem-Cache).",
|
|
3645
|
+
helpUrlPunct: " Abschluss-Satzzeichen (./,/)) werden automatisch entfernt.",
|
|
3646
|
+
helpSessionsTitle: "Sitzungen (standardm\xE4\xDFig aktiviert, hei\xDFen 'default'):",
|
|
3647
|
+
helpSessionCustom: " reasonix chat --session <name> eine andere benannte Sitzung verwenden",
|
|
3648
|
+
helpSessionNone: " reasonix chat --no-session Persistenz f\xFCr diesen Lauf deaktivieren",
|
|
3649
|
+
retryNone: "Nichts zu wiederholen \u2014 keine vorherige Benutzernachricht im Log dieser Sitzung.",
|
|
3650
|
+
retryInfo: '\u25B8 wiederhole: "{preview}"',
|
|
3651
|
+
loopTuiOnly: "/loop ist nur in der interaktiven TUI verf\xFCgbar (nicht in run/replay).",
|
|
3652
|
+
loopStopped: "\u25B8 Loop gestoppt.",
|
|
3653
|
+
loopNoActive: "Kein aktiver Loop zum Stoppen.",
|
|
3654
|
+
loopNoActiveHint: "kein aktiver Loop. Starte einen mit `/loop <intervall> <prompt>` (z.B. /loop 30s npm test).\nWird abgebrochen bei: /loop stop \xB7 Esc \xB7 /clear /new \xB7 jeder benutzereingegebene Prompt.",
|
|
3655
|
+
loopStarted: '\u25B8 Loop gestartet \u2014 \xBB{prompt}" wird alle {duration} erneut gesendet. Tippe etwas (oder /loop stop) zum Abbrechen.',
|
|
3656
|
+
keysNeedsTui: "/keys ben\xF6tigt einen TUI-Kontext (postKeys angeschlossen).",
|
|
3657
|
+
aboutHeader: "Reasonix v{version} \u2014 ein Cache-First-DeepSeek-Coding-Agent",
|
|
3658
|
+
aboutWebsiteLabel: "Webseite",
|
|
3659
|
+
aboutRepoLabel: "GitHub ",
|
|
3660
|
+
aboutLicenseLabel: "Lizenz",
|
|
3661
|
+
unknownCommand: "Unbekannter Befehl: /{cmd} \u2014 meintest du {list}?",
|
|
3662
|
+
unknownCommandShort: "Unbekannter Befehl: /{cmd} (siehe /help)"
|
|
3663
|
+
},
|
|
3664
|
+
sessions: {
|
|
3665
|
+
...EN.handlers.sessions,
|
|
3666
|
+
titleUnavailable: "/title ist nur in einer aktiven persistierten TUI-Sitzung verf\xFCgbar.",
|
|
3667
|
+
titleStarted: "\u25B8 benenne Sitzung...",
|
|
3668
|
+
titleFailed: "\u25B8 Sitzungstitel fehlgeschlagen: {reason}"
|
|
3669
|
+
},
|
|
3670
|
+
qq: {
|
|
3671
|
+
...EN.handlers.qq,
|
|
3672
|
+
unavailable: "/qq ist in dieser Sitzung nicht verf\xFCgbar.",
|
|
3673
|
+
connecting: "QQ: verbinde...",
|
|
3674
|
+
connectFailed: "QQ-Verbindung fehlgeschlagen: {reason}",
|
|
3675
|
+
disconnecting: "QQ: trenne...",
|
|
3676
|
+
disconnectFailed: "QQ-Trennung fehlgeschlagen: {reason}",
|
|
3677
|
+
usage: "Verwendung: /qq connect [appId appSecret [sandbox]] | /qq status | /qq disconnect",
|
|
3678
|
+
promptAppId: "QQ-Setup: gib deine QQ-Open-Platform-App-ID ein, dann Enter. Tippe /cancel zum Abbrechen.",
|
|
3679
|
+
promptAppSecret: "QQ-Setup: gib dein QQ-Open-Platform-App-Secret ein, dann Enter. Tippe /cancel zum Abbrechen.",
|
|
3680
|
+
setupWaitingAppId: "Warte auf App-ID",
|
|
3681
|
+
setupWaitingAppSecret: "Warte auf App-Secret",
|
|
3682
|
+
setupCancelled: "QQ-Setup abgebrochen.",
|
|
3683
|
+
credentialsRequired: "QQ-App-ID und App-Secret sind erforderlich.",
|
|
3684
|
+
connected: "QQ im {mode}-Modus verbunden. Es wird bei zuk\xFCnftigen Starts automatisch gestartet.",
|
|
3685
|
+
alreadyConnected: "QQ ist bereits im {mode}-Modus verbunden. Autostart ist aktiviert.",
|
|
3686
|
+
disconnected: "QQ getrennt. Autostart ist deaktiviert.",
|
|
3687
|
+
status: "QQ: {connected}, Autostart {enabled}, Anmeldedaten {configured}, App-ID {appId}, {sandbox}, Zugriff {access}, aktueller Modus {mode}.",
|
|
3688
|
+
statusSetup: "QQ: Setup l\xE4uft \u2014 {step}",
|
|
3689
|
+
stateConnected: "verbunden",
|
|
3690
|
+
stateDisconnected: "getrennt",
|
|
3691
|
+
stateEnabled: "aktiviert",
|
|
3692
|
+
stateDisabled: "deaktiviert",
|
|
3693
|
+
stateConfigured: "konfiguriert",
|
|
3694
|
+
stateNotConfigured: "Nicht konfiguriert",
|
|
3695
|
+
sandbox: "Sandbox",
|
|
3696
|
+
production: "Produktion",
|
|
3697
|
+
none: "keine",
|
|
3698
|
+
modeChat: "Chat",
|
|
3699
|
+
modeCode: "Code",
|
|
3700
|
+
accessOwner: "Besitzer {owner}",
|
|
3701
|
+
accessOwnerWithAllowlist: "Besitzer {owner}, Allowlist {count}",
|
|
3702
|
+
accessAllowlist: "Allowlist {count}",
|
|
3703
|
+
accessRuntime: "Erstabsender (nur zur Laufzeit, {owner})",
|
|
3704
|
+
accessOpen: "Offen (ungebunden)",
|
|
3705
|
+
lockAlreadyRunning: "QQ-Kanal l\xE4uft bereits in Prozess {pid}. Stoppe diesen Prozess, bevor du einen weiteren QQ-Kanal startest.",
|
|
3706
|
+
unauthorizedMessage: "QQ hat Nachricht von nicht autorisierter OpenID {openid} ignoriert. Aktueller Zugriff: {access}.",
|
|
3707
|
+
runtimeBound: "QQ hat diesen Lauf vor\xFCbergehend an den Erstabsender {openid} gebunden. Setze `qq.ownerOpenId` in der Konfiguration, um den Zugriff dauerhaft zu machen.",
|
|
3708
|
+
missingAppId: "QQ-App-ID erforderlich. F\xFChre `/qq connect` zum Konfigurieren aus.",
|
|
3709
|
+
missingAppSecret: "QQ-App-Secret erforderlich. F\xFChre `/qq connect` zum Konfigurieren aus.",
|
|
3710
|
+
authFailed: "QQ-Bot-Authentifizierung fehlgeschlagen \u2014 \xFCberpr\xFCfe deine App-ID und dein App-Secret.",
|
|
3711
|
+
readyTimeout: "QQ-Bot hat READY nicht innerhalb von 15s erhalten \u2014 \xFCberpr\xFCfe deine App-ID und dein App-Secret."
|
|
3712
|
+
},
|
|
3713
|
+
admin: {
|
|
3714
|
+
...EN.handlers.admin,
|
|
3715
|
+
doctorNeedsTui: "/doctor ben\xF6tigt einen TUI-Kontext (postDoctor angeschlossen).",
|
|
3716
|
+
doctorRunning: "\u2695 Doctor \u2014 f\xFChre Gesundheitschecks aus...",
|
|
3717
|
+
hooksReloadUnavailable: "/hooks reload ist in diesem Kontext nicht verf\xFCgbar (kein Reload-Callback angeschlossen).",
|
|
3718
|
+
hooksReloaded: "\u25B8 Hooks neu geladen \xB7 {count} aktiv",
|
|
3719
|
+
hooksUsage: "Verwendung: /hooks aktive Hooks auflisten\n /hooks reload settings.json-Dateien neu lesen",
|
|
3720
|
+
hooksNone: "Keine Hooks konfiguriert.",
|
|
3721
|
+
hooksDropHint: "Lege eine settings.json mit einem `hooks`-Schl\xFCssel in einem der folgenden Pfade ab:",
|
|
3722
|
+
hooksProject: " \xB7 {path} (Projekt)",
|
|
3723
|
+
hooksProjectFallback: " \xB7 <projekt>/.reasonix/settings.json (Projekt)",
|
|
3724
|
+
hooksGlobal: " \xB7 {path} (global)",
|
|
3725
|
+
hooksEvents: "Ereignisse: PreToolUse, PostToolUse, UserPromptSubmit, Stop",
|
|
3726
|
+
hooksExitCodes: "Exit 0 = bestanden \xB7 Exit 2 = blockieren (Pre*) \xB7 andere = warnen",
|
|
3727
|
+
hooksLoaded: "\u25B8 {count} Hook(s) geladen",
|
|
3728
|
+
hooksSources: "Quellen: Projekt={project} \xB7 global={global}",
|
|
3729
|
+
updateCurrent: "Aktuell: reasonix {version}",
|
|
3730
|
+
updateLatestPending: "Neueste: (noch nicht aufgel\xF6st \u2014 Hintergrundpr\xFCfung l\xE4uft oder offline)",
|
|
3731
|
+
updateRetryHint: "hat einen frischen Registry-Abruf ausgel\xF6st \u2014 versuche `/update` in ein paar Sekunden erneut,",
|
|
3732
|
+
updateRetryHint2: "oder f\xFChre `reasonix update` in einem anderen Terminal aus, um es synchron zu erzwingen.",
|
|
3733
|
+
updateLatest: "Neueste: reasonix {version}",
|
|
3734
|
+
updateUpToDate: "Du bist auf dem neuesten Stand. Nichts zu tun.",
|
|
3735
|
+
updateNpxHint: "du verwendest npx \u2014 der n\xE4chste `npx reasonix ...`-Start l\xE4dt automatisch die neueste Version.",
|
|
3736
|
+
updateNpxForce: "Um fr\xFCher zu aktualisieren: `npm cache clean --force`.",
|
|
3737
|
+
updateUpgradeHint: "Zum Aktualisieren beende diese Sitzung und f\xFChre aus:",
|
|
3738
|
+
updateUpgradeCmd1: " reasonix update (interaktiv, --dry-run wird unterst\xFCtzt)",
|
|
3739
|
+
updateUpgradeCmd2: " {command} (direkt)",
|
|
3740
|
+
updateInSessionDisabled: "Die Installation innerhalb einer Sitzung ist bewusst deaktiviert \u2014 der Installationsprozess w\xFCrde",
|
|
3741
|
+
updateInSessionDisabled2: "die Darstellung dieser TUI beeintr\xE4chtigen und Windows kann die laufende Bin\xE4rdatei sperren.",
|
|
3742
|
+
statsNoData: "Noch keine Nutzungsdaten.",
|
|
3743
|
+
statsEveryTurn: "jeder hier ausgef\xFChrte Turn h\xE4ngt einen Datensatz an \u2014 die Turns dieser Sitzung",
|
|
3744
|
+
statsWillAppear: "Werden im Dashboard angezeigt, sobald du eine Nachricht sendest."
|
|
3745
|
+
},
|
|
3746
|
+
edits: {
|
|
3747
|
+
...EN.handlers.edits,
|
|
3748
|
+
undoCodeOnly: "/undo ist nur innerhalb von `reasonix code` verf\xFCgbar \u2014 der Chat-Modus wendet keine Edits an.",
|
|
3749
|
+
historyCodeOnly: "/history ist nur innerhalb von `reasonix code` verf\xFCgbar.",
|
|
3750
|
+
showCodeOnly: "/show ist nur innerhalb von `reasonix code` verf\xFCgbar.",
|
|
3751
|
+
applyCodeOnly: "/apply ist nur innerhalb von `reasonix code` verf\xFCgbar (hier gibt es nichts anzuwenden).",
|
|
3752
|
+
discardCodeOnly: "/discard ist nur innerhalb von `reasonix code` verf\xFCgbar.",
|
|
3753
|
+
planCodeOnly: "/plan ist nur innerhalb von `reasonix code` verf\xFCgbar \u2014 der Chat-Modus blockiert keine Tool-Schreibzugriffe.",
|
|
3754
|
+
planOn: "\u25B8 Plan-Modus EIN \u2014 Schreibwerkzeuge sind blockiert; das Modell MUSS `submit_plan` aufrufen, bevor etwas ausgef\xFChrt wird. (Das Modell kann auch eigenst\xE4ndig submit_plan f\xFCr gro\xDFe Aufgaben aufrufen, selbst wenn der Plan-Modus aus ist \u2014 dieser Schalter ist die strengere, explizite Einschr\xE4nkung.) Tippe /plan off zum Verlassen.",
|
|
3755
|
+
planOff: "\u25B8 Plan-Modus AUS \u2014 Schreibwerkzeuge sind wieder aktiv. Modelle k\xF6nnen weiterhin eigenst\xE4ndig Pl\xE4ne f\xFCr gro\xDFe Aufgaben vorschlagen.",
|
|
3756
|
+
modeCodeOnly: "/mode ist nur innerhalb von `reasonix code` verf\xFCgbar.",
|
|
3757
|
+
modeUsage: "Verwendung: /mode <review|auto|yolo> (Shift+Tab schaltet auch um)",
|
|
3758
|
+
modeYolo: "\u25B8 Edit-Modus: YOLO \u2014 Edits UND Shell-Befehle auto-ausf\xFChren ohne Nachfrage. /undo macht Edits immer noch r\xFCckg\xE4ngig. Vorsicht.",
|
|
3759
|
+
modeAuto: "\u25B8 Edit-Modus: AUTO \u2014 Edits werden sofort angewandt; dr\xFCcke u innerhalb von 5s zum R\xFCckg\xE4ngigmachen, oder /undo sp\xE4ter. Shell-Befehle fragen weiterhin.",
|
|
3760
|
+
modeReview: "\u25B8 Edit-Modus: review \u2014 Edits warten auf /apply (oder y) / /discard (oder n)",
|
|
3761
|
+
commitCodeOnly: "/commit ist nur innerhalb von `reasonix code` verf\xFCgbar (ben\xF6tigt ein Git-Repo als Wurzel).",
|
|
3762
|
+
commitUsage: 'Verwendung: /commit "deine Commit-Nachricht" \u2014 f\xFChrt `git add -A && git commit -m "\u2026"` in {root} aus',
|
|
3763
|
+
walkCodeOnly: "/walk ist nur innerhalb von `reasonix code` verf\xFCgbar.",
|
|
3764
|
+
checkpointCodeOnly: "/checkpoint ist nur innerhalb von `reasonix code` verf\xFCgbar \u2014 der Chat-Modus wendet keine Edits an.",
|
|
3765
|
+
checkpointNone: "noch keine Checkpoints \u2014 `/checkpoint <name>` sichert jede Datei, die die Sitzung ber\xFChrt hat. Sp\xE4ter mit `/restore <name>` wiederherstellbar.",
|
|
3766
|
+
checkpointHeader: "\u25C8 Checkpoints \xB7 {count} gespeichert",
|
|
3767
|
+
checkpointRestoreHint: " /restore <name|id> \xB7 /checkpoint forget <id> \xB7 /checkpoint <name> zum Hinzuf\xFCgen",
|
|
3768
|
+
checkpointForgetUsage: "Verwendung: /checkpoint forget <id|name>",
|
|
3769
|
+
checkpointNoMatch: '\u25B8 kein Checkpoint gefunden f\xFCr "{name}" \u2014 siehe /checkpoint list',
|
|
3770
|
+
checkpointDeleted: "\u25B8 Checkpoint {id} gel\xF6scht ({name})",
|
|
3771
|
+
checkpointDeleteFailed: "\u25B8 Konnte {id} nicht l\xF6schen (bereits entfernt?)",
|
|
3772
|
+
checkpointSaveUsage: "Verwendung: /checkpoint <name> (oder /checkpoint list zum Anzeigen vorhandener)",
|
|
3773
|
+
checkpointSavedEmpty: '\u25B8 Checkpoint "{name}" gespeichert ({id}) \u2014 aber es wurden noch keine Dateien ber\xFChrt, daher ist es eine leere Basislinie. Nach diesem Punkt vorgenommene Edits k\xF6nnen r\xFCckg\xE4ngig gemacht werden.',
|
|
3774
|
+
checkpointSaved: '\u25B8 Checkpoint "{name}" gespeichert ({id}) \u2014 {files} Datei{en}, {size} KB. Wiederherstellen: /restore {name}',
|
|
3775
|
+
restoreCodeOnly: "/restore ist nur innerhalb von `reasonix code` verf\xFCgbar.",
|
|
3776
|
+
restoreUsage: "Verwendung: /restore <name|id> (siehe /checkpoint list f\xFCr IDs)",
|
|
3777
|
+
restoreNoMatch: '\u25B8 kein Checkpoint gefunden f\xFCr "{target}" \u2014 versuche /checkpoint list',
|
|
3778
|
+
restoreInfo: '\u25B8 "{name}" ({id}) wiederhergestellt von {when}',
|
|
3779
|
+
restoreWrote: " \xB7 {count} Datei{en} zur\xFCckgeschrieben",
|
|
3780
|
+
restoreRemoved: " \xB7 {count} Datei{en} entfernt (existierten zum Checkpoint-Zeitpunkt nicht)",
|
|
3781
|
+
restoreSkipped: " \u2717 {count} Datei{en} \xFCbersprungen:",
|
|
3782
|
+
cwdCodeOnly: "/cwd ist nur innerhalb von `reasonix code` verf\xFCgbar.",
|
|
3783
|
+
cwdUsage: "Verwendung: /cwd <pfad> (aktuelles Root: {current}). Richtet Dateisystem-/Shell-/Memory-Tools auf <pfad> neu aus.",
|
|
3784
|
+
cwdUsageNoCurrent: "Verwendung: /cwd <pfad> richtet den Workspace-Root auf <pfad> neu aus."
|
|
3785
|
+
},
|
|
3786
|
+
model: {
|
|
3787
|
+
...EN.handlers.model,
|
|
3788
|
+
modelHint: "versuche deepseek-v4-flash oder deepseek-v4-pro \u2014 f\xFChre /models aus, um die Live-Liste abzurufen",
|
|
3789
|
+
modelUsage: "Verwendung: /model <id> ({hint})",
|
|
3790
|
+
modelNotInCatalog: "Modell \u2192 {id} (\u26A0 nicht im abgerufenen Katalog: {list}. Falls das falsch ist, wird der n\xE4chste Aufruf 400 geben \u2014 f\xFChre /models zum Aktualisieren aus.)",
|
|
3791
|
+
modelSet: "Modell \u2192 {id}",
|
|
3792
|
+
effortStatus: "Effort \u2192 {current} (Auswahl: {list})",
|
|
3793
|
+
effortUsage: "Verwendung: /effort <{list}> (high ist der sichere Standard; max ist eine DeepSeek-Erweiterung)",
|
|
3794
|
+
effortUsageNoMax: "Verwendung: /effort <{list}>",
|
|
3795
|
+
effortSet: "Effort \u2192 {effort}",
|
|
3796
|
+
budgetNoCap: "Kein Sitzungsbudget festgelegt \u2014 Reasonix wird weiterlaufen, bis du es stoppst. Setze eines mit: /budget <usd> (z.B. /budget 5)",
|
|
3797
|
+
budgetStatus: "Budget: ${spent} von ${cap} ({pct}%) \xB7 /budget off zum Entfernen, /budget <usd> zum \xC4ndern",
|
|
3798
|
+
budgetOff: "Budget \u2192 aus (keine Grenze)",
|
|
3799
|
+
budgetUsage: 'Verwendung: /budget <usd> (erhalten: "{arg}" \u2014 muss eine positive Zahl sein, z.B. /budget 5 oder /budget 12.50)',
|
|
3800
|
+
budgetExhausted: "\u25B2 Budget \u2192 ${cap} aber bereits ${spent} ausgegeben. Der n\xE4chste Turn wird verweigert \u2014 erh\xF6he die Grenze, um fortzufahren, oder beende die Sitzung.",
|
|
3801
|
+
budgetSet: "Budget \u2192 ${cap} (bisher: ${spent} \xB7 warnt bei 80 %, verweigert n\xE4chsten Turn bei 100 % \xB7 /budget off zum Entfernen)"
|
|
3802
|
+
},
|
|
3803
|
+
permissions: {
|
|
3804
|
+
...EN.handlers.permissions,
|
|
3805
|
+
mutateCodeOnly: "/permissions add / remove / clear sind nur innerhalb von `reasonix code` verf\xFCgbar \u2014 sie bearbeiten die projektbezogene Allowlist (`~/.reasonix/config.json` projects[<root>].shellAllowed).",
|
|
3806
|
+
addUsage: 'Verwendung: /permissions add <pr\xE4fix> (mehrere Tokens OK: /permissions add "git push origin")',
|
|
3807
|
+
addAlready: "\u25B8 bereits erlaubt: {prefix}",
|
|
3808
|
+
addBuiltin: "\u25B8 `{prefix}` ist bereits in der Builtin-Allowlist \u2014 kein projektspezifischer Eintrag n\xF6tig. (Builtin-Eintr\xE4ge sind immer aktiv.)",
|
|
3809
|
+
addInfo: "\u25B8 hinzugef\xFCgt: {prefix}\n \u2192 n\xE4chste `{prefix}`-Ausf\xFChrung erfolgt ohne Nachfrage in diesem Projekt.",
|
|
3810
|
+
removeUsage: "Verwendung: /permissions remove <pr\xE4fix-oder-index> (z.B. /permissions remove 3, oder /permissions remove npm)",
|
|
3811
|
+
removeEmpty: "\u25B8 keine Projekt-Allowlist-Eintr\xE4ge zum Entfernen.",
|
|
3812
|
+
removeIndexOob: "\u25B8 Index au\xDFerhalb des Bereichs: {idx} (Projektliste hat {count} Eintr\xE4ge)",
|
|
3813
|
+
removeNothing: "\u25B8 nichts zu entfernen.",
|
|
3814
|
+
removeBuiltin: "\u25B8 `{prefix}` ist in der Builtin-Allowlist (schreibgesch\xFCtzt). Builtin-Eintr\xE4ge k\xF6nnen zur Laufzeit nicht entfernt werden \u2014 sie sind in die Bin\xE4rdatei eingebrannt.",
|
|
3815
|
+
removeInfo: "\u25B8 entfernt: {prefix}",
|
|
3816
|
+
removeNotFound: "\u25B8 kein solcher Projekt-Eintrag: {prefix} (versuche /permissions list, um zu sehen, was gespeichert ist)",
|
|
3817
|
+
clearAlready: "\u25B8 Projekt-Allowlist ist bereits leer.",
|
|
3818
|
+
clearConfirm: "Es werden {count} Projekt-Allowlist-Eintr\xE4g{e} f\xFCr {root} gel\xF6scht. F\xFChre den Befehl mit dem Wort 'confirm' erneut aus: /permissions clear confirm",
|
|
3819
|
+
clearedNone: "\u25B8 Projekt-Allowlist war bereits leer \u2014 nichts ge\xE4ndert.",
|
|
3820
|
+
cleared: "\u25B8 {count} Projekt-Allowlist-Eintr\xE4g{e} gel\xF6scht.",
|
|
3821
|
+
usage: 'Verwendung: /permissions [list] aktuellen Status anzeigen\n /permissions add <pr\xE4fix> speichern (z.B. "npm run build")\n /permissions remove <pr\xE4fix-oder-N> Eintrag entfernen\n /permissions clear confirm alle Projekteintr\xE4ge l\xF6schen',
|
|
3822
|
+
modeYolo: "\u25B8 Edit-Modus: YOLO \u2014 jeder Shell-Befehl l\xE4uft automatisch, Allowlist wird umgangen. /mode review zum Reaktivieren der Nachfragen.",
|
|
3823
|
+
modeAuto: "\u25B8 Edit-Modus: auto \u2014 Edits auto-anwenden, Shell weiterhin durch Allowlist gesch\xFCtzt (oder ShellConfirm-Nachfrage bei nicht-allowlisteten).",
|
|
3824
|
+
modeReview: "\u25B8 Edit-Modus: review \u2014 sowohl Edits als auch nicht-allowlistete Shell-Befehle fragen vor der Ausf\xFChrung.",
|
|
3825
|
+
projectHeader: "Projekt-Allowlist ({count}) \u2014 {root}",
|
|
3826
|
+
projectNone1: ' (keine \u2014 w\xE4hle \xBBimmer erlauben" in einer ShellConfirm-Eingabeaufforderung, um einen hinzuzuf\xFCgen,',
|
|
3827
|
+
projectNone2: " oder `/permissions add <pr\xE4fix>` direkt.)",
|
|
3828
|
+
projectNoRoot: "Projekt-Allowlist \u2014 (kein Projekt-Root; Chat-Modus zeigt nur Builtin-Eintr\xE4ge)",
|
|
3829
|
+
builtinHeader: "Builtin-Allowlist ({count}) \u2014 schreibgesch\xFCtzt, fest eincompiliert",
|
|
3830
|
+
subcommands: "Unterbefehle: /permissions add <pr\xE4fix> \xB7 /permissions remove <pr\xE4fix-oder-N> \xB7 /permissions clear confirm"
|
|
3831
|
+
},
|
|
3832
|
+
dashboard: {
|
|
3833
|
+
...EN.handlers.dashboard,
|
|
3834
|
+
notAvailable: "/dashboard ist in diesem Kontext nicht verf\xFCgbar (kein startDashboard-Callback angeschlossen).",
|
|
3835
|
+
stopNoCallback: "/dashboard stop: kein Stop-Callback angeschlossen.",
|
|
3836
|
+
notRunning: "\u25B8 Dashboard l\xE4uft nicht.",
|
|
3837
|
+
stopping: "\u25B8 Dashboard wird gestoppt...",
|
|
3838
|
+
alreadyRunning: "\u25B8 Dashboard l\xE4uft bereits:",
|
|
3839
|
+
alreadyRunningHint: "\xD6ffne es in einem beliebigen Browser. Tippe `/dashboard stop` zum Herunterfahren.",
|
|
3840
|
+
ready: "\u25B8 Dashboard bereit:",
|
|
3841
|
+
readyHint: "127.0.0.1 only \xB7 token-gesichert. Tippe `/dashboard stop` zum Herunterfahren.",
|
|
3842
|
+
failed: "\u25B8 Dashboard konnte nicht gestartet werden: {reason}",
|
|
3843
|
+
starting: "\u25B8 starte Dashboard-Server...",
|
|
3844
|
+
copied: "\u25B8 Dashboard-URL in Zwischenablage kopiert: {url}",
|
|
3845
|
+
tokenResetting: "\u25B8 rotiere Dashboard-Token \u2014 starte Server neu...",
|
|
3846
|
+
tokenReset: "\u25B8 Dashboard-Token rotiert. Neue URL:"
|
|
3847
|
+
},
|
|
3848
|
+
observability: {
|
|
3849
|
+
...EN.handlers.observability,
|
|
3850
|
+
contextInfo: "Kontext: ~{total} von {max} ({pct}%) \xB7 System {sys} \xB7 Tools {tools} \xB7 Log {log}",
|
|
3851
|
+
compactStarting: "\u25B8 falte \xE4ltere Turns in eine Zusammenfassung...",
|
|
3852
|
+
compactNoop: "\u25B8 nichts zu falten \u2014 Log bereits klein oder aktuelle Turns allein \xFCberschreiten das Budget.",
|
|
3853
|
+
compactDone: "\u25B8 {before} Nachrichten \u2192 {after} gefaltet (Zusammenfassung {chars} Zeichen). Fahre fort.",
|
|
3854
|
+
compactFailed: "\u25B8 Falten fehlgeschlagen: {reason}",
|
|
3855
|
+
costNoTurn: "noch kein Turn \u2014 `/cost` zeigt die Token- und Kostenaufschl\xFCsselung des letzten Turns.",
|
|
3856
|
+
costNeedsTui: "/cost ben\xF6tigt einen TUI-Kontext (postUsage angeschlossen).",
|
|
3857
|
+
costNoPricing: '\u25B8 /cost: keine Preistabelle f\xFCr Modell "{model}". F\xFCge eine in telemetry/stats.ts hinzu.',
|
|
3858
|
+
costEstimate: "\u25B8 /cost Sch\xE4tzung \xB7 {model} \xB7 {prompt} Prompt-Tokens (sys {sys} + tools {tools} + log {log} + msg {msg})",
|
|
3859
|
+
costWorstCase: " schlimmster Fall (vollst\xE4ndiger Fehlschlag): {input} Eingabe + ~{output} Ausgabe ({avg} \xD8) \u2248 {total}",
|
|
3860
|
+
costLikely: " wahrscheinlich ({pct}% Session-Cache-Treffer): {input} Eingabe + ~{output} Ausgabe \u2248 {total}",
|
|
3861
|
+
costLikelyCold: " wahrscheinlich: entspricht worst case bis der Cache gef\xFCllt ist (noch keine abgeschlossenen Turns)",
|
|
3862
|
+
statusModel: " Modell {model}",
|
|
3863
|
+
statusFlags: " Flags stream={stream} \xB7 effort={effort}",
|
|
3864
|
+
statusCtx: " Kontext {bar} {used}/{max} ({pct}%)",
|
|
3865
|
+
statusCtxNone: " Kontext noch keine Turns",
|
|
3866
|
+
statusCost: " Kosten ${cost} \xB7 Cache {bar} {pct}% \xB7 Turns {turns}",
|
|
3867
|
+
statusCostCold: " Kosten ${cost} \xB7 Turns {turns} (Cache w\xE4rmt sich auf)",
|
|
3868
|
+
statusBudget: " Budget ${spent} / ${cap} ({pct}%){tag}",
|
|
3869
|
+
statusSession: ' Sitzung "{name}" \xB7 {count} Nachrichten im Log (fortgesetzt {resumed})',
|
|
3870
|
+
statusSessionEphemeral: " Sitzung (ephemer \u2014 keine Persistenz)",
|
|
3871
|
+
statusWorkspace: " Arbeitsbereich {path} \xB7 beim Start festgelegt (mit --dir <pfad> neu starten zum Wechseln)",
|
|
3872
|
+
statusMcp: " MCP {servers} Server, {tools} Tools im Register",
|
|
3873
|
+
statusEdits: " Edits {count} ausstehend (/apply zum \xDCbernehmen, /discard zum Verwerfen)",
|
|
3874
|
+
statusPlan: " Plan EIN \u2014 Schreibzugriffe blockiert (submit_plan + Genehmigung)",
|
|
3875
|
+
statusLifecycle: " Lebenszyklus {mode}/{state} \xB7 {progress}{evidence}",
|
|
3876
|
+
lifecycleNoPlan: "Kein Plan",
|
|
3877
|
+
lifecycleEvidencePending: "Nachweis ausstehend",
|
|
3878
|
+
lifecycleRejected: "Lebenszyklus: {tool} blockiert in {state} \u2014 n\xE4chster: {next}",
|
|
3879
|
+
lifecycleEvidenceRejected: "Lebenszyklus: Schritt {stepId} ben\xF6tigt Nachweis \u2014 n\xE4chster: {next}",
|
|
3880
|
+
lifecycleRepeatedRejected: "Lebenszyklus: wiederholte {tool}-Ablehnung \u2014 wiederhole nicht identische Argumente",
|
|
3881
|
+
statusModeYolo: " Modus YOLO \u2014 Edits + Shell auto-ausf\xFChren ohne Nachfrage (/undo macht immer noch r\xFCckg\xE4ngig \xB7 Shift+Tab zum Umschalten)",
|
|
3882
|
+
statusModeAuto: " Modus AUTO \u2014 Edits werden sofort angewandt (u zum R\xFCckg\xE4ngigmachen innerhalb von 5s \xB7 Shift+Tab zum Umschalten)",
|
|
3883
|
+
statusModeReview: " Modus review \u2014 Edits warten auf /apply oder y (Shift+Tab zum Umschalten)",
|
|
3884
|
+
statusDash: " Dash {url} (im Browser \xF6ffnen \xB7 /dashboard stop)"
|
|
3885
|
+
},
|
|
3886
|
+
plans: {
|
|
3887
|
+
...EN.handlers.plans,
|
|
3888
|
+
noSession: "keine Sitzung angeh\xE4ngt \u2014 `/plans` ist pro Sitzung. F\xFChre `reasonix code` in einem Projekt aus, um eine Sitzung zu erhalten.",
|
|
3889
|
+
activePlan: "\u25B8 aktiver Plan{label} \u2014 {done}/{total} Schritt{e} erledigt \xB7 zuletzt bearbeitet {when}",
|
|
3890
|
+
activeNone: "\u25B8 aktiver Plan: (keiner)",
|
|
3891
|
+
noArchives: "noch keine archivierten Pl\xE4ne f\xFCr diese Sitzung \u2014 sie werden automatisch archiviert, wenn alle Schritte erledigt sind",
|
|
3892
|
+
archivedHeader: "Archiviert ({count}):",
|
|
3893
|
+
evidencePending: " ! Nachweis ausstehend \u2014 aktueller Schritt ben\xF6tigt Verifikation/Diff/Checkpoint/manuellen Nachweis",
|
|
3894
|
+
evidenceLine: " Nachweis {stepId}: {summary}",
|
|
3895
|
+
archivedEvidenceLine: " Nachweis: {summary}",
|
|
3896
|
+
replayNoSession: "keine Sitzung angeh\xE4ngt \u2014 `/replay` ist pro Sitzung. F\xFChre `reasonix code` in einem Projekt aus, um eine Sitzung zu erhalten.",
|
|
3897
|
+
replayNoArchives: "noch keine archivierten Pl\xE4ne f\xFCr diese Sitzung \u2014 `/replay` wird aktiv, sobald ein Plan abgeschlossen ist (auto-archiviert wenn alle Schritte erledigt).",
|
|
3898
|
+
replayInvalidIndex: "ung\xFCltiger Index \u2014 `/replay` akzeptiert 1..{max} (neuester = 1). Verwende `/plans`, um die Liste zu sehen.",
|
|
3899
|
+
archivedRow: " \u2713 {when} {total} Schritt{e} \xB7 {completion} {label}",
|
|
3900
|
+
completionComplete: "abgeschlossen",
|
|
3901
|
+
stopAborted: "\u25B8 Plan gestoppt \u2014 Modell abgebrochen; tippe eine Folgenachricht, um fortzufahren oder eine neue Aufgabe zu starten.",
|
|
3902
|
+
doneUsage: "Verwendung: /plans done <stepId> \xB7 /plans done all \u2014 manuelle \xDCberschreibung, wenn das Modell vergessen hat, mark_step_complete aufzurufen",
|
|
3903
|
+
doneUnavailable: "/plans done ist nur innerhalb einer aktiven Sitzung verf\xFCgbar.",
|
|
3904
|
+
doneNoPlan: "Kein aktiver Plan \u2014 nichts als erledigt zu markieren.",
|
|
3905
|
+
doneNotInPlan: "Schritt `{id}` ist nicht im aktiven Plan. F\xFChre /plans aus, um die Schritt-IDs zu sehen.",
|
|
3906
|
+
doneAlready: "Schritt `{id}` wurde bereits als erledigt markiert.",
|
|
3907
|
+
doneOk: "\u25B8 Schritt `{id}` als erledigt markiert.",
|
|
3908
|
+
doneAllNoop: "Jeder Schritt ist bereits erledigt.",
|
|
3909
|
+
doneAllOk: "\u25B8 {count} Schritt(e) als erledigt markiert."
|
|
3910
|
+
},
|
|
3911
|
+
jobs: {
|
|
3912
|
+
...EN.handlers.jobs,
|
|
3913
|
+
codeOnly: "/jobs ist nur innerhalb von `reasonix code` verf\xFCgbar.",
|
|
3914
|
+
killCodeOnly: "/kill ist nur innerhalb von `reasonix code` verf\xFCgbar.",
|
|
3915
|
+
logsCodeOnly: "/logs ist nur innerhalb von `reasonix code` verf\xFCgbar.",
|
|
3916
|
+
empty: "\u25C8 Jobs \xB7 0 laufend \xB7 0 gesamt\n (run_background startet einen \u2014 Dev-Server, Watcher, langlebige Skripte)",
|
|
3917
|
+
header: "\u25C8 Jobs \xB7 {running} laufend \xB7 {total} gesamt",
|
|
3918
|
+
footer: " /logs <id> tail \xB7 /kill <id> SIGTERM \u2192 SIGKILL",
|
|
3919
|
+
killUsage: "Verwendung: /kill <id> (siehe /jobs f\xFCr IDs)",
|
|
3920
|
+
killNotFound: "Job {id}: nicht gefunden",
|
|
3921
|
+
killAlreadyExited: "Job {id} bereits beendet ({code})",
|
|
3922
|
+
killStopping: "\u25B8 stoppe Job {id} (Tree-Kill: SIGTERM \u2192 SIGKILL nach 2s Gnadenfrist; Windows: taskkill /T /F)",
|
|
3923
|
+
killStatus: "\u25B8 Job {id} {status}",
|
|
3924
|
+
killStillAlive: "Nach SIGKILL noch am Leben (!) \u2014 melde dies als Fehler",
|
|
3925
|
+
logsUsage: "Verwendung: /logs <id> [zeilen] (Standard letzte 80 Zeilen)",
|
|
3926
|
+
logsNotFound: "Job {id}: nicht gefunden",
|
|
3927
|
+
logsStatus: "[Job {id} \xB7 {status}]\n$ {command}",
|
|
3928
|
+
logsRunning: "L\xE4uft \xB7 PID {pid}",
|
|
3929
|
+
logsExited: "Beendet {code}",
|
|
3930
|
+
logsFailed: "Fehlgeschlagen ({reason})",
|
|
3931
|
+
logsStopped: "gestoppt"
|
|
3932
|
+
},
|
|
3933
|
+
memory: {
|
|
3934
|
+
...EN.handlers.memory,
|
|
3935
|
+
disabled: "Memory ist deaktiviert (REASONIX_MEMORY=off in der Umgebung). Entferne die Variable zur Reaktivierung \u2014 es werden weder REASONIX.md noch ~/.reasonix/memory-Inhalte eingef\xFCgt.",
|
|
3936
|
+
noRoot: "kein Arbeitsverzeichnis in dieser Sitzung \u2014 `/memory` ben\xF6tigt ein Root, um REASONIX.md aufzul\xF6sen. (L\xE4uft in einer Test-Umgebung?)",
|
|
3937
|
+
listEmpty: "noch keine Benutzer-Memories. Das Modell kann `remember` aufrufen, um einen zu speichern, oder du kannst Dateien manuell in ~/.reasonix/memory/global/ oder dem projektspezifischen Unterverzeichnis erstellen.",
|
|
3938
|
+
listHeader: "Benutzer-Memories ({count}):",
|
|
3939
|
+
listFooter: "Body anzeigen: /memory show <name> L\xF6schen: /memory forget <name>",
|
|
3940
|
+
showUsage: "Verwendung: /memory show <name> oder /memory show <scope>/<name>",
|
|
3941
|
+
showNotFound: "Kein Memory gefunden: {target}",
|
|
3942
|
+
showFailed: "Anzeige fehlgeschlagen: {reason}",
|
|
3943
|
+
forgetUsage: "Verwendung: /memory forget <name> oder /memory forget <scope>/<name>",
|
|
3944
|
+
forgetNotFound: "Kein Memory gefunden: {target}",
|
|
3945
|
+
forgetInfo: "\u25B8 {scope}/{name} entfernt. N\xE4chstes /new oder der n\xE4chste Start wird es nicht mehr sehen.",
|
|
3946
|
+
forgetFailed: "Konnte {scope}/{name} nicht entfernen (bereits weg?)",
|
|
3947
|
+
forgetError: "Entfernen fehlgeschlagen: {reason}",
|
|
3948
|
+
clearUsage: "Verwendung: /memory clear <global|project> confirm",
|
|
3949
|
+
clearConfirm: "Alle Memories im Bereich {scope} werden gel\xF6scht. F\xFChre den Befehl mit dem Wort 'confirm' erneut aus: /memory clear {scope} confirm",
|
|
3950
|
+
cleared: "\u25B8 Bereich {scope} geleert \u2014 {count} Memory-Datei(en) gel\xF6scht.",
|
|
3951
|
+
noMemory: "Kein Memory in {root} eingef\xFCgt.",
|
|
3952
|
+
layers: "Drei Ebenen sind verf\xFCgbar:",
|
|
3953
|
+
layerProject: " 1. {file} \u2014 commitierbares Team-Memory (im Repo).",
|
|
3954
|
+
layerGlobal: " 2. ~/.reasonix/memory/global/ \u2014 dein projekt\xFCbergreifendes privates Memory.",
|
|
3955
|
+
layerProjectHash: " 3. ~/.reasonix/memory/<projekt-hash>/ \u2014 privates Memory dieses Projekts.",
|
|
3956
|
+
askModel: "Bitte das Modell, etwas zu `remember`, oder bearbeite die Dateien direkt.",
|
|
3957
|
+
changesNote: "\xC4nderungen werden beim n\xE4chsten /new oder Start wirksam \u2014 der System-Prompt wird einmal pro Sitzung gehasht, um den Prefix-Cache warm zu halten.",
|
|
3958
|
+
subcommands: "Unterbefehle: /memory list | /memory show <name> | /memory forget <name> | /memory clear <scope> confirm",
|
|
3959
|
+
changesNoteShort: "\xC4nderungen werden beim n\xE4chsten /new oder Start wirksam. Unterbefehle: /memory list | show | forget | clear"
|
|
3960
|
+
},
|
|
3961
|
+
mcp: {
|
|
3962
|
+
...EN.handlers.mcp,
|
|
3963
|
+
noServers: 'keine MCP-Server angeh\xE4ngt. F\xFChre `reasonix setup` aus, um welche auszuw\xE4hlen, oder starte mit --mcp "<spec>". `reasonix mcp list` zeigt den Katalog. Hinweis: vom Modell aufgerufene Shell-Befehle werden pro Aufruf abgefragt (einmal erlauben / immer erlauben / ablehnen) \u2014 kein globales Allow-All-Flag.',
|
|
3964
|
+
toolsLabel: " Tools {count}",
|
|
3965
|
+
resourcesHint: "`/resource` zum Durchsuchen+Lesen",
|
|
3966
|
+
promptsHint: "`/prompt` zum Durchsuchen+Abrufen",
|
|
3967
|
+
awarenessOnly: "Der Chat-Modus verbraucht Tools aktuell; Ressourcen+Prompts werden hier zur Information angezeigt.",
|
|
3968
|
+
catalogHint: "Vollst\xE4ndiger Katalog: `reasonix mcp list` \xB7 tiefere Diagnose: `reasonix mcp inspect <spec>`.",
|
|
3969
|
+
fallbackServers: "MCP-Server ({count}):",
|
|
3970
|
+
fallbackTools: "Tools im Register ({count}):",
|
|
3971
|
+
fallbackChange: "Um diesen Satz zu \xE4ndern, beende und f\xFChre `reasonix setup` aus.",
|
|
3972
|
+
usageDisableEnable: "Verwendung: /mcp {action} <name> \xB7 w\xE4hle einen in /mcp angezeigten Namen (anonyme Server k\xF6nnen nicht nach Namen umgeschaltet werden).",
|
|
3973
|
+
usageReconnect: "Verwendung: /mcp reconnect <name> \xB7 w\xE4hle einen in /mcp angezeigten Namen.",
|
|
3974
|
+
unknownServer: 'unbekannter MCP-Server "{name}". Bekannt: {list}.',
|
|
3975
|
+
noneList: "(keine)",
|
|
3976
|
+
reconnectNoTui: "/mcp reconnect ben\xF6tigt die interaktive TUI (postInfo nicht angeschlossen).",
|
|
3977
|
+
liveTab: "Live",
|
|
3978
|
+
marketplaceTab: "Marktplatz",
|
|
3979
|
+
tabHint: "Tab zum Umschalten"
|
|
3980
|
+
},
|
|
3981
|
+
init: {
|
|
3982
|
+
...EN.handlers.init,
|
|
3983
|
+
codeOnly: "/init funktioniert nur im Code-Modus (es ben\xF6tigt Dateisystem-Werkzeuge).\nF\xFChre `reasonix code [pfad]` aus, um eine Sitzung zu starten, die im\nProjekt verwurzelt ist, das du initialisieren m\xF6chtest, und f\xFChre dann /init aus.",
|
|
3984
|
+
exists: "\u25B8 REASONIX.md existiert bereits unter {path}",
|
|
3985
|
+
existsForce: " /init force von Grund auf neu generieren (\xFCberschreibt)",
|
|
3986
|
+
existsEdit: " Oder bearbeite es von Hand \u2014 es ist nur Markdown. Die aktuelle Datei wird",
|
|
3987
|
+
existsPinned: " bei jedem Start unver\xE4ndert in den System-Prompt eingef\xFCgt.",
|
|
3988
|
+
info: "\u25B8 /init \u2014 Modell scannt das Projekt und synthetisiert REASONIX.md.\n Das Ergebnis landet als ausstehender Edit; mit /apply oder /walk reviewen."
|
|
3989
|
+
},
|
|
3990
|
+
webSearchEngine: {
|
|
3991
|
+
...EN.handlers.webSearchEngine,
|
|
3992
|
+
currentEngine: "Aktuelle Websuchmaschine: {engine}",
|
|
3993
|
+
endpoint: "SearXNG-Endpunkt: {url}",
|
|
3994
|
+
usageHeader: "Verwendung:",
|
|
3995
|
+
usageBing: " /search-engine bing Bing verwenden (Standard, funktioniert von CN ohne Proxy)",
|
|
3996
|
+
usageSearxng: " /search-engine searxng SearXNG verwenden (Standard-Endpunkt)",
|
|
3997
|
+
usageSearxngUrl: " /search-engine searxng <url> SearXNG mit benutzerdefiniertem Endpunkt",
|
|
3998
|
+
usageMetaso: " /search-engine metaso Metaso-API verwenden (100/Tag kostenlos, konfiguriere eigenen API-Schl\xFCssel f\xFCr mehr)",
|
|
3999
|
+
usageTavily: " /search-engine tavily Tavily-API verwenden (LLM-freundlich, kostenlos 1000/Monat \u2014 setze TAVILY_API_KEY oder tavilyApiKey in der Konfiguration; erhalte einen unter https://tavily.com)",
|
|
4000
|
+
usagePerplexity: " /search-engine perplexity Perplexity AI verwenden (AI-native Antwort + Quellenangaben \u2014 setze PERPLEXITY_API_KEY oder perplexityApiKey in der Konfiguration; erhalte einen unter https://perplexity.ai/settings/api)",
|
|
4001
|
+
usageExa: " /search-engine exa Exa-API verwenden (AI-native Antwort + Quellenangaben, kostenlos 1000/Monat \u2014 setze EXA_API_KEY oder exaApiKey in der Konfiguration; registriere dich unter https://exa.ai)",
|
|
4002
|
+
alias: "Alias: /se",
|
|
4003
|
+
searxngInfo: "SearXNG ist eine selbst gehostete Metasuchmaschine (https://github.com/searxng/searxng).",
|
|
4004
|
+
searxngInstall: "Installiere mit: docker run -d -p 8080:8080 searxng/searxng",
|
|
4005
|
+
switched: 'Websuchmaschine auf "{engine}" umgestellt.{note}',
|
|
4006
|
+
switchedSearxngNote: " Stelle sicher, dass SearXNG unter {endpoint} l\xE4uft.",
|
|
4007
|
+
switchedMetasoNote: " Es gibt ein t\xE4gliches Kontingent von 100 (konfiguriere einen eigenen API-Schl\xFCssel f\xFCr h\xF6here Grenzen).",
|
|
4008
|
+
switchedTavilyNote: " Setze TAVILY_API_KEY oder `tavilyApiKey` in der Konfiguration; kostenlos 1000/Monat unter https://tavily.com.",
|
|
4009
|
+
switchedPerplexityNote: " Setze PERPLEXITY_API_KEY oder `perplexityApiKey` in der Konfiguration; erhalte einen unter https://perplexity.ai/settings/api.",
|
|
4010
|
+
switchedExaNote: " Setze EXA_API_KEY oder `exaApiKey` in der Konfiguration; registriere dich unter https://exa.ai.",
|
|
4011
|
+
keyNeeded: 'Kein API-Schl\xFCssel f\xFCr "{engine}" konfiguriert.\n\n 1. Setze die {envVar}-Umgebungsvariable\n 2. Oder gib ihn inline an: /search-engine {engine} <dein-schl\xFCssel>\n 3. Oder f\xFCge "{engine}ApiKey" zu ~/.reasonix/config.json hinzu\n\nWiederhole dann /search-engine {engine}.',
|
|
4012
|
+
keySaved: " API-Schl\xFCssel in der Konfiguration gespeichert.",
|
|
4013
|
+
confirmed: 'Websuchmaschine auf "{engine}" gesetzt{detail}. Der n\xE4chste Assistenten-Turn \xFCbernimmt die \xC4nderung.',
|
|
4014
|
+
confirmedDetail: " ({endpoint})"
|
|
4015
|
+
},
|
|
4016
|
+
skill: {
|
|
4017
|
+
...EN.handlers.skill,
|
|
4018
|
+
listEmpty: "Keine Skills gefunden. Reasonix liest Skills von:",
|
|
4019
|
+
listProjectScope: " \xB7 <projekt>/.reasonix/skills/<name>/SKILL.md (oder <name>.md) \u2014 Projekt-Bereich",
|
|
4020
|
+
listGlobalScope: " \xB7 ~/.reasonix/skills/<name>/SKILL.md (oder <name>.md) \u2014 globaler Bereich",
|
|
4021
|
+
listProjectOnly: " (Projekt-Bereich ist nur in `reasonix code` aktiv)",
|
|
4022
|
+
listFrontmatter: "Die Frontmatter jeder Datei ben\xF6tigt mindestens `name` und `description`.",
|
|
4023
|
+
listInvoke: "F\xFChre einen Skill aus mit `/skill <name> [args]` oder indem du das Modell bittest, `run_skill` aufzurufen.",
|
|
4024
|
+
listHeader: "Benutzer-Skills ({count}):",
|
|
4025
|
+
listFooter: "Anzeigen: /skill show <name> Ausf\xFChren: /skill <name> [args] Neu: /skill new <name>",
|
|
4026
|
+
listEmptyNewHint: "Erstelle einen mit: /skill new <name> (Projekt-Bereich) \u2014 es gibt noch kein entferntes Register; du erstellst Skills direkt.",
|
|
4027
|
+
showUsage: "Verwendung: /skill show <name>",
|
|
4028
|
+
showNotFound: "Kein Skill gefunden: {name}",
|
|
4029
|
+
runNotFound: "Kein Skill gefunden: {name} (versuche /skill list)",
|
|
4030
|
+
runInfo: "\u25B8 f\xFChre Skill aus: {name}{args}",
|
|
4031
|
+
newUsage: "Verwendung: /skill new <name> [--global]",
|
|
4032
|
+
newCreated: "\u25B8 Skill erstellt: {name}\n {path}\n bearbeite ihn, dann `/skill {name}` zum Ausf\xFChren",
|
|
4033
|
+
newError: "\u25B2 /skill new fehlgeschlagen: {reason}",
|
|
4034
|
+
pathsHeader: "Skill-Pfade (Priorit\xE4tsreihenfolge):",
|
|
4035
|
+
pathsPriority: "Priorit\xE4t: Projekt > benutzerdefinierte Pfade in Konfigurationsreihenfolge > global > builtin. \xC4nderungen wirken sich auf den System-Prompt beim n\xE4chsten /new oder einer neuen Sitzung aus.",
|
|
4036
|
+
pathsUsage: "Verwendung: /skill paths [list]\n /skill paths add <pfad>\n /skill paths remove <pfad|N>",
|
|
4037
|
+
pathsAddUsage: "Verwendung: /skill paths add <pfad>",
|
|
4038
|
+
pathsRemoveUsage: "Verwendung: /skill paths remove <pfad|N>",
|
|
4039
|
+
pathsAdded: "\u25B8 benutzerdefinierten Skill-Pfad hinzugef\xFCgt: {path}",
|
|
4040
|
+
pathsAlready: "\u25B8 benutzerdefinierter Skill-Pfad bereits konfiguriert: {path}",
|
|
4041
|
+
pathsRemoved: "\u25B8 benutzerdefinierten Skill-Pfad entfernt: {path}",
|
|
4042
|
+
pathsRemoveNotFound: "\u25B8 kein benutzerdefinierter Skill-Pfad entspricht: {target}",
|
|
4043
|
+
pathsRestartHint: "Der System-Prompt der aktuellen Sitzung ist unver\xE4ndert; f\xFChre /new aus oder starte eine neue Sitzung, um das Skills-Register zu aktualisieren."
|
|
4044
|
+
}
|
|
4045
|
+
},
|
|
4046
|
+
statusBar: {
|
|
4047
|
+
...EN.statusBar,
|
|
4048
|
+
turn: "Turn",
|
|
4049
|
+
cache: "Cache",
|
|
4050
|
+
spent: "ausgegeben",
|
|
4051
|
+
left: " \xFCbrig",
|
|
4052
|
+
slow: "langsam",
|
|
4053
|
+
disconnect: "trennen",
|
|
4054
|
+
reconnecting: "Verbinde neu\u2026",
|
|
4055
|
+
approvingIn: "Genehmige in ",
|
|
4056
|
+
escToInterrupt: "Esc zum Unterbrechen",
|
|
4057
|
+
recordingGlyph: "Aufnahme",
|
|
4058
|
+
mb: " MB",
|
|
4059
|
+
evt: " Ereignis",
|
|
4060
|
+
editsLabel: "Edits:",
|
|
4061
|
+
mcpLoading: "MCP",
|
|
4062
|
+
ctx: "Kontext",
|
|
4063
|
+
shortcutsHint: "Strg+P Tastenk\xFCrzel"
|
|
4064
|
+
},
|
|
4065
|
+
editMode: {
|
|
4066
|
+
...EN.editMode,
|
|
4067
|
+
plan: "PLAN-MODUS",
|
|
4068
|
+
yolo: "YOLO",
|
|
4069
|
+
auto: "AUTO",
|
|
4070
|
+
review: "REVIEW",
|
|
4071
|
+
writesGated: " Schreibzugriffe blockiert \xB7 /plan off zum Verlassen",
|
|
4072
|
+
editsShellAuto: "Edits + Shell auto \xB7 /undo zum R\xFCckg\xE4ngigmachen",
|
|
4073
|
+
editsLandNow: "Edits werden sofort angewandt \xB7 u zum R\xFCckg\xE4ngigmachen",
|
|
4074
|
+
queuedApplyDiscard: "{count} in Warteschlange \xB7 y anwenden \xB7 n verwerfen",
|
|
4075
|
+
editsQueued: "Edits in Warteschlange \xB7 y anwenden \xB7 n verwerfen",
|
|
4076
|
+
shiftTabFlip: " {mid} \xB7 Shift+Tab zum Umschalten",
|
|
4077
|
+
queuedDots: "In Warteschlange\u2026"
|
|
4078
|
+
},
|
|
4079
|
+
composer: {
|
|
4080
|
+
...EN.composer,
|
|
4081
|
+
placeholder: "Frag etwas \xB7 slash f\xFCr Befehle \xB7 at-Zeichen f\xFCr Dateien",
|
|
4082
|
+
waitingForResponse: "\u2026warte auf Antwort\u2026",
|
|
4083
|
+
hintSend: "senden",
|
|
4084
|
+
hintNewline: "Neue Zeile",
|
|
4085
|
+
hintClear: "leeren",
|
|
4086
|
+
hintScroll: "scrollen",
|
|
4087
|
+
hintHistory: "Verlauf",
|
|
4088
|
+
hintAbort: "abbrechen",
|
|
4089
|
+
hintQuit: "beenden",
|
|
4090
|
+
abortedHint: "Turn vom Benutzer abgebrochen \xB7 erneut Esc zum Leeren \xB7 \u23CE f\xFCr eine Folgefrage",
|
|
4091
|
+
editorNoRawMode: "externer Editor nicht verf\xFCgbar \u2014 stdin unterst\xFCtzt Raw-Mode-Umschaltung auf diesem Terminal nicht",
|
|
4092
|
+
editorFailed: "Externer Editor:",
|
|
4093
|
+
editorMissing: "kein $EDITOR / $VISUAL / $GIT_EDITOR gesetzt \u2014 exportiere einen (z.B. `export EDITOR=nano`) und versuche es erneut",
|
|
4094
|
+
editorExited: "Editor mit Code {code} beendet",
|
|
4095
|
+
typeaheadStaged: "\u25B8 {count} Zeile(n) bereitgestellt \xB7 Esc zur\xFCckrufen",
|
|
4096
|
+
steerPlaceholder: "tippe, um die aktuelle Aufgabe zu steuern \u2014 Befehle sind deaktiviert, solange besch\xE4ftigt",
|
|
4097
|
+
steerHint: "Senden \u2014 mid-Turn eingef\xFCgt",
|
|
4098
|
+
stashNothing: "Nichts zu speichern",
|
|
4099
|
+
stashSaved: "Gespeichert",
|
|
4100
|
+
stashRecall: "Abgerufen"
|
|
4101
|
+
},
|
|
4102
|
+
pathConfirm: {
|
|
4103
|
+
...EN.pathConfirm,
|
|
4104
|
+
title: "Pfad au\xDFerhalb des Sandbox",
|
|
4105
|
+
subtitleRead: "{tool} m\xF6chte eine Datei AUSSERHALB des Projekt-Sandbox lesen",
|
|
4106
|
+
subtitleWrite: "{tool} m\xF6chte eine Datei AUSSERHALB des Projekt-Sandbox schreiben",
|
|
4107
|
+
awaiting: "wartet",
|
|
4108
|
+
denyTitle: "Ablehnen \u2014 Kontext angeben",
|
|
4109
|
+
optional: "optional",
|
|
4110
|
+
denyFooter: "Kontext eingeben \xB7 \u23CE mit Grund absenden \xB7 Esc \xFCberspringen (ohne Grund ablehnen)",
|
|
4111
|
+
pickFooter: "\u2191\u2193 ausw\xE4hlen \xB7 \u23CE best\xE4tigen \xB7 Tab Kontext hinzuf\xFCgen \xB7 Esc abbrechen",
|
|
4112
|
+
allowOnce: "Einmal erlauben",
|
|
4113
|
+
allowOnceDesc: "Diesen Zugriff erlauben; das Verzeichnis f\xFCr den Rest dieser Sitzung merken",
|
|
4114
|
+
allowAlways: "Immer erlauben",
|
|
4115
|
+
allowAlwaysDesc: "`{prefix}` f\xFCr dieses Projekt merken (gespeichert in ~/.reasonix/config.json)",
|
|
4116
|
+
deny: "ablehnen",
|
|
4117
|
+
denyDesc: "Tab dr\xFCcken, um dem Modell den Grund mitzuteilen",
|
|
4118
|
+
pathLabel: "Pfad",
|
|
4119
|
+
sandboxLabel: "Sandbox",
|
|
4120
|
+
allowPrefixLabel: "Pr\xE4fix",
|
|
4121
|
+
promptTitleRead: "Pfadzugriff \u2014 lesen",
|
|
4122
|
+
promptTitleWrite: "Pfadzugriff \u2014 schreiben",
|
|
4123
|
+
actionAllowRead: "Lesen erlauben",
|
|
4124
|
+
actionAllowWrite: "Schreiben erlauben",
|
|
4125
|
+
actionAlwaysAllow: "Immer erlauben \u2014 {prefix}",
|
|
4126
|
+
actionDeny: "Ablehnen"
|
|
4127
|
+
},
|
|
4128
|
+
shellConfirm: {
|
|
4129
|
+
...EN.shellConfirm,
|
|
4130
|
+
title: "Shell-Befehl",
|
|
4131
|
+
bgTitle: "Hintergrundprozess",
|
|
4132
|
+
subtitle: "Modell m\xF6chte einen Shell-Befehl ausf\xFChren",
|
|
4133
|
+
bgSubtitle: "Langlebiger Prozess \u2014 l\xE4uft nach Genehmigung weiter, /kill zum Stoppen",
|
|
4134
|
+
denyTitle: "Ablehnen \u2014 Kontext angeben",
|
|
4135
|
+
optional: "optional",
|
|
4136
|
+
denyFooter: "Kontext eingeben \xB7 \u23CE mit Grund absenden \xB7 Esc \xFCberspringen (ohne Grund ablehnen)",
|
|
4137
|
+
awaiting: "wartet",
|
|
4138
|
+
pickFooter: "\u2191\u2193 ausw\xE4hlen \xB7 \u23CE best\xE4tigen \xB7 Tab Kontext hinzuf\xFCgen \xB7 Esc abbrechen",
|
|
4139
|
+
allowOnce: "Einmal erlauben",
|
|
4140
|
+
allowOnceDesc: "Diesen Befehl ausf\xFChren, beim n\xE4chsten Mal erneut fragen",
|
|
4141
|
+
allowAlways: "Immer erlauben",
|
|
4142
|
+
allowAlwaysDesc: "`{prefix}` f\xFCr dieses Projekt merken",
|
|
4143
|
+
deny: "ablehnen",
|
|
4144
|
+
denyDesc: "Tab dr\xFCcken, um dem Modell den Grund mitzuteilen",
|
|
4145
|
+
cwdLabel: "awd",
|
|
4146
|
+
timeoutLabel: "Timeout",
|
|
4147
|
+
waitLabel: "warten",
|
|
4148
|
+
previewMore: "\u2026 {n} weitere Zeile ausgeblendet \u2014 Esc dr\xFCcken, Modell bitten, sie aufzuteilen",
|
|
4149
|
+
previewMorePlural: "\u2026 {n} weitere Zeilen ausgeblendet \u2014 Esc dr\xFCcken, Modell bitten, sie aufzuteilen",
|
|
4150
|
+
promptTitleRunCommand: "Befehl ausf\xFChren",
|
|
4151
|
+
promptTitleRunBackground: "Hintergrundbefehl ausf\xFChren",
|
|
4152
|
+
actionRunOnce: "Einmal ausf\xFChren",
|
|
4153
|
+
actionAlwaysAllow: "Immer erlauben \u2014 {prefix}",
|
|
4154
|
+
actionDeny: "Ablehnen"
|
|
4155
|
+
},
|
|
4156
|
+
editConfirm: {
|
|
4157
|
+
...EN.editConfirm,
|
|
4158
|
+
footer: "[y/Enter] anwenden \xB7 [n] mit Grund ablehnen \xB7 [a] Rest anwenden \xB7 [A] AUTO umschalten \xB7 [\u2191\u2193/Leertaste] scrollen \xB7 [Esc] abbrechen",
|
|
4159
|
+
newTag: "NEU",
|
|
4160
|
+
editTag: "BEARBEITET",
|
|
4161
|
+
linesCount: "-{removed} +{added} Zeilen",
|
|
4162
|
+
viewingRange: "Zeige {start}-{end}/{total}",
|
|
4163
|
+
denyFooter: "\u23CE absenden \xB7 Esc \xFCberspringen (ohne Grund ablehnen)",
|
|
4164
|
+
oldLabel: " - alt",
|
|
4165
|
+
newLabel: " + neu",
|
|
4166
|
+
sideBySide: " nebeneinander \xB7 entfernte Zeilen links, hinzugef\xFCgte rechts \xB7 paarweise nach Versatz",
|
|
4167
|
+
linesAbove: " \u2191 {count} Zeile dar\xFCber (\u2191/k oder Bild\u2191)",
|
|
4168
|
+
linesAbovePlural: " \u2191 {count} Zeilen dar\xFCber (\u2191/k oder Bild\u2191)",
|
|
4169
|
+
linesBelow: " \u2193 {count} Zeile darunter (\u2193/j oder Leertaste/Bild\u2193)",
|
|
4170
|
+
linesBelowPlural: " \u2193 {count} Zeilen darunter (\u2193/j oder Leertaste/Bild\u2193)"
|
|
4171
|
+
},
|
|
4172
|
+
editPicker: {
|
|
4173
|
+
...EN.editPicker,
|
|
4174
|
+
title: "Vorherige Nachricht bearbeiten",
|
|
4175
|
+
hint: "\u2191\u2193 ausw\xE4hlen \xB7 Enter zum Laden in den Composer \xB7 Esc abbrechen",
|
|
4176
|
+
empty: "Noch keine Benutzer-Turns \u2014 nichts zu bearbeiten",
|
|
4177
|
+
dismiss: "Esc zum Schlie\xDFen",
|
|
4178
|
+
forked: "\u25B8 bei Turn #{turn} abgezweigt \u2014 Puffer enth\xE4lt den Originaltext"
|
|
4179
|
+
},
|
|
4180
|
+
sessionPicker: {
|
|
4181
|
+
...EN.sessionPicker,
|
|
4182
|
+
header: " \u25C8 REASONIX \xB7 Sitzung ausw\xE4hlen ",
|
|
4183
|
+
title: "Sitzung ausw\xE4hlen \u2014 {workspace}",
|
|
4184
|
+
messages: "{count} Nachricht",
|
|
4185
|
+
messagesPlural: "{count} Nachrichten",
|
|
4186
|
+
turns: "{count} Turns",
|
|
4187
|
+
pickerHint: "\u2191\u2193 ausw\xE4hlen \xB7 / suchen \xB7 \u23CE \xF6ffnen \xB7 [n] neu \xB7 [d] l\xF6schen \xB7 [r] umbenennen \xB7 Esc beenden",
|
|
4188
|
+
empty: " noch keine gespeicherten Sitzungen in diesem Arbeitsbereich \u2014 dr\xFCcke ",
|
|
4189
|
+
emptyNew: " um eine neue zu starten",
|
|
4190
|
+
renamePrompt: ' "{from}" umbenennen \u2192 ',
|
|
4191
|
+
renameHint: " \u23CE Umbenennung best\xE4tigen \xB7 Esc abbrechen",
|
|
4192
|
+
searchPrompt: " Sitzungen durchsuchen: /",
|
|
4193
|
+
searchHint: " tippen zum Filtern \xB7 \u23CE Treffer \xF6ffnen \xB7 Esc zur\xFCcksetzen",
|
|
4194
|
+
searchEmpty: " keine Sitzungen entsprechen dieser Suche",
|
|
4195
|
+
emptyHint: " \u23CE neue Sitzung \xB7 Esc beenden",
|
|
4196
|
+
justNow: "Gerade eben",
|
|
4197
|
+
minAgo: "Vor {count} Min",
|
|
4198
|
+
yesterday: "gestern",
|
|
4199
|
+
hoursAgo: "Vor {count}h",
|
|
4200
|
+
daysAgo: "Vor {count} Tagen"
|
|
4201
|
+
},
|
|
4202
|
+
workspacePicker: {
|
|
4203
|
+
...EN.workspacePicker,
|
|
4204
|
+
header: " \u25C8 REASONIX \xB7 Arbeitsbereich ausw\xE4hlen ",
|
|
4205
|
+
title: "Arbeitsbereich ausw\xE4hlen \u2014 {workspace}",
|
|
4206
|
+
sessions: "{count} Sitzung",
|
|
4207
|
+
sessionsPlural: "{count} Sitzungen",
|
|
4208
|
+
current: "aktuell",
|
|
4209
|
+
pickerHint: "\u2191\u2193 ausw\xE4hlen \xB7 / suchen \xB7 \u23CE wechseln + Sitzung ausw\xE4hlen \xB7 Esc beenden \xB7 /cwd <pfad> f\xFCgt einen hinzu",
|
|
4210
|
+
empty: " noch keine bekannten Arbeitsbereiche \u2014 f\xFChre /cwd <pfad> einmal aus, um einen hinzuzuf\xFCgen",
|
|
4211
|
+
searchPrompt: " Arbeitsbereiche durchsuchen: /",
|
|
4212
|
+
searchHint: " tippen zum Filtern \xB7 \u23CE wechseln + Sitzung ausw\xE4hlen \xB7 Esc zur\xFCcksetzen",
|
|
4213
|
+
searchEmpty: " keine Arbeitsbereiche entsprechen dieser Suche"
|
|
4214
|
+
},
|
|
4215
|
+
modelPicker: {
|
|
4216
|
+
...EN.modelPicker,
|
|
4217
|
+
header: " \u25C8 REASONIX \xB7 Einrichtung ausw\xE4hlen ",
|
|
4218
|
+
loading: " \xB7 lade Katalog\u2026",
|
|
4219
|
+
catalogEmpty: " \xB7 Katalog leer \u2014 verwende bekannte Fallbacks",
|
|
4220
|
+
modelsAvailable: " \xB7 {count} Modelle verf\xFCgbar",
|
|
4221
|
+
effortHeader: " EFFORT \xB7 Reasoning-Effort-Grenze",
|
|
4222
|
+
modelsHeader: " MODELLE \xB7 DeepSeek-kompatible IDs",
|
|
4223
|
+
effortDesc: {
|
|
4224
|
+
...EN.modelPicker.effortDesc,
|
|
4225
|
+
low: "Am schnellsten \u2014 minimales Reasoning",
|
|
4226
|
+
medium: "ausgewogen",
|
|
4227
|
+
high: "Standard \u2014 sicher f\xFCr vLLM / Azure",
|
|
4228
|
+
max: "DeepSeek-Erweiterung; von stock OpenAI / vLLM abgelehnt"
|
|
4229
|
+
},
|
|
4230
|
+
pickerFooter: " \u2191\u2193 ausw\xE4hlen \xB7 \u23CE best\xE4tigen \xB7 [r] aktualisieren \xB7 Esc abbrechen",
|
|
4231
|
+
currentLabel: " \xB7 aktuell"
|
|
4232
|
+
},
|
|
4233
|
+
slashSuggestions: {
|
|
4234
|
+
...EN.slashSuggestions,
|
|
4235
|
+
noMatch: "Kein Slash-Befehl entspricht diesem Pr\xE4fix",
|
|
4236
|
+
backspaceHint: " \u2014 R\xFCcktaste zum Bearbeiten, oder /help f\xFCr die vollst\xE4ndige Liste",
|
|
4237
|
+
commandCount: "{count} Befehl",
|
|
4238
|
+
commandCountPlural: "{count} Befehle",
|
|
4239
|
+
aboveLabel: " \u2191 {count} dar\xFCber",
|
|
4240
|
+
belowLabel: " \u2193 {count} darunter",
|
|
4241
|
+
advancedHint: " + {count} erweitert \xB7 tippe einen Buchstaben zum Suchen",
|
|
4242
|
+
footerHint: " \u2191\u2193 navigieren \xB7 Tab / \u23CE ausw\xE4hlen \xB7 Esc abbrechen",
|
|
4243
|
+
groupChat: "CHAT",
|
|
4244
|
+
groupSetup: "SETUP",
|
|
4245
|
+
groupInfo: "INFO",
|
|
4246
|
+
groupSession: "SITZUNG",
|
|
4247
|
+
groupExtend: "ERWEITERN",
|
|
4248
|
+
groupCode: "CODE",
|
|
4249
|
+
groupJobs: "JOBS",
|
|
4250
|
+
groupAdvanced: "ERWEITERT",
|
|
4251
|
+
groupDetailSetup: "Modell + Kosten",
|
|
4252
|
+
groupDetailInfo: "Aktueller Zustand",
|
|
4253
|
+
groupDetailChat: "T\xE4gliche Turn-Operationen",
|
|
4254
|
+
groupDetailExtend: "MCP, Memory, Skills",
|
|
4255
|
+
groupDetailSession: "Gespeicherte Sitzungen",
|
|
4256
|
+
groupDetailCode: "Edits + Pl\xE4ne (Code-Modus)",
|
|
4257
|
+
groupDetailJobs: "Hintergrundprozesse (Code-Modus)",
|
|
4258
|
+
groupDetailAdvanced: "Selten oder einmalig"
|
|
4259
|
+
},
|
|
4260
|
+
atMentions: {
|
|
4261
|
+
...EN.atMentions,
|
|
4262
|
+
loading: "lade\u2026",
|
|
4263
|
+
entrySingular: "{count} Eintrag",
|
|
4264
|
+
entryPlural: "{count} Eintr\xE4ge",
|
|
4265
|
+
searching: "suche\u2026",
|
|
4266
|
+
scanned: "gescannt",
|
|
4267
|
+
match: "Treffer",
|
|
4268
|
+
matches: "Treffer",
|
|
4269
|
+
forFilter: 'f\xFCr "{filter}"',
|
|
4270
|
+
noMatch: 'keine Dateien entsprechen "{filter}"',
|
|
4271
|
+
emptyDir: "Leeres Verzeichnis",
|
|
4272
|
+
scanning: "Durchsuche Verzeichnisbaum\u2026",
|
|
4273
|
+
footerBrowse: "\u2191\u2193 navigieren \xB7 Tab in Ordner eintauchen \xB7 \u23CE einf\xFCgen \xB7 Esc abbrechen",
|
|
4274
|
+
footerBrowseSearch: "\u2191\u2193 navigieren \xB7 Tab / \u23CE als @pfad einf\xFCgen \xB7 Esc abbrechen",
|
|
4275
|
+
footerInsert: "\u2191\u2193 navigieren \xB7 Tab / \u23CE als @pfad einf\xFCgen \xB7 Esc abbrechen"
|
|
4276
|
+
},
|
|
4277
|
+
statsPanel: {
|
|
4278
|
+
...EN.statsPanel,
|
|
4279
|
+
modePlan: "PLAN",
|
|
4280
|
+
modeYolo: "yolo",
|
|
4281
|
+
modeAuto: "auto",
|
|
4282
|
+
modeReview: "review",
|
|
4283
|
+
pro: "\u21E7 pro",
|
|
4284
|
+
budget: " Budget "
|
|
4285
|
+
},
|
|
4286
|
+
welcomeBanner: {
|
|
4287
|
+
...EN.welcomeBanner,
|
|
4288
|
+
workspace: "\u25B8 Arbeitsbereich",
|
|
4289
|
+
relaunchHint: " (mit --dir <pfad> neu starten zum Wechseln)",
|
|
4290
|
+
dashboard: "\u25B8 Web"
|
|
4291
|
+
},
|
|
4292
|
+
ctxBreakdown: {
|
|
4293
|
+
...EN.ctxBreakdown,
|
|
4294
|
+
title: "\u25A3 Kontext",
|
|
4295
|
+
compactHint: " /compact faltet (automatisch bei 50 %) \xB7 /new l\xF6scht Log",
|
|
4296
|
+
topTools: " Top-Tool-Ergebnisse nach Kosten ({count}):",
|
|
4297
|
+
msg: "Nachr",
|
|
4298
|
+
turnLabel: "Turn"
|
|
4299
|
+
},
|
|
4300
|
+
startup: {
|
|
4301
|
+
...EN.startup,
|
|
4302
|
+
codeRooted: '\u25B8 reasonix code: verwurzelt in {rootDir}, Sitzung "{session}" \xB7 {tools} native Tool{s}{semantic}',
|
|
4303
|
+
ephemeral: "(ephemer)",
|
|
4304
|
+
semanticOn: " \xB7 Semantic-Search an"
|
|
4305
|
+
},
|
|
4306
|
+
doctorErrors: {
|
|
4307
|
+
...EN.doctorErrors,
|
|
4308
|
+
unreadable: "{path} nicht lesbar \u2014 {message}",
|
|
4309
|
+
cannotList: "Kann nicht auflisten \u2014 {message}",
|
|
4310
|
+
parseFailed: "settings.json konnte nicht geparst werden \u2014 {message}",
|
|
4311
|
+
probeFailed: "Test fehlgeschlagen \u2014 {message}"
|
|
4312
|
+
},
|
|
4313
|
+
webErrors: {
|
|
4314
|
+
...EN.webErrors,
|
|
4315
|
+
status: "web_search {status} \u2014 versuche: Das Such-Backend hat einen Fehler zur\xFCckgegeben; formuliere die Abfrage um oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa",
|
|
4316
|
+
rateLimit429: "web_search 429 \u2014 versuche: 10s warten vor erneuter Abfrage oder Abfrage umformulieren; das Such-Backend ratelimited diesen Client",
|
|
4317
|
+
forbidden403: "web_search 403 \u2014 versuche: Das Such-Backend blockiert diesen Client; wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa oder warte und versuche es sp\xE4ter erneut",
|
|
4318
|
+
serverError5xx: "web_search {status} \u2014 versuche: \xD6ffne die Such-URL in einem Browser; falls sie l\xE4dt, ist dies vor\xFCbergehend und ein erneuter Versuch in 30s kann helfen",
|
|
4319
|
+
bingBlocked: "web_search: Bing-Anti-Bot-Seite \u2014 ratelimited oder blockiert \u2014 versuche: 30s warten und erneut versuchen, oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa",
|
|
4320
|
+
bingNoResults: "web_search: 0 Ergebnisse, aber die Antwort sieht nicht wie eine echte leere Seite aus ({chars} Zeichen, erste 120: {preview}) \u2014 versuche: formuliere die Abfrage mit einfacheren Begriffen um oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa",
|
|
4321
|
+
invalidEndpoint: 'web_search: ung\xFCltiger SearXNG-Endpunkt "{endpoint}" \u2014 versuche: setze eine g\xFCltige URL mit /search-endpoint http://host:port',
|
|
4322
|
+
endpointMustBeHttp: "web_search: SearXNG-Endpunkt muss http(s) sein, {protocol} erhalten \u2014 versuche: setze eine g\xFCltige URL mit /search-endpoint http://host:port",
|
|
4323
|
+
cannotReach: "web_search: SearXNG-Server unter {endpoint} nicht erreichbar \u2014 versuche: SearXNG installieren und starten (https://github.com/searxng/searxng, z.B. `docker run -d -p 8080:8080 searxng/searxng`), oder wechsle zu einer anderen Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa",
|
|
4324
|
+
searxngNoResults: "web_search: 0 Ergebnisse, aber SearXNG-Antwort sieht nicht wie eine leere Ergebnisseite aus ({chars} Zeichen) \u2014 versuche: formuliere die Abfrage mit einfacheren Begriffen um oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa",
|
|
4325
|
+
metasoMissingKey: "web_search: Metaso ben\xF6tigt einen API-Schl\xFCssel \u2014 setze METASO_API_KEY oder konfiguriere einen mit /search-engine metaso <schl\xFCssel>. Erhalte einen unter https://metaso.cn/search-api/playground",
|
|
4326
|
+
metasoDailyLimit: "web_search: Metaso-Tageslimit erreicht \u2014 setze METASO_API_KEY oder erhalte einen Schl\xFCssel unter https://metaso.cn/search-api/playground",
|
|
4327
|
+
metasoUnauthorized: "web_search: Metaso-API-Schl\xFCssel abgelehnt \u2014 \xFCberpr\xFCfe METASO_API_KEY oder erhalte einen unter https://metaso.cn/search-api/playground",
|
|
4328
|
+
metasoRateLimit: "web_search: Metaso ratelimited \u2014 warte und versuche es erneut, oder erhalte einen eigenen API-Schl\xFCssel unter https://metaso.cn/search-api/playground",
|
|
4329
|
+
metasoServerError: "web_search: Metaso-Serverfehler ({status}) \u2014 versuche es sp\xE4ter erneut oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa",
|
|
4330
|
+
metasoParseError: "web_search: Metaso hat unparsbare Antwort zur\xFCckgegeben (HTTP {status}) \u2014 versuche es sp\xE4ter erneut",
|
|
4331
|
+
metasoApiError: "web_search: Metaso-API-Fehler (Code {code}: {message}) \u2014 versuche es sp\xE4ter erneut",
|
|
4332
|
+
tavilyMissingKey: "web_search: Tavily-Backend ben\xF6tigt einen API-Schl\xFCssel \u2014 setze TAVILY_API_KEY-Umgebungsvariable oder `tavilyApiKey` in ~/.reasonix/config.json; kostenlose 1000/Monat-Registrierung unter https://tavily.com",
|
|
4333
|
+
tavilyUnauthorized: "web_search: Tavily-API-Schl\xFCssel abgelehnt \u2014 \xFCberpr\xFCfe TAVILY_API_KEY oder erhalte einen unter https://tavily.com",
|
|
4334
|
+
tavilyRateLimit: "web_search: Tavily ratelimited oder monatliches Kontingent \xFCberschritten \u2014 warte, wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa oder upgrade deinen Tavily-Plan",
|
|
4335
|
+
tavilyServerError: "web_search: Tavily-Serverfehler ({status}) \u2014 versuche es sp\xE4ter erneut oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa",
|
|
4336
|
+
tavilyParseError: "web_search: Tavily hat unparsbare Antwort zur\xFCckgegeben (HTTP {status}) \u2014 versuche es sp\xE4ter erneut",
|
|
4337
|
+
perplexityMissingKey: "web_search: Perplexity-Backend ben\xF6tigt einen API-Schl\xFCssel \u2014 setze PERPLEXITY_API_KEY-Umgebungsvariable oder `perplexityApiKey` in ~/.reasonix/config.json; erhalte einen unter https://perplexity.ai/settings/api",
|
|
4338
|
+
perplexityUnauthorized: "web_search: Perplexity-API-Schl\xFCssel abgelehnt \u2014 \xFCberpr\xFCfe PERPLEXITY_API_KEY oder erhalte einen unter https://perplexity.ai/settings/api",
|
|
4339
|
+
perplexityRateLimit: "web_search: Perplexity ratelimited \u2014 warte und versuche es erneut, oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa",
|
|
4340
|
+
perplexityServerError: "web_search: Perplexity-Serverfehler ({status}) \u2014 versuche es sp\xE4ter erneut oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa",
|
|
4341
|
+
perplexityParseError: "web_search: Perplexity hat unparsbare Antwort zur\xFCckgegeben (HTTP {status}) \u2014 versuche es sp\xE4ter erneut",
|
|
4342
|
+
exaMissingKey: "web_search: Exa-Backend ben\xF6tigt einen API-Schl\xFCssel \u2014 setze EXA_API_KEY-Umgebungsvariable oder `exaApiKey` in ~/.reasonix/config.json; kostenlose 1000/Monat-Registrierung unter https://exa.ai",
|
|
4343
|
+
exaUnauthorized: "web_search: Exa-API-Schl\xFCssel abgelehnt \u2014 \xFCberpr\xFCfe EXA_API_KEY oder erhalte einen unter https://exa.ai",
|
|
4344
|
+
exaRateLimit: "web_search: Exa-API ratelimited oder monatliches Kontingent \xFCberschritten \u2014 warte oder upgrade unter https://exa.ai/pricing",
|
|
4345
|
+
exaServerError: "web_search: Exa-Serverfehler ({status}) \u2014 versuche es sp\xE4ter erneut oder wechsle die Engine mit /search-engine bing|searxng|metaso|tavily|perplexity|exa",
|
|
4346
|
+
exaParseError: "web_search: Exa hat unparsbare Antwort zur\xFCckgegeben (HTTP {status}) \u2014 versuche es sp\xE4ter erneut",
|
|
4347
|
+
fetchStatus: "web_fetch {status} f\xFCr {url} \u2014 versuche: Best\xE4tige, dass die URL im Browser aufgel\xF6st wird; der Status deutet darauf hin, dass der Host eine Fehlerseite zur\xFCckgegeben hat",
|
|
4348
|
+
fetchRateLimit429: "web_fetch 429 f\xFCr {url} \u2014 versuche: 10s warten vor erneuter Abfrage; der Host ratelimitet diesen Client",
|
|
4349
|
+
fetchForbidden403: "web_fetch 403 f\xFCr {url} \u2014 versuche: Der Host blockiert diesen Client; die Seite erfordert m\xF6glicherweise eine Anmeldung oder blockiert Bots \u2014 verwende stattdessen web_search-Ausz\xFCge",
|
|
4350
|
+
fetchServerError5xx: "web_fetch {status} f\xFCr {url} \u2014 versuche: \xD6ffne die URL in einem Browser; falls sie l\xE4dt, ist dies vor\xFCbergehend und ein erneuter Versuch in 30s kann helfen",
|
|
4351
|
+
fetchTimeout: "web_fetch: Zeit\xFCberschreitung nach {ms}ms f\xFCr {url} \u2014 versuche: eine k\xFCrzere URL oder kleinere Inhalte; dies k\xF6nnte ein langsames CDN sein, oder einmal erneut versuchen",
|
|
4352
|
+
fetchTooLarge: "web_fetch abgelehnt: content-length {len} Bytes \xFCberschreitet {cap}-Byte-Grenze ({url}) \u2014 versuche: eine andere URL mit kleineren Inhalten; diese Seite ist zu gro\xDF zum Abrufen",
|
|
4353
|
+
fetchBodyTooLarge: "web_fetch abgelehnt: Antwortbody \xFCberschritt {cap}-Byte-Grenze ({seen} Bytes gesehen) \u2014 versuche: eine andere URL mit kleineren Inhalten; diese Seite hat die Gr\xF6\xDFenbeschr\xE4nkung \xFCberschritten",
|
|
4354
|
+
fetchInvalidUrl: "web_fetch: URL muss mit http:// oder https:// beginnen \u2014 versuche: eine absolute http(s)-URL \xFCbergeben (die URL ist fehlerhaft oder verwendet ein nicht unterst\xFCtztes Schema)"
|
|
4355
|
+
},
|
|
4356
|
+
choiceConfirm: {
|
|
4357
|
+
...EN.choiceConfirm,
|
|
4358
|
+
customLabel: "Eigene Antwort eingeben",
|
|
4359
|
+
customDesc: "Keine der Optionen passt \u2014 gib eine Freitext-Antwort ein. Das Modell liest sie w\xF6rtlich.",
|
|
4360
|
+
cancelLabel: "Abbrechen \u2014 Frage verwerfen",
|
|
4361
|
+
cancelDesc: "Modell stoppt und fragt, was du stattdessen m\xF6chtest."
|
|
4362
|
+
},
|
|
4363
|
+
cardTitles: {
|
|
4364
|
+
...EN.cardTitles,
|
|
4365
|
+
usage: "Nutzung",
|
|
4366
|
+
context: "Kontext",
|
|
4367
|
+
search: "Suche",
|
|
4368
|
+
subagent: "Subagent",
|
|
4369
|
+
reply: "Antwort",
|
|
4370
|
+
reasoning: "Reasoning",
|
|
4371
|
+
reasoningAborted: "Reasoning (abgebrochen)",
|
|
4372
|
+
reasoningEllipsis: "Reasoning\u2026",
|
|
4373
|
+
error: "Fehler",
|
|
4374
|
+
doctor: "Doctor",
|
|
4375
|
+
you: "du",
|
|
4376
|
+
task: "Aufgabe"
|
|
4377
|
+
},
|
|
4378
|
+
cardLabels: {
|
|
4379
|
+
...EN.cardLabels,
|
|
4380
|
+
prompt: "Prompt",
|
|
4381
|
+
reason: "Grund",
|
|
4382
|
+
output: "Ausgabe",
|
|
4383
|
+
cache: "Cache",
|
|
4384
|
+
session: "Sitzung",
|
|
4385
|
+
balance: "Guthaben",
|
|
4386
|
+
turn: "Turn",
|
|
4387
|
+
system: "System",
|
|
4388
|
+
tools: "Tools",
|
|
4389
|
+
log: "Log",
|
|
4390
|
+
input: "Eingabe",
|
|
4391
|
+
topTools: "Top-Tools",
|
|
4392
|
+
logMsgs: "Log-Nachr",
|
|
4393
|
+
hitSingular: "{count} Treffer \xB7 {files} Datei",
|
|
4394
|
+
hitsPlural: "{count} Treffer \xB7 {files} Dateien",
|
|
4395
|
+
moreHitSingular: "\u22EE +{count} weiterer Treffer",
|
|
4396
|
+
moreHitsPlural: "\u22EE +{count} weitere Treffer",
|
|
4397
|
+
earlierLine: "\u22EE {count} ausgeblendete Zeile (Strg+R f\xFCr vollst\xE4ndige Ausgabe)",
|
|
4398
|
+
earlierLines: "\u22EE {count} ausgeblendete Zeilen (Strg+R f\xFCr vollst\xE4ndige Ausgabe)",
|
|
4399
|
+
hiddenLine: "\u22EE {count} ausgeblendete Zeile",
|
|
4400
|
+
hiddenLines: "\u22EE {count} ausgeblendete Zeilen",
|
|
4401
|
+
earlierStackLine: "\u22EE {count} fr\xFChere Stack-Zeile ausgeblendet",
|
|
4402
|
+
earlierStackLines: "\u22EE {count} fr\xFChere Stack-Zeilen ausgeblendet",
|
|
4403
|
+
agent: "Agent \xB7 {name}",
|
|
4404
|
+
response: "Antwort",
|
|
4405
|
+
writing: "Schreibe \u2026",
|
|
4406
|
+
tok: "Tok",
|
|
4407
|
+
pilcrow: "\xB6",
|
|
4408
|
+
aborted: "abgebrochen",
|
|
4409
|
+
truncatedByEsc: "[durch Esc gek\xFCrzt]",
|
|
4410
|
+
rejected: "abgelehnt",
|
|
4411
|
+
exit: "Exit {code}",
|
|
4412
|
+
bytesIn: "{bytes} rein",
|
|
4413
|
+
elapsedSec: "{secs}s",
|
|
4414
|
+
stackTrace: "Stacktrace",
|
|
4415
|
+
retries: "Wiederholungen",
|
|
4416
|
+
reasoningLabel: "Reasoning \xB7 {count} \xB6",
|
|
4417
|
+
runningLabel: "l\xE4uft",
|
|
4418
|
+
workingLabel: "arbeitet",
|
|
4419
|
+
defaultFooter: "\u2191\u2193 ausw\xE4hlen \xB7 \u23CE best\xE4tigen \xB7 Esc abbrechen",
|
|
4420
|
+
applyAction: "[a] anwenden",
|
|
4421
|
+
skipAction: "[s] \xFCberspringen",
|
|
4422
|
+
rejectAction: "[r] ablehnen",
|
|
4423
|
+
levelOk: "OK",
|
|
4424
|
+
levelWarn: "Warn",
|
|
4425
|
+
levelFail: "FEHLGESCHLAGEN",
|
|
4426
|
+
checksLabel: "Pr\xFCfungen",
|
|
4427
|
+
passed: "bestanden",
|
|
4428
|
+
warnTag: "Warn",
|
|
4429
|
+
failTag: "Fehl",
|
|
4430
|
+
stepLabel: "Schritt",
|
|
4431
|
+
done: "erledigt",
|
|
4432
|
+
inProgress: "\u2190 in Bearbeitung",
|
|
4433
|
+
upcoming: "bevorstehend",
|
|
4434
|
+
resumed: "fortgesetzt \xB7 ",
|
|
4435
|
+
archive: "\u23E4 archivieren \xB7 ",
|
|
4436
|
+
more: "\u22EE +{count} weitere",
|
|
4437
|
+
categoryUser: "Benutzer",
|
|
4438
|
+
categoryFeedback: "Feedback",
|
|
4439
|
+
categoryProject: "Projekt",
|
|
4440
|
+
categoryReference: "Referenz"
|
|
4441
|
+
},
|
|
4442
|
+
mcpHealth: {
|
|
4443
|
+
...EN.mcpHealth,
|
|
4444
|
+
noData: "Keine Inspektionsdaten",
|
|
4445
|
+
healthy: "Gesund \xB7 {ms}ms",
|
|
4446
|
+
slow: "Langsam \xB7 {ms}ms",
|
|
4447
|
+
verySlow: "Sehr langsam \xB7 {ms}ms",
|
|
4448
|
+
slowToast: "\u26A0 MCP `{name}` langsam \xB7 {seconds}s p95 \xFCber die letzten {sampleSize} Aufrufe",
|
|
4449
|
+
emptyHint: "\u2139 keine MCP-Server konfiguriert \u2014 versuche: `reasonix setup` zur erneuten Auswahl, oder `reasonix mcp install filesystem` \xB7 Shell-Befehle werden pro Aufruf abgefragt (einmal erlauben / immer erlauben / ablehnen), kein globales Allow-All"
|
|
4450
|
+
},
|
|
4451
|
+
denyContextInput: {
|
|
4452
|
+
...EN.denyContextInput,
|
|
4453
|
+
description: "Sag dem Agenten, warum du abgelehnt hast. Der n\xE4chste Versuch sieht deinen Grund als zus\xE4tzlichen Kontext."
|
|
4454
|
+
},
|
|
4455
|
+
cardStream: {
|
|
4456
|
+
...EN.cardStream,
|
|
4457
|
+
scrollAbove: " \u2191 {scroll} / {max} Zeile dar\xFCber",
|
|
4458
|
+
scrollAbovePlural: " \u2191 {scroll} / {max} Zeilen dar\xFCber",
|
|
4459
|
+
scrollMore: " \u2014 {remaining} weitere",
|
|
4460
|
+
scrollPgUp: " \xB7 Bild\u2191 / Mausrad",
|
|
4461
|
+
scrollCopy: " \xB7 /copy aktiviert Kopiermodus"
|
|
4462
|
+
},
|
|
4463
|
+
slashArgPicker: {
|
|
4464
|
+
...EN.slashArgPicker,
|
|
4465
|
+
noMatch: 'keine \xDCbereinstimmung f\xFCr "{partial}"',
|
|
4466
|
+
keepTyping: " \u2014 tippe weiter, oder R\xFCcktaste zum Bearbeiten",
|
|
4467
|
+
above: " \u2191 {hidden} dar\xFCber",
|
|
4468
|
+
below: " \u2193 {hidden} darunter",
|
|
4469
|
+
footer: " \u2191\u2193 navigieren \xB7 Tab / \u23CE ausw\xE4hlen \xB7 Esc abbrechen"
|
|
4470
|
+
},
|
|
4471
|
+
mcpMarketplace: {
|
|
4472
|
+
...EN.mcpMarketplace,
|
|
4473
|
+
title: "MCP-Marktplatz",
|
|
4474
|
+
filter: "Filter: ",
|
|
4475
|
+
filterPlaceholder: "(tippen zum Filtern)",
|
|
4476
|
+
matchSingular: "{n} Treffer",
|
|
4477
|
+
matchPlural: "{n} Treffer",
|
|
4478
|
+
loading: "lade\u2026",
|
|
4479
|
+
noEntries: "Keine Eintr\xE4ge",
|
|
4480
|
+
opening: "\xD6ffne Registry\u2026",
|
|
4481
|
+
cached: "\xB7 zwischengespeichert",
|
|
4482
|
+
exhausted: "\xB7 ersch\xF6pft",
|
|
4483
|
+
loadingMore: "Lade mehr\u2026",
|
|
4484
|
+
allLoaded: "Alle Seiten geladen",
|
|
4485
|
+
fetchingDetail: "Hole Smithery-Details\u2026",
|
|
4486
|
+
noInstallInfo: "keine Installationsinfo f\xFCr {name} - versuche `npx -y @smithery/cli install {name}`",
|
|
4487
|
+
alreadyInstalled: "Bereits installiert: {spec}",
|
|
4488
|
+
installed: "Installiert \u2192 {spec}",
|
|
4489
|
+
uninstalled: "{name} deinstalliert",
|
|
4490
|
+
installFailed: "Installation fehlgeschlagen: {message}",
|
|
4491
|
+
notInstalled: "Nicht installiert: {name}",
|
|
4492
|
+
bridged: "\u2713 {name} installiert - verbunden",
|
|
4493
|
+
bridgeFailed: "\u25B2 {name} installiert - Verbindung fehlgeschlagen: {reason}",
|
|
4494
|
+
bridgeReloadFailed: "\u2713 {name} installiert - starte `reasonix code` neu zur Verbindung (Neuladen fehlgeschlagen: {message})",
|
|
4495
|
+
restartBridge: "\u2713 {name} installiert - starte `reasonix code` neu zur Verbindung",
|
|
4496
|
+
needsEnv: " \xB7 ben\xF6tigt Umgebungsvariable: {env}",
|
|
4497
|
+
badgeOfficial: "[off]",
|
|
4498
|
+
badgeSmithery: "[smt]",
|
|
4499
|
+
badgeLocal: "[loc]",
|
|
4500
|
+
footerHint: "Filter eingeben \xB7 \u2191\u2193 ausw\xE4hlen \xB7 \u23CE installieren/umschalten \xB7 Bild\u2193 mehr laden \xB7 Esc schlie\xDFen",
|
|
4501
|
+
specLine: "Spec: {runtime} {id} \xB7 {transport}",
|
|
4502
|
+
smitheryDetail: "(Smithery-Eintrag \u2014 Installationsdetails werden bei Enter abgerufen)",
|
|
4503
|
+
statusError: "Fehler: {message}"
|
|
4504
|
+
},
|
|
4505
|
+
mcpBrowser: {
|
|
4506
|
+
...EN.mcpBrowser,
|
|
4507
|
+
title: "\u25C8 MCP-Browser",
|
|
4508
|
+
empty: "Keine MCP-Server angeh\xE4ngt. F\xFChre `reasonix setup` aus, um welche auszuw\xE4hlen, oder starte mit --mcp.",
|
|
4509
|
+
serverCount: "{count} Server",
|
|
4510
|
+
footer: "\u2191\u2193 ausw\xE4hlen \xB7 [r] neu verbinden \xB7 [d] deaktivieren \xB7 Esc beenden"
|
|
4511
|
+
},
|
|
4512
|
+
mcpBrowse: {
|
|
4513
|
+
...EN.mcpBrowse,
|
|
4514
|
+
noResources: "Keine Ressourcen auf einem verbundenen MCP-Server (oder keine Server verbunden). `/mcp` zeigt den aktuellen Satz.",
|
|
4515
|
+
readOne: "Lese einen: `/resource <uri>` \u2014 oder verwende Tab in der Auswahl.",
|
|
4516
|
+
noPrompts: "Keine Prompts auf einem verbundenen MCP-Server (oder keine Server verbunden). `/mcp` zeigt den aktuellen Satz.",
|
|
4517
|
+
fetchOne: "Rufe einen ab: `/prompt <name>` \u2014 Argumente werden noch nicht unterst\xFCtzt; Prompts mit erforderlichen Argumenten geben einen Fehler vom Server zur\xFCck.",
|
|
4518
|
+
noServerForResource: 'kein Server bietet Ressource "{name}"',
|
|
4519
|
+
resourceHint: "`/resource` ohne Argument listet verf\xFCgbare Ressourcen.",
|
|
4520
|
+
readFailed: "readResource fehlgeschlagen",
|
|
4521
|
+
noServerForPrompt: 'kein Server bietet Prompt "{name}"',
|
|
4522
|
+
promptHint: "`/prompt` ohne Argument listet verf\xFCgbare Prompts.",
|
|
4523
|
+
fetchFailed: "getPrompt fehlgeschlagen"
|
|
4524
|
+
},
|
|
4525
|
+
mcpLifecycle: {
|
|
4526
|
+
...EN.mcpLifecycle,
|
|
4527
|
+
handshake: "Handshake\u2026",
|
|
4528
|
+
connected: "verbunden",
|
|
4529
|
+
failed: "fehlgeschlagen",
|
|
4530
|
+
disabled: "deaktiviert",
|
|
4531
|
+
reconnect: "Wiederverbinden\u2026",
|
|
4532
|
+
initDetail: "initialisiere \u2192 tools/list \u2192 resources/list",
|
|
4533
|
+
reconnectDetail: "baue ab \xB7 neuer Handshake \xB7 liste Tools",
|
|
4534
|
+
disabledDetail: "via /mcp disable {name}",
|
|
4535
|
+
failedSetupHint: "\u2192 f\xFChre `reasonix setup` aus, um diesen Eintrag zu entfernen, oder behebe das zugrunde liegende Problem (fehlendes npm-Paket, Netzwerk usw.).",
|
|
4536
|
+
failedSetupConfigHint: "\u2192 f\xFChre `reasonix setup` aus, um fehlerhafte Eintr\xE4ge aus deiner gespeicherten Konfiguration zu entfernen.",
|
|
4537
|
+
abortedHint: "MCP-Start abgebrochen \u2014 {count} Server \xFCbersprungen. F\xFChre /mcp aus, um es erneut zu versuchen, sobald du das zugrunde liegende Problem behoben hast.",
|
|
4538
|
+
toolsReady: "Tools bereit",
|
|
4539
|
+
warnLabel: "Warn"
|
|
4540
|
+
},
|
|
4541
|
+
checkpointPicker: {
|
|
4542
|
+
...EN.checkpointPicker,
|
|
4543
|
+
title: "Checkpoint wiederherstellen \u2014 {workspace}",
|
|
4544
|
+
header: " \u25C8 REASONIX \xB7 Checkpoint ausw\xE4hlen ",
|
|
4545
|
+
empty: " noch keine Checkpoints in diesem Arbeitsbereich - siehe /checkpoint zum Erstellen",
|
|
4546
|
+
more: " \u2026 {hidden} weitere",
|
|
4547
|
+
footer: " \u2191\u2193 ausw\xE4hlen \xB7 \u23CE wiederherstellen \xB7 [d] vergessen \xB7 Esc beenden",
|
|
4548
|
+
footerEmpty: " Esc beenden"
|
|
4549
|
+
},
|
|
4550
|
+
planReviseConfirm: {
|
|
4551
|
+
...EN.planReviseConfirm,
|
|
4552
|
+
title: "Plan-\xDCberarbeitung vorgeschlagen",
|
|
4553
|
+
metaRight: "\u2212{removed} +{added} \xB7 {kept} behalten",
|
|
4554
|
+
updatedSummary: "Aktualisierte Zusammenfassung: {summary}",
|
|
4555
|
+
acceptLabel: "\xDCberarbeitung annehmen \u2014 neue Schrittliste anwenden",
|
|
4556
|
+
acceptHint: "Ersetzt den Restplan durch die vorgeschlagenen Schritte. Erledigte Schritte bleiben unber\xFChrt.",
|
|
4557
|
+
rejectLabel: "Ablehnen \u2014 Originalplan behalten",
|
|
4558
|
+
rejectHint: "Vorschlag verwerfen. Modell f\xE4hrt mit den urspr\xFCnglichen verbleibenden Schritten fort."
|
|
4559
|
+
},
|
|
4560
|
+
diffApp: {
|
|
4561
|
+
...EN.diffApp,
|
|
4562
|
+
title: "reasonix diff",
|
|
4563
|
+
turnLabel: "Turn {turn} ({current}/{total})",
|
|
4564
|
+
turnsAligned: "{count} Turns ausgerichtet",
|
|
4565
|
+
paneEmpty: "(keine Datens\xE4tze auf dieser Seite f\xFCr diesen Turn)",
|
|
4566
|
+
kindMatch: "\u2713 \xDCbereinstimmung",
|
|
4567
|
+
kindDiverge: "\u2605 Abweichung",
|
|
4568
|
+
kindOnlyInA: "\u2190 nur in A",
|
|
4569
|
+
kindOnlyInB: "\u2192 nur in B"
|
|
4570
|
+
},
|
|
4571
|
+
recordView: {
|
|
4572
|
+
...EN.recordView,
|
|
4573
|
+
userPrefix: "Du \xBB ",
|
|
4574
|
+
assistant: "Assistent",
|
|
4575
|
+
toolPrefix: "Tool<",
|
|
4576
|
+
argsLabel: " Args: ",
|
|
4577
|
+
resultArrow: " \u2192 ",
|
|
4578
|
+
error: "Fehler ",
|
|
4579
|
+
cache: " \xB7 Cache ",
|
|
4580
|
+
toolCallOnly: "(nur Tool-Call-Antwort)",
|
|
4581
|
+
truncateExtra: "(+{extra} Zeichen)"
|
|
4582
|
+
},
|
|
4583
|
+
replayApp: {
|
|
4584
|
+
...EN.replayApp,
|
|
4585
|
+
emptyTranscript: "Leeres Transkript",
|
|
4586
|
+
turnProgress: "Turn {current}/{total}",
|
|
4587
|
+
noRecords: "Keine Datens\xE4tze",
|
|
4588
|
+
untracked: "(nicht verfolgt)",
|
|
4589
|
+
churned: "(umgewandelt \xD7{count})"
|
|
4590
|
+
},
|
|
4591
|
+
builtinSkills: {
|
|
4592
|
+
...EN.builtinSkills,
|
|
4593
|
+
explore: 'Durchsuche die Codebasis in einem isolierten Subagenten \u2014 breit angelegte, schreibgesch\xFCtzte Untersuchung, die eine destillierte Antwort zur\xFCckgibt. Am besten f\xFCr: \xBBFinde alle Stellen, die\u2026", \xBBWie funktioniert X im gesamten Projekt", \xBBDurchsuche den Code nach Y".',
|
|
4594
|
+
research: 'Recherchiere eine Frage durch Kombination von Websuche + Codelesen in einem isolierten Subagenten. Am besten f\xFCr: \xBBWird X-Feature von Bibliothek Y unterst\xFCtzt?", \xBBWas ist der kanonische Weg, Z zu tun?", \xBBVergleiche unsere Implementierung mit dem Standard".',
|
|
4595
|
+
review: "\xDCberpr\xFCfe die ausstehenden \xC4nderungen (aktueller Branch-Diff) in einem isolierten Subagenten \u2014 kennzeichnet Korrektheit, Sicherheit, fehlende Tests, versteckte Verhaltens\xE4nderungen; meldet Befund + pro-Problem datei:zeile. Schreibgesch\xFCtzt; das \xFCbergeordnete Element entscheidet, was zu tun ist.",
|
|
4596
|
+
securityReview: "Sicherheitsfokussierte \xDCberpr\xFCfung des aktuellen Branch-Diffs in einem isolierten Subagenten \u2014 kennzeichnet Injection/Authz/Secrets/Deserialisierung/Pfad-Traversal/Krypto-Probleme, mit Schweregrad. Schreibgesch\xFCtzt. Verwende beim Ausliefern von \xC4nderungen, die Auth, Eingabeanalyse, Datei-E/A oder externe Anfragen betreffen.",
|
|
4597
|
+
test: "F\xFChre die Testsuite des Projekts aus, diagnostiziere Fehler, schlage SEARCH/REPLACE-Fixes vor, wiederhole bis gr\xFCn (oder stoppe nach 2 Fixversuchen beim gleichen Fehler). Inline \u2014 l\xE4uft in der \xFCbergeordneten Schleife, sodass du die Edit-Blocks siehst und /apply verwenden kannst. Erkennt npm/pnpm/yarn/pytest/go/cargo."
|
|
4598
|
+
},
|
|
4599
|
+
shortcutsHelp: {
|
|
4600
|
+
...EN.shortcutsHelp,
|
|
4601
|
+
title: "Tastenk\xFCrzel",
|
|
4602
|
+
groupInput: "Eingabe",
|
|
4603
|
+
groupNavigation: "Navigation",
|
|
4604
|
+
groupSession: "Sitzung",
|
|
4605
|
+
groupSystem: "System",
|
|
4606
|
+
descEnter: "Nachricht senden",
|
|
4607
|
+
descShiftEnter: "Neue Zeile",
|
|
4608
|
+
descCtrlEnter: "Neue Zeile",
|
|
4609
|
+
descCtrlJ: "Neue Zeile",
|
|
4610
|
+
descCtrlU: "Eingabe leeren",
|
|
4611
|
+
descCtrlW: "Wort l\xF6schen",
|
|
4612
|
+
descCtrlP: "Tastenk\xFCrzel anzeigen/ausblenden",
|
|
4613
|
+
descCtrlX: "Im Editor \xF6ffnen",
|
|
4614
|
+
descArrows: "Eingabeverlauf",
|
|
4615
|
+
descPgUpDown: "Seite scrollen",
|
|
4616
|
+
descCtrlL: "Bildschirm leeren",
|
|
4617
|
+
descCtrlB: "Seitenleiste umschalten",
|
|
4618
|
+
descNewSession: "Neue Sitzung",
|
|
4619
|
+
descListSessions: "Sitzungen auflisten",
|
|
4620
|
+
descSwitchModel: "Modell wechseln",
|
|
4621
|
+
descSwitchEffort: "Reasoning-Effort wechseln",
|
|
4622
|
+
descSwitchTheme: "Theme wechseln",
|
|
4623
|
+
descCtrlC: "Beenden",
|
|
4624
|
+
descEsc: "Stoppen / Abbrechen",
|
|
4625
|
+
descCtrlR: "Ausf\xFChrlich umschalten",
|
|
4626
|
+
descCtrlO: "Antwort erweitern (nur w\xE4hrend Streaming)",
|
|
4627
|
+
descHelp: "Alle Befehle anzeigen",
|
|
4628
|
+
descShiftTab: "Edit-Modus wechseln",
|
|
4629
|
+
descAltS: "Eingabe speichern / abrufen"
|
|
4630
|
+
},
|
|
4631
|
+
mcpCli: {
|
|
4632
|
+
...EN.mcpCli,
|
|
4633
|
+
bundledCatalog: "Mitgelieferte MCP-Server (Offline-Katalog):",
|
|
4634
|
+
justFetched: "Gerade abgerufen",
|
|
4635
|
+
cachedAge: "Zwischengespeichert, {age}",
|
|
4636
|
+
moreAvailable: "Mehr verf\xFCgbar",
|
|
4637
|
+
allLoaded: "Alle geladen",
|
|
4638
|
+
morePagesAvailable: "\u25B8 mehr Seiten verf\xFCgbar \u2014 `reasonix mcp list --pages <n>` oder --all",
|
|
4639
|
+
installHint: "Installieren: reasonix mcp install <name>",
|
|
4640
|
+
usageSearch: "Verwendung: reasonix mcp search <abfrage>",
|
|
4641
|
+
usageInstall: "Verwendung: reasonix mcp install <name>",
|
|
4642
|
+
noMatchesFor: 'Keine Treffer f\xFCr "{q}" in {count} geladenen Eintr\xE4gen ({source})',
|
|
4643
|
+
matchCount: '{count} Treffer f\xFCr "{q}" in {source}-Registry ({loaded} durchsuchte Eintr\xE4ge):',
|
|
4644
|
+
moreLoaded: "\u2026 {count} weitere geladen \u2014 verwende `reasonix mcp search <abfrage>` zum Filtern",
|
|
4645
|
+
moreMatches: "\u2026 {count} weitere Treffer",
|
|
4646
|
+
installed: "Installiert: {spec}",
|
|
4647
|
+
noServerFound: 'Kein MCP-Server namens "{target}" gefunden nach {pages} Seite(n) der {source}-Registry.',
|
|
4648
|
+
noServerTryMore: "Versuche: reasonix mcp install {target} --max-pages 100",
|
|
4649
|
+
noInstallMeta: 'Konnte Installationsmetadaten f\xFCr "{name}" nicht ableiten \u2014 versuche `npx -y @smithery/cli install {name}` direkt.',
|
|
4650
|
+
buildSpecFailed: "Kann Installationsspec f\xFCr {name} nicht erstellen: {message}",
|
|
4651
|
+
alreadyInstalled: "Bereits installiert: {spec}"
|
|
4652
|
+
}
|
|
4653
|
+
};
|
|
4654
|
+
|
|
2915
4655
|
// src/i18n/zh-CN.ts
|
|
2916
4656
|
var zhCN = {
|
|
2917
4657
|
common: {
|
|
@@ -3569,6 +5309,8 @@ var zhCN = {
|
|
|
3569
5309
|
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",
|
|
3570
5310
|
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",
|
|
3571
5311
|
deepseek5xxActionRetry: " \u5EFA\u8BAE\uFF1A(1) \u7B49 30 \u79D2\u540E\u91CD\u8BD5\uFF0C(2) \u7528 /model \u5207\u6362\u6A21\u578B\uFF0C(3) \u67E5\u770B\u72B6\u6001\u9875 https://status.deepseek.com\u3002",
|
|
5312
|
+
upstream5xxHead: "\u4E0A\u6E38\u670D\u52A1\u4E0D\u53EF\u7528\uFF08{status}\uFF09\uFF0C\u76EE\u6807\u5730\u5740 {host} \u2014 \u4F60\u914D\u7F6E\u7684 API \u7AEF\u70B9\u8FD4\u56DE\u4E86\u670D\u52A1\u5668\u9519\u8BEF\uFF0C\u4E0D\u662F Reasonix \u6545\u969C\u3002\u5DF2\u6309\u6307\u6570\u9000\u907F\u91CD\u8BD5 4 \u6B21\u3002",
|
|
5313
|
+
upstream5xxActionRetry: " \u5EFA\u8BAE\uFF1A(1) \u786E\u8BA4\u672C\u5730/\u4EE3\u7406\u6A21\u578B\u670D\u52A1\u5728\u7EBF\uFF0C(2) \u7B49\u4E00\u4F1A\u513F\u518D\u91CD\u8BD5\uFF0C(3) \u7528 /model \u5207\u6362\u6A21\u578B\u3002",
|
|
3572
5314
|
innerNoMessage: "\uFF08\u65E0\u9519\u8BEF\u4FE1\u606F\uFF09",
|
|
3573
5315
|
reasonAborted: "[\u7528\u6237\u5DF2\u4E2D\u65AD\uFF08Esc\uFF09 \u2014 \u6B63\u5728\u603B\u7ED3\u5230\u76EE\u524D\u4E3A\u6B62\u7684\u53D1\u73B0]",
|
|
3574
5316
|
reasonContextGuard: "[\u4E0A\u4E0B\u6587\u989D\u5EA6\u5373\u5C06\u8017\u5C3D \u2014 \u5728\u4E0B\u4E00\u6B21\u8C03\u7528\u6EA2\u51FA\u4E4B\u524D\u5148\u603B\u7ED3]",
|
|
@@ -3749,6 +5491,7 @@ var zhCN = {
|
|
|
3749
5491
|
modelSet: "model \u2192 {id}",
|
|
3750
5492
|
effortStatus: "effort \u2192 {current} \uFF08\u53EF\u9009\uFF1A{list}\uFF09",
|
|
3751
5493
|
effortUsage: "\u7528\u6CD5\uFF1A/effort <{list}> \uFF08high \u4E3A\u5B89\u5168\u9ED8\u8BA4\uFF1Bmax \u662F DeepSeek \u6269\u5C55\uFF09",
|
|
5494
|
+
effortUsageNoMax: "\u7528\u6CD5\uFF1A/effort <{list}>",
|
|
3752
5495
|
effortSet: "effort \u2192 {effort}",
|
|
3753
5496
|
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",
|
|
3754
5497
|
budgetStatus: "\u9884\u7B97\uFF1A${spent} / ${cap}\uFF08{pct}%\uFF09\xB7 /budget off \u6E05\u9664\uFF0C/budget <usd> \u66F4\u6539",
|
|
@@ -4564,13 +6307,18 @@ var zhCN = {
|
|
|
4564
6307
|
// src/i18n/index.ts
|
|
4565
6308
|
var translations = {
|
|
4566
6309
|
EN,
|
|
4567
|
-
"zh-CN": zhCN
|
|
6310
|
+
"zh-CN": zhCN,
|
|
6311
|
+
de
|
|
4568
6312
|
};
|
|
4569
|
-
function detectSystemLanguage(locale =
|
|
6313
|
+
function detectSystemLanguage(locale = systemLocale()) {
|
|
4570
6314
|
if (locale.startsWith("zh")) return "zh-CN";
|
|
4571
6315
|
if (locale.startsWith("en")) return "EN";
|
|
6316
|
+
if (locale.startsWith("de")) return "de";
|
|
4572
6317
|
return null;
|
|
4573
6318
|
}
|
|
6319
|
+
function systemLocale() {
|
|
6320
|
+
return process.env.LC_ALL || process.env.LC_MESSAGES || process.env.LANG || Intl.DateTimeFormat().resolvedOptions().locale;
|
|
6321
|
+
}
|
|
4574
6322
|
var currentLang = loadLanguage() ?? detectSystemLanguage() ?? "EN";
|
|
4575
6323
|
function t(path2, params) {
|
|
4576
6324
|
const parts = path2.split(".");
|
|
@@ -4667,7 +6415,7 @@ function matchesTool(hook, toolName) {
|
|
|
4667
6415
|
}
|
|
4668
6416
|
var HOOK_OUTPUT_CAP_BYTES = 256 * 1024;
|
|
4669
6417
|
function defaultSpawner(input) {
|
|
4670
|
-
return new Promise((
|
|
6418
|
+
return new Promise((resolve16) => {
|
|
4671
6419
|
const child = spawn(input.command, {
|
|
4672
6420
|
cwd: input.cwd,
|
|
4673
6421
|
shell: true,
|
|
@@ -4712,7 +6460,7 @@ function defaultSpawner(input) {
|
|
|
4712
6460
|
child.stderr.on("data", (chunk) => onChunk("stderr", chunk));
|
|
4713
6461
|
child.once("error", (err) => {
|
|
4714
6462
|
clearTimeout(timer);
|
|
4715
|
-
|
|
6463
|
+
resolve16({
|
|
4716
6464
|
exitCode: null,
|
|
4717
6465
|
stdout: Buffer.concat(stdoutChunks).toString("utf8"),
|
|
4718
6466
|
stderr: Buffer.concat(stderrChunks).toString("utf8"),
|
|
@@ -4723,7 +6471,7 @@ function defaultSpawner(input) {
|
|
|
4723
6471
|
});
|
|
4724
6472
|
child.once("close", (code) => {
|
|
4725
6473
|
clearTimeout(timer);
|
|
4726
|
-
|
|
6474
|
+
resolve16({
|
|
4727
6475
|
exitCode: code,
|
|
4728
6476
|
stdout: Buffer.concat(stdoutChunks).toString("utf8").trim(),
|
|
4729
6477
|
stderr: Buffer.concat(stderrChunks).toString("utf8").trim(),
|
|
@@ -4795,6 +6543,59 @@ import { createRequire } from "module";
|
|
|
4795
6543
|
import { dirname as dirname2, join as join3 } from "path";
|
|
4796
6544
|
import { fileURLToPath } from "url";
|
|
4797
6545
|
import { gunzipSync } from "zlib";
|
|
6546
|
+
|
|
6547
|
+
// src/core/lru.ts
|
|
6548
|
+
var LruCache = class {
|
|
6549
|
+
constructor(limit) {
|
|
6550
|
+
this.limit = limit;
|
|
6551
|
+
}
|
|
6552
|
+
limit;
|
|
6553
|
+
map = /* @__PURE__ */ new Map();
|
|
6554
|
+
get(key) {
|
|
6555
|
+
if (!this.map.has(key)) return void 0;
|
|
6556
|
+
const v = this.map.get(key);
|
|
6557
|
+
this.map.delete(key);
|
|
6558
|
+
this.map.set(key, v);
|
|
6559
|
+
return v;
|
|
6560
|
+
}
|
|
6561
|
+
set(key, value) {
|
|
6562
|
+
if (this.map.has(key)) {
|
|
6563
|
+
this.map.delete(key);
|
|
6564
|
+
} else if (this.map.size >= this.limit) {
|
|
6565
|
+
const oldest = this.map.keys().next().value;
|
|
6566
|
+
if (oldest !== void 0) this.map.delete(oldest);
|
|
6567
|
+
}
|
|
6568
|
+
this.map.set(key, value);
|
|
6569
|
+
}
|
|
6570
|
+
get size() {
|
|
6571
|
+
return this.map.size;
|
|
6572
|
+
}
|
|
6573
|
+
clear() {
|
|
6574
|
+
this.map.clear();
|
|
6575
|
+
}
|
|
6576
|
+
};
|
|
6577
|
+
var TtlLruCache = class {
|
|
6578
|
+
constructor(limit, ttlMs) {
|
|
6579
|
+
this.ttlMs = ttlMs;
|
|
6580
|
+
this.inner = new LruCache(limit);
|
|
6581
|
+
}
|
|
6582
|
+
ttlMs;
|
|
6583
|
+
inner;
|
|
6584
|
+
get(key) {
|
|
6585
|
+
const e = this.inner.get(key);
|
|
6586
|
+
if (!e) return void 0;
|
|
6587
|
+
if (e.expiresAt <= Date.now()) return void 0;
|
|
6588
|
+
return e.v;
|
|
6589
|
+
}
|
|
6590
|
+
set(key, value) {
|
|
6591
|
+
this.inner.set(key, { v: value, expiresAt: Date.now() + this.ttlMs });
|
|
6592
|
+
}
|
|
6593
|
+
clear() {
|
|
6594
|
+
this.inner.clear();
|
|
6595
|
+
}
|
|
6596
|
+
};
|
|
6597
|
+
|
|
6598
|
+
// src/tokenizer.ts
|
|
4798
6599
|
function buildByteToChar() {
|
|
4799
6600
|
const result = new Array(256);
|
|
4800
6601
|
const bs = [];
|
|
@@ -4897,10 +6698,13 @@ function byteLevelEncode(s, byteToChar) {
|
|
|
4897
6698
|
for (let i = 0; i < bytes.length; i++) out += byteToChar[bytes[i]];
|
|
4898
6699
|
return out;
|
|
4899
6700
|
}
|
|
6701
|
+
var bpeCache = new LruCache(8192);
|
|
4900
6702
|
function bpeEncode(piece, mergeRank) {
|
|
4901
6703
|
if (piece.length <= 1) return piece ? [piece] : [];
|
|
4902
|
-
|
|
4903
|
-
|
|
6704
|
+
const cached2 = bpeCache.get(piece);
|
|
6705
|
+
if (cached2 !== void 0) return cached2;
|
|
6706
|
+
const word = Array.from(piece);
|
|
6707
|
+
while (word.length > 1) {
|
|
4904
6708
|
let bestIdx = -1;
|
|
4905
6709
|
let bestRank = Number.POSITIVE_INFINITY;
|
|
4906
6710
|
for (let i = 0; i < word.length - 1; i++) {
|
|
@@ -4913,13 +6717,9 @@ function bpeEncode(piece, mergeRank) {
|
|
|
4913
6717
|
}
|
|
4914
6718
|
}
|
|
4915
6719
|
if (bestIdx < 0) break;
|
|
4916
|
-
word
|
|
4917
|
-
...word.slice(0, bestIdx),
|
|
4918
|
-
word[bestIdx] + word[bestIdx + 1],
|
|
4919
|
-
...word.slice(bestIdx + 2)
|
|
4920
|
-
];
|
|
4921
|
-
if (word.length === 1) break;
|
|
6720
|
+
word.splice(bestIdx, 2, word[bestIdx] + word[bestIdx + 1]);
|
|
4922
6721
|
}
|
|
6722
|
+
bpeCache.set(piece, word);
|
|
4923
6723
|
return word;
|
|
4924
6724
|
}
|
|
4925
6725
|
function encode(text) {
|
|
@@ -4974,10 +6774,6 @@ function countTokensBounded(text, maxChars = DEFAULT_BOUNDED_TOKENIZE_CHARS) {
|
|
|
4974
6774
|
const ratio = sampleChars > 0 ? sampleTokens / sampleChars : 0.3;
|
|
4975
6775
|
return Math.max(1, Math.ceil(text.length * ratio));
|
|
4976
6776
|
}
|
|
4977
|
-
var BOS = "<\uFF5Cbegin\u2581of\u2581sentence\uFF5C>";
|
|
4978
|
-
var EOS = "<\uFF5Cend\u2581of\u2581sentence\uFF5C>";
|
|
4979
|
-
var USER_SP = "<\uFF5CUser\uFF5C>";
|
|
4980
|
-
var ASSISTANT_SP = "<\uFF5CAssistant\uFF5C>";
|
|
4981
6777
|
var THINK_START = "<think>";
|
|
4982
6778
|
var THINK_END = "</think>";
|
|
4983
6779
|
var DSML = "\uFF5CDSML\uFF5C";
|
|
@@ -4986,7 +6782,6 @@ var TC_END = `</${DSML}tool_calls>`;
|
|
|
4986
6782
|
var INVOKE_BEGIN = `<${DSML}invoke name="`;
|
|
4987
6783
|
var INVOKE_END = `</${DSML}invoke>`;
|
|
4988
6784
|
var PARAM_TEMPLATE = `<${DSML}parameter name="{key}" string="{is_str}">{value}</${DSML}parameter>`;
|
|
4989
|
-
var TOOL_RESULT_TEMPLATE = "<tool_result>{content}</tool_result>";
|
|
4990
6785
|
var toolsTemplateCache = /* @__PURE__ */ new WeakMap();
|
|
4991
6786
|
function renderTools(tools) {
|
|
4992
6787
|
const cached2 = toolsTemplateCache.get(tools);
|
|
@@ -5023,142 +6818,53 @@ You MUST strictly follow the above defined tool name and parameter schemas to in
|
|
|
5023
6818
|
toolsTemplateCache.set(tools, rendered);
|
|
5024
6819
|
return rendered;
|
|
5025
6820
|
}
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
).join("\n");
|
|
5036
|
-
}
|
|
5037
|
-
function renderToolCallsDsml(toolCalls) {
|
|
5038
|
-
const invokes = toolCalls.map((tc) => {
|
|
5039
|
-
const name = tc.function?.name ?? "";
|
|
5040
|
-
const argsJson = tc.function?.arguments ?? "{}";
|
|
5041
|
-
return `${INVOKE_BEGIN + name}">
|
|
5042
|
-
${encodeArgumentsToDsml(argsJson)}
|
|
5043
|
-
${INVOKE_END}`;
|
|
5044
|
-
}).join("\n");
|
|
5045
|
-
return `
|
|
5046
|
-
|
|
5047
|
-
${TC_BEGIN}
|
|
5048
|
-
${invokes}
|
|
5049
|
-
${TC_END}`;
|
|
6821
|
+
var PER_MESSAGE_TEMPLATE_TOKENS = 6;
|
|
6822
|
+
var contentTokenCache = new LruCache(4096);
|
|
6823
|
+
function cachedBoundedTokens(s) {
|
|
6824
|
+
if (s.length === 0) return 0;
|
|
6825
|
+
const cached2 = contentTokenCache.get(s);
|
|
6826
|
+
if (cached2 !== void 0) return cached2;
|
|
6827
|
+
const n = countTokensBounded(s);
|
|
6828
|
+
contentTokenCache.set(s, n);
|
|
6829
|
+
return n;
|
|
5050
6830
|
}
|
|
5051
|
-
function
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
if (role === "tool") {
|
|
5056
|
-
const toolBlock = TOOL_RESULT_TEMPLATE.replace("{content}", msg.content ?? "");
|
|
5057
|
-
const last = merged[merged.length - 1];
|
|
5058
|
-
if (last && last.role === "user" && Array.isArray(last._toolBlocks) && Array.isArray(last._textParts)) {
|
|
5059
|
-
last._toolBlocks.push(toolBlock);
|
|
5060
|
-
last.content = `${last._textParts.join("\n\n")}
|
|
5061
|
-
|
|
5062
|
-
${last._toolBlocks.join("\n")}`.replace(
|
|
5063
|
-
/^\n\n/,
|
|
5064
|
-
""
|
|
5065
|
-
);
|
|
5066
|
-
} else {
|
|
5067
|
-
merged.push({
|
|
5068
|
-
role: "user",
|
|
5069
|
-
content: toolBlock,
|
|
5070
|
-
_textParts: [],
|
|
5071
|
-
_toolBlocks: [toolBlock]
|
|
5072
|
-
});
|
|
5073
|
-
}
|
|
5074
|
-
} else if (role === "user") {
|
|
5075
|
-
const text = msg.content ?? "";
|
|
5076
|
-
const last = merged[merged.length - 1];
|
|
5077
|
-
if (last && last.role === "user" && Array.isArray(last._toolBlocks) && Array.isArray(last._textParts)) {
|
|
5078
|
-
last._textParts.push(text);
|
|
5079
|
-
last.content = `${last._textParts.join("\n\n")}
|
|
5080
|
-
|
|
5081
|
-
${last._toolBlocks.join("\n\n")}`.replace(
|
|
5082
|
-
/^\n\n/,
|
|
5083
|
-
""
|
|
5084
|
-
);
|
|
5085
|
-
} else {
|
|
5086
|
-
merged.push({
|
|
5087
|
-
...msg,
|
|
5088
|
-
role: "user",
|
|
5089
|
-
content: text,
|
|
5090
|
-
_textParts: [text],
|
|
5091
|
-
_toolBlocks: []
|
|
5092
|
-
});
|
|
5093
|
-
}
|
|
5094
|
-
} else {
|
|
5095
|
-
merged.push({ ...msg });
|
|
5096
|
-
}
|
|
5097
|
-
}
|
|
5098
|
-
for (const m of merged) {
|
|
5099
|
-
m._textParts = void 0;
|
|
5100
|
-
m._toolBlocks = void 0;
|
|
6831
|
+
function tokensForMessage(m, dropThisReasoning) {
|
|
6832
|
+
let n = 0;
|
|
6833
|
+
if (typeof m.content === "string" && m.content.length > 0) {
|
|
6834
|
+
n += cachedBoundedTokens(m.content);
|
|
5101
6835
|
}
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
let lastUserIdx = -1;
|
|
5106
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
5107
|
-
const role = messages[i].role;
|
|
5108
|
-
if (role === "user" || role === "developer") {
|
|
5109
|
-
lastUserIdx = i;
|
|
5110
|
-
break;
|
|
6836
|
+
if (m.role === "assistant") {
|
|
6837
|
+
if (!dropThisReasoning && typeof m.reasoning_content === "string" && m.reasoning_content.length > 0) {
|
|
6838
|
+
n += cachedBoundedTokens(m.reasoning_content);
|
|
5111
6839
|
}
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
for (let i = 0; i < messages.length; i++) {
|
|
5116
|
-
const msg = messages[i];
|
|
5117
|
-
if (i < lastUserIdx && msg.role === "developer") continue;
|
|
5118
|
-
if (i < lastUserIdx && msg.role === "assistant") {
|
|
5119
|
-
result.push({ ...msg, reasoning_content: null });
|
|
5120
|
-
} else {
|
|
5121
|
-
result.push(msg);
|
|
6840
|
+
const tcs = m.tool_calls;
|
|
6841
|
+
if (Array.isArray(tcs) && tcs.length > 0) {
|
|
6842
|
+
n += cachedBoundedTokens(JSON.stringify(tcs));
|
|
5122
6843
|
}
|
|
5123
6844
|
}
|
|
5124
|
-
return
|
|
6845
|
+
return n;
|
|
5125
6846
|
}
|
|
5126
|
-
function
|
|
5127
|
-
if (messages.length === 0) return
|
|
5128
|
-
let
|
|
6847
|
+
function estimateConversationTokens(messages, drop_thinking = false) {
|
|
6848
|
+
if (messages.length === 0) return 0;
|
|
6849
|
+
let lastUserOrDev = -1;
|
|
5129
6850
|
if (drop_thinking) {
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
const msg = merged[i];
|
|
5136
|
-
const role = msg.role ?? "user";
|
|
5137
|
-
const nextRole = i + 1 < merged.length ? merged[i + 1].role ?? "user" : null;
|
|
5138
|
-
if (role === "system") {
|
|
5139
|
-
prompt += msg.content ?? "";
|
|
5140
|
-
} else if (role === "user") {
|
|
5141
|
-
prompt += USER_SP + (msg.content ?? "");
|
|
5142
|
-
if (nextRole === "assistant" || nextRole === null) {
|
|
5143
|
-
prompt += ASSISTANT_SP + THINK_END;
|
|
5144
|
-
}
|
|
5145
|
-
} else if (role === "assistant") {
|
|
5146
|
-
if (msg.reasoning_content) {
|
|
5147
|
-
prompt += THINK_START + msg.reasoning_content + THINK_END;
|
|
5148
|
-
}
|
|
5149
|
-
if (msg.content) prompt += msg.content;
|
|
5150
|
-
const tcs = msg.tool_calls;
|
|
5151
|
-
if (Array.isArray(tcs) && tcs.length > 0) {
|
|
5152
|
-
prompt += renderToolCallsDsml(tcs);
|
|
6851
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
6852
|
+
const r = messages[i].role;
|
|
6853
|
+
if (r === "user" || r === "developer") {
|
|
6854
|
+
lastUserOrDev = i;
|
|
6855
|
+
break;
|
|
5153
6856
|
}
|
|
5154
|
-
prompt += EOS;
|
|
5155
6857
|
}
|
|
5156
6858
|
}
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
6859
|
+
let total = 2;
|
|
6860
|
+
for (let i = 0; i < messages.length; i++) {
|
|
6861
|
+
const m = messages[i];
|
|
6862
|
+
if (drop_thinking && i < lastUserOrDev && m.role === "developer") continue;
|
|
6863
|
+
total += PER_MESSAGE_TEMPLATE_TOKENS;
|
|
6864
|
+
const dropReasoning = drop_thinking && i < lastUserOrDev && m.role === "assistant";
|
|
6865
|
+
total += tokensForMessage(m, dropReasoning);
|
|
6866
|
+
}
|
|
6867
|
+
return total;
|
|
5162
6868
|
}
|
|
5163
6869
|
function estimateRequestTokens(messages, toolSpecs, drop_thinking = false) {
|
|
5164
6870
|
let total = estimateConversationTokens(messages, drop_thinking);
|
|
@@ -5236,6 +6942,81 @@ function setByPath(target, path2, value) {
|
|
|
5236
6942
|
cur[path2[path2.length - 1]] = value;
|
|
5237
6943
|
}
|
|
5238
6944
|
|
|
6945
|
+
// src/tools/truncated-result-saver.ts
|
|
6946
|
+
import { randomUUID } from "crypto";
|
|
6947
|
+
import {
|
|
6948
|
+
chmodSync as chmodSync2,
|
|
6949
|
+
existsSync as existsSync3,
|
|
6950
|
+
mkdirSync as mkdirSync2,
|
|
6951
|
+
readdirSync,
|
|
6952
|
+
rmSync,
|
|
6953
|
+
statSync,
|
|
6954
|
+
writeFileSync as writeFileSync2
|
|
6955
|
+
} from "fs";
|
|
6956
|
+
import { homedir as homedir3 } from "os";
|
|
6957
|
+
import { join as join4, relative, resolve as resolve2 } from "path";
|
|
6958
|
+
var TRUNCATED_DIR = "truncated-results";
|
|
6959
|
+
var DEFAULT_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
6960
|
+
function sanitizeToolName(name) {
|
|
6961
|
+
return name.replace(/[^\w\-]/g, "_").slice(0, 48) || "unknown";
|
|
6962
|
+
}
|
|
6963
|
+
function storageDir(rootDir) {
|
|
6964
|
+
const base = rootDir ? join4(resolve2(rootDir), ".reasonix") : join4(homedir3(), ".reasonix");
|
|
6965
|
+
return join4(base, TRUNCATED_DIR);
|
|
6966
|
+
}
|
|
6967
|
+
function resultFilename(toolName) {
|
|
6968
|
+
const ts = Date.now().toString();
|
|
6969
|
+
const suffix = randomUUID().slice(0, 8);
|
|
6970
|
+
const safeName = sanitizeToolName(toolName);
|
|
6971
|
+
return `${ts}-${suffix}-${safeName}.txt`;
|
|
6972
|
+
}
|
|
6973
|
+
function saveTruncatedResult(content, toolName, rootDir) {
|
|
6974
|
+
cleanupOldResults(rootDir);
|
|
6975
|
+
const dir = storageDir(rootDir);
|
|
6976
|
+
if (!existsSync3(dir)) {
|
|
6977
|
+
mkdirSync2(dir, { recursive: true });
|
|
6978
|
+
}
|
|
6979
|
+
const filename = resultFilename(toolName);
|
|
6980
|
+
const absPath = join4(dir, filename);
|
|
6981
|
+
writeFileSync2(absPath, content, "utf-8");
|
|
6982
|
+
try {
|
|
6983
|
+
chmodSync2(absPath, 384);
|
|
6984
|
+
} catch {
|
|
6985
|
+
}
|
|
6986
|
+
if (rootDir) {
|
|
6987
|
+
const absRoot = resolve2(rootDir);
|
|
6988
|
+
return relative(absRoot, absPath).replaceAll("\\", "/");
|
|
6989
|
+
}
|
|
6990
|
+
return absPath.replaceAll("\\", "/");
|
|
6991
|
+
}
|
|
6992
|
+
function cleanupOldResults(rootDir, maxAgeMs = DEFAULT_MAX_AGE_MS) {
|
|
6993
|
+
const dir = storageDir(rootDir);
|
|
6994
|
+
if (!existsSync3(dir)) return;
|
|
6995
|
+
const cutoff = Date.now() - maxAgeMs;
|
|
6996
|
+
let entries;
|
|
6997
|
+
try {
|
|
6998
|
+
entries = readdirSync(dir);
|
|
6999
|
+
} catch {
|
|
7000
|
+
return;
|
|
7001
|
+
}
|
|
7002
|
+
for (const entry of entries) {
|
|
7003
|
+
if (!entry.endsWith(".txt")) continue;
|
|
7004
|
+
const abs = join4(dir, entry);
|
|
7005
|
+
try {
|
|
7006
|
+
const st = statSync(abs);
|
|
7007
|
+
if (st.isFile() && st.mtimeMs < cutoff) {
|
|
7008
|
+
rmSync(abs);
|
|
7009
|
+
}
|
|
7010
|
+
} catch {
|
|
7011
|
+
}
|
|
7012
|
+
}
|
|
7013
|
+
}
|
|
7014
|
+
function shouldSkipSave(toolName, skipTruncationSave) {
|
|
7015
|
+
if (skipTruncationSave) return true;
|
|
7016
|
+
const alwaysSkip = /* @__PURE__ */ new Set(["get_env", "everything_get-env"]);
|
|
7017
|
+
return alwaysSkip.has(toolName);
|
|
7018
|
+
}
|
|
7019
|
+
|
|
5239
7020
|
// src/tools.ts
|
|
5240
7021
|
var ToolRegistry = class {
|
|
5241
7022
|
_tools = /* @__PURE__ */ new Map();
|
|
@@ -5413,7 +7194,20 @@ var ToolRegistry = class {
|
|
|
5413
7194
|
if (opts.maxResultChars !== void 0) {
|
|
5414
7195
|
clipped = truncateForModel(clipped, opts.maxResultChars);
|
|
5415
7196
|
}
|
|
5416
|
-
|
|
7197
|
+
if (clipped !== str && !shouldSkipSave(name, tool?.skipTruncationSave)) {
|
|
7198
|
+
const relPath = saveTruncatedResult(str, name, opts.rootDir ?? process.cwd());
|
|
7199
|
+
const note = `Full result saved at: ${relPath}`;
|
|
7200
|
+
let annotated = str;
|
|
7201
|
+
if (opts.maxResultTokens !== void 0) {
|
|
7202
|
+
annotated = truncateForModelByTokens(annotated, opts.maxResultTokens, note);
|
|
7203
|
+
}
|
|
7204
|
+
if (opts.maxResultChars !== void 0) {
|
|
7205
|
+
annotated = truncateForModel(annotated, opts.maxResultChars, note);
|
|
7206
|
+
}
|
|
7207
|
+
finalResult = annotated;
|
|
7208
|
+
} else {
|
|
7209
|
+
finalResult = clipped;
|
|
7210
|
+
}
|
|
5417
7211
|
} catch (err) {
|
|
5418
7212
|
const e = err;
|
|
5419
7213
|
if (typeof e.toToolResult === "function") {
|
|
@@ -5633,12 +7427,12 @@ async function waitForReady(ready, timeoutMs, serverName, signal) {
|
|
|
5633
7427
|
let timer;
|
|
5634
7428
|
let onAbort;
|
|
5635
7429
|
try {
|
|
5636
|
-
await new Promise((
|
|
7430
|
+
await new Promise((resolve16, reject) => {
|
|
5637
7431
|
ready.then(
|
|
5638
7432
|
() => {
|
|
5639
7433
|
if (settled) return;
|
|
5640
7434
|
settled = true;
|
|
5641
|
-
|
|
7435
|
+
resolve16();
|
|
5642
7436
|
},
|
|
5643
7437
|
(err) => {
|
|
5644
7438
|
if (settled) return;
|
|
@@ -5744,25 +7538,30 @@ function validateResultShape(result) {
|
|
|
5744
7538
|
}
|
|
5745
7539
|
}
|
|
5746
7540
|
}
|
|
5747
|
-
function truncateForModel(s, maxChars) {
|
|
7541
|
+
function truncateForModel(s, maxChars, extraNote) {
|
|
5748
7542
|
if (s.length <= maxChars) return s;
|
|
5749
7543
|
const tailBudget = Math.min(1024, Math.floor(maxChars * 0.1));
|
|
5750
7544
|
const headBudget = Math.max(0, maxChars - tailBudget);
|
|
5751
7545
|
const head = s.slice(0, headBudget);
|
|
5752
7546
|
const tail = s.slice(-tailBudget);
|
|
5753
7547
|
const dropped = s.length - head.length - tail.length;
|
|
7548
|
+
const note = extraNote ? ` \u2014 ${extraNote}` : "";
|
|
5754
7549
|
return `${head}
|
|
5755
7550
|
|
|
5756
|
-
[\u2026truncated ${dropped} chars \u2014 raise BridgeOptions.maxResultChars, or call the tool with a narrower scope (filter, head, pagination)\u2026]
|
|
7551
|
+
[\u2026truncated ${dropped} chars \u2014 raise BridgeOptions.maxResultChars, or call the tool with a narrower scope (filter, head, pagination)${note}\u2026]
|
|
5757
7552
|
|
|
5758
7553
|
${tail}`;
|
|
5759
7554
|
}
|
|
5760
|
-
function truncateForModelByTokens(s, maxTokens) {
|
|
7555
|
+
function truncateForModelByTokens(s, maxTokens, extraNote) {
|
|
5761
7556
|
if (maxTokens <= 0) return "";
|
|
5762
7557
|
if (s.length <= maxTokens) return s;
|
|
5763
7558
|
if (s.length <= maxTokens * 4) {
|
|
5764
|
-
const
|
|
5765
|
-
if (
|
|
7559
|
+
const est = countTokensBounded(s);
|
|
7560
|
+
if (Math.ceil(est * 1.15) <= maxTokens) return s;
|
|
7561
|
+
if (est <= maxTokens) {
|
|
7562
|
+
const tokens = countTokens(s);
|
|
7563
|
+
if (tokens <= maxTokens) return s;
|
|
7564
|
+
}
|
|
5766
7565
|
}
|
|
5767
7566
|
const markerOverhead = 48;
|
|
5768
7567
|
const contentBudget = Math.max(0, maxTokens - markerOverhead);
|
|
@@ -5778,9 +7577,10 @@ function truncateForModelByTokens(s, maxTokens) {
|
|
|
5778
7577
|
const ratio = sampleChars > 0 ? sampleTokens / sampleChars : 0.3;
|
|
5779
7578
|
const estTotalTokens = Math.ceil(s.length * ratio);
|
|
5780
7579
|
const droppedTokens = Math.max(0, estTotalTokens - sampleTokens);
|
|
7580
|
+
const note = extraNote ? ` \u2014 ${extraNote}` : "";
|
|
5781
7581
|
return `${head}
|
|
5782
7582
|
|
|
5783
|
-
[\u2026truncated ~${droppedTokens} tokens (${droppedChars} chars) \u2014 raise BridgeOptions.maxResultTokens, or call the tool with a narrower scope (filter, head, pagination)\u2026]
|
|
7583
|
+
[\u2026truncated ~${droppedTokens} tokens (${droppedChars} chars) \u2014 raise BridgeOptions.maxResultTokens, or call the tool with a narrower scope (filter, head, pagination)${note}\u2026]
|
|
5784
7584
|
|
|
5785
7585
|
${tail}`;
|
|
5786
7586
|
}
|
|
@@ -5822,7 +7622,7 @@ function blockToString(block) {
|
|
|
5822
7622
|
var COMPACTION_SUMMARY_MARKER = "[CONVERSATION HISTORY SUMMARY \u2014 earlier turns folded for context efficiency]\n\n";
|
|
5823
7623
|
|
|
5824
7624
|
// packages/core-utils/src/tildeify.ts
|
|
5825
|
-
import { homedir as
|
|
7625
|
+
import { homedir as homedir4 } from "os";
|
|
5826
7626
|
|
|
5827
7627
|
// src/loop/thinking.ts
|
|
5828
7628
|
function isThinkingModeModel(model) {
|
|
@@ -5862,19 +7662,19 @@ function buildSyntheticAssistantMessage(content, fallbackModel) {
|
|
|
5862
7662
|
import { execFileSync } from "child_process";
|
|
5863
7663
|
import {
|
|
5864
7664
|
appendFileSync,
|
|
5865
|
-
chmodSync as
|
|
5866
|
-
copyFileSync,
|
|
5867
|
-
existsSync as
|
|
5868
|
-
mkdirSync as
|
|
7665
|
+
chmodSync as chmodSync3,
|
|
7666
|
+
copyFileSync as copyFileSync2,
|
|
7667
|
+
existsSync as existsSync4,
|
|
7668
|
+
mkdirSync as mkdirSync3,
|
|
5869
7669
|
readFileSync as readFileSync4,
|
|
5870
|
-
readdirSync,
|
|
7670
|
+
readdirSync as readdirSync2,
|
|
5871
7671
|
renameSync as renameSync2,
|
|
5872
|
-
statSync,
|
|
5873
|
-
unlinkSync,
|
|
5874
|
-
writeFileSync as
|
|
7672
|
+
statSync as statSync2,
|
|
7673
|
+
unlinkSync as unlinkSync2,
|
|
7674
|
+
writeFileSync as writeFileSync3
|
|
5875
7675
|
} from "fs";
|
|
5876
|
-
import { homedir as
|
|
5877
|
-
import { dirname as dirname3, join as
|
|
7676
|
+
import { homedir as homedir5 } from "os";
|
|
7677
|
+
import { dirname as dirname3, join as join5, posix as posixPath, win32 as win32Path } from "path";
|
|
5878
7678
|
var SESSION_SIDECAR_EXTS = [
|
|
5879
7679
|
".events.jsonl",
|
|
5880
7680
|
".meta.json",
|
|
@@ -5883,10 +7683,10 @@ var SESSION_SIDECAR_EXTS = [
|
|
|
5883
7683
|
".jsonl.bak"
|
|
5884
7684
|
];
|
|
5885
7685
|
function sessionsDir() {
|
|
5886
|
-
return
|
|
7686
|
+
return join5(homedir5(), ".reasonix", "sessions");
|
|
5887
7687
|
}
|
|
5888
7688
|
function sessionPath(name) {
|
|
5889
|
-
return
|
|
7689
|
+
return join5(sessionsDir(), `${sanitizeName(name)}.jsonl`);
|
|
5890
7690
|
}
|
|
5891
7691
|
function sanitizeName(name) {
|
|
5892
7692
|
const cleaned = name.replace(/[^\w\-\u4e00-\u9fa5]/g, "_").slice(0, 64);
|
|
@@ -5897,7 +7697,7 @@ function timestampSuffix() {
|
|
|
5897
7697
|
}
|
|
5898
7698
|
function loadSessionMessages(name) {
|
|
5899
7699
|
const path2 = sessionPath(name);
|
|
5900
|
-
if (!
|
|
7700
|
+
if (!existsSync4(path2)) return [];
|
|
5901
7701
|
const live = readSessionMessages(path2);
|
|
5902
7702
|
if (live && (live.messages.length > 0 || !live.hadContent)) return live.messages;
|
|
5903
7703
|
const backup = readSessionMessages(sessionBackupPath(path2));
|
|
@@ -5924,33 +7724,43 @@ function readSessionMessages(path2) {
|
|
|
5924
7724
|
}
|
|
5925
7725
|
function appendSessionMessage(name, message) {
|
|
5926
7726
|
const path2 = sessionPath(name);
|
|
5927
|
-
|
|
7727
|
+
mkdirSync3(dirname3(path2), { recursive: true });
|
|
5928
7728
|
appendFileSync(path2, `${JSON.stringify(message)}
|
|
5929
7729
|
`, "utf8");
|
|
5930
7730
|
try {
|
|
5931
|
-
|
|
7731
|
+
chmodSync3(path2, 384);
|
|
5932
7732
|
} catch {
|
|
5933
7733
|
}
|
|
5934
7734
|
}
|
|
5935
7735
|
function listSessions(opts) {
|
|
5936
7736
|
const dir = sessionsDir();
|
|
5937
|
-
if (!
|
|
7737
|
+
if (!existsSync4(dir)) return [];
|
|
5938
7738
|
const want = opts?.workspaceFilter ? normalizeWorkspace(opts.workspaceFilter) : null;
|
|
7739
|
+
const legacyPrefix = want && opts?.includeLegacyWorkspaceMatches ? legacySessionPrefixForWorkspace(opts.workspaceFilter) : null;
|
|
5939
7740
|
try {
|
|
5940
|
-
const files =
|
|
7741
|
+
const files = readdirSync2(dir).filter(
|
|
5941
7742
|
(f) => f.endsWith(".jsonl") && !f.endsWith(".events.jsonl")
|
|
5942
7743
|
);
|
|
5943
7744
|
return files.flatMap((file) => {
|
|
5944
|
-
const path2 =
|
|
7745
|
+
const path2 = join5(dir, file);
|
|
5945
7746
|
const name = file.replace(/\.jsonl$/, "");
|
|
5946
7747
|
const meta = loadSessionMeta(name);
|
|
7748
|
+
let workspaceStatus;
|
|
5947
7749
|
if (want !== null) {
|
|
5948
|
-
if (typeof meta.workspace
|
|
5949
|
-
|
|
7750
|
+
if (typeof meta.workspace === "string") {
|
|
7751
|
+
if (normalizeWorkspace(meta.workspace) !== want) return [];
|
|
7752
|
+
workspaceStatus = "matched";
|
|
7753
|
+
} else if (legacyPrefix && name.startsWith(legacyPrefix)) {
|
|
7754
|
+
workspaceStatus = "legacy_missing_meta";
|
|
7755
|
+
} else {
|
|
7756
|
+
return [];
|
|
7757
|
+
}
|
|
5950
7758
|
}
|
|
5951
|
-
const stat2 =
|
|
7759
|
+
const stat2 = statSync2(path2);
|
|
5952
7760
|
const messageCount = countLines(path2);
|
|
5953
|
-
return [
|
|
7761
|
+
return [
|
|
7762
|
+
{ name, path: path2, size: stat2.size, messageCount, mtime: stat2.mtime, meta, workspaceStatus }
|
|
7763
|
+
];
|
|
5954
7764
|
}).sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
|
|
5955
7765
|
} catch {
|
|
5956
7766
|
return [];
|
|
@@ -5964,12 +7774,17 @@ function normalizeWorkspace(p, platform = process.platform) {
|
|
|
5964
7774
|
}
|
|
5965
7775
|
return posixPath.resolve(p);
|
|
5966
7776
|
}
|
|
7777
|
+
function legacySessionPrefixForWorkspace(workspace) {
|
|
7778
|
+
const normalized = normalizeWorkspace(workspace);
|
|
7779
|
+
const base = process.platform === "win32" ? win32Path.basename(normalized) : posixPath.basename(normalized);
|
|
7780
|
+
return `${sanitizeName(`code-${base}`)}-`;
|
|
7781
|
+
}
|
|
5967
7782
|
function metaPath(name) {
|
|
5968
|
-
return
|
|
7783
|
+
return join5(sessionsDir(), `${sanitizeName(name)}.meta.json`);
|
|
5969
7784
|
}
|
|
5970
7785
|
function loadSessionMeta(name) {
|
|
5971
7786
|
const p = metaPath(name);
|
|
5972
|
-
if (!
|
|
7787
|
+
if (!existsSync4(p)) return {};
|
|
5973
7788
|
try {
|
|
5974
7789
|
const raw = JSON.parse(readFileSync4(p, "utf8"));
|
|
5975
7790
|
return raw && typeof raw === "object" ? raw : {};
|
|
@@ -5981,10 +7796,10 @@ function patchSessionMeta(name, patch) {
|
|
|
5981
7796
|
const cur = loadSessionMeta(name);
|
|
5982
7797
|
const next = { ...cur, ...patch };
|
|
5983
7798
|
const p = metaPath(name);
|
|
5984
|
-
|
|
5985
|
-
|
|
7799
|
+
mkdirSync3(dirname3(p), { recursive: true });
|
|
7800
|
+
writeFileSync3(p, JSON.stringify(next), "utf8");
|
|
5986
7801
|
try {
|
|
5987
|
-
|
|
7802
|
+
chmodSync3(p, 384);
|
|
5988
7803
|
} catch {
|
|
5989
7804
|
}
|
|
5990
7805
|
return next;
|
|
@@ -5995,12 +7810,12 @@ function renameSession(oldName, newName) {
|
|
|
5995
7810
|
if (safeOld === safeNew) return false;
|
|
5996
7811
|
const oldJsonl = sessionPath(oldName);
|
|
5997
7812
|
const newJsonl = sessionPath(newName);
|
|
5998
|
-
if (!
|
|
7813
|
+
if (!existsSync4(oldJsonl) || existsSync4(newJsonl)) return false;
|
|
5999
7814
|
renameSync2(oldJsonl, newJsonl);
|
|
6000
7815
|
for (const ext of SESSION_SIDECAR_EXTS) {
|
|
6001
7816
|
const oldP = oldJsonl.replace(/\.jsonl$/, ext);
|
|
6002
7817
|
const newP = newJsonl.replace(/\.jsonl$/, ext);
|
|
6003
|
-
if (
|
|
7818
|
+
if (existsSync4(oldP)) {
|
|
6004
7819
|
try {
|
|
6005
7820
|
renameSync2(oldP, newP);
|
|
6006
7821
|
} catch {
|
|
@@ -6012,11 +7827,11 @@ function renameSession(oldName, newName) {
|
|
|
6012
7827
|
function deleteSession(name) {
|
|
6013
7828
|
const path2 = sessionPath(name);
|
|
6014
7829
|
try {
|
|
6015
|
-
|
|
7830
|
+
unlinkSync2(path2);
|
|
6016
7831
|
for (const ext of SESSION_SIDECAR_EXTS) {
|
|
6017
7832
|
const sidecar = path2.replace(/\.jsonl$/, ext);
|
|
6018
7833
|
try {
|
|
6019
|
-
|
|
7834
|
+
unlinkSync2(sidecar);
|
|
6020
7835
|
} catch {
|
|
6021
7836
|
}
|
|
6022
7837
|
}
|
|
@@ -6027,33 +7842,22 @@ function deleteSession(name) {
|
|
|
6027
7842
|
}
|
|
6028
7843
|
function rewriteSession(name, messages) {
|
|
6029
7844
|
const path2 = sessionPath(name);
|
|
6030
|
-
|
|
7845
|
+
mkdirSync3(dirname3(path2), { recursive: true });
|
|
6031
7846
|
const body = messages.map((m) => JSON.stringify(m)).join("\n");
|
|
6032
7847
|
const tmp = `${path2}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
chmodPrivate(
|
|
6037
|
-
if (existsSync3(path2) && statSync(path2).size > 0) {
|
|
6038
|
-
const backup = sessionBackupPath(path2);
|
|
6039
|
-
copyFileSync(path2, backup);
|
|
6040
|
-
chmodPrivate(backup);
|
|
6041
|
-
}
|
|
6042
|
-
renameSync2(tmp, path2);
|
|
6043
|
-
chmodPrivate(path2);
|
|
6044
|
-
} catch (err) {
|
|
6045
|
-
try {
|
|
6046
|
-
unlinkSync(tmp);
|
|
6047
|
-
} catch {
|
|
6048
|
-
}
|
|
6049
|
-
throw err;
|
|
7848
|
+
if (existsSync4(path2) && statSync2(path2).size > 0) {
|
|
7849
|
+
const backup = sessionBackupPath(path2);
|
|
7850
|
+
copyFileSync2(path2, backup);
|
|
7851
|
+
chmodPrivate(backup);
|
|
6050
7852
|
}
|
|
7853
|
+
atomicWriteSync(path2, body ? `${body}
|
|
7854
|
+
` : "", tmp);
|
|
6051
7855
|
}
|
|
6052
7856
|
function archiveSession(name) {
|
|
6053
7857
|
const path2 = sessionPath(name);
|
|
6054
|
-
if (!
|
|
7858
|
+
if (!existsSync4(path2)) return null;
|
|
6055
7859
|
try {
|
|
6056
|
-
if (
|
|
7860
|
+
if (statSync2(path2).size === 0) return null;
|
|
6057
7861
|
} catch {
|
|
6058
7862
|
return null;
|
|
6059
7863
|
}
|
|
@@ -6081,7 +7885,7 @@ function sessionBackupPath(path2) {
|
|
|
6081
7885
|
}
|
|
6082
7886
|
function chmodPrivate(path2) {
|
|
6083
7887
|
try {
|
|
6084
|
-
|
|
7888
|
+
chmodSync3(path2, 384);
|
|
6085
7889
|
} catch {
|
|
6086
7890
|
}
|
|
6087
7891
|
}
|
|
@@ -6544,8 +8348,88 @@ var InflightSet = class {
|
|
|
6544
8348
|
}
|
|
6545
8349
|
};
|
|
6546
8350
|
|
|
8351
|
+
// src/loop/dispatch.ts
|
|
8352
|
+
function readParallelMax() {
|
|
8353
|
+
const raw = Number.parseInt(process.env.REASONIX_PARALLEL_MAX ?? "", 10);
|
|
8354
|
+
return Number.isFinite(raw) && raw >= 1 ? Math.min(raw, 16) : 3;
|
|
8355
|
+
}
|
|
8356
|
+
function readDispatchSerial() {
|
|
8357
|
+
return (process.env.REASONIX_TOOL_DISPATCH ?? "auto").toLowerCase() === "serial";
|
|
8358
|
+
}
|
|
8359
|
+
async function* dispatchToolCallsChunked(repairedCalls, ctx) {
|
|
8360
|
+
const dispatchSerial = readDispatchSerial();
|
|
8361
|
+
const parallelMax = readParallelMax();
|
|
8362
|
+
let callIdx = 0;
|
|
8363
|
+
while (callIdx < repairedCalls.length) {
|
|
8364
|
+
const chunk = [];
|
|
8365
|
+
if (!dispatchSerial) {
|
|
8366
|
+
while (callIdx < repairedCalls.length && chunk.length < parallelMax && ctx.isParallelSafe(repairedCalls[callIdx]?.function?.name ?? "")) {
|
|
8367
|
+
chunk.push(repairedCalls[callIdx++]);
|
|
8368
|
+
}
|
|
8369
|
+
}
|
|
8370
|
+
if (chunk.length === 0) {
|
|
8371
|
+
chunk.push(repairedCalls[callIdx++]);
|
|
8372
|
+
}
|
|
8373
|
+
for (const call of chunk) {
|
|
8374
|
+
const callId = ctx.inflightIdFor(call);
|
|
8375
|
+
ctx.inflightAdd(callId);
|
|
8376
|
+
yield {
|
|
8377
|
+
turn: ctx.turn,
|
|
8378
|
+
role: "tool_start",
|
|
8379
|
+
content: "",
|
|
8380
|
+
toolName: call.function?.name ?? "",
|
|
8381
|
+
toolArgs: call.function?.arguments ?? "{}",
|
|
8382
|
+
callId
|
|
8383
|
+
};
|
|
8384
|
+
}
|
|
8385
|
+
const settled = await Promise.allSettled(chunk.map((c) => ctx.runOne(c, ctx.signal)));
|
|
8386
|
+
for (let k = 0; k < chunk.length; k++) {
|
|
8387
|
+
const call = chunk[k];
|
|
8388
|
+
const name = call.function?.name ?? "";
|
|
8389
|
+
const args = call.function?.arguments ?? "{}";
|
|
8390
|
+
const s = settled[k];
|
|
8391
|
+
let result;
|
|
8392
|
+
let preWarnings = [];
|
|
8393
|
+
let postWarnings = [];
|
|
8394
|
+
if (s.status === "fulfilled") {
|
|
8395
|
+
preWarnings = s.value.preWarnings;
|
|
8396
|
+
postWarnings = s.value.postWarnings;
|
|
8397
|
+
result = s.value.result;
|
|
8398
|
+
} else {
|
|
8399
|
+
const err = s.reason instanceof Error ? s.reason : new Error(String(s.reason));
|
|
8400
|
+
result = JSON.stringify({ error: `${err.name}: ${err.message}` });
|
|
8401
|
+
}
|
|
8402
|
+
for (const w of preWarnings) yield w;
|
|
8403
|
+
for (const w of postWarnings) yield w;
|
|
8404
|
+
const rateLimited = parseRateLimitedToolResult(result);
|
|
8405
|
+
if (rateLimited && !ctx.rateLimitState.shown) {
|
|
8406
|
+
ctx.rateLimitState.shown = true;
|
|
8407
|
+
yield {
|
|
8408
|
+
turn: ctx.turn,
|
|
8409
|
+
role: "warning",
|
|
8410
|
+
content: rateLimited.message
|
|
8411
|
+
};
|
|
8412
|
+
}
|
|
8413
|
+
ctx.appendAndPersist({
|
|
8414
|
+
role: "tool",
|
|
8415
|
+
tool_call_id: call.id ?? "",
|
|
8416
|
+
name,
|
|
8417
|
+
content: result
|
|
8418
|
+
});
|
|
8419
|
+
yield {
|
|
8420
|
+
turn: ctx.turn,
|
|
8421
|
+
role: "tool",
|
|
8422
|
+
content: result,
|
|
8423
|
+
toolName: name,
|
|
8424
|
+
toolArgs: args,
|
|
8425
|
+
callId: ctx.inflightIdFor(call)
|
|
8426
|
+
};
|
|
8427
|
+
}
|
|
8428
|
+
}
|
|
8429
|
+
}
|
|
8430
|
+
|
|
6547
8431
|
// src/loop/errors.ts
|
|
6548
|
-
function formatLoopError(err, probe) {
|
|
8432
|
+
function formatLoopError(err, probe, opts) {
|
|
6549
8433
|
const msg = err.message ?? "";
|
|
6550
8434
|
if (msg.includes("maximum context length")) {
|
|
6551
8435
|
const reqMatch = msg.match(/requested\s+(\d+)\s+tokens/);
|
|
@@ -6562,7 +8446,7 @@ function formatLoopError(err, probe) {
|
|
|
6562
8446
|
if (status === "422") return t("errors.badparam422", { inner });
|
|
6563
8447
|
if (status === "400") return t("errors.badrequest400", { inner });
|
|
6564
8448
|
if (status === "429") return t("errors.concurrency429", { inner });
|
|
6565
|
-
if (is5xxStatus(status)) return
|
|
8449
|
+
if (is5xxStatus(status)) return format5xx(status, probe, opts?.upstreamHost);
|
|
6566
8450
|
return msg;
|
|
6567
8451
|
}
|
|
6568
8452
|
function is5xxError(err) {
|
|
@@ -6574,15 +8458,40 @@ async function probeDeepSeekReachable(client, timeoutMs = 1500) {
|
|
|
6574
8458
|
const balance = await client.getBalance({ signal: AbortSignal.timeout(timeoutMs) });
|
|
6575
8459
|
return { reachable: balance !== null };
|
|
6576
8460
|
}
|
|
8461
|
+
function isDeepSeekHost(baseUrl) {
|
|
8462
|
+
if (!baseUrl) return false;
|
|
8463
|
+
try {
|
|
8464
|
+
const host = new URL(baseUrl).hostname.toLowerCase();
|
|
8465
|
+
return host === "api.deepseek.com";
|
|
8466
|
+
} catch {
|
|
8467
|
+
return false;
|
|
8468
|
+
}
|
|
8469
|
+
}
|
|
6577
8470
|
function is5xxStatus(status) {
|
|
6578
8471
|
return status === "500" || status === "502" || status === "503" || status === "504";
|
|
6579
8472
|
}
|
|
8473
|
+
function format5xx(status, probe, upstreamHost) {
|
|
8474
|
+
if (upstreamHost !== void 0 && !isDeepSeekHost(upstreamHost)) {
|
|
8475
|
+
return formatUpstream5xx(status, upstreamHost);
|
|
8476
|
+
}
|
|
8477
|
+
return formatDeepSeek5xx(status, probe);
|
|
8478
|
+
}
|
|
6580
8479
|
function formatDeepSeek5xx(status, probe) {
|
|
6581
8480
|
const head = t("errors.deepseek5xxHead", { status });
|
|
6582
8481
|
const probeNote = probe === void 0 ? "" : probe.reachable ? t("errors.deepseek5xxReachable") : t("errors.deepseek5xxUnreachable");
|
|
6583
8482
|
const action = probe?.reachable === false ? t("errors.deepseek5xxActionNetwork") : t("errors.deepseek5xxActionRetry");
|
|
6584
8483
|
return `${head}${probeNote}${action}`;
|
|
6585
8484
|
}
|
|
8485
|
+
function formatUpstream5xx(status, baseUrl) {
|
|
8486
|
+
let host = baseUrl;
|
|
8487
|
+
try {
|
|
8488
|
+
host = new URL(baseUrl).host || baseUrl;
|
|
8489
|
+
} catch {
|
|
8490
|
+
}
|
|
8491
|
+
const head = t("errors.upstream5xxHead", { status, host });
|
|
8492
|
+
const action = t("errors.upstream5xxActionRetry");
|
|
8493
|
+
return `${head}${action}`;
|
|
8494
|
+
}
|
|
6586
8495
|
function reasonPrefixFor(reason) {
|
|
6587
8496
|
if (reason === "aborted") return t("errors.reasonAborted");
|
|
6588
8497
|
if (reason === "context-guard") return t("errors.reasonContextGuard");
|
|
@@ -6695,6 +8604,56 @@ function shrinkOversizedToolResultsByTokens(messages, maxTokens) {
|
|
|
6695
8604
|
});
|
|
6696
8605
|
return { messages: out, healedCount, tokensSaved, charsSaved };
|
|
6697
8606
|
}
|
|
8607
|
+
function shrinkOversizedToolCallArgsByTokens(messages, maxTokens) {
|
|
8608
|
+
let healedCount = 0;
|
|
8609
|
+
let tokensSaved = 0;
|
|
8610
|
+
let charsSaved = 0;
|
|
8611
|
+
const out = messages.map((msg) => {
|
|
8612
|
+
if (msg.role !== "assistant" || !Array.isArray(msg.tool_calls)) return msg;
|
|
8613
|
+
let changed = false;
|
|
8614
|
+
const newCalls = msg.tool_calls.map((call) => {
|
|
8615
|
+
const args = call.function?.arguments;
|
|
8616
|
+
if (typeof args !== "string" || args.length <= maxTokens) return call;
|
|
8617
|
+
const beforeTokens = countTokensBounded(args);
|
|
8618
|
+
if (beforeTokens <= maxTokens) return call;
|
|
8619
|
+
const shrunk = shrinkJsonLongStrings(args);
|
|
8620
|
+
const afterTokens = countTokens(shrunk);
|
|
8621
|
+
if (afterTokens >= beforeTokens) return call;
|
|
8622
|
+
changed = true;
|
|
8623
|
+
healedCount += 1;
|
|
8624
|
+
tokensSaved += beforeTokens - afterTokens;
|
|
8625
|
+
charsSaved += args.length - shrunk.length;
|
|
8626
|
+
return { ...call, function: { ...call.function, arguments: shrunk } };
|
|
8627
|
+
});
|
|
8628
|
+
if (!changed) return msg;
|
|
8629
|
+
return { ...msg, tool_calls: newCalls };
|
|
8630
|
+
});
|
|
8631
|
+
return { messages: out, healedCount, tokensSaved, charsSaved };
|
|
8632
|
+
}
|
|
8633
|
+
function shrinkJsonLongStrings(jsonStr) {
|
|
8634
|
+
let parsed;
|
|
8635
|
+
try {
|
|
8636
|
+
parsed = JSON.parse(jsonStr);
|
|
8637
|
+
} catch {
|
|
8638
|
+
const head = jsonStr.slice(0, 200);
|
|
8639
|
+
return `${head}\u2026[shrunk: ${jsonStr.length} chars, unparsed]`;
|
|
8640
|
+
}
|
|
8641
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
8642
|
+
return jsonStr;
|
|
8643
|
+
}
|
|
8644
|
+
const LONG_THRESHOLD = 300;
|
|
8645
|
+
const input = parsed;
|
|
8646
|
+
const output = {};
|
|
8647
|
+
for (const [k, v] of Object.entries(input)) {
|
|
8648
|
+
if (typeof v === "string" && v.length > LONG_THRESHOLD) {
|
|
8649
|
+
const newlines = v.match(/\n/g)?.length ?? 0;
|
|
8650
|
+
output[k] = `[\u2026shrunk: ${v.length} chars, ${newlines} lines \u2014 tool already responded, see result]`;
|
|
8651
|
+
} else {
|
|
8652
|
+
output[k] = v;
|
|
8653
|
+
}
|
|
8654
|
+
}
|
|
8655
|
+
return JSON.stringify(output);
|
|
8656
|
+
}
|
|
6698
8657
|
|
|
6699
8658
|
// src/loop/healing.ts
|
|
6700
8659
|
var _stampSeq = 0;
|
|
@@ -6765,12 +8724,13 @@ function stampMissingReasoningForThinkingMode(messages, model) {
|
|
|
6765
8724
|
function healLoadedMessagesByTokens(messages, maxTokens) {
|
|
6766
8725
|
const shrunk = shrinkOversizedToolResultsByTokens(messages, maxTokens);
|
|
6767
8726
|
const paired = fixToolCallPairing(shrunk.messages);
|
|
6768
|
-
const
|
|
8727
|
+
const argsShrunk = shrinkOversizedToolCallArgsByTokens(paired.messages, maxTokens);
|
|
8728
|
+
const healedCount = shrunk.healedCount + argsShrunk.healedCount + paired.droppedAssistantCalls + paired.droppedStrayTools;
|
|
6769
8729
|
return {
|
|
6770
|
-
messages:
|
|
8730
|
+
messages: argsShrunk.messages,
|
|
6771
8731
|
healedCount,
|
|
6772
|
-
tokensSaved: shrunk.tokensSaved,
|
|
6773
|
-
charsSaved: shrunk.charsSaved
|
|
8732
|
+
tokensSaved: shrunk.tokensSaved + argsShrunk.tokensSaved,
|
|
8733
|
+
charsSaved: shrunk.charsSaved + argsShrunk.charsSaved
|
|
6774
8734
|
};
|
|
6775
8735
|
}
|
|
6776
8736
|
|
|
@@ -6789,6 +8749,112 @@ function* hookWarnings(outcomes, turn) {
|
|
|
6789
8749
|
}
|
|
6790
8750
|
}
|
|
6791
8751
|
|
|
8752
|
+
// src/loop/reasoning-retention.ts
|
|
8753
|
+
function hasToolCalls(msg) {
|
|
8754
|
+
return Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0;
|
|
8755
|
+
}
|
|
8756
|
+
function stripDroppableReasoningContent(messages) {
|
|
8757
|
+
let lastUser = -1;
|
|
8758
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
8759
|
+
if (messages[i].role === "user") {
|
|
8760
|
+
lastUser = i;
|
|
8761
|
+
break;
|
|
8762
|
+
}
|
|
8763
|
+
}
|
|
8764
|
+
if (lastUser < 0) {
|
|
8765
|
+
return { messages, prunedCount: 0, charsDropped: 0 };
|
|
8766
|
+
}
|
|
8767
|
+
let next = null;
|
|
8768
|
+
let prunedCount = 0;
|
|
8769
|
+
let charsDropped = 0;
|
|
8770
|
+
for (let i = 0; i < messages.length; i++) {
|
|
8771
|
+
const msg = messages[i];
|
|
8772
|
+
if (msg.role !== "assistant" || i > lastUser || hasToolCalls(msg) || !Object.hasOwn(msg, "reasoning_content")) {
|
|
8773
|
+
continue;
|
|
8774
|
+
}
|
|
8775
|
+
if (next === null) next = messages.slice();
|
|
8776
|
+
const { reasoning_content: dropped, ...replacement } = msg;
|
|
8777
|
+
if (typeof dropped === "string") charsDropped += dropped.length;
|
|
8778
|
+
next[i] = replacement;
|
|
8779
|
+
prunedCount += 1;
|
|
8780
|
+
}
|
|
8781
|
+
return {
|
|
8782
|
+
messages: next ?? messages,
|
|
8783
|
+
prunedCount,
|
|
8784
|
+
charsDropped
|
|
8785
|
+
};
|
|
8786
|
+
}
|
|
8787
|
+
|
|
8788
|
+
// src/loop/streaming.ts
|
|
8789
|
+
async function* streamModelResponse(opts) {
|
|
8790
|
+
const { client, model, messages, toolSpecs, signal, reasoningEffort, turn } = opts;
|
|
8791
|
+
let assistantContent = "";
|
|
8792
|
+
let reasoningContent = "";
|
|
8793
|
+
let usage = null;
|
|
8794
|
+
const callBuf = /* @__PURE__ */ new Map();
|
|
8795
|
+
const readyIndices = /* @__PURE__ */ new Set();
|
|
8796
|
+
for await (const chunk of client.stream({
|
|
8797
|
+
model,
|
|
8798
|
+
messages,
|
|
8799
|
+
tools: toolSpecs.length ? toolSpecs : void 0,
|
|
8800
|
+
signal,
|
|
8801
|
+
thinking: thinkingModeForModel(model),
|
|
8802
|
+
reasoningEffort
|
|
8803
|
+
})) {
|
|
8804
|
+
if (chunk.reasoningDelta) {
|
|
8805
|
+
reasoningContent += chunk.reasoningDelta;
|
|
8806
|
+
yield {
|
|
8807
|
+
turn,
|
|
8808
|
+
role: "assistant_delta",
|
|
8809
|
+
content: "",
|
|
8810
|
+
reasoningDelta: chunk.reasoningDelta
|
|
8811
|
+
};
|
|
8812
|
+
}
|
|
8813
|
+
if (chunk.contentDelta) {
|
|
8814
|
+
assistantContent += chunk.contentDelta;
|
|
8815
|
+
yield {
|
|
8816
|
+
turn,
|
|
8817
|
+
role: "assistant_delta",
|
|
8818
|
+
content: chunk.contentDelta
|
|
8819
|
+
};
|
|
8820
|
+
}
|
|
8821
|
+
if (chunk.toolCallDelta) {
|
|
8822
|
+
const d = chunk.toolCallDelta;
|
|
8823
|
+
const cur = callBuf.get(d.index) ?? {
|
|
8824
|
+
id: d.id,
|
|
8825
|
+
type: "function",
|
|
8826
|
+
function: { name: "", arguments: "" }
|
|
8827
|
+
};
|
|
8828
|
+
if (d.id) cur.id = d.id;
|
|
8829
|
+
if (d.name) cur.function.name = (cur.function.name ?? "") + d.name;
|
|
8830
|
+
if (d.argumentsDelta)
|
|
8831
|
+
cur.function.arguments = (cur.function.arguments ?? "") + d.argumentsDelta;
|
|
8832
|
+
callBuf.set(d.index, cur);
|
|
8833
|
+
if (!readyIndices.has(d.index) && cur.function.name && looksLikeCompleteJson(cur.function.arguments ?? "")) {
|
|
8834
|
+
readyIndices.add(d.index);
|
|
8835
|
+
}
|
|
8836
|
+
if (cur.function.name) {
|
|
8837
|
+
yield {
|
|
8838
|
+
turn,
|
|
8839
|
+
role: "tool_call_delta",
|
|
8840
|
+
content: "",
|
|
8841
|
+
toolName: cur.function.name,
|
|
8842
|
+
toolCallArgsChars: (cur.function.arguments ?? "").length,
|
|
8843
|
+
toolCallIndex: d.index,
|
|
8844
|
+
toolCallReadyCount: readyIndices.size
|
|
8845
|
+
};
|
|
8846
|
+
}
|
|
8847
|
+
}
|
|
8848
|
+
if (chunk.usage) usage = chunk.usage;
|
|
8849
|
+
}
|
|
8850
|
+
return {
|
|
8851
|
+
assistantContent,
|
|
8852
|
+
reasoningContent,
|
|
8853
|
+
toolCalls: [...callBuf.values()],
|
|
8854
|
+
usage
|
|
8855
|
+
};
|
|
8856
|
+
}
|
|
8857
|
+
|
|
6792
8858
|
// src/memory/runtime.ts
|
|
6793
8859
|
import { createHash } from "crypto";
|
|
6794
8860
|
var ImmutablePrefix = class {
|
|
@@ -7254,6 +9320,10 @@ var MID_TURN_STEER_WRAPPER = "[Mid-turn steer queued by the user. Do not treat t
|
|
|
7254
9320
|
function formatSteerUserMessage(content) {
|
|
7255
9321
|
return [MID_TURN_STEER_WRAPPER, content].join("\n");
|
|
7256
9322
|
}
|
|
9323
|
+
function shrinkMessageForRetention(message) {
|
|
9324
|
+
if (message.role !== "assistant" || !Array.isArray(message.tool_calls)) return message;
|
|
9325
|
+
return shrinkOversizedToolCallArgsByTokens([message], DEFAULT_MAX_RESULT_TOKENS).messages[0] ?? message;
|
|
9326
|
+
}
|
|
7257
9327
|
var CacheFirstLoop = class {
|
|
7258
9328
|
client;
|
|
7259
9329
|
prefix;
|
|
@@ -7347,7 +9417,8 @@ var CacheFirstLoop = class {
|
|
|
7347
9417
|
const prior = loadSessionMessages(this.sessionName);
|
|
7348
9418
|
const shrunk = healLoadedMessagesByTokens(prior, DEFAULT_MAX_RESULT_TOKENS);
|
|
7349
9419
|
const stamped = stampMissingReasoningForThinkingMode(shrunk.messages, this.model);
|
|
7350
|
-
const
|
|
9420
|
+
const pruned = stripDroppableReasoningContent(stamped.messages);
|
|
9421
|
+
const messages = pruned.messages;
|
|
7351
9422
|
const healedCount = shrunk.healedCount + stamped.stampedCount;
|
|
7352
9423
|
const tokensSaved = shrunk.tokensSaved;
|
|
7353
9424
|
for (const msg of messages) this.log.append(msg);
|
|
@@ -7364,15 +9435,17 @@ var CacheFirstLoop = class {
|
|
|
7364
9435
|
lastPromptTokens: meta.lastPromptTokens
|
|
7365
9436
|
});
|
|
7366
9437
|
}
|
|
7367
|
-
if (healedCount > 0) {
|
|
9438
|
+
if (healedCount > 0 || pruned.prunedCount > 0) {
|
|
7368
9439
|
try {
|
|
7369
9440
|
rewriteSession(this.sessionName, messages);
|
|
7370
9441
|
} catch {
|
|
7371
9442
|
}
|
|
7372
|
-
|
|
7373
|
-
|
|
9443
|
+
if (healedCount > 0) {
|
|
9444
|
+
process.stderr.write(
|
|
9445
|
+
`\u25B8 session "${this.sessionName}": healed ${healedCount} entr${healedCount === 1 ? "y" : "ies"}${tokensSaved > 0 ? ` (shrunk ${tokensSaved.toLocaleString()} tokens of oversized tool output/arguments)` : " (dropped dangling tool_calls tail)"}. Rewrote session file.
|
|
7374
9446
|
`
|
|
7375
|
-
|
|
9447
|
+
);
|
|
9448
|
+
}
|
|
7376
9449
|
}
|
|
7377
9450
|
} else {
|
|
7378
9451
|
this.resumedMessageCount = 0;
|
|
@@ -7399,21 +9472,23 @@ var CacheFirstLoop = class {
|
|
|
7399
9472
|
return this.context.getLogTokens();
|
|
7400
9473
|
}
|
|
7401
9474
|
appendAndPersist(message) {
|
|
7402
|
-
|
|
9475
|
+
const retained = shrinkMessageForRetention(message);
|
|
9476
|
+
this.log.append(retained);
|
|
7403
9477
|
if (this.sessionName) {
|
|
7404
9478
|
try {
|
|
7405
|
-
appendSessionMessage(this.sessionName,
|
|
9479
|
+
appendSessionMessage(this.sessionName, retained);
|
|
7406
9480
|
} catch {
|
|
7407
9481
|
}
|
|
7408
9482
|
}
|
|
7409
9483
|
}
|
|
7410
9484
|
/** Swap the just-appended assistant entry — used by self-correction to restore the original tool_calls without dropping reasoning_content. */
|
|
7411
9485
|
replaceTailAssistantMessage(message) {
|
|
9486
|
+
const retained = shrinkMessageForRetention(message);
|
|
7412
9487
|
const entries = this.log.entries;
|
|
7413
9488
|
const tail = entries[entries.length - 1];
|
|
7414
9489
|
if (!tail || tail.role !== "assistant") return;
|
|
7415
9490
|
const kept = entries.slice(0, -1);
|
|
7416
|
-
kept.push(
|
|
9491
|
+
kept.push(retained);
|
|
7417
9492
|
this.log.compactInPlace(kept);
|
|
7418
9493
|
if (this.sessionName) {
|
|
7419
9494
|
try {
|
|
@@ -7439,6 +9514,8 @@ var CacheFirstLoop = class {
|
|
|
7439
9514
|
this.stats.reset();
|
|
7440
9515
|
this._turn = 0;
|
|
7441
9516
|
this._budgetWarned = false;
|
|
9517
|
+
this._steerQueue.length = 0;
|
|
9518
|
+
this._steerConsumed = false;
|
|
7442
9519
|
let systemRebuilt = false;
|
|
7443
9520
|
if (this._rebuildSystem) {
|
|
7444
9521
|
try {
|
|
@@ -7462,6 +9539,8 @@ var CacheFirstLoop = class {
|
|
|
7462
9539
|
this.log.compactInPlace([]);
|
|
7463
9540
|
this.scratch.reset();
|
|
7464
9541
|
this._inflight.clear();
|
|
9542
|
+
this._steerQueue.length = 0;
|
|
9543
|
+
this._steerConsumed = false;
|
|
7465
9544
|
this.sessionName = opts.sessionName;
|
|
7466
9545
|
if (this._rebuildSystem) {
|
|
7467
9546
|
try {
|
|
@@ -7539,7 +9618,8 @@ ${reason}`
|
|
|
7539
9618
|
signal,
|
|
7540
9619
|
maxResultTokens: DEFAULT_MAX_RESULT_TOKENS,
|
|
7541
9620
|
confirmationGate: this.confirmationGate,
|
|
7542
|
-
readTracker: this.readTracker
|
|
9621
|
+
readTracker: this.readTracker,
|
|
9622
|
+
rootDir: this.hookCwd
|
|
7543
9623
|
});
|
|
7544
9624
|
const postReport = await runHooks({
|
|
7545
9625
|
hooks: this.hooks,
|
|
@@ -7574,15 +9654,22 @@ ${reason}`
|
|
|
7574
9654
|
healActiveLogBeforeSend() {
|
|
7575
9655
|
const current = this.log.toMessages();
|
|
7576
9656
|
const healed = healLoadedMessages(current, DEFAULT_MAX_RESULT_CHARS);
|
|
7577
|
-
|
|
7578
|
-
|
|
9657
|
+
const argsShrunk = shrinkOversizedToolCallArgsByTokens(
|
|
9658
|
+
healed.messages,
|
|
9659
|
+
DEFAULT_MAX_RESULT_TOKENS
|
|
9660
|
+
);
|
|
9661
|
+
const pruned = stripDroppableReasoningContent(argsShrunk.messages);
|
|
9662
|
+
if (healed.healedCount === 0 && argsShrunk.healedCount === 0 && pruned.prunedCount === 0) {
|
|
9663
|
+
return current;
|
|
9664
|
+
}
|
|
9665
|
+
this.log.compactInPlace(pruned.messages);
|
|
7579
9666
|
if (this.sessionName) {
|
|
7580
9667
|
try {
|
|
7581
|
-
rewriteSession(this.sessionName,
|
|
9668
|
+
rewriteSession(this.sessionName, pruned.messages);
|
|
7582
9669
|
} catch {
|
|
7583
9670
|
}
|
|
7584
9671
|
}
|
|
7585
|
-
return
|
|
9672
|
+
return pruned.messages;
|
|
7586
9673
|
}
|
|
7587
9674
|
abort(opts = {}) {
|
|
7588
9675
|
if (opts.discardCurrentTurn) this._discardAbortRequested = true;
|
|
@@ -7692,7 +9779,7 @@ ${reason}`
|
|
|
7692
9779
|
const turnStartLogIndex = this.log.length;
|
|
7693
9780
|
this.appendAndPersist({ role: "user", content: userInput });
|
|
7694
9781
|
const toolSpecs = this.prefix.tools();
|
|
7695
|
-
|
|
9782
|
+
const rateLimitState = { shown: false };
|
|
7696
9783
|
{
|
|
7697
9784
|
const turnStart = this.context.estimateTurnStart(
|
|
7698
9785
|
this.buildMessages(),
|
|
@@ -7705,7 +9792,9 @@ ${reason}`
|
|
|
7705
9792
|
role: "status",
|
|
7706
9793
|
content: t("loop.turnStartFoldStatus")
|
|
7707
9794
|
};
|
|
7708
|
-
const result = await this.context.fold(this.model, {
|
|
9795
|
+
const result = await this.context.fold(this.model, {
|
|
9796
|
+
requireTailBoundary: true
|
|
9797
|
+
});
|
|
7709
9798
|
if (result.folded) {
|
|
7710
9799
|
this._foldedThisTurn = true;
|
|
7711
9800
|
yield {
|
|
@@ -7773,64 +9862,19 @@ ${reason}`
|
|
|
7773
9862
|
let usage = null;
|
|
7774
9863
|
try {
|
|
7775
9864
|
if (this.stream) {
|
|
7776
|
-
const
|
|
7777
|
-
|
|
7778
|
-
|
|
7779
|
-
for await (const chunk of this.client.stream({
|
|
7780
|
-
model: callModel,
|
|
9865
|
+
const result = yield* streamModelResponse({
|
|
9866
|
+
client: this.client,
|
|
9867
|
+
model: this.model,
|
|
7781
9868
|
messages,
|
|
7782
|
-
|
|
9869
|
+
toolSpecs,
|
|
7783
9870
|
signal,
|
|
7784
|
-
|
|
7785
|
-
|
|
7786
|
-
})
|
|
7787
|
-
|
|
7788
|
-
|
|
7789
|
-
|
|
7790
|
-
|
|
7791
|
-
role: "assistant_delta",
|
|
7792
|
-
content: "",
|
|
7793
|
-
reasoningDelta: chunk.reasoningDelta
|
|
7794
|
-
};
|
|
7795
|
-
}
|
|
7796
|
-
if (chunk.contentDelta) {
|
|
7797
|
-
assistantContent += chunk.contentDelta;
|
|
7798
|
-
yield {
|
|
7799
|
-
turn: this._turn,
|
|
7800
|
-
role: "assistant_delta",
|
|
7801
|
-
content: chunk.contentDelta
|
|
7802
|
-
};
|
|
7803
|
-
}
|
|
7804
|
-
if (chunk.toolCallDelta) {
|
|
7805
|
-
const d = chunk.toolCallDelta;
|
|
7806
|
-
const cur = callBuf.get(d.index) ?? {
|
|
7807
|
-
id: d.id,
|
|
7808
|
-
type: "function",
|
|
7809
|
-
function: { name: "", arguments: "" }
|
|
7810
|
-
};
|
|
7811
|
-
if (d.id) cur.id = d.id;
|
|
7812
|
-
if (d.name) cur.function.name = (cur.function.name ?? "") + d.name;
|
|
7813
|
-
if (d.argumentsDelta)
|
|
7814
|
-
cur.function.arguments = (cur.function.arguments ?? "") + d.argumentsDelta;
|
|
7815
|
-
callBuf.set(d.index, cur);
|
|
7816
|
-
if (!readyIndices.has(d.index) && cur.function.name && looksLikeCompleteJson(cur.function.arguments ?? "")) {
|
|
7817
|
-
readyIndices.add(d.index);
|
|
7818
|
-
}
|
|
7819
|
-
if (cur.function.name) {
|
|
7820
|
-
yield {
|
|
7821
|
-
turn: this._turn,
|
|
7822
|
-
role: "tool_call_delta",
|
|
7823
|
-
content: "",
|
|
7824
|
-
toolName: cur.function.name,
|
|
7825
|
-
toolCallArgsChars: (cur.function.arguments ?? "").length,
|
|
7826
|
-
toolCallIndex: d.index,
|
|
7827
|
-
toolCallReadyCount: readyIndices.size
|
|
7828
|
-
};
|
|
7829
|
-
}
|
|
7830
|
-
}
|
|
7831
|
-
if (chunk.usage) usage = chunk.usage;
|
|
7832
|
-
}
|
|
7833
|
-
toolCalls = [...callBuf.values()];
|
|
9871
|
+
reasoningEffort: this.reasoningEffort,
|
|
9872
|
+
turn: this._turn
|
|
9873
|
+
});
|
|
9874
|
+
assistantContent = result.assistantContent;
|
|
9875
|
+
reasoningContent = result.reasoningContent;
|
|
9876
|
+
toolCalls = result.toolCalls;
|
|
9877
|
+
usage = result.usage;
|
|
7834
9878
|
} else {
|
|
7835
9879
|
const callModel = this.model;
|
|
7836
9880
|
const resp = await this.client.chat({
|
|
@@ -7857,12 +9901,14 @@ ${reason}`
|
|
|
7857
9901
|
this._steerQueue.length = 0;
|
|
7858
9902
|
return;
|
|
7859
9903
|
}
|
|
7860
|
-
const
|
|
9904
|
+
const upstreamHost = this.client.baseUrl;
|
|
9905
|
+
const dsHost = isDeepSeekHost(upstreamHost);
|
|
9906
|
+
const probe = is5xxError(err) && dsHost ? await probeDeepSeekReachable(this.client) : void 0;
|
|
7861
9907
|
yield {
|
|
7862
9908
|
turn: this._turn,
|
|
7863
9909
|
role: "error",
|
|
7864
9910
|
content: "",
|
|
7865
|
-
error: formatLoopError(err, probe)
|
|
9911
|
+
error: formatLoopError(err, probe, { upstreamHost })
|
|
7866
9912
|
};
|
|
7867
9913
|
this._steerQueue.length = 0;
|
|
7868
9914
|
return;
|
|
@@ -7988,76 +10034,16 @@ ${reason}`
|
|
|
7988
10034
|
this._steerQueue.length = 0;
|
|
7989
10035
|
return;
|
|
7990
10036
|
}
|
|
7991
|
-
|
|
7992
|
-
|
|
7993
|
-
|
|
7994
|
-
|
|
7995
|
-
|
|
7996
|
-
|
|
7997
|
-
|
|
7998
|
-
|
|
7999
|
-
|
|
8000
|
-
|
|
8001
|
-
}
|
|
8002
|
-
if (chunk.length === 0) {
|
|
8003
|
-
chunk.push(repairedCalls[callIdx++]);
|
|
8004
|
-
}
|
|
8005
|
-
for (const call of chunk) {
|
|
8006
|
-
const callId = this.inflightIdFor(call);
|
|
8007
|
-
this._inflight.add(callId);
|
|
8008
|
-
yield {
|
|
8009
|
-
turn: this._turn,
|
|
8010
|
-
role: "tool_start",
|
|
8011
|
-
content: "",
|
|
8012
|
-
toolName: call.function?.name ?? "",
|
|
8013
|
-
toolArgs: call.function?.arguments ?? "{}",
|
|
8014
|
-
callId
|
|
8015
|
-
};
|
|
8016
|
-
}
|
|
8017
|
-
const settled = await Promise.allSettled(chunk.map((c) => this.runOneToolCall(c, signal)));
|
|
8018
|
-
for (let k = 0; k < chunk.length; k++) {
|
|
8019
|
-
const call = chunk[k];
|
|
8020
|
-
const name = call.function?.name ?? "";
|
|
8021
|
-
const args = call.function?.arguments ?? "{}";
|
|
8022
|
-
const s = settled[k];
|
|
8023
|
-
let result;
|
|
8024
|
-
let preWarnings = [];
|
|
8025
|
-
let postWarnings = [];
|
|
8026
|
-
if (s.status === "fulfilled") {
|
|
8027
|
-
preWarnings = s.value.preWarnings;
|
|
8028
|
-
postWarnings = s.value.postWarnings;
|
|
8029
|
-
result = s.value.result;
|
|
8030
|
-
} else {
|
|
8031
|
-
const err = s.reason instanceof Error ? s.reason : new Error(String(s.reason));
|
|
8032
|
-
result = JSON.stringify({ error: `${err.name}: ${err.message}` });
|
|
8033
|
-
}
|
|
8034
|
-
for (const w of preWarnings) yield w;
|
|
8035
|
-
for (const w of postWarnings) yield w;
|
|
8036
|
-
const rateLimited = parseRateLimitedToolResult(result);
|
|
8037
|
-
if (rateLimited && !rateLimitWarningShown) {
|
|
8038
|
-
rateLimitWarningShown = true;
|
|
8039
|
-
yield {
|
|
8040
|
-
turn: this._turn,
|
|
8041
|
-
role: "warning",
|
|
8042
|
-
content: rateLimited.message
|
|
8043
|
-
};
|
|
8044
|
-
}
|
|
8045
|
-
this.appendAndPersist({
|
|
8046
|
-
role: "tool",
|
|
8047
|
-
tool_call_id: call.id ?? "",
|
|
8048
|
-
name,
|
|
8049
|
-
content: result
|
|
8050
|
-
});
|
|
8051
|
-
yield {
|
|
8052
|
-
turn: this._turn,
|
|
8053
|
-
role: "tool",
|
|
8054
|
-
content: result,
|
|
8055
|
-
toolName: name,
|
|
8056
|
-
toolArgs: args,
|
|
8057
|
-
callId: this.inflightIdFor(call)
|
|
8058
|
-
};
|
|
8059
|
-
}
|
|
8060
|
-
}
|
|
10037
|
+
yield* dispatchToolCallsChunked(repairedCalls, {
|
|
10038
|
+
turn: this._turn,
|
|
10039
|
+
signal,
|
|
10040
|
+
isParallelSafe: (name) => this.tools.isParallelSafe(name),
|
|
10041
|
+
inflightIdFor: (call) => this.inflightIdFor(call),
|
|
10042
|
+
inflightAdd: (id) => this._inflight.add(id),
|
|
10043
|
+
runOne: (call, sig) => this.runOneToolCall(call, sig),
|
|
10044
|
+
appendAndPersist: (m) => this.appendAndPersist(m),
|
|
10045
|
+
rateLimitState
|
|
10046
|
+
});
|
|
8061
10047
|
}
|
|
8062
10048
|
}
|
|
8063
10049
|
summaryContext() {
|
|
@@ -8087,28 +10073,42 @@ function parsePositiveIntEnv(raw) {
|
|
|
8087
10073
|
}
|
|
8088
10074
|
|
|
8089
10075
|
// src/at-mentions.ts
|
|
8090
|
-
import { existsSync as
|
|
10076
|
+
import { existsSync as existsSync5, readFileSync as readFileSync6, readdirSync as readdirSync3, statSync as statSync3 } from "fs";
|
|
8091
10077
|
import { readdir, stat } from "fs/promises";
|
|
8092
|
-
import { isAbsolute as isAbsolute2, join as
|
|
10078
|
+
import { isAbsolute as isAbsolute2, join as join6, relative as relative2, resolve as resolve4 } from "path";
|
|
8093
10079
|
|
|
8094
10080
|
// src/gitignore.ts
|
|
8095
10081
|
import { readFileSync as readFileSync5 } from "fs";
|
|
8096
10082
|
import { readFile } from "fs/promises";
|
|
8097
10083
|
import path from "path";
|
|
8098
10084
|
import ignore from "ignore";
|
|
10085
|
+
var gitignoreCache = new TtlLruCache(256, 5e3);
|
|
10086
|
+
function buildIgnore(text) {
|
|
10087
|
+
return ignore().add(text);
|
|
10088
|
+
}
|
|
8099
10089
|
async function loadGitignoreAt(dirAbs) {
|
|
10090
|
+
const cached2 = gitignoreCache.get(dirAbs);
|
|
10091
|
+
if (cached2 !== void 0) return cached2;
|
|
10092
|
+
let result;
|
|
8100
10093
|
try {
|
|
8101
|
-
|
|
10094
|
+
result = buildIgnore(await readFile(path.join(dirAbs, ".gitignore"), "utf8"));
|
|
8102
10095
|
} catch {
|
|
8103
|
-
|
|
10096
|
+
result = null;
|
|
8104
10097
|
}
|
|
10098
|
+
gitignoreCache.set(dirAbs, result);
|
|
10099
|
+
return result;
|
|
8105
10100
|
}
|
|
8106
10101
|
function loadGitignoreAtSync(dirAbs) {
|
|
10102
|
+
const cached2 = gitignoreCache.get(dirAbs);
|
|
10103
|
+
if (cached2 !== void 0) return cached2;
|
|
10104
|
+
let result;
|
|
8107
10105
|
try {
|
|
8108
|
-
|
|
10106
|
+
result = buildIgnore(readFileSync5(path.join(dirAbs, ".gitignore"), "utf8"));
|
|
8109
10107
|
} catch {
|
|
8110
|
-
|
|
10108
|
+
result = null;
|
|
8111
10109
|
}
|
|
10110
|
+
gitignoreCache.set(dirAbs, result);
|
|
10111
|
+
return result;
|
|
8112
10112
|
}
|
|
8113
10113
|
function ignoredByLayers(layers, abs, isDir) {
|
|
8114
10114
|
for (const layer of layers) {
|
|
@@ -8144,7 +10144,7 @@ function listFilesSync(root, opts = {}) {
|
|
|
8144
10144
|
function listFilesWithStatsSync(root, opts = {}) {
|
|
8145
10145
|
const maxResults = Math.max(1, opts.maxResults ?? 2e3);
|
|
8146
10146
|
const ignoreDirs = new Set(opts.ignoreDirs ?? DEFAULT_PICKER_IGNORE_DIRS);
|
|
8147
|
-
const rootAbs =
|
|
10147
|
+
const rootAbs = resolve4(root);
|
|
8148
10148
|
const respectGi = opts.respectGitignore !== false;
|
|
8149
10149
|
const out = [];
|
|
8150
10150
|
const walk2 = (dirAbs, dirRel, layers) => {
|
|
@@ -8156,7 +10156,7 @@ function listFilesWithStatsSync(root, opts = {}) {
|
|
|
8156
10156
|
}
|
|
8157
10157
|
let entries;
|
|
8158
10158
|
try {
|
|
8159
|
-
entries =
|
|
10159
|
+
entries = readdirSync3(dirAbs, { withFileTypes: true });
|
|
8160
10160
|
} catch {
|
|
8161
10161
|
return;
|
|
8162
10162
|
}
|
|
@@ -8164,7 +10164,7 @@ function listFilesWithStatsSync(root, opts = {}) {
|
|
|
8164
10164
|
for (const ent of entries) {
|
|
8165
10165
|
if (out.length >= maxResults) return;
|
|
8166
10166
|
const relPath = dirRel ? `${dirRel}/${ent.name}` : ent.name;
|
|
8167
|
-
const absPath =
|
|
10167
|
+
const absPath = join6(dirAbs, ent.name);
|
|
8168
10168
|
if (ent.isDirectory()) {
|
|
8169
10169
|
if (ent.name.startsWith(".") || ignoreDirs.has(ent.name)) continue;
|
|
8170
10170
|
if (ignoredByLayers(effectiveLayers, absPath, true)) continue;
|
|
@@ -8173,14 +10173,14 @@ function listFilesWithStatsSync(root, opts = {}) {
|
|
|
8173
10173
|
if (ignoredByLayers(effectiveLayers, absPath, false)) continue;
|
|
8174
10174
|
let mtimeMs = 0;
|
|
8175
10175
|
try {
|
|
8176
|
-
mtimeMs =
|
|
10176
|
+
mtimeMs = statSync3(absPath).mtimeMs;
|
|
8177
10177
|
} catch {
|
|
8178
10178
|
}
|
|
8179
10179
|
out.push({ path: relPath, mtimeMs });
|
|
8180
10180
|
} else if (ent.isSymbolicLink()) {
|
|
8181
10181
|
let target = null;
|
|
8182
10182
|
try {
|
|
8183
|
-
target =
|
|
10183
|
+
target = statSync3(absPath);
|
|
8184
10184
|
} catch {
|
|
8185
10185
|
continue;
|
|
8186
10186
|
}
|
|
@@ -8208,7 +10208,7 @@ async function listFilesWithStatsAsync(root, opts = {}) {
|
|
|
8208
10208
|
async function walkFilesStream(root, opts) {
|
|
8209
10209
|
const ignoreDirs = new Set(opts.ignoreDirs ?? DEFAULT_PICKER_IGNORE_DIRS);
|
|
8210
10210
|
const respectGi = opts.respectGitignore !== false;
|
|
8211
|
-
const rootAbs =
|
|
10211
|
+
const rootAbs = resolve4(root);
|
|
8212
10212
|
const progressGap = Math.max(0, opts.progressIntervalMs ?? 100);
|
|
8213
10213
|
let scanned = 0;
|
|
8214
10214
|
let halted = false;
|
|
@@ -8244,7 +10244,7 @@ async function walkFilesStream(root, opts) {
|
|
|
8244
10244
|
const fileEnts = [];
|
|
8245
10245
|
for (const ent of entries) {
|
|
8246
10246
|
if (halted || opts.signal?.aborted) break;
|
|
8247
|
-
const absPath =
|
|
10247
|
+
const absPath = join6(dirAbs, ent.name);
|
|
8248
10248
|
if (ent.isDirectory()) {
|
|
8249
10249
|
if (ent.name.startsWith(".") || ignoreDirs.has(ent.name)) continue;
|
|
8250
10250
|
if (ignoredByLayers(effectiveLayers, absPath, true)) continue;
|
|
@@ -8267,10 +10267,10 @@ async function walkFilesStream(root, opts) {
|
|
|
8267
10267
|
return { scanned, cancelled: !!opts.signal?.aborted };
|
|
8268
10268
|
}
|
|
8269
10269
|
async function flushFiles(ents, dirAbs, dirRel, layers, emit) {
|
|
8270
|
-
const accepted = ents.filter((e) => !ignoredByLayers(layers,
|
|
10270
|
+
const accepted = ents.filter((e) => !ignoredByLayers(layers, join6(dirAbs, e.name), false));
|
|
8271
10271
|
const stats = await Promise.all(
|
|
8272
10272
|
accepted.map(
|
|
8273
|
-
(e) => stat(
|
|
10273
|
+
(e) => stat(join6(dirAbs, e.name)).then((s) => ({ mtimeMs: s.mtimeMs, isFile: s.isFile() })).catch(() => null)
|
|
8274
10274
|
)
|
|
8275
10275
|
);
|
|
8276
10276
|
for (let i = 0; i < accepted.length; i++) {
|
|
@@ -8283,13 +10283,17 @@ async function flushFiles(ents, dirAbs, dirRel, layers, emit) {
|
|
|
8283
10283
|
});
|
|
8284
10284
|
}
|
|
8285
10285
|
}
|
|
10286
|
+
var listDirectoryCache = new TtlLruCache(64, 5e3);
|
|
8286
10287
|
async function listDirectory(root, relDir, opts = {}) {
|
|
8287
10288
|
const ignoreDirs = new Set(opts.ignoreDirs ?? DEFAULT_PICKER_IGNORE_DIRS);
|
|
8288
10289
|
const respectGi = opts.respectGitignore !== false;
|
|
8289
|
-
const rootAbs =
|
|
8290
|
-
const dirAbs =
|
|
8291
|
-
const rel =
|
|
10290
|
+
const rootAbs = resolve4(root);
|
|
10291
|
+
const dirAbs = resolve4(rootAbs, relDir);
|
|
10292
|
+
const rel = relative2(rootAbs, dirAbs);
|
|
8292
10293
|
if (rel.startsWith("..") || isAbsolute2(rel)) return [];
|
|
10294
|
+
const cacheKey = `${dirAbs}\0${respectGi ? "g" : ""}\0${[...ignoreDirs].sort().join(",")}`;
|
|
10295
|
+
const cached2 = listDirectoryCache.get(cacheKey);
|
|
10296
|
+
if (cached2) return cached2;
|
|
8293
10297
|
const layers = [];
|
|
8294
10298
|
if (respectGi) {
|
|
8295
10299
|
const segs = rel ? rel.split(/[\\/]/) : [];
|
|
@@ -8297,7 +10301,7 @@ async function listDirectory(root, relDir, opts = {}) {
|
|
|
8297
10301
|
const ig = await loadGitignoreAt(cursor);
|
|
8298
10302
|
if (ig) layers.push({ dirAbs: cursor, ig });
|
|
8299
10303
|
for (const seg of segs) {
|
|
8300
|
-
cursor =
|
|
10304
|
+
cursor = join6(cursor, seg);
|
|
8301
10305
|
const igSeg = await loadGitignoreAt(cursor);
|
|
8302
10306
|
if (igSeg) layers.push({ dirAbs: cursor, ig: igSeg });
|
|
8303
10307
|
}
|
|
@@ -8312,7 +10316,7 @@ async function listDirectory(root, relDir, opts = {}) {
|
|
|
8312
10316
|
const dirs = [];
|
|
8313
10317
|
const files = [];
|
|
8314
10318
|
for (const ent of raw) {
|
|
8315
|
-
const absPath =
|
|
10319
|
+
const absPath = join6(dirAbs, ent.name);
|
|
8316
10320
|
if (ent.isDirectory()) {
|
|
8317
10321
|
if (ent.name.startsWith(".") || ignoreDirs.has(ent.name)) continue;
|
|
8318
10322
|
if (ignoredByLayers(layers, absPath, true)) continue;
|
|
@@ -8329,7 +10333,7 @@ async function listDirectory(root, relDir, opts = {}) {
|
|
|
8329
10333
|
}
|
|
8330
10334
|
const stats = await Promise.all(
|
|
8331
10335
|
files.map(
|
|
8332
|
-
(e) => stat(
|
|
10336
|
+
(e) => stat(join6(dirAbs, e.name)).then((s) => ({ mtimeMs: s.mtimeMs, isFile: s.isFile() })).catch(() => null)
|
|
8333
10337
|
)
|
|
8334
10338
|
);
|
|
8335
10339
|
const fileEntries = [];
|
|
@@ -8346,7 +10350,9 @@ async function listDirectory(root, relDir, opts = {}) {
|
|
|
8346
10350
|
}
|
|
8347
10351
|
dirs.sort((a, b) => a.name.localeCompare(b.name));
|
|
8348
10352
|
fileEntries.sort((a, b) => a.name.localeCompare(b.name));
|
|
8349
|
-
|
|
10353
|
+
const result = [...dirs, ...fileEntries];
|
|
10354
|
+
listDirectoryCache.set(cacheKey, result);
|
|
10355
|
+
return result;
|
|
8350
10356
|
}
|
|
8351
10357
|
function parseAtQuery(query) {
|
|
8352
10358
|
const normalized = query.replace(/\\/g, "/");
|
|
@@ -8451,8 +10457,8 @@ var AT_MENTION_PATTERN = /(?<=^|\s)@([\p{L}\p{N}_./\\-]+)/gu;
|
|
|
8451
10457
|
function expandAtMentions(text, rootDir, opts = {}) {
|
|
8452
10458
|
const maxBytes = opts.maxBytes ?? DEFAULT_AT_MENTION_MAX_BYTES;
|
|
8453
10459
|
const maxDirEntries = Math.max(1, opts.maxDirEntries ?? DEFAULT_AT_DIR_MAX_ENTRIES);
|
|
8454
|
-
const fs5 = opts.fs ??
|
|
8455
|
-
const root =
|
|
10460
|
+
const fs5 = opts.fs ?? defaultFs2;
|
|
10461
|
+
const root = resolve4(rootDir);
|
|
8456
10462
|
const seen = /* @__PURE__ */ new Map();
|
|
8457
10463
|
const expansions = [];
|
|
8458
10464
|
const dirListings = /* @__PURE__ */ new Map();
|
|
@@ -8499,8 +10505,8 @@ function resolveMention(rawPath, root, maxBytes, maxDirEntries, fs5, dirListings
|
|
|
8499
10505
|
if (isAbsolute2(rawPath)) {
|
|
8500
10506
|
return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "escape" };
|
|
8501
10507
|
}
|
|
8502
|
-
const resolved =
|
|
8503
|
-
const rel =
|
|
10508
|
+
const resolved = resolve4(root, rawPath);
|
|
10509
|
+
const rel = relative2(root, resolved);
|
|
8504
10510
|
if (rel.startsWith("..") || isAbsolute2(rel)) {
|
|
8505
10511
|
return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "escape" };
|
|
8506
10512
|
}
|
|
@@ -8529,31 +10535,31 @@ function resolveMention(rawPath, root, maxBytes, maxDirEntries, fs5, dirListings
|
|
|
8529
10535
|
return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "not-file" };
|
|
8530
10536
|
}
|
|
8531
10537
|
function readSafe(root, rawPath, fs5) {
|
|
8532
|
-
const resolved =
|
|
10538
|
+
const resolved = resolve4(root, rawPath);
|
|
8533
10539
|
try {
|
|
8534
10540
|
return fs5.read(resolved);
|
|
8535
10541
|
} catch {
|
|
8536
10542
|
return "(read failed)";
|
|
8537
10543
|
}
|
|
8538
10544
|
}
|
|
8539
|
-
var
|
|
8540
|
-
exists: (p) =>
|
|
10545
|
+
var defaultFs2 = {
|
|
10546
|
+
exists: (p) => existsSync5(p),
|
|
8541
10547
|
isFile: (p) => {
|
|
8542
10548
|
try {
|
|
8543
|
-
return
|
|
10549
|
+
return statSync3(p).isFile();
|
|
8544
10550
|
} catch {
|
|
8545
10551
|
return false;
|
|
8546
10552
|
}
|
|
8547
10553
|
},
|
|
8548
10554
|
isDir: (p) => {
|
|
8549
10555
|
try {
|
|
8550
|
-
return
|
|
10556
|
+
return statSync3(p).isDirectory();
|
|
8551
10557
|
} catch {
|
|
8552
10558
|
return false;
|
|
8553
10559
|
}
|
|
8554
10560
|
},
|
|
8555
10561
|
listDir: (dirAbs, root, max) => {
|
|
8556
|
-
const dirRel =
|
|
10562
|
+
const dirRel = relative2(root, dirAbs).split(/[\\/]/).join("/");
|
|
8557
10563
|
const walkCap = Math.max(max * 4, 5e3);
|
|
8558
10564
|
const all = listFilesSync(root, { maxResults: walkCap });
|
|
8559
10565
|
const prefix = dirRel ? `${dirRel}/` : "";
|
|
@@ -8565,7 +10571,7 @@ var defaultFs = {
|
|
|
8565
10571
|
},
|
|
8566
10572
|
size: (p) => {
|
|
8567
10573
|
try {
|
|
8568
|
-
return
|
|
10574
|
+
return statSync3(p).size;
|
|
8569
10575
|
} catch {
|
|
8570
10576
|
return 0;
|
|
8571
10577
|
}
|
|
@@ -8574,20 +10580,26 @@ var defaultFs = {
|
|
|
8574
10580
|
};
|
|
8575
10581
|
|
|
8576
10582
|
// src/memory/project.ts
|
|
8577
|
-
import { existsSync as
|
|
8578
|
-
import { basename, join as
|
|
10583
|
+
import { existsSync as existsSync6, readFileSync as readFileSync7, statSync as statSync4 } from "fs";
|
|
10584
|
+
import { basename, join as join7 } from "path";
|
|
8579
10585
|
var PROJECT_MEMORY_FILE = "REASONIX.md";
|
|
8580
|
-
var PROJECT_MEMORY_FILES = [
|
|
10586
|
+
var PROJECT_MEMORY_FILES = [
|
|
10587
|
+
"REASONIX.md",
|
|
10588
|
+
".claude/CLAUDE.md",
|
|
10589
|
+
"CLAUDE.md",
|
|
10590
|
+
"AGENTS.md",
|
|
10591
|
+
"AGENT.md"
|
|
10592
|
+
];
|
|
8581
10593
|
var PROJECT_MEMORY_MAX_CHARS = 8e3;
|
|
8582
10594
|
function findProjectMemoryPath(rootDir) {
|
|
8583
10595
|
for (const name of PROJECT_MEMORY_FILES) {
|
|
8584
|
-
const path2 =
|
|
8585
|
-
if (
|
|
10596
|
+
const path2 = join7(rootDir, name);
|
|
10597
|
+
if (existsSync6(path2)) return path2;
|
|
8586
10598
|
}
|
|
8587
10599
|
return null;
|
|
8588
10600
|
}
|
|
8589
10601
|
function resolveProjectMemoryWritePath(rootDir) {
|
|
8590
|
-
return findProjectMemoryPath(rootDir) ??
|
|
10602
|
+
return findProjectMemoryPath(rootDir) ?? join7(rootDir, PROJECT_MEMORY_FILE);
|
|
8591
10603
|
}
|
|
8592
10604
|
function readProjectMemory(rootDir) {
|
|
8593
10605
|
const path2 = findProjectMemoryPath(rootDir);
|
|
@@ -8631,15 +10643,15 @@ ${mem.content}
|
|
|
8631
10643
|
// src/memory/user.ts
|
|
8632
10644
|
import { createHash as createHash2 } from "crypto";
|
|
8633
10645
|
import {
|
|
8634
|
-
existsSync as
|
|
8635
|
-
mkdirSync as
|
|
10646
|
+
existsSync as existsSync8,
|
|
10647
|
+
mkdirSync as mkdirSync5,
|
|
8636
10648
|
readFileSync as readFileSync9,
|
|
8637
|
-
readdirSync as
|
|
8638
|
-
unlinkSync as
|
|
8639
|
-
writeFileSync as
|
|
10649
|
+
readdirSync as readdirSync5,
|
|
10650
|
+
unlinkSync as unlinkSync3,
|
|
10651
|
+
writeFileSync as writeFileSync5
|
|
8640
10652
|
} from "fs";
|
|
8641
|
-
import { homedir as
|
|
8642
|
-
import { join as
|
|
10653
|
+
import { homedir as homedir7 } from "os";
|
|
10654
|
+
import { join as join9, resolve as resolve6 } from "path";
|
|
8643
10655
|
|
|
8644
10656
|
// src/frontmatter.ts
|
|
8645
10657
|
var KEY_RE = /^([a-zA-Z_][a-zA-Z0-9_-]*):\s*(.*)$/;
|
|
@@ -8691,16 +10703,16 @@ function parseFrontmatter(raw) {
|
|
|
8691
10703
|
// src/skills.ts
|
|
8692
10704
|
import {
|
|
8693
10705
|
constants,
|
|
8694
|
-
existsSync as
|
|
8695
|
-
mkdirSync as
|
|
10706
|
+
existsSync as existsSync7,
|
|
10707
|
+
mkdirSync as mkdirSync4,
|
|
8696
10708
|
readFileSync as readFileSync8,
|
|
8697
|
-
readdirSync as
|
|
8698
|
-
statSync as
|
|
8699
|
-
writeFileSync as
|
|
10709
|
+
readdirSync as readdirSync4,
|
|
10710
|
+
statSync as statSync5,
|
|
10711
|
+
writeFileSync as writeFileSync4
|
|
8700
10712
|
} from "fs";
|
|
8701
10713
|
import { accessSync } from "fs";
|
|
8702
|
-
import { homedir as
|
|
8703
|
-
import { dirname as dirname4, isAbsolute as isAbsolute3, join as
|
|
10714
|
+
import { homedir as homedir6 } from "os";
|
|
10715
|
+
import { dirname as dirname4, isAbsolute as isAbsolute3, join as join8, resolve as resolve5 } from "path";
|
|
8704
10716
|
|
|
8705
10717
|
// src/prompt-fragments.ts
|
|
8706
10718
|
var TUI_FORMATTING_RULES = `Formatting (rendered in a TUI with a real markdown renderer):
|
|
@@ -8755,8 +10767,8 @@ var SkillStore = class {
|
|
|
8755
10767
|
disableBuiltins;
|
|
8756
10768
|
subagentModels;
|
|
8757
10769
|
constructor(opts = {}) {
|
|
8758
|
-
this.homeDir = opts.homeDir ??
|
|
8759
|
-
this.projectRoot = opts.projectRoot ?
|
|
10770
|
+
this.homeDir = opts.homeDir ?? homedir6();
|
|
10771
|
+
this.projectRoot = opts.projectRoot ? resolve5(opts.projectRoot) : void 0;
|
|
8760
10772
|
const baseDir = this.projectRoot ?? process.cwd();
|
|
8761
10773
|
this.customSkillPaths = dedupePaths(
|
|
8762
10774
|
opts.customSkillPaths?.map((p) => resolveCustomSkillPath(p, baseDir, this.homeDir)) ?? []
|
|
@@ -8773,22 +10785,22 @@ var SkillStore = class {
|
|
|
8773
10785
|
const out = [];
|
|
8774
10786
|
if (this.projectRoot) {
|
|
8775
10787
|
out.push({
|
|
8776
|
-
dir:
|
|
10788
|
+
dir: join8(this.projectRoot, ".reasonix", SKILLS_DIRNAME),
|
|
8777
10789
|
scope: "project"
|
|
8778
10790
|
});
|
|
8779
10791
|
out.push({
|
|
8780
|
-
dir:
|
|
10792
|
+
dir: join8(this.projectRoot, ".agents", SKILLS_DIRNAME),
|
|
8781
10793
|
scope: "project"
|
|
8782
10794
|
});
|
|
8783
10795
|
out.push({
|
|
8784
|
-
dir:
|
|
10796
|
+
dir: join8(this.projectRoot, ".claude", SKILLS_DIRNAME),
|
|
8785
10797
|
scope: "project"
|
|
8786
10798
|
});
|
|
8787
10799
|
}
|
|
8788
10800
|
for (const dir of this.customSkillPaths) out.push({ dir, scope: "custom" });
|
|
8789
|
-
out.push({ dir:
|
|
8790
|
-
out.push({ dir:
|
|
8791
|
-
out.push({ dir:
|
|
10801
|
+
out.push({ dir: join8(this.homeDir, ".reasonix", SKILLS_DIRNAME), scope: "global" });
|
|
10802
|
+
out.push({ dir: join8(this.homeDir, ".agents", SKILLS_DIRNAME), scope: "global" });
|
|
10803
|
+
out.push({ dir: join8(this.homeDir, ".claude", SKILLS_DIRNAME), scope: "global" });
|
|
8792
10804
|
return out.map((root, priority) => ({ ...root, priority, status: skillPathStatus(root.dir) }));
|
|
8793
10805
|
}
|
|
8794
10806
|
customRoots() {
|
|
@@ -8801,7 +10813,7 @@ var SkillStore = class {
|
|
|
8801
10813
|
if (status !== "ok") continue;
|
|
8802
10814
|
let entries;
|
|
8803
10815
|
try {
|
|
8804
|
-
entries =
|
|
10816
|
+
entries = readdirSync4(dir, { withFileTypes: true });
|
|
8805
10817
|
} catch {
|
|
8806
10818
|
continue;
|
|
8807
10819
|
}
|
|
@@ -8837,15 +10849,15 @@ var SkillStore = class {
|
|
|
8837
10849
|
if (scope === "project" && !this.projectRoot) {
|
|
8838
10850
|
return { error: "project scope requires a workspace \u2014 run from `reasonix code`" };
|
|
8839
10851
|
}
|
|
8840
|
-
const root = scope === "project" ?
|
|
8841
|
-
const flat =
|
|
8842
|
-
const folder =
|
|
8843
|
-
if (
|
|
10852
|
+
const root = scope === "project" ? join8(this.projectRoot ?? "", ".reasonix", SKILLS_DIRNAME) : join8(this.homeDir, ".reasonix", SKILLS_DIRNAME);
|
|
10853
|
+
const flat = join8(root, `${name}.md`);
|
|
10854
|
+
const folder = join8(root, name, SKILL_FILE);
|
|
10855
|
+
if (existsSync7(folder)) {
|
|
8844
10856
|
return { error: `skill "${name}" already exists at ${folder}` };
|
|
8845
10857
|
}
|
|
8846
|
-
|
|
10858
|
+
mkdirSync4(dirname4(flat), { recursive: true });
|
|
8847
10859
|
try {
|
|
8848
|
-
|
|
10860
|
+
writeFileSync4(flat, content, { encoding: "utf8", flag: "wx" });
|
|
8849
10861
|
} catch (err) {
|
|
8850
10862
|
if (err.code === "EEXIST") {
|
|
8851
10863
|
return { error: `skill "${name}" already exists at ${flat}` };
|
|
@@ -8859,12 +10871,12 @@ var SkillStore = class {
|
|
|
8859
10871
|
if (!isValidSkillName(name)) return null;
|
|
8860
10872
|
for (const { dir, scope, status } of this.roots()) {
|
|
8861
10873
|
if (status !== "ok") continue;
|
|
8862
|
-
const dirCandidate =
|
|
8863
|
-
if (
|
|
10874
|
+
const dirCandidate = join8(dir, name, SKILL_FILE);
|
|
10875
|
+
if (existsSync7(dirCandidate) && statSync5(dirCandidate).isFile()) {
|
|
8864
10876
|
return this.parse(dirCandidate, name, scope);
|
|
8865
10877
|
}
|
|
8866
|
-
const flatCandidate =
|
|
8867
|
-
if (
|
|
10878
|
+
const flatCandidate = join8(dir, `${name}.md`);
|
|
10879
|
+
if (existsSync7(flatCandidate) && statSync5(flatCandidate).isFile()) {
|
|
8868
10880
|
return this.parse(flatCandidate, name, scope);
|
|
8869
10881
|
}
|
|
8870
10882
|
}
|
|
@@ -8878,14 +10890,14 @@ var SkillStore = class {
|
|
|
8878
10890
|
readEntry(dir, scope, entry) {
|
|
8879
10891
|
if (entry.isDirectory()) {
|
|
8880
10892
|
if (!isValidSkillName(entry.name)) return null;
|
|
8881
|
-
const file =
|
|
8882
|
-
if (!
|
|
10893
|
+
const file = join8(dir, entry.name, SKILL_FILE);
|
|
10894
|
+
if (!existsSync7(file)) return null;
|
|
8883
10895
|
return this.parse(file, entry.name, scope);
|
|
8884
10896
|
}
|
|
8885
10897
|
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
8886
10898
|
const stem = entry.name.slice(0, -3);
|
|
8887
10899
|
if (!isValidSkillName(stem)) return null;
|
|
8888
|
-
return this.parse(
|
|
10900
|
+
return this.parse(join8(dir, entry.name), stem, scope);
|
|
8889
10901
|
}
|
|
8890
10902
|
return null;
|
|
8891
10903
|
}
|
|
@@ -8929,12 +10941,12 @@ function dedupePaths(paths) {
|
|
|
8929
10941
|
}
|
|
8930
10942
|
function resolveCustomSkillPath(path2, baseDir, homeDir) {
|
|
8931
10943
|
const trimmed = path2.trim();
|
|
8932
|
-
const expanded = trimmed === "~" ? homeDir : trimmed.startsWith("~/") || trimmed.startsWith("~\\") ?
|
|
8933
|
-
return
|
|
10944
|
+
const expanded = trimmed === "~" ? homeDir : trimmed.startsWith("~/") || trimmed.startsWith("~\\") ? join8(homeDir, trimmed.slice(2)) : trimmed;
|
|
10945
|
+
return resolve5(isAbsolute3(expanded) ? expanded : join8(baseDir, expanded));
|
|
8934
10946
|
}
|
|
8935
10947
|
function skillPathStatus(dir) {
|
|
8936
10948
|
try {
|
|
8937
|
-
const stat2 =
|
|
10949
|
+
const stat2 = statSync5(dir);
|
|
8938
10950
|
if (!stat2.isDirectory()) return "not-directory";
|
|
8939
10951
|
accessSync(dir, constants.R_OK);
|
|
8940
10952
|
return "ok";
|
|
@@ -9203,20 +11215,20 @@ function sanitizeMemoryName(raw) {
|
|
|
9203
11215
|
return trimmed;
|
|
9204
11216
|
}
|
|
9205
11217
|
function projectHash(rootDir) {
|
|
9206
|
-
const abs =
|
|
11218
|
+
const abs = resolve6(rootDir);
|
|
9207
11219
|
return createHash2("sha1").update(abs).digest("hex").slice(0, 16);
|
|
9208
11220
|
}
|
|
9209
11221
|
function scopeDir(opts) {
|
|
9210
11222
|
if (opts.scope === "global") {
|
|
9211
|
-
return
|
|
11223
|
+
return join9(opts.homeDir, USER_MEMORY_DIR, "global");
|
|
9212
11224
|
}
|
|
9213
11225
|
if (!opts.projectRoot) {
|
|
9214
11226
|
throw new Error("scope=project requires a projectRoot on MemoryStore");
|
|
9215
11227
|
}
|
|
9216
|
-
return
|
|
11228
|
+
return join9(opts.homeDir, USER_MEMORY_DIR, projectHash(opts.projectRoot));
|
|
9217
11229
|
}
|
|
9218
11230
|
function ensureDir(p) {
|
|
9219
|
-
if (!
|
|
11231
|
+
if (!existsSync8(p)) mkdirSync5(p, { recursive: true });
|
|
9220
11232
|
}
|
|
9221
11233
|
function formatFrontmatter(e) {
|
|
9222
11234
|
const lines = [
|
|
@@ -9252,8 +11264,8 @@ var MemoryStore = class {
|
|
|
9252
11264
|
homeDir;
|
|
9253
11265
|
projectRoot;
|
|
9254
11266
|
constructor(opts = {}) {
|
|
9255
|
-
this.homeDir = opts.homeDir ??
|
|
9256
|
-
this.projectRoot = opts.projectRoot ?
|
|
11267
|
+
this.homeDir = opts.homeDir ?? join9(homedir7(), ".reasonix");
|
|
11268
|
+
this.projectRoot = opts.projectRoot ? resolve6(opts.projectRoot) : void 0;
|
|
9257
11269
|
}
|
|
9258
11270
|
/** Directory this store writes `scope` files into, creating it if needed. */
|
|
9259
11271
|
dir(scope) {
|
|
@@ -9263,7 +11275,7 @@ var MemoryStore = class {
|
|
|
9263
11275
|
}
|
|
9264
11276
|
/** Absolute path to a memory file (no existence check). */
|
|
9265
11277
|
pathFor(scope, name) {
|
|
9266
|
-
return
|
|
11278
|
+
return join9(this.dir(scope), `${sanitizeMemoryName(name)}.md`);
|
|
9267
11279
|
}
|
|
9268
11280
|
/** True iff this store is configured with a project scope available. */
|
|
9269
11281
|
hasProjectScope() {
|
|
@@ -9271,11 +11283,11 @@ var MemoryStore = class {
|
|
|
9271
11283
|
}
|
|
9272
11284
|
loadIndex(scope) {
|
|
9273
11285
|
if (scope === "project" && !this.projectRoot) return null;
|
|
9274
|
-
const file =
|
|
11286
|
+
const file = join9(
|
|
9275
11287
|
scopeDir({ homeDir: this.homeDir, scope, projectRoot: this.projectRoot }),
|
|
9276
11288
|
MEMORY_INDEX_FILE
|
|
9277
11289
|
);
|
|
9278
|
-
if (!
|
|
11290
|
+
if (!existsSync8(file)) return null;
|
|
9279
11291
|
let raw;
|
|
9280
11292
|
try {
|
|
9281
11293
|
raw = readFileSync9(file, "utf8");
|
|
@@ -9293,7 +11305,7 @@ var MemoryStore = class {
|
|
|
9293
11305
|
/** Read one memory file's body (frontmatter stripped). Throws if missing. */
|
|
9294
11306
|
read(scope, name) {
|
|
9295
11307
|
const file = this.pathFor(scope, name);
|
|
9296
|
-
if (!
|
|
11308
|
+
if (!existsSync8(file)) {
|
|
9297
11309
|
throw new Error(`memory not found: scope=${scope} name=${name}`);
|
|
9298
11310
|
}
|
|
9299
11311
|
const raw = readFileSync9(file, "utf8");
|
|
@@ -9318,10 +11330,10 @@ var MemoryStore = class {
|
|
|
9318
11330
|
const scopes = this.projectRoot ? ["global", "project"] : ["global"];
|
|
9319
11331
|
for (const scope of scopes) {
|
|
9320
11332
|
const dir = scopeDir({ homeDir: this.homeDir, scope, projectRoot: this.projectRoot });
|
|
9321
|
-
if (!
|
|
11333
|
+
if (!existsSync8(dir)) continue;
|
|
9322
11334
|
let entries;
|
|
9323
11335
|
try {
|
|
9324
|
-
entries =
|
|
11336
|
+
entries = readdirSync5(dir);
|
|
9325
11337
|
} catch {
|
|
9326
11338
|
continue;
|
|
9327
11339
|
}
|
|
@@ -9356,10 +11368,10 @@ var MemoryStore = class {
|
|
|
9356
11368
|
if (input.priority) entry.priority = input.priority;
|
|
9357
11369
|
if (input.expires) entry.expires = input.expires;
|
|
9358
11370
|
const dir = this.dir(input.scope);
|
|
9359
|
-
const file =
|
|
11371
|
+
const file = join9(dir, `${name}.md`);
|
|
9360
11372
|
const content = `${formatFrontmatter(entry)}${body}
|
|
9361
11373
|
`;
|
|
9362
|
-
|
|
11374
|
+
writeFileSync5(file, content, "utf8");
|
|
9363
11375
|
this.regenerateIndex(input.scope);
|
|
9364
11376
|
return file;
|
|
9365
11377
|
}
|
|
@@ -9369,25 +11381,25 @@ var MemoryStore = class {
|
|
|
9369
11381
|
throw new Error("cannot delete project-scoped memory: no projectRoot configured");
|
|
9370
11382
|
}
|
|
9371
11383
|
const file = this.pathFor(scope, rawName);
|
|
9372
|
-
if (!
|
|
9373
|
-
|
|
11384
|
+
if (!existsSync8(file)) return false;
|
|
11385
|
+
unlinkSync3(file);
|
|
9374
11386
|
this.regenerateIndex(scope);
|
|
9375
11387
|
return true;
|
|
9376
11388
|
}
|
|
9377
11389
|
/** Sorted by name — same file set must produce byte-identical MEMORY.md for stable prefix hashing. */
|
|
9378
11390
|
regenerateIndex(scope) {
|
|
9379
11391
|
const dir = scopeDir({ homeDir: this.homeDir, scope, projectRoot: this.projectRoot });
|
|
9380
|
-
if (!
|
|
11392
|
+
if (!existsSync8(dir)) return;
|
|
9381
11393
|
let files;
|
|
9382
11394
|
try {
|
|
9383
|
-
files =
|
|
11395
|
+
files = readdirSync5(dir);
|
|
9384
11396
|
} catch {
|
|
9385
11397
|
return;
|
|
9386
11398
|
}
|
|
9387
11399
|
const mdFiles = files.filter((f) => f !== MEMORY_INDEX_FILE && f.endsWith(".md")).sort((a, b) => a.localeCompare(b));
|
|
9388
|
-
const indexPath =
|
|
11400
|
+
const indexPath = join9(dir, MEMORY_INDEX_FILE);
|
|
9389
11401
|
if (mdFiles.length === 0) {
|
|
9390
|
-
if (
|
|
11402
|
+
if (existsSync8(indexPath)) unlinkSync3(indexPath);
|
|
9391
11403
|
return;
|
|
9392
11404
|
}
|
|
9393
11405
|
const lines = [];
|
|
@@ -9400,13 +11412,13 @@ var MemoryStore = class {
|
|
|
9400
11412
|
lines.push(`- [${name}](${name}.md) \u2014 (malformed, check frontmatter)`);
|
|
9401
11413
|
}
|
|
9402
11414
|
}
|
|
9403
|
-
|
|
11415
|
+
writeFileSync5(indexPath, `${lines.join("\n")}
|
|
9404
11416
|
`, "utf8");
|
|
9405
11417
|
}
|
|
9406
11418
|
};
|
|
9407
|
-
function readGlobalReasonixMemory(homeDir =
|
|
9408
|
-
const path2 =
|
|
9409
|
-
if (!
|
|
11419
|
+
function readGlobalReasonixMemory(homeDir = join9(homedir7(), ".reasonix")) {
|
|
11420
|
+
const path2 = join9(homeDir, "REASONIX.md");
|
|
11421
|
+
if (!existsSync8(path2)) return null;
|
|
9410
11422
|
let raw;
|
|
9411
11423
|
try {
|
|
9412
11424
|
raw = readFileSync9(path2, "utf8");
|
|
@@ -9423,7 +11435,7 @@ function readGlobalReasonixMemory(homeDir = join8(homedir6(), ".reasonix")) {
|
|
|
9423
11435
|
}
|
|
9424
11436
|
function applyGlobalReasonixMemory(basePrompt, homeDir) {
|
|
9425
11437
|
if (!memoryEnabled()) return basePrompt;
|
|
9426
|
-
const dir = homeDir ??
|
|
11438
|
+
const dir = homeDir ?? join9(homedir7(), ".reasonix");
|
|
9427
11439
|
const mem = readGlobalReasonixMemory(dir);
|
|
9428
11440
|
if (!mem) return basePrompt;
|
|
9429
11441
|
return [
|
|
@@ -9438,6 +11450,39 @@ function applyGlobalReasonixMemory(basePrompt, homeDir) {
|
|
|
9438
11450
|
"```"
|
|
9439
11451
|
].join("\n");
|
|
9440
11452
|
}
|
|
11453
|
+
function readGlobalClaudeMemory(homeDir = homedir7()) {
|
|
11454
|
+
const path2 = join9(homeDir, ".claude", "CLAUDE.md");
|
|
11455
|
+
if (!existsSync8(path2)) return null;
|
|
11456
|
+
let raw;
|
|
11457
|
+
try {
|
|
11458
|
+
raw = readFileSync9(path2, "utf8");
|
|
11459
|
+
} catch {
|
|
11460
|
+
return null;
|
|
11461
|
+
}
|
|
11462
|
+
const trimmed = raw.trim();
|
|
11463
|
+
if (!trimmed) return null;
|
|
11464
|
+
const originalChars = trimmed.length;
|
|
11465
|
+
const truncated = originalChars > 8e3;
|
|
11466
|
+
const content = truncated ? `${trimmed.slice(0, 8e3)}
|
|
11467
|
+
\u2026 (truncated ${originalChars - 8e3} chars)` : trimmed;
|
|
11468
|
+
return { path: path2, content, originalChars, truncated };
|
|
11469
|
+
}
|
|
11470
|
+
function applyGlobalClaudeMemory(basePrompt) {
|
|
11471
|
+
if (!memoryEnabled()) return basePrompt;
|
|
11472
|
+
const mem = readGlobalClaudeMemory();
|
|
11473
|
+
if (!mem) return basePrompt;
|
|
11474
|
+
return [
|
|
11475
|
+
basePrompt,
|
|
11476
|
+
"",
|
|
11477
|
+
"# Global memory (~/.claude/CLAUDE.md)",
|
|
11478
|
+
"",
|
|
11479
|
+
"Cross-project notes from your Claude Code configuration. Treat as authoritative \u2014 same level of trust as project memory.",
|
|
11480
|
+
"",
|
|
11481
|
+
"```",
|
|
11482
|
+
mem.content,
|
|
11483
|
+
"```"
|
|
11484
|
+
].join("\n");
|
|
11485
|
+
}
|
|
9441
11486
|
function effectivePriority(entry, cfg) {
|
|
9442
11487
|
if (entry.priority) return entry.priority;
|
|
9443
11488
|
return memoryTypeDefaults(entry.type, cfg).priority;
|
|
@@ -9500,9 +11545,10 @@ function applyMemoryStack(basePrompt, rootDir, opts = {}) {
|
|
|
9500
11545
|
const withProject = applyProjectMemory(basePrompt, rootDir);
|
|
9501
11546
|
const withGlobal = applyGlobalReasonixMemory(
|
|
9502
11547
|
withProject,
|
|
9503
|
-
homeDir ?
|
|
11548
|
+
homeDir ? join9(homeDir, ".reasonix") : void 0
|
|
9504
11549
|
);
|
|
9505
|
-
const
|
|
11550
|
+
const withGlobalClaude = applyGlobalClaudeMemory(withGlobal);
|
|
11551
|
+
const withMemory = applyUserMemory(withGlobalClaude, { projectRoot: rootDir, homeDir, cfg });
|
|
9506
11552
|
const customSkillPaths = cfg?.skills?.paths ? resolveSkillPaths(cfg.skills.paths, rootDir) : loadResolvedSkillPaths(rootDir);
|
|
9507
11553
|
return applySkillsIndex(withMemory, { projectRoot: rootDir, homeDir, customSkillPaths });
|
|
9508
11554
|
}
|
|
@@ -9513,7 +11559,7 @@ import * as pathMod6 from "path";
|
|
|
9513
11559
|
import picomatch3 from "picomatch";
|
|
9514
11560
|
|
|
9515
11561
|
// src/code/file-encoding.ts
|
|
9516
|
-
import { promises as fsp, readFileSync as readFileSync10, writeFileSync as
|
|
11562
|
+
import { promises as fsp, readFileSync as readFileSync10, writeFileSync as writeFileSync6 } from "fs";
|
|
9517
11563
|
import iconv from "iconv-lite";
|
|
9518
11564
|
var UTF8_BOM = Buffer.from([239, 187, 191]);
|
|
9519
11565
|
function decodeFileBuffer(buf) {
|
|
@@ -9542,21 +11588,21 @@ function encodeFile(text, encoding) {
|
|
|
9542
11588
|
}
|
|
9543
11589
|
|
|
9544
11590
|
// src/memory/subdir.ts
|
|
9545
|
-
import { existsSync as
|
|
9546
|
-
import { dirname as dirname5, join as
|
|
11591
|
+
import { existsSync as existsSync9, readFileSync as readFileSync11 } from "fs";
|
|
11592
|
+
import { dirname as dirname5, join as join10, relative as relative3, resolve as resolve7 } from "path";
|
|
9547
11593
|
function findDirMemory(absDir, rootDir) {
|
|
9548
|
-
const root =
|
|
9549
|
-
const target =
|
|
9550
|
-
const rel =
|
|
11594
|
+
const root = resolve7(rootDir);
|
|
11595
|
+
const target = resolve7(absDir);
|
|
11596
|
+
const rel = relative3(root, target);
|
|
9551
11597
|
if (rel.startsWith("..")) return [];
|
|
9552
11598
|
const found = [];
|
|
9553
11599
|
let cur = target;
|
|
9554
11600
|
while (cur !== root) {
|
|
9555
|
-
const r =
|
|
11601
|
+
const r = relative3(root, cur);
|
|
9556
11602
|
if (!r || r.startsWith("..")) break;
|
|
9557
11603
|
for (const name of PROJECT_MEMORY_FILES) {
|
|
9558
|
-
const path2 =
|
|
9559
|
-
if (
|
|
11604
|
+
const path2 = join10(cur, name);
|
|
11605
|
+
if (existsSync9(path2)) {
|
|
9560
11606
|
found.push(path2);
|
|
9561
11607
|
break;
|
|
9562
11608
|
}
|
|
@@ -9568,7 +11614,7 @@ function findDirMemory(absDir, rootDir) {
|
|
|
9568
11614
|
return found;
|
|
9569
11615
|
}
|
|
9570
11616
|
function findSubdirMemoryAncestors(absPath, rootDir) {
|
|
9571
|
-
return findDirMemory(dirname5(
|
|
11617
|
+
return findDirMemory(dirname5(resolve7(absPath)), rootDir);
|
|
9572
11618
|
}
|
|
9573
11619
|
function readSubdirMemoryContent(path2) {
|
|
9574
11620
|
let raw;
|
|
@@ -10061,7 +12107,7 @@ var RegexRunner = class {
|
|
|
10061
12107
|
this.defaultTimeoutMs = opts.defaultTimeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
10062
12108
|
}
|
|
10063
12109
|
testLines(text, source, flags, opts = {}) {
|
|
10064
|
-
return new Promise((
|
|
12110
|
+
return new Promise((resolve16, reject) => {
|
|
10065
12111
|
if (opts.signal?.aborted) {
|
|
10066
12112
|
reject(new Error("regex evaluation aborted"));
|
|
10067
12113
|
return;
|
|
@@ -10074,7 +12120,7 @@ var RegexRunner = class {
|
|
|
10074
12120
|
this.killWorker();
|
|
10075
12121
|
reject(new Error(`regex evaluation exceeded ${timeoutMs}ms`));
|
|
10076
12122
|
}, timeoutMs);
|
|
10077
|
-
const entry = { resolve:
|
|
12123
|
+
const entry = { resolve: resolve16, reject, timer };
|
|
10078
12124
|
if (opts.signal) {
|
|
10079
12125
|
entry.signal = opts.signal;
|
|
10080
12126
|
entry.onAbort = () => {
|
|
@@ -10205,6 +12251,7 @@ async function searchFiles(ctx, startAbs, args) {
|
|
|
10205
12251
|
var MAX_HITS_PER_FILE = 30;
|
|
10206
12252
|
var SUMMARY_MODE_TRIGGER_RATIO = 0.8;
|
|
10207
12253
|
var WALK_DEADLINE_MS = 12e4;
|
|
12254
|
+
var REGEX_METACHARS = /[\\.+*?()[\]{}|^$]/;
|
|
10208
12255
|
async function searchContent(ctx, startAbs, args) {
|
|
10209
12256
|
throwIfAborted(args.signal);
|
|
10210
12257
|
const caseSensitive = args.case_sensitive === true;
|
|
@@ -10212,12 +12259,15 @@ async function searchContent(ctx, startAbs, args) {
|
|
|
10212
12259
|
const ctxLines = Math.max(0, Math.min(20, Math.floor(args.context ?? 0)));
|
|
10213
12260
|
const summaryOnly = args.summary_only === true;
|
|
10214
12261
|
const reFlags = caseSensitive ? "" : "i";
|
|
12262
|
+
const hasMeta = REGEX_METACHARS.test(args.pattern);
|
|
10215
12263
|
let reSource = null;
|
|
10216
|
-
|
|
10217
|
-
|
|
10218
|
-
|
|
10219
|
-
|
|
10220
|
-
|
|
12264
|
+
if (hasMeta) {
|
|
12265
|
+
try {
|
|
12266
|
+
new RegExp(args.pattern, reFlags);
|
|
12267
|
+
reSource = args.pattern;
|
|
12268
|
+
} catch {
|
|
12269
|
+
reSource = null;
|
|
12270
|
+
}
|
|
10221
12271
|
}
|
|
10222
12272
|
const needle = caseSensitive ? args.pattern : args.pattern.toLowerCase();
|
|
10223
12273
|
const matches = [];
|
|
@@ -10306,9 +12356,10 @@ async function searchContent(ctx, startAbs, args) {
|
|
|
10306
12356
|
if (firstNul !== -1 && firstNul < 8 * 1024) continue;
|
|
10307
12357
|
const text = raw.toString("utf8");
|
|
10308
12358
|
const rel = displayRel3(ctx.rootDir, full);
|
|
10309
|
-
const lines = text.split(/\r?\n/);
|
|
10310
12359
|
let hits;
|
|
12360
|
+
let lines;
|
|
10311
12361
|
if (reSource !== null) {
|
|
12362
|
+
lines = text.split(/\r?\n/);
|
|
10312
12363
|
try {
|
|
10313
12364
|
hits = await getRegexRunner().testLines(text, reSource, reFlags, {
|
|
10314
12365
|
signal: args.signal
|
|
@@ -10320,9 +12371,14 @@ async function searchContent(ctx, startAbs, args) {
|
|
|
10320
12371
|
continue;
|
|
10321
12372
|
}
|
|
10322
12373
|
} else {
|
|
12374
|
+
const haystack = caseSensitive ? text : text.toLowerCase();
|
|
12375
|
+
if (haystack.indexOf(needle) === -1) {
|
|
12376
|
+
scanned++;
|
|
12377
|
+
continue;
|
|
12378
|
+
}
|
|
12379
|
+
lines = text.split(/\r?\n/);
|
|
10323
12380
|
hits = [];
|
|
10324
12381
|
for (let li = 0; li < lines.length; li++) {
|
|
10325
|
-
throwIfAborted(args.signal);
|
|
10326
12382
|
const lineForCheck = caseSensitive ? lines[li] : lines[li].toLowerCase();
|
|
10327
12383
|
if (lineForCheck.includes(needle)) hits.push(li);
|
|
10328
12384
|
}
|
|
@@ -10530,6 +12586,7 @@ ${body}`;
|
|
|
10530
12586
|
registry.register({
|
|
10531
12587
|
name: "read_file",
|
|
10532
12588
|
parallelSafe: true,
|
|
12589
|
+
skipTruncationSave: true,
|
|
10533
12590
|
description: `Read a file under the sandbox root. Default returns FULL CONTENT for files \u2264 ${Math.round(DEFAULT_OUTLINE_THRESHOLD_BYTES / 1024)} KiB. Optional scoping: head/tail (N lines), range "A-B" (1-indexed inclusive). Larger files auto-switch to outline mode (metadata + head + symbol outline for TS/JS/Python/Go/Rust/Markdown/Protobuf/text) \u2014 drill in with range or search_content. Files over ${Math.round(HARD_MAX_FILE_BYTES / (1024 * 1024))} MiB and binaries are refused \u2014 use get_file_info for stat.`,
|
|
10534
12591
|
readOnly: true,
|
|
10535
12592
|
stormExempt: true,
|
|
@@ -10627,6 +12684,7 @@ ${slice.join("\n")}`);
|
|
|
10627
12684
|
registry.register({
|
|
10628
12685
|
name: "list_directory",
|
|
10629
12686
|
parallelSafe: true,
|
|
12687
|
+
skipTruncationSave: true,
|
|
10630
12688
|
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.",
|
|
10631
12689
|
readOnly: true,
|
|
10632
12690
|
stormExempt: true,
|
|
@@ -10649,6 +12707,7 @@ ${slice.join("\n")}`);
|
|
|
10649
12707
|
registry.register({
|
|
10650
12708
|
name: "directory_tree",
|
|
10651
12709
|
parallelSafe: true,
|
|
12710
|
+
skipTruncationSave: true,
|
|
10652
12711
|
description: `Recursively list entries with indented tree structure (dirs marked '/'). Budget-aware: maxDepth defaults to 2, large subtrees (>50 children) auto-collapse to "[N hidden \u2014 list_directory to inspect]", and ${[...SKIP_DIR_NAMES].sort().join(" / ")} are skipped unless include_deps:true. For single-level use list_directory; for path lookups use search_files; for code lookups use search_content.`,
|
|
10653
12712
|
readOnly: true,
|
|
10654
12713
|
parameters: {
|
|
@@ -10724,6 +12783,7 @@ ${slice.join("\n")}`);
|
|
|
10724
12783
|
registry.register({
|
|
10725
12784
|
name: "search_files",
|
|
10726
12785
|
parallelSafe: true,
|
|
12786
|
+
skipTruncationSave: true,
|
|
10727
12787
|
description: "Find files whose NAME matches a substring or regex. Case-insensitive. Walks the directory recursively under the sandbox root. Returns one path per line. Skips dependency / VCS / build directories (node_modules, .git, dist, build, .next, target, .venv) by default.",
|
|
10728
12788
|
readOnly: true,
|
|
10729
12789
|
parameters: {
|
|
@@ -10750,6 +12810,7 @@ ${slice.join("\n")}`);
|
|
|
10750
12810
|
registry.register({
|
|
10751
12811
|
name: "search_content",
|
|
10752
12812
|
parallelSafe: true,
|
|
12813
|
+
skipTruncationSave: true,
|
|
10753
12814
|
description: "Recursively grep file CONTENTS for a substring or regex \u2014 'where is X called', 'what files contain Y'. Returns one match per line as `path:line: text`. Per-file hit cap 30; when the byte budget is mostly spent, remaining files switch to a `rel: N matches` histogram. Pass `summary_only:true` for just the histogram. Skips dependency / VCS / build dirs and binary files. For file NAMES use search_files.",
|
|
10754
12815
|
readOnly: true,
|
|
10755
12816
|
parameters: {
|
|
@@ -10801,6 +12862,7 @@ ${slice.join("\n")}`);
|
|
|
10801
12862
|
registry.register({
|
|
10802
12863
|
name: "glob",
|
|
10803
12864
|
parallelSafe: true,
|
|
12865
|
+
skipTruncationSave: true,
|
|
10804
12866
|
description: "List files matching a glob pattern, sorted by mtime (most-recently-modified first) by default. Use this for 'what changed lately', 'find all *.test.ts', 'all configs under src/'. Glob syntax matches the cross-tool standard: `*` (any chars in one segment), `**` (any segments), `?` (one char), `{a,b}` (alternation). Pattern matches against the path RELATIVE to the search root (e.g. 'src/**/*.ts' from project root). Skips node_modules / .git / dist / build / etc by default. Default limit 200; raise via `limit` (max 1000). Different from `search_files` (substring on basename) and `search_content` (matches inside file contents).",
|
|
10805
12867
|
readOnly: true,
|
|
10806
12868
|
parameters: {
|
|
@@ -10839,6 +12901,7 @@ ${slice.join("\n")}`);
|
|
|
10839
12901
|
registry.register({
|
|
10840
12902
|
name: "get_file_info",
|
|
10841
12903
|
parallelSafe: true,
|
|
12904
|
+
skipTruncationSave: true,
|
|
10842
12905
|
description: "Stat a path under the sandbox root. Returns type (file|directory|symlink), size in bytes, mtime in ISO-8601.",
|
|
10843
12906
|
readOnly: true,
|
|
10844
12907
|
parameters: {
|
|
@@ -12512,16 +14575,16 @@ ${job.output.slice(start)}`;
|
|
|
12512
14575
|
let wakeOutput = null;
|
|
12513
14576
|
if (waitFor === "output-or-exit") {
|
|
12514
14577
|
racers.push(
|
|
12515
|
-
new Promise((
|
|
12516
|
-
wakeOutput =
|
|
12517
|
-
job.outputWaiters.add(
|
|
14578
|
+
new Promise((resolve16) => {
|
|
14579
|
+
wakeOutput = resolve16;
|
|
14580
|
+
job.outputWaiters.add(resolve16);
|
|
12518
14581
|
})
|
|
12519
14582
|
);
|
|
12520
14583
|
}
|
|
12521
14584
|
let timer = null;
|
|
12522
14585
|
racers.push(
|
|
12523
|
-
new Promise((
|
|
12524
|
-
timer = setTimeout(
|
|
14586
|
+
new Promise((resolve16) => {
|
|
14587
|
+
timer = setTimeout(resolve16, timeoutMs);
|
|
12525
14588
|
})
|
|
12526
14589
|
);
|
|
12527
14590
|
await Promise.race(racers);
|
|
@@ -12643,7 +14706,7 @@ function latestOutputSince(before, after) {
|
|
|
12643
14706
|
|
|
12644
14707
|
// src/tools/shell/exec.ts
|
|
12645
14708
|
import { spawn as spawn4, spawnSync } from "child_process";
|
|
12646
|
-
import { existsSync as
|
|
14709
|
+
import { existsSync as existsSync10, statSync as statSync6 } from "fs";
|
|
12647
14710
|
import * as pathMod10 from "path";
|
|
12648
14711
|
|
|
12649
14712
|
// src/tools/shell-chain.ts
|
|
@@ -13073,9 +15136,9 @@ async function runPipeGroup(segments, opts) {
|
|
|
13073
15136
|
}
|
|
13074
15137
|
const exits = await Promise.all(
|
|
13075
15138
|
children.map(
|
|
13076
|
-
(c) => new Promise((
|
|
13077
|
-
c.once("error", () =>
|
|
13078
|
-
c.once("close", (code) =>
|
|
15139
|
+
(c) => new Promise((resolve16) => {
|
|
15140
|
+
c.once("error", () => resolve16(null));
|
|
15141
|
+
c.once("close", (code) => resolve16(code));
|
|
13079
15142
|
})
|
|
13080
15143
|
)
|
|
13081
15144
|
);
|
|
@@ -13119,7 +15182,7 @@ var OutputBuffer = class {
|
|
|
13119
15182
|
};
|
|
13120
15183
|
|
|
13121
15184
|
// src/tools/shell/parse.ts
|
|
13122
|
-
import { homedir as
|
|
15185
|
+
import { homedir as homedir8 } from "os";
|
|
13123
15186
|
import * as pathMod9 from "path";
|
|
13124
15187
|
var BUILTIN_ALLOWLIST = [
|
|
13125
15188
|
// Repo inspection
|
|
@@ -13320,12 +15383,12 @@ function resolveSensitivePath(token, projectRoot) {
|
|
|
13320
15383
|
return null;
|
|
13321
15384
|
let expanded = token;
|
|
13322
15385
|
if (expanded.startsWith("~")) {
|
|
13323
|
-
expanded = pathMod9.join(
|
|
15386
|
+
expanded = pathMod9.join(homedir8(), expanded.slice(1));
|
|
13324
15387
|
}
|
|
13325
15388
|
return pathMod9.resolve(projectRoot, expanded);
|
|
13326
15389
|
}
|
|
13327
15390
|
function expandPrefix(prefix) {
|
|
13328
|
-
if (prefix.startsWith("~")) return pathMod9.join(
|
|
15391
|
+
if (prefix.startsWith("~")) return pathMod9.join(homedir8(), prefix.slice(1));
|
|
13329
15392
|
return pathMod9.resolve(prefix);
|
|
13330
15393
|
}
|
|
13331
15394
|
function pathStartsWithPrefix(normalized, prefix) {
|
|
@@ -13498,7 +15561,7 @@ async function runCommand(cmd, opts) {
|
|
|
13498
15561
|
};
|
|
13499
15562
|
const { bin, args, spawnOverrides } = prepareSpawn(argv, { env: normalizedEnv });
|
|
13500
15563
|
const effectiveSpawnOpts = { ...spawnOpts, ...spawnOverrides };
|
|
13501
|
-
return await new Promise((
|
|
15564
|
+
return await new Promise((resolve16, reject) => {
|
|
13502
15565
|
let child;
|
|
13503
15566
|
try {
|
|
13504
15567
|
child = spawn4(bin, args, effectiveSpawnOpts);
|
|
@@ -13552,7 +15615,7 @@ async function runCommand(cmd, opts) {
|
|
|
13552
15615
|
const output = buf.length > maxChars ? `${buf.slice(0, maxChars)}
|
|
13553
15616
|
|
|
13554
15617
|
[\u2026 truncated ${buf.length - maxChars} chars \u2026]` : buf;
|
|
13555
|
-
|
|
15618
|
+
resolve16({ exitCode: code, output, timedOut });
|
|
13556
15619
|
});
|
|
13557
15620
|
});
|
|
13558
15621
|
}
|
|
@@ -13637,7 +15700,7 @@ function mergeWindowsPathLike(values, delimiter2) {
|
|
|
13637
15700
|
}
|
|
13638
15701
|
function defaultIsFile(full) {
|
|
13639
15702
|
try {
|
|
13640
|
-
return
|
|
15703
|
+
return existsSync10(full) && statSync6(full).isFile();
|
|
13641
15704
|
} catch {
|
|
13642
15705
|
return false;
|
|
13643
15706
|
}
|
|
@@ -14676,11 +16739,11 @@ ${i + 1}. ${r.title}`);
|
|
|
14676
16739
|
|
|
14677
16740
|
// src/env.ts
|
|
14678
16741
|
import { readFileSync as readFileSync12 } from "fs";
|
|
14679
|
-
import { resolve as
|
|
16742
|
+
import { resolve as resolve13 } from "path";
|
|
14680
16743
|
function loadDotenv(path2 = ".env") {
|
|
14681
16744
|
let raw;
|
|
14682
16745
|
try {
|
|
14683
|
-
raw = readFileSync12(
|
|
16746
|
+
raw = readFileSync12(resolve13(process.cwd(), path2), "utf8");
|
|
14684
16747
|
} catch {
|
|
14685
16748
|
return;
|
|
14686
16749
|
}
|
|
@@ -15129,13 +17192,13 @@ function truncate(s, n) {
|
|
|
15129
17192
|
}
|
|
15130
17193
|
|
|
15131
17194
|
// src/mcp/client.ts
|
|
15132
|
-
import { basename as basename3, resolve as
|
|
17195
|
+
import { basename as basename3, resolve as resolve14 } from "path";
|
|
15133
17196
|
import { pathToFileURL } from "url";
|
|
15134
17197
|
|
|
15135
17198
|
// src/version.ts
|
|
15136
|
-
import { existsSync as
|
|
15137
|
-
import { homedir as
|
|
15138
|
-
import { dirname as dirname8, join as
|
|
17199
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync14, writeFileSync as writeFileSync7 } from "fs";
|
|
17200
|
+
import { homedir as homedir9 } from "os";
|
|
17201
|
+
import { dirname as dirname8, join as join15 } from "path";
|
|
15139
17202
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
15140
17203
|
var REGISTRY_URL = "https://registry.npmjs.org/reasonix/latest";
|
|
15141
17204
|
var LATEST_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -15144,8 +17207,8 @@ function readPackageVersion() {
|
|
|
15144
17207
|
try {
|
|
15145
17208
|
let dir = dirname8(fileURLToPath2(import.meta.url));
|
|
15146
17209
|
for (let i = 0; i < 6; i++) {
|
|
15147
|
-
const p =
|
|
15148
|
-
if (
|
|
17210
|
+
const p = join15(dir, "package.json");
|
|
17211
|
+
if (existsSync11(p)) {
|
|
15149
17212
|
const pkg = JSON.parse(readFileSync14(p, "utf8"));
|
|
15150
17213
|
if (pkg?.name === "reasonix" && typeof pkg.version === "string") {
|
|
15151
17214
|
return pkg.version;
|
|
@@ -15161,7 +17224,7 @@ function readPackageVersion() {
|
|
|
15161
17224
|
}
|
|
15162
17225
|
var VERSION = readPackageVersion();
|
|
15163
17226
|
function cachePath(homeDirOverride) {
|
|
15164
|
-
return
|
|
17227
|
+
return join15(homeDirOverride ?? homedir9(), ".reasonix", "version-cache.json");
|
|
15165
17228
|
}
|
|
15166
17229
|
function readCache(homeDirOverride) {
|
|
15167
17230
|
try {
|
|
@@ -15177,8 +17240,8 @@ function readCache(homeDirOverride) {
|
|
|
15177
17240
|
function writeCache(entry, homeDirOverride) {
|
|
15178
17241
|
try {
|
|
15179
17242
|
const p = cachePath(homeDirOverride);
|
|
15180
|
-
|
|
15181
|
-
|
|
17243
|
+
mkdirSync6(dirname8(p), { recursive: true });
|
|
17244
|
+
writeFileSync7(p, JSON.stringify(entry), "utf8");
|
|
15182
17245
|
} catch {
|
|
15183
17246
|
}
|
|
15184
17247
|
}
|
|
@@ -15285,7 +17348,7 @@ var McpClient = class {
|
|
|
15285
17348
|
this.clientInfo = opts.clientInfo ?? { name: "reasonix", version: VERSION };
|
|
15286
17349
|
const workspaceDir = opts.workspaceDir?.trim();
|
|
15287
17350
|
if (workspaceDir) {
|
|
15288
|
-
this.workspaceDir =
|
|
17351
|
+
this.workspaceDir = resolve14(workspaceDir);
|
|
15289
17352
|
this.workspaceRoot = {
|
|
15290
17353
|
uri: pathToFileURL(this.workspaceDir).href,
|
|
15291
17354
|
name: basename3(this.workspaceDir) || this.workspaceDir
|
|
@@ -15408,7 +17471,7 @@ var McpClient = class {
|
|
|
15408
17471
|
const id = this.nextId++;
|
|
15409
17472
|
const frame = { jsonrpc: "2.0", id, method, params };
|
|
15410
17473
|
let abortHandler = null;
|
|
15411
|
-
const promise = new Promise((
|
|
17474
|
+
const promise = new Promise((resolve16, reject) => {
|
|
15412
17475
|
const timeout = setTimeout(() => {
|
|
15413
17476
|
this.pending.delete(id);
|
|
15414
17477
|
if (abortHandler && signal) signal.removeEventListener("abort", abortHandler);
|
|
@@ -15417,7 +17480,7 @@ var McpClient = class {
|
|
|
15417
17480
|
);
|
|
15418
17481
|
}, this.requestTimeoutMs);
|
|
15419
17482
|
this.pending.set(id, {
|
|
15420
|
-
resolve:
|
|
17483
|
+
resolve: resolve16,
|
|
15421
17484
|
reject,
|
|
15422
17485
|
timeout
|
|
15423
17486
|
});
|
|
@@ -15567,12 +17630,12 @@ var StdioTransport = class {
|
|
|
15567
17630
|
}
|
|
15568
17631
|
async send(message) {
|
|
15569
17632
|
if (this.closed) throw new Error("MCP transport is closed");
|
|
15570
|
-
return new Promise((
|
|
17633
|
+
return new Promise((resolve16, reject) => {
|
|
15571
17634
|
const line = `${JSON.stringify(message)}
|
|
15572
17635
|
`;
|
|
15573
17636
|
this.child.stdin.write(line, "utf8", (err) => {
|
|
15574
17637
|
if (err) reject(err);
|
|
15575
|
-
else
|
|
17638
|
+
else resolve16();
|
|
15576
17639
|
});
|
|
15577
17640
|
});
|
|
15578
17641
|
}
|
|
@@ -15583,8 +17646,8 @@ var StdioTransport = class {
|
|
|
15583
17646
|
continue;
|
|
15584
17647
|
}
|
|
15585
17648
|
if (this.closed) return;
|
|
15586
|
-
const next = await new Promise((
|
|
15587
|
-
this.waiters.push(
|
|
17649
|
+
const next = await new Promise((resolve16) => {
|
|
17650
|
+
this.waiters.push(resolve16);
|
|
15588
17651
|
});
|
|
15589
17652
|
if (next === null) return;
|
|
15590
17653
|
yield next;
|
|
@@ -15664,8 +17727,8 @@ var SseTransport = class {
|
|
|
15664
17727
|
constructor(opts) {
|
|
15665
17728
|
this.url = opts.url;
|
|
15666
17729
|
this.headers = opts.headers ?? {};
|
|
15667
|
-
this.endpointReady = new Promise((
|
|
15668
|
-
this.resolveEndpoint =
|
|
17730
|
+
this.endpointReady = new Promise((resolve16, reject) => {
|
|
17731
|
+
this.resolveEndpoint = resolve16;
|
|
15669
17732
|
this.rejectEndpoint = reject;
|
|
15670
17733
|
});
|
|
15671
17734
|
this.endpointReady.catch(() => void 0);
|
|
@@ -15692,8 +17755,8 @@ var SseTransport = class {
|
|
|
15692
17755
|
continue;
|
|
15693
17756
|
}
|
|
15694
17757
|
if (this.closed) return;
|
|
15695
|
-
const next = await new Promise((
|
|
15696
|
-
this.waiters.push(
|
|
17758
|
+
const next = await new Promise((resolve16) => {
|
|
17759
|
+
this.waiters.push(resolve16);
|
|
15697
17760
|
});
|
|
15698
17761
|
if (next === null) return;
|
|
15699
17762
|
yield next;
|
|
@@ -15879,8 +17942,8 @@ var StreamableHttpTransport = class {
|
|
|
15879
17942
|
continue;
|
|
15880
17943
|
}
|
|
15881
17944
|
if (this.closed) return;
|
|
15882
|
-
const next = await new Promise((
|
|
15883
|
-
this.waiters.push(
|
|
17945
|
+
const next = await new Promise((resolve16) => {
|
|
17946
|
+
this.waiters.push(resolve16);
|
|
15884
17947
|
});
|
|
15885
17948
|
if (next === null) return;
|
|
15886
17949
|
yield next;
|
|
@@ -15972,19 +18035,22 @@ async function trySection(load) {
|
|
|
15972
18035
|
|
|
15973
18036
|
// src/code/edit-blocks.ts
|
|
15974
18037
|
import {
|
|
18038
|
+
chmodSync as chmodSync4,
|
|
15975
18039
|
closeSync as closeSync2,
|
|
15976
|
-
existsSync as
|
|
18040
|
+
existsSync as existsSync12,
|
|
15977
18041
|
fstatSync,
|
|
15978
|
-
|
|
15979
|
-
mkdirSync as
|
|
18042
|
+
fsyncSync,
|
|
18043
|
+
mkdirSync as mkdirSync7,
|
|
15980
18044
|
openSync as openSync2,
|
|
15981
18045
|
readFileSync as readFileSync15,
|
|
15982
18046
|
readSync,
|
|
15983
|
-
|
|
15984
|
-
|
|
18047
|
+
realpathSync as realpathSync2,
|
|
18048
|
+
renameSync as renameSync3,
|
|
18049
|
+
unlinkSync as unlinkSync4,
|
|
18050
|
+
writeFileSync as writeFileSync8,
|
|
15985
18051
|
writeSync
|
|
15986
18052
|
} from "fs";
|
|
15987
|
-
import { dirname as dirname9, isAbsolute as isAbsolute9, relative as
|
|
18053
|
+
import { dirname as dirname9, isAbsolute as isAbsolute9, relative as relative11, resolve as resolve15 } from "path";
|
|
15988
18054
|
var BLOCK_RE = /^(\S[^\n]*)\n<{7} SEARCH\n([\s\S]*?)\n?={7}\n([\s\S]*?)\n?>{7} REPLACE/gm;
|
|
15989
18055
|
function parseEditBlocks(text) {
|
|
15990
18056
|
const out = [];
|
|
@@ -16002,15 +18068,15 @@ function parseEditBlocks(text) {
|
|
|
16002
18068
|
return out;
|
|
16003
18069
|
}
|
|
16004
18070
|
function resolveEditPath(rootDir, rawPath) {
|
|
16005
|
-
const absRoot =
|
|
18071
|
+
const absRoot = resolve15(rootDir);
|
|
16006
18072
|
if (/^[A-Za-z]:[\\/]/.test(rawPath) || looksLikeAbsoluteSystemPath2(rawPath)) {
|
|
16007
|
-
return
|
|
18073
|
+
return resolve15(rawPath);
|
|
16008
18074
|
}
|
|
16009
18075
|
let rooted = rawPath;
|
|
16010
18076
|
while (rooted.startsWith("/") || rooted.startsWith("\\")) {
|
|
16011
18077
|
rooted = rooted.slice(1);
|
|
16012
18078
|
}
|
|
16013
|
-
return
|
|
18079
|
+
return resolve15(absRoot, rooted || ".");
|
|
16014
18080
|
}
|
|
16015
18081
|
function looksLikeAbsoluteSystemPath2(rawPath) {
|
|
16016
18082
|
return /^\/(?:home|Users|etc|var|opt|tmp|usr|mnt|Library|Volumes|proc|sys|dev|run|srv|media|Applications|System|root|boot|private)(?:[/\\]|$)/.test(
|
|
@@ -16018,11 +18084,59 @@ function looksLikeAbsoluteSystemPath2(rawPath) {
|
|
|
16018
18084
|
);
|
|
16019
18085
|
}
|
|
16020
18086
|
function pathIsUnder4(child, parent) {
|
|
16021
|
-
const rel =
|
|
18087
|
+
const rel = relative11(parent, child);
|
|
16022
18088
|
return rel === "" || !rel.startsWith("..") && !isAbsolute9(rel);
|
|
16023
18089
|
}
|
|
18090
|
+
function writeAllSync(fd, buf) {
|
|
18091
|
+
let written = 0;
|
|
18092
|
+
while (written < buf.length) {
|
|
18093
|
+
const n = writeSync(fd, buf, written, buf.length - written, written);
|
|
18094
|
+
if (n <= 0) throw new Error("write returned 0 bytes before completing");
|
|
18095
|
+
written += n;
|
|
18096
|
+
}
|
|
18097
|
+
}
|
|
18098
|
+
function fsyncDirectoryBestEffort(path2) {
|
|
18099
|
+
let fd;
|
|
18100
|
+
try {
|
|
18101
|
+
fd = openSync2(path2, "r");
|
|
18102
|
+
fsyncSync(fd);
|
|
18103
|
+
} catch {
|
|
18104
|
+
} finally {
|
|
18105
|
+
if (fd !== void 0) closeSync2(fd);
|
|
18106
|
+
}
|
|
18107
|
+
}
|
|
18108
|
+
function atomicReplaceFileSync(path2, buf, mode) {
|
|
18109
|
+
const tmp = `${path2}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
18110
|
+
const permissions = mode & 4095;
|
|
18111
|
+
let fd;
|
|
18112
|
+
try {
|
|
18113
|
+
fd = openSync2(tmp, "wx", permissions);
|
|
18114
|
+
writeAllSync(fd, buf);
|
|
18115
|
+
try {
|
|
18116
|
+
chmodSync4(tmp, permissions);
|
|
18117
|
+
} catch {
|
|
18118
|
+
}
|
|
18119
|
+
fsyncSync(fd);
|
|
18120
|
+
closeSync2(fd);
|
|
18121
|
+
fd = void 0;
|
|
18122
|
+
renameSync3(tmp, path2);
|
|
18123
|
+
fsyncDirectoryBestEffort(dirname9(path2));
|
|
18124
|
+
} catch (err) {
|
|
18125
|
+
if (fd !== void 0) {
|
|
18126
|
+
try {
|
|
18127
|
+
closeSync2(fd);
|
|
18128
|
+
} catch {
|
|
18129
|
+
}
|
|
18130
|
+
}
|
|
18131
|
+
try {
|
|
18132
|
+
unlinkSync4(tmp);
|
|
18133
|
+
} catch {
|
|
18134
|
+
}
|
|
18135
|
+
throw err;
|
|
18136
|
+
}
|
|
18137
|
+
}
|
|
16024
18138
|
function applyEditBlock(block, rootDir) {
|
|
16025
|
-
const absRoot =
|
|
18139
|
+
const absRoot = resolve15(rootDir);
|
|
16026
18140
|
const absTarget = resolveEditPath(rootDir, block.path);
|
|
16027
18141
|
if (!pathIsUnder4(absTarget, absRoot)) {
|
|
16028
18142
|
return {
|
|
@@ -16034,7 +18148,7 @@ function applyEditBlock(block, rootDir) {
|
|
|
16034
18148
|
const searchEmpty = block.search.length === 0;
|
|
16035
18149
|
if (searchEmpty) {
|
|
16036
18150
|
try {
|
|
16037
|
-
|
|
18151
|
+
mkdirSync7(dirname9(absTarget), { recursive: true });
|
|
16038
18152
|
const fd = openSync2(absTarget, "wx");
|
|
16039
18153
|
try {
|
|
16040
18154
|
writeSync(fd, block.replace);
|
|
@@ -16055,9 +18169,22 @@ function applyEditBlock(block, rootDir) {
|
|
|
16055
18169
|
}
|
|
16056
18170
|
}
|
|
16057
18171
|
try {
|
|
18172
|
+
let writeTarget;
|
|
18173
|
+
try {
|
|
18174
|
+
writeTarget = realpathSync2(absTarget);
|
|
18175
|
+
} catch (err) {
|
|
18176
|
+
if (err.code === "ENOENT") {
|
|
18177
|
+
return {
|
|
18178
|
+
path: block.path,
|
|
18179
|
+
status: "file-missing",
|
|
18180
|
+
message: "file does not exist; to create it, use an empty SEARCH block"
|
|
18181
|
+
};
|
|
18182
|
+
}
|
|
18183
|
+
throw err;
|
|
18184
|
+
}
|
|
16058
18185
|
let fd;
|
|
16059
18186
|
try {
|
|
16060
|
-
fd = openSync2(
|
|
18187
|
+
fd = openSync2(writeTarget, "r+");
|
|
16061
18188
|
} catch (err) {
|
|
16062
18189
|
if (err.code === "ENOENT") {
|
|
16063
18190
|
return {
|
|
@@ -16098,17 +18225,12 @@ function applyEditBlock(block, rootDir) {
|
|
|
16098
18225
|
};
|
|
16099
18226
|
}
|
|
16100
18227
|
const replaced = `${content.slice(0, idx)}${adaptedReplace}${content.slice(idx + adaptedSearch.length)}`;
|
|
16101
|
-
|
|
16102
|
-
|
|
16103
|
-
|
|
16104
|
-
while (written < outBuf.length) {
|
|
16105
|
-
const n = writeSync(fd, outBuf, written, outBuf.length - written, written);
|
|
16106
|
-
if (n <= 0) break;
|
|
16107
|
-
written += n;
|
|
16108
|
-
}
|
|
18228
|
+
closeSync2(fd);
|
|
18229
|
+
fd = void 0;
|
|
18230
|
+
atomicReplaceFileSync(writeTarget, encodeFile(replaced, encoding), stat2.mode);
|
|
16109
18231
|
return { path: block.path, status: "applied" };
|
|
16110
18232
|
} finally {
|
|
16111
|
-
closeSync2(fd);
|
|
18233
|
+
if (fd !== void 0) closeSync2(fd);
|
|
16112
18234
|
}
|
|
16113
18235
|
} catch (err) {
|
|
16114
18236
|
return { path: block.path, status: "error", message: err.message };
|
|
@@ -16118,7 +18240,7 @@ function applyEditBlocks(blocks, rootDir) {
|
|
|
16118
18240
|
return blocks.map((b) => applyEditBlock(b, rootDir));
|
|
16119
18241
|
}
|
|
16120
18242
|
function snapshotBeforeEdits(blocks, rootDir) {
|
|
16121
|
-
const absRoot =
|
|
18243
|
+
const absRoot = resolve15(rootDir);
|
|
16122
18244
|
const seen = /* @__PURE__ */ new Set();
|
|
16123
18245
|
const snapshots = [];
|
|
16124
18246
|
for (const b of blocks) {
|
|
@@ -16126,7 +18248,7 @@ function snapshotBeforeEdits(blocks, rootDir) {
|
|
|
16126
18248
|
if (!pathIsUnder4(abs, absRoot)) continue;
|
|
16127
18249
|
if (seen.has(abs)) continue;
|
|
16128
18250
|
seen.add(abs);
|
|
16129
|
-
if (!
|
|
18251
|
+
if (!existsSync12(abs)) {
|
|
16130
18252
|
snapshots.push({ path: b.path, prevContent: null });
|
|
16131
18253
|
continue;
|
|
16132
18254
|
}
|
|
@@ -16140,7 +18262,7 @@ function snapshotBeforeEdits(blocks, rootDir) {
|
|
|
16140
18262
|
return snapshots;
|
|
16141
18263
|
}
|
|
16142
18264
|
function restoreSnapshots(snapshots, rootDir) {
|
|
16143
|
-
const absRoot =
|
|
18265
|
+
const absRoot = resolve15(rootDir);
|
|
16144
18266
|
return snapshots.map((snap) => {
|
|
16145
18267
|
const abs = resolveEditPath(rootDir, snap.path);
|
|
16146
18268
|
if (!pathIsUnder4(abs, absRoot)) {
|
|
@@ -16152,14 +18274,14 @@ function restoreSnapshots(snapshots, rootDir) {
|
|
|
16152
18274
|
}
|
|
16153
18275
|
try {
|
|
16154
18276
|
if (snap.prevContent === null) {
|
|
16155
|
-
if (
|
|
18277
|
+
if (existsSync12(abs)) unlinkSync4(abs);
|
|
16156
18278
|
return {
|
|
16157
18279
|
path: snap.path,
|
|
16158
18280
|
status: "applied",
|
|
16159
18281
|
message: "removed (the edit had created it)"
|
|
16160
18282
|
};
|
|
16161
18283
|
}
|
|
16162
|
-
|
|
18284
|
+
writeFileSync8(abs, encodeFile(snap.prevContent, snap.prevEncoding ?? "utf8"));
|
|
16163
18285
|
return {
|
|
16164
18286
|
path: snap.path,
|
|
16165
18287
|
status: "applied",
|
|
@@ -16175,8 +18297,8 @@ function lineEndingOf(text) {
|
|
|
16175
18297
|
}
|
|
16176
18298
|
|
|
16177
18299
|
// src/code/prompt.ts
|
|
16178
|
-
import { existsSync as
|
|
16179
|
-
import { join as
|
|
18300
|
+
import { existsSync as existsSync13, readFileSync as readFileSync16 } from "fs";
|
|
18301
|
+
import { join as join16 } from "path";
|
|
16180
18302
|
var DEFAULT_CODE_MODEL = "deepseek-v4-flash";
|
|
16181
18303
|
function codeSystemBase(modelId) {
|
|
16182
18304
|
return CODE_SYSTEM_TEMPLATE.replace("__ESCALATION_CONTRACT__", escalationContract(modelId));
|
|
@@ -16305,9 +18427,9 @@ function codeSystemPrompt(rootDir, opts = {}) {
|
|
|
16305
18427
|
const codeBase = codeSystemBase(opts.modelId ?? DEFAULT_CODE_MODEL);
|
|
16306
18428
|
const base = opts.hasSemanticSearch ? `${codeBase}${SEMANTIC_SEARCH_ROUTING}` : codeBase;
|
|
16307
18429
|
const withMemory = applyMemoryStack(base, rootDir);
|
|
16308
|
-
const gitignorePath =
|
|
18430
|
+
const gitignorePath = join16(rootDir, ".gitignore");
|
|
16309
18431
|
let result = withMemory;
|
|
16310
|
-
if (
|
|
18432
|
+
if (existsSync13(gitignorePath)) {
|
|
16311
18433
|
let content;
|
|
16312
18434
|
try {
|
|
16313
18435
|
content = readFileSync16(gitignorePath, "utf8");
|
|
@@ -16344,21 +18466,21 @@ ${appendParts.join("\n\n")}`;
|
|
|
16344
18466
|
import {
|
|
16345
18467
|
appendFileSync as appendFileSync2,
|
|
16346
18468
|
closeSync as closeSync3,
|
|
16347
|
-
existsSync as
|
|
18469
|
+
existsSync as existsSync14,
|
|
16348
18470
|
fstatSync as fstatSync2,
|
|
16349
|
-
mkdirSync as
|
|
18471
|
+
mkdirSync as mkdirSync8,
|
|
16350
18472
|
openSync as openSync3,
|
|
16351
18473
|
readFileSync as readFileSync17,
|
|
16352
18474
|
readSync as readSync2,
|
|
16353
|
-
renameSync as
|
|
16354
|
-
statSync as
|
|
16355
|
-
unlinkSync as
|
|
16356
|
-
writeFileSync as
|
|
18475
|
+
renameSync as renameSync4,
|
|
18476
|
+
statSync as statSync7,
|
|
18477
|
+
unlinkSync as unlinkSync5,
|
|
18478
|
+
writeFileSync as writeFileSync9
|
|
16357
18479
|
} from "fs";
|
|
16358
|
-
import { homedir as
|
|
16359
|
-
import { dirname as dirname10, join as
|
|
18480
|
+
import { homedir as homedir10 } from "os";
|
|
18481
|
+
import { dirname as dirname10, join as join17 } from "path";
|
|
16360
18482
|
function defaultUsageLogPath(homeDirOverride) {
|
|
16361
|
-
return
|
|
18483
|
+
return join17(homeDirOverride ?? homedir10(), ".reasonix", "usage.jsonl");
|
|
16362
18484
|
}
|
|
16363
18485
|
var USAGE_COMPACTION_THRESHOLD_BYTES = 5 * 1024 * 1024;
|
|
16364
18486
|
var USAGE_RETENTION_DAYS = 365;
|
|
@@ -16397,12 +18519,12 @@ function compactUsageLogIfLarge(path2, now) {
|
|
|
16397
18519
|
if (kept.length === lines.filter((l) => l.trim()).length) return;
|
|
16398
18520
|
const tmp = `${path2}.compacting`;
|
|
16399
18521
|
try {
|
|
16400
|
-
|
|
18522
|
+
writeFileSync9(tmp, kept.length > 0 ? `${kept.join("\n")}
|
|
16401
18523
|
` : "", "utf8");
|
|
16402
|
-
|
|
18524
|
+
renameSync4(tmp, path2);
|
|
16403
18525
|
} catch {
|
|
16404
18526
|
try {
|
|
16405
|
-
|
|
18527
|
+
unlinkSync5(tmp);
|
|
16406
18528
|
} catch {
|
|
16407
18529
|
}
|
|
16408
18530
|
}
|
|
@@ -16423,7 +18545,7 @@ function appendUsage(input) {
|
|
|
16423
18545
|
if (input.subagent) record.subagent = input.subagent;
|
|
16424
18546
|
const path2 = input.path ?? defaultUsageLogPath();
|
|
16425
18547
|
try {
|
|
16426
|
-
|
|
18548
|
+
mkdirSync8(dirname10(path2), { recursive: true });
|
|
16427
18549
|
appendFileSync2(path2, `${JSON.stringify(record)}
|
|
16428
18550
|
`, "utf8");
|
|
16429
18551
|
compactUsageLogIfLarge(path2, record.ts);
|
|
@@ -16432,7 +18554,7 @@ function appendUsage(input) {
|
|
|
16432
18554
|
return record;
|
|
16433
18555
|
}
|
|
16434
18556
|
function readUsageLog(path2 = defaultUsageLogPath()) {
|
|
16435
|
-
if (!
|
|
18557
|
+
if (!existsSync14(path2)) return [];
|
|
16436
18558
|
let raw;
|
|
16437
18559
|
try {
|
|
16438
18560
|
raw = readFileSync17(path2, "utf8");
|
|
@@ -16542,9 +18664,9 @@ function aggregateUsage(records, opts = {}) {
|
|
|
16542
18664
|
};
|
|
16543
18665
|
}
|
|
16544
18666
|
function formatLogSize(path2 = defaultUsageLogPath()) {
|
|
16545
|
-
if (!
|
|
18667
|
+
if (!existsSync14(path2)) return "";
|
|
16546
18668
|
try {
|
|
16547
|
-
const s =
|
|
18669
|
+
const s = statSync7(path2);
|
|
16548
18670
|
const bytes = s.size;
|
|
16549
18671
|
if (bytes < 1024) return `${bytes} B`;
|
|
16550
18672
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|